Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
live-management-web
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
haojie
live-management-web
Commits
4bb22ea8
Commit
4bb22ea8
authored
Aug 16, 2023
by
haojie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
动作
parent
ebbd8963
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
789 additions
and
339 deletions
+789
-339
src/components/MultipleUpload/index.less
+1
-1
src/components/MultipleUpload/index.tsx
+1
-0
src/components/Select.vue
+21
-2
src/components/radio/index.less
+36
-0
src/components/radio/index.tsx
+45
-0
src/hooks/useScript.ts
+41
-39
src/pages/InteractiveResponse/index.vue
+0
-6
src/pages/OnlyVideoLive/index.vue
+5
-7
src/pages/createAction/components/createSuccess/index.tsx
+1
-1
src/pages/createAction/index.tsx
+6
-4
src/pages/createLive/components/TextScriptDialog.vue
+74
-2
src/pages/createLive/components/audioScriptDialog.vue
+200
-0
src/pages/createLive/components/scripts.vue
+153
-108
src/pages/createLive/index.vue
+32
-99
src/pages/home/index.vue
+3
-1
src/pages/startLive/index.vue
+0
-6
src/service/Common.ts
+5
-4
src/service/CreateLive.ts
+155
-57
src/utils/tool.ts
+10
-2
No files found.
src/components/MultipleUpload/index.less
View file @
4bb22ea8
...
...
@@ -22,7 +22,7 @@
justify-content: space-between;
align-items: center;
.custom-real-upload-component {
width: 572px;
//
width: 572px;
height: 200px;
overflow-y: auto;
overflow-x: hidden;
...
...
src/components/MultipleUpload/index.tsx
View file @
4bb22ea8
...
...
@@ -237,6 +237,7 @@ export default defineComponent({
url
:
''
,
ref
:
null
,
});
Curfile
.
status
=
1
;
openpercentage
();
return
alyOssUpload
(
props
.
config
,
file
,
UploadSuccessCallback
,
UploadErrorCallback
,
uuid
);
};
...
...
src/components/Select.vue
View file @
4bb22ea8
...
...
@@ -5,6 +5,8 @@
:autoWidth=
"autoWidth"
:placeholder=
"placeholder"
:multiple=
"multiple"
:align=
"align"
:clearable=
"clear"
@
change=
"SelectChange"
:popupProps=
"
{
overlayClassName: [className, 'custom-select-popup'],
...
...
@@ -27,12 +29,16 @@ const props = withDefaults(
className
?:
string
;
autoWidth
?:
boolean
;
multiple
?:
boolean
;
align
?:
string
;
clear
?:
boolean
;
}
>
(),
{
width
:
'50%'
,
placeholder
:
'请选择'
,
autoWidth
:
true
,
multiple
:
false
,
align
:
'left'
,
clear
:
false
,
},
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'change'
]);
...
...
@@ -41,7 +47,11 @@ const SelectValue = ref(props.modelValue);
watch
(
()
=>
SelectValue
.
value
,
(
v
)
=>
{
emit
(
'update:modelValue'
,
v
);
if
(
v
)
{
emit
(
'update:modelValue'
,
v
);
}
else
{
emit
(
'update:modelValue'
,
''
);
}
},
);
watch
(
...
...
@@ -117,13 +127,22 @@ const SelectChange = (value: string | any) => {
background-color
:
#181818
;
border
:
none
;
border-radius
:
8px
;
.t-input__clear
{
.t-icon
{
color
:
#00dddd
;
}
}
.t-input__inner
{
text-align
:
center
;
color
:
#ffffff
;
&::placeholder
{
color
:
#888fa1
;
}
}
&
:hover
{
.t-fake-arrow
{
color
:
#00dddd
;
}
}
}
.t-is-focused
{
box-shadow
:
0px
0px
0px
1px
#00dddd
;
...
...
src/components/radio/index.less
0 → 100644
View file @
4bb22ea8
@import '@/style/variables';
.c-radio-group {
.da();
.default-radio {
.da();
.dot {
border-radius: 50%;
border: 1px solid #9f9f9f;
background: transparent;
width: 18px;
height: 18px;
cursor: pointer;
transition: all 0.2s;
}
.group-label {
font-size: @size-13;
color: #b4b4b4;
margin-left: 6px;
transition: all 0.2s;
}
}
.default-radio + .default-radio {
margin-left: 12px;
}
.radio-active {
.dot {
border-color: #04ae8a;
background: #04ae8a;
transition: all 0.2s;
}
.group-label {
color: #04ae8a;
transition: all 0.2s;
}
}
}
src/components/radio/index.tsx
0 → 100644
View file @
4bb22ea8
import
'./index.less'
;
import
{
computed
,
defineComponent
}
from
'vue'
;
export
default
defineComponent
({
props
:
{
modelValue
:
[
String
,
Number
],
list
:
{
type
:
Array
,
default
:
()
=>
[],
},
cancel
:
{
type
:
Boolean
,
default
:
false
,
},
},
emits
:
[
'update:modelValue'
],
setup
(
props
,
{
emit
})
{
const
currentValue
=
computed
({
get
()
{
return
props
.
modelValue
;
},
set
(
value
)
{
if
(
props
.
cancel
&&
currentValue
.
value
==
value
)
{
emit
(
'update:modelValue'
,
''
);
}
else
{
emit
(
'update:modelValue'
,
value
);
}
},
});
const
groupEvent
=
(
item
:
any
)
=>
{
currentValue
.
value
=
item
.
value
;
};
return
()
=>
(
<
div
class=
"c-radio-group"
>
{
props
.
list
.
map
((
item
:
any
)
=>
(
<
div
key=
{
item
.
value
}
class=
{
[
'default-radio'
,
currentValue
.
value
==
item
.
value
?
'radio-active'
:
''
]
}
>
<
div
class=
"dot"
onClick=
{
groupEvent
.
bind
(
this
,
item
)
}
></
div
>
<
div
class=
"group-label"
>
{
item
.
label
}
</
div
>
</
div
>
))
}
</
div
>
);
},
});
src/hooks/useScript.ts
View file @
4bb22ea8
import
{
computed
,
onBeforeUnmount
,
ref
,
watch
}
from
'vue'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
,
createLiveVersion
,
filterFiled
,
getAudioStartTimeAndEndTime
}
from
'@/service/CreateLive'
;
import
{
createLiveKeys
,
createLiveVersion
,
filterFiled
,
onAudioProcessed
}
from
'@/service/CreateLive'
;
import
{
getLiveTtsCallback
,
createLiveTask
,
liveTts
,
liveTaskRegenerate
}
from
'@/utils/api/userApi'
;
import
{
ecursionDeepCopy
,
isDev
,
show_message
}
from
'@/utils/tool'
;
import
{
TableSortAsc
,
dimensionalConvert
,
ecursionDeepCopy
,
isDev
,
show_message
}
from
'@/utils/tool'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
onUpdateLiveTask
,
audioStart
,
uploadToAly
}
from
'@/service/Common'
;
import
{
v4
}
from
'uuid'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
import
routerConfig
from
'@/router/tool'
;
import
useConfuse
from
'@/hooks/useConfuse'
;
import
CustomException
from
'@/utils/error'
;
import
{
callPyjsInWindow
,
writeLog
}
from
'@/utils/pyqt'
;
// 轮询处理文本脚本语音生成回调
...
...
@@ -45,6 +44,7 @@ export const processTextCallback = () => {
tone_id
:
item
[
createLiveKeys
.
textTones
],
content
:
list
[
i
].
content
,
uuid
:
getTaskId
(
true
),
id
:
i
,
};
// 生成音频
await
liveTts
(
params
);
...
...
@@ -125,8 +125,11 @@ export const processTextCallback = () => {
}
// 回首页
backHome
();
loading
.
value
=
false
;
return
true
;
}
loading
.
value
=
false
;
return
false
;
}
catch
(
e
)
{
writeLog
({
name
:
'更新直播失败'
,
...
...
@@ -134,6 +137,7 @@ export const processTextCallback = () => {
});
loading
.
value
=
false
;
console
.
log
(
e
);
return
false
;
}
}
};
...
...
@@ -224,18 +228,21 @@ export const processTextCallback = () => {
});
if
(
res
.
code
==
0
)
{
if
(
isDev
())
{
for
(
let
i
=
0
;
i
<
3
;
i
++
)
{
for
(
let
i
=
0
;
i
<
1
;
i
++
)
{
let
params
=
{
data
:
{
audio_address
:
'http://
nls-cloud-cn-shanghai.oss-cn-shanghai.aliyuncs.com/jupiter-flow/tmp/e56d8750eb3a44f9930f73703489acb1.wav?Expires=1692087730&OSSAccessKeyId=LTAIUpwNp2H7pBG5&Signature=FtKSld5Dn55po9GyTm%2BefRKmPqw%3D
'
,
'http://
yunyi-live.oss-cn-hangzhou.aliyuncs.com/upload/1/2023-08-16fcc74a89-d3f1-4545-a17c-d155dfa7978f.wav
'
,
task_id
:
0
,
id
:
i
,
},
};
res
.
data
.
push
(
params
);
}
}
if
(
res
.
data
.
length
)
{
// 根据id升序排列
res
.
data
=
TableSortAsc
(
res
.
data
,
'data.id'
);
console
.
log
(
'音频任务回调成功'
);
console
.
log
(
res
.
data
);
if
(
!
isConfuse
)
{
...
...
@@ -243,8 +250,8 @@ export const processTextCallback = () => {
// 关闭定时器
closeInterval
();
let
list
=
JSON
.
parse
(
JSON
.
stringify
(
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
]));
let
audio_list
=
[];
res
.
data
.
forEach
((
item
:
any
)
=>
{
for
(
let
i
=
0
;
i
<
res
.
data
.
length
;
i
++
)
{
let
item
=
res
.
data
[
i
];
// 根据task_id更新数组对象
let
data
=
item
.
data
;
if
(
...
...
@@ -252,33 +259,41 @@ export const processTextCallback = () => {
data
.
audio_address
&&
(
typeof
data
.
task_id
===
'string'
||
typeof
data
.
task_id
===
'number'
)
)
{
audio_list
.
push
(
data
.
audio_address
);
console
.
log
(
list
,
'list'
);
let
index
=
list
.
findIndex
((
it
:
any
)
=>
it
.
task_id
==
data
.
task_id
);
if
(
index
!==
-
1
)
{
list
[
index
].
audio_address
=
data
.
audio_address
;
// 音频处理
let
resultList
=
await
audioStart
([
data
.
audio_address
],
true
);
// 转一维
resultList
=
dimensionalConvert
(
resultList
);
let
newList
=
resultList
.
map
((
row
:
any
)
=>
{
return
{
content
:
row
.
content
,
movement_type
:
list
[
index
].
movement_type
,
movement_name
:
list
[
index
].
movement_name
,
};
});
// 要提交的数组
list
[
index
].
newList
=
newList
;
commitInfo
({
[
createLiveKeys
.
textScriptList
]:
list
,
});
}
else
{
console
.
log
(
'未找到对应的task_id'
);
}
}
else
{
show_message
(
'缺少音频或id'
);
}
});
// 获取音频时长
let
durationList
=
await
getAudioStartTimeAndEndTime
(
res
.
data
);
console
.
log
(
durationList
,
'不洗稿durationList'
);
if
(
!
audio_list
.
length
)
{
throw
new
CustomException
(
'没有要处理的音频'
);
}
let
resultList
=
await
audioStart
(
audio_list
,
true
);
// 修改store的type_content
commitInfo
({
[
createLiveKeys
.
textScriptValue
]:
resultList
,
});
console
.
log
(
'执行完毕,准备提交'
);
// 提交
await
submit
(
type
);
let
status
=
await
submit
(
type
);
if
(
!
status
)
{
show_message
(
'创建失败'
);
loading
.
value
=
false
;
return
;
}
// 需要洗稿
if
(
createLiveInfo
.
value
[
createLiveKeys
.
isDisorganize
])
{
...
...
@@ -306,28 +321,15 @@ export const processTextCallback = () => {
}
}
}
else
{
// 旧版洗稿回调,直播时用的是这个
if
(
res
.
data
.
length
>=
confuseLength
)
{
closeInterval
();
let
audio_list
=
[];
// 洗稿任务
res
.
data
.
forEach
((
item
:
any
)
=>
{
let
data
=
item
.
data
;
if
(
data
&&
data
.
audio_address
)
{
audio_list
.
push
(
data
.
audio_address
);
}
else
{
writeLog
({
naem
:
'useScript-洗稿缺少参数'
,
value
:
data
,
});
show_message
(
'洗稿缺少参数'
);
}
});
let
resultList
=
await
audioStart
(
audio_list
,
true
);
let
list
=
await
onAudioProcessed
(
res
,
ecursionDeepCopy
(
createLiveInfo
.
value
));
// 提交
if
(
customRegenerate
)
{
await
customRegenerate
(
resultL
ist
);
await
customRegenerate
(
l
ist
);
}
else
{
await
regenerate
(
resultL
ist
,
successCallback
);
await
regenerate
(
l
ist
,
successCallback
);
}
loading
.
value
=
false
;
}
...
...
src/pages/InteractiveResponse/index.vue
View file @
4bb22ea8
...
...
@@ -167,12 +167,6 @@ const mergeCallback = (params: any) => {
onMounted
(
async
()
=>
{
// 将通知方法注入window
injectWindow
(
'mergeCallback'
,
mergeCallback
);
// 传递用户token
try
{
window
.
pyjs
.
setToken
(
getUserCookie
());
}
catch
(
e
)
{
console
.
error
(
'没有pyjs'
);
}
// if (isDev()) {
// mergeCallback({
...
...
src/pages/OnlyVideoLive/index.vue
View file @
4bb22ea8
...
...
@@ -147,6 +147,7 @@ const submitAudioTask = async (list: any[]) => {
tone_id
:
liveDetail
.
value
.
tone_id
,
content
:
list
[
i
].
content
,
uuid
:
currentConfuseId
.
value
,
id
:
i
,
};
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
...
...
@@ -524,7 +525,10 @@ const submitVideo = () => {
let
index
=
realVideoList
.
value
.
findIndex
((
item
:
any
)
=>
!
item
.
remove
&&
!
item
.
submit
);
if
(
index
!==
-
1
)
{
realVideoList
.
value
[
index
].
submit
=
true
;
window
.
pyjs
.
run
(
realVideoList
.
value
[
index
].
url
,
routeQuery
.
id
,
route
.
query
.
window_index
,
index
);
let
list
=
realVideoList
.
value
[
index
].
url
.
map
((
item
:
any
)
=>
{
return
item
.
url
;
});
window
.
pyjs
.
run
(
list
,
routeQuery
.
id
,
route
.
query
.
window_index
,
index
);
console
.
log
(
`本次提交-
${
index
}
`
);
console
.
log
(
realVideoList
.
value
);
}
else
{
...
...
@@ -629,12 +633,6 @@ onMounted(async () => {
// 将通知方法注入window
injectWindow
(
'mergeCallback'
,
mergeCallback
);
injectWindow
(
'closeLive'
,
closeLive
);
// 传递用户token
try
{
window
.
pyjs
.
setToken
(
getUserCookie
());
}
catch
(
e
)
{
console
.
error
(
'没有pyjs'
);
}
// 获取后台互动
startLiveInterval
();
...
...
src/pages/createAction/components/createSuccess/index.tsx
View file @
4bb22ea8
import
'./index.less'
;
import
{
defineComponent
,
ref
}
from
'vue'
;
import
{
defineComponent
}
from
'vue'
;
import
{
LIVE_AUDIT_STATUS
}
from
'@/service/Live'
;
import
CardOneVue
from
'@/components/cardOne.vue'
;
import
Button
from
'@/components/Button.vue'
;
...
...
src/pages/createAction/index.tsx
View file @
4bb22ea8
...
...
@@ -82,7 +82,7 @@ export default defineComponent({
url
:
item
.
url
,
digital_man_id
:
currentCard
.
value
,
};
if
(
!
item
.
videoCover
)
{
if
(
item
.
videoCoverBlob
)
{
let
result
=
await
alyOssUpload
(
ossConfig
.
value
,
item
.
videoCoverBlob
,
...
...
@@ -111,17 +111,19 @@ export default defineComponent({
name
:
routerConfig
.
createAction
.
name
,
query
:
{},
});
reset
();
// 重新获取生产记录
getMovement
();
}
}
else
{
let
res
:
any
=
await
createLiveMovement
(
list
);
if
(
res
.
code
==
0
)
{
show_message
(
'提交成功,等待审核'
,
'success'
);
reset
();
// 重新获取生产记录
getMovement
();
}
}
// 重新获取生产记录
getMovement
();
globalLoading
.
value
=
false
;
}
catch
(
e
)
{
globalLoading
.
value
=
false
;
...
...
src/pages/createLive/components/TextScriptDialog.vue
View file @
4bb22ea8
...
...
@@ -2,23 +2,34 @@
<Dialog
v-model=
"visible"
@
confirm=
"confirm"
>
<div
class=
"text-script-dialog-body"
>
<div
class=
"input-box"
>
<div
class=
"label"
>
标题:
</div>
<div
class=
"label
center
"
>
标题:
</div>
<CustomInput
v-model=
"titleValue"
align=
"left"
placeholder=
"请输入标题"
></CustomInput>
</div>
<div
class=
"input-box"
>
<div
class=
"label"
>
内容:
</div>
<CustomTextarea
v-model=
"contentValue"
></CustomTextarea>
</div>
<div
class=
"input-box"
>
<div
class=
"label center"
>
动作:
</div>
<Select
v-model=
"currentSelect"
align=
"left"
clear
:options=
"actionList"
:autoWidth=
"false"
></Select>
<div
class=
"radio-group-parent"
>
<CustomRadio
v-model=
"currentRadio"
:list=
"radioGroup"
cancel
></CustomRadio>
</div>
</div>
</div>
</Dialog>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
watch
,
ref
}
from
'vue'
;
import
{
watch
,
ref
,
onMounted
}
from
'vue'
;
import
Select
from
'@/components/Select.vue'
;
import
Dialog
from
'@/components/Dialog.vue'
;
import
CustomInput
from
'@/components/input/index.vue'
;
import
CustomTextarea
from
'@/components/textarea.vue'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
getLiveMovementList
}
from
'@/service/Common'
;
import
{
movementTypeStart
,
movementTypeEnd
}
from
'@/service/CreateLive'
;
import
CustomRadio
from
'@/components/radio'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
...
...
@@ -34,7 +45,50 @@ const visible = ref(props.modelValue);
const
titleValue
=
ref
(
''
);
const
contentValue
=
ref
(
''
);
// 当前选择的动作
const
currentSelect
=
ref
(
''
);
const
actionList
=
ref
([]);
const
currentRadio
=
ref
(
''
);
// 单选列表
const
radioGroup
=
[
{
label
:
'开头插入'
,
value
:
movementTypeStart
,
},
{
label
:
'结尾插入'
,
value
:
movementTypeEnd
,
},
];
const
getAction
=
async
()
=>
{
let
list
=
await
getLiveMovementList
(
true
);
actionList
.
value
=
list
.
map
((
item
:
any
)
=>
{
return
{
label
:
item
.
name
,
value
:
item
.
id
,
url
:
item
.
url
,
};
});
};
onMounted
(()
=>
{
getAction
();
});
const
confirm
=
()
=>
{
let
movement_name
=
''
;
let
movement_url
=
''
;
if
(
currentSelect
.
value
)
{
// 找到对应的数据
let
obj
=
actionList
.
value
.
find
((
item
:
any
)
=>
item
.
value
==
currentSelect
.
value
);
if
(
obj
)
{
movement_name
=
obj
.
label
;
movement_url
=
obj
.
url
;
}
}
if
(
titleValue
.
value
&&
contentValue
.
value
)
{
const
{
info
}
=
props
;
visible
.
value
=
false
;
...
...
@@ -42,6 +96,10 @@ const confirm = () => {
title
:
titleValue
.
value
,
content
:
contentValue
.
value
,
index
:
typeof
info
.
index
===
'number'
?
info
.
index
:
false
,
movement_id
:
currentSelect
.
value
,
movement_type
:
currentRadio
.
value
,
movement_name
:
movement_name
,
movement_url
:
movement_url
,
});
// 清空
...
...
@@ -58,6 +116,13 @@ watch(
if
(
Object
.
keys
(
v
).
length
)
{
titleValue
.
value
=
v
.
title
;
contentValue
.
value
=
v
.
content
;
currentSelect
.
value
=
v
.
movement_id
;
currentRadio
.
value
=
v
.
movement_type
;
}
else
{
titleValue
.
value
=
''
;
contentValue
.
value
=
''
;
currentSelect
.
value
=
''
;
currentRadio
.
value
=
''
;
}
},
);
...
...
@@ -88,6 +153,13 @@ watch(
font-size
:
@
size-14
;
white-space
:
nowrap
;
}
.center
{
.dja();
}
.radio-group-parent
{
margin-left
:
12px
;
.da();
}
}
.input-box
+
.input-box
{
margin-top
:
12px
;
...
...
src/pages/createLive/components/audioScriptDialog.vue
0 → 100644
View file @
4bb22ea8
<
template
>
<Dialog
v-model=
"visible"
@
confirm=
"confirm"
className=
"audio-script-dialog"
>
<div
class=
"audio-script-dialog-body"
>
<div
class=
"input-box"
>
<div
class=
"label center"
>
标题:
</div>
<CustomInput
v-model=
"titleValue"
align=
"left"
placeholder=
"请输入标题"
></CustomInput>
</div>
<div
class=
"input-box"
>
<div
class=
"label"
>
内容:
</div>
<div
class=
"value"
>
<MultipleUpload
v-model=
"audioList"
:config=
"ossConfig"
:computedDuration=
"true"
label=
"选择音频"
:accept=
"audioAccept"
></MultipleUpload>
</div>
</div>
<div
class=
"input-box"
>
<div
class=
"label center"
>
动作:
</div>
<Select
v-model=
"currentSelect"
align=
"left"
clear
:options=
"actionList"
:autoWidth=
"false"
></Select>
<div
class=
"radio-group-parent"
>
<CustomRadio
v-model=
"currentRadio"
:list=
"radioGroup"
cancel
></CustomRadio>
</div>
</div>
</div>
</Dialog>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
watch
,
ref
,
onMounted
}
from
'vue'
;
import
Select
from
'@/components/Select.vue'
;
import
Dialog
from
'@/components/Dialog.vue'
;
import
CustomInput
from
'@/components/input/index.vue'
;
import
{
show_message
}
from
'@/utils/tool'
;
import
{
getLiveMovementList
}
from
'@/service/Common'
;
import
{
movementTypeStart
,
movementTypeEnd
}
from
'@/service/CreateLive'
;
import
CustomRadio
from
'@/components/radio'
;
import
MultipleUpload
from
'@/components/MultipleUpload'
;
import
{
audioAccept
}
from
'@/constants/token'
;
const
props
=
withDefaults
(
defineProps
<
{
modelValue
:
boolean
;
info
:
any
;
ossConfig
:
any
;
}
>
(),
{},
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'submit'
]);
const
visible
=
ref
(
props
.
modelValue
);
// 标题
const
titleValue
=
ref
(
''
);
// 音频列表
const
audioList
=
ref
([]);
// 当前选择的动作
const
currentSelect
=
ref
(
''
);
const
actionList
=
ref
([]);
const
currentRadio
=
ref
(
''
);
// 单选列表
const
radioGroup
=
[
{
label
:
'开头插入'
,
value
:
movementTypeStart
,
},
{
label
:
'结尾插入'
,
value
:
movementTypeEnd
,
},
];
const
getAction
=
async
()
=>
{
let
list
=
await
getLiveMovementList
(
true
);
actionList
.
value
=
list
.
map
((
item
:
any
)
=>
{
return
{
label
:
item
.
name
,
value
:
item
.
id
,
url
:
item
.
url
,
};
});
};
onMounted
(()
=>
{
getAction
();
});
const
confirm
=
()
=>
{
if
(
!
titleValue
.
value
)
{
show_message
(
'标题必填'
);
return
;
}
if
(
!
audioList
.
value
.
length
)
{
show_message
(
'音频至少上传一个'
);
return
;
}
let
movement_name
=
''
;
let
movement_url
=
''
;
if
(
currentSelect
.
value
)
{
// 找到对应的数据
let
obj
=
actionList
.
value
.
find
((
item
:
any
)
=>
item
.
value
==
currentSelect
.
value
);
if
(
obj
)
{
movement_name
=
obj
.
label
;
movement_url
=
obj
.
url
;
}
}
const
{
info
}
=
props
;
visible
.
value
=
false
;
emit
(
'submit'
,
{
title
:
titleValue
.
value
,
audioList
:
audioList
.
value
,
index
:
typeof
info
.
index
===
'number'
?
info
.
index
:
false
,
movement_id
:
currentSelect
.
value
,
movement_type
:
currentRadio
.
value
,
movement_name
:
movement_name
,
movement_url
:
movement_url
,
});
// 清空
titleValue
.
value
=
''
;
};
watch
(
()
=>
props
.
info
,
(
v
)
=>
{
if
(
Object
.
keys
(
v
).
length
)
{
titleValue
.
value
=
v
.
title
;
audioList
.
value
=
v
.
audioList
;
currentSelect
.
value
=
v
.
movement_id
;
currentRadio
.
value
=
v
.
movement_type
;
}
else
{
titleValue
.
value
=
''
;
audioList
.
value
=
[];
currentSelect
.
value
=
''
;
currentRadio
.
value
=
''
;
}
},
);
watch
(
()
=>
visible
.
value
,
(
v
)
=>
{
emit
(
'update:modelValue'
,
v
);
},
);
watch
(
()
=>
props
.
modelValue
,
(
v
)
=>
{
visible
.
value
=
v
;
},
);
</
script
>
<
style
lang=
"less"
>
@import
'@/style/variables'
;
.audio-script-dialog
{
.t-dialog
{
width
:
auto
;
}
}
.audio-script-dialog-body
{
margin
:
16px
0
;
.input-box
{
display
:
flex
;
.label
{
color
:
#fff
;
font-size
:
@
size-14
;
white-space
:
nowrap
;
}
.center
{
.dja();
}
.value
{
flex
:
1
;
.custom-multiple-upload
{
background-color
:
rgb
(
30
,
30
,
30
);
width
:
778px
;
height
:
256px
;
.real-upload-content
{
width
:
100%
;
.custom-real-upload-component
{
width
:
100%
;
}
}
}
}
.radio-group-parent
{
margin-left
:
12px
;
.da();
}
}
.input-box
+
.input-box
{
margin-top
:
12px
;
}
}
</
style
>
src/pages/createLive/components/scripts.vue
View file @
4bb22ea8
...
...
@@ -124,6 +124,15 @@
{{
item
.
content
}}
</div>
</div>
<div
class=
"action-box"
>
<div
class=
"label"
>
动作:
</div>
<div
class=
"value"
>
{{
item
.
movement_name
}}
</div>
<div
class=
"tag"
v-if=
"item.movement_type"
>
{{
item
.
movement_type
==
1
?
'开头插入'
:
'结尾插入'
}}
</div>
</div>
</div>
</ScriptTemplate>
</
template
>
...
...
@@ -137,34 +146,52 @@
<div
class=
"script-setting-upload flex1 narrow-scrollbar"
v-show=
"currentOption === scriptTypePhonetics"
>
<!-- edit -->
<
template
v-for=
"(item, index) in audioScriptList"
:key=
"index"
>
<ScriptTemplate
height=
"250px"
:showEdit=
"false"
@
edit=
"uploadAudioEdit(index)"
@
delete=
"onDeleteAudio(index)"
>
<div
class=
"script-template-body__audio-add"
>
<MultipleUpload
v-model=
"item.data"
:config=
"ossConfig"
:computedDuration=
"true"
label=
"选择音频"
:accept=
"audioAccept"
@
change=
"uploadEdit"
></MultipleUpload>
<ScriptTemplate
height=
"250px"
@
edit=
"uploadAudioEdit(item, index)"
@
delete=
"onDeleteAudio(index)"
>
<div
class=
"script-template-body__text"
>
<div
class=
"title-box"
>
<div
class=
"label"
>
标题:
</div>
<div
class=
"value"
>
{{
item
.
title
}}
</div>
</div>
<div
class=
"content-box"
>
<div
class=
"label"
>
内容:
</div>
<div
class=
"value narrow-scrollbar"
>
<div
class=
"uploaded-audio-list"
>
<div
v-for=
"row in item.audioList"
:key=
"row.url"
>
<AudioSvg></AudioSvg>
<div>
{{
row
.
file
.
name
}}
</div>
</div>
</div>
</div>
</div>
<div
class=
"action-box"
>
<div
class=
"label"
>
动作:
</div>
<div
class=
"value"
>
{{
item
.
movement_name
}}
</div>
<div
class=
"tag"
v-if=
"item.movement_type"
>
{{
item
.
movement_type
==
1
?
'开头插入'
:
'结尾插入'
}}
</div>
</div>
</div>
</ScriptTemplate>
</
template
>
<!-- create -->
<ScriptTemplate
:showTool=
"false"
height=
"250px"
>
<div
class=
"script-template-body__audio-add"
>
<MultipleUpload
v-model=
"mp3UrlList"
:config=
"ossConfig"
:computedDuration=
"true"
label=
"选择音频"
:accept=
"audioAccept"
@
change=
"createUploadFile"
></MultipleUpload>
<ScriptTemplate
:showTool=
"false"
>
<div
class=
"script-template-body__text-add"
@
click=
"addAudioScript"
>
<img
:src=
"imgs.add"
alt=
""
/>
<div
class=
"label"
>
添加音频
</div>
</div>
</ScriptTemplate>
</div>
<TextScriptDialog
v-model=
"textScriptVisible"
@
submit=
"textScriptSubmit"
:info=
"editTextInfo"
></TextScriptDialog>
<AudioScriptDialog
v-model=
"audioScriptVisible"
:ossConfig=
"ossConfig"
@
submit=
"audioScriptSubmit"
:info=
"editAudioInfo"
></AudioScriptDialog>
<ConfirmDialog
v-model=
"confirmDeleteVisible"
title=
"确定要删除该声音吗?"
...
...
@@ -180,6 +207,7 @@
<
script
lang=
"tsx"
setup
>
import
{
computed
,
onMounted
,
reactive
,
ref
,
watch
,
toRaw
}
from
'vue'
;
import
AudioSvg
from
'@/assets/svg/upload/audio.svg'
;
import
Button
from
'@/components/Button.vue'
;
import
MultipleUpload
from
'@/components/MultipleUpload'
;
import
CheckBox
from
'@/components/CheckBox.vue'
;
...
...
@@ -190,6 +218,7 @@ import Select from '@/components/Select.vue';
import
SelectionPopup
from
'@/components/SelectionPopup.vue'
;
import
{
show_message
,
isDev
,
ecursionDeepCopy
}
from
'@/utils/tool'
;
import
{
audioAccept
}
from
'@/constants/token'
;
import
AudioScriptDialog
from
'./audioScriptDialog.vue'
;
import
{
createLiveKeys
,
scriptTypeList
,
...
...
@@ -201,6 +230,7 @@ import { useLiveInfoSubmit } from '@/hooks/useStoreCommit';
import
{
getUploadConfig
,
getTonesList
}
from
'@/service/Common'
;
import
{
useStore
}
from
'vuex'
;
import
{
useRoute
}
from
'vue-router'
;
import
{
v4
}
from
'uuid'
;
import
useCopy
from
'@/hooks/useCopy'
;
const
{
doCopy
}
=
useCopy
();
...
...
@@ -232,6 +262,7 @@ const audioScriptList = ref([]);
const
scriptSettingText
=
ref
<
HTMLDivElement
>
();
// 文本编辑时的行信息
const
editTextInfo
=
ref
({});
const
editAudioInfo
=
ref
({});
// 文本脚本删除时选择的下标
const
deleteTextId
=
ref
();
// 确认删除弹窗
...
...
@@ -266,6 +297,7 @@ const disabled = ref(true);
// 文本脚本弹窗
const
textScriptVisible
=
ref
(
false
);
const
audioScriptVisible
=
ref
(
false
);
// 阿里云上传配置
const
ossConfig
=
ref
({});
...
...
@@ -284,20 +316,6 @@ const textareaValue = ref('');
const
currentOption
=
ref
(
scriptTypeText
);
// 音频脚本上传后
const
createUploadFile
=
(
list
:
any
[],
oldList
:
any
[])
=>
{
// 添加到数组中
audioScriptList
.
value
.
push
({
data
:
oldList
,
});
// 提交到store
uploadChange
();
setTimeout
(()
=>
{
// 清空当前url
mp3UrlList
.
value
=
[];
},
0
);
};
// 音频脚本编辑后
const
uploadEdit
=
(
list
:
any
[],
oldList
:
any
[])
=>
{
uploadChange
();
...
...
@@ -315,18 +333,11 @@ const onDeleteAudio = (index: number) => {
};
// 编辑按钮 音频脚本
const
uploadAudioEdit
=
(
index
:
number
)
=>
{
// 调用对应的上传事件
if
(
uploadRef
.
value
&&
uploadRef
.
value
.
length
)
{
let
element
:
HTMLDivElement
=
uploadRef
.
value
[
index
].
$el
;
if
(
element
)
{
// 找到上传元素
let
clickElement
=
element
.
getElementsByClassName
(
'custom-upload-click-box'
);
if
(
clickElement
&&
clickElement
.
length
)
{
clickElement
[
0
].
click
();
}
}
}
const
uploadAudioEdit
=
(
item
:
any
,
index
:
number
)
=>
{
item
.
index
=
index
;
// 打开弹窗
editAudioInfo
.
value
=
item
;
audioScriptVisible
.
value
=
true
;
};
// 洗稿checkbox变化
...
...
@@ -343,6 +354,11 @@ const addTextScript = () => {
textScriptVisible
.
value
=
true
;
};
const
addAudioScript
=
()
=>
{
editAudioInfo
.
value
=
{};
audioScriptVisible
.
value
=
true
;
};
// 编辑脚本
const
editTextScript
=
(
item
:
any
,
index
:
number
)
=>
{
item
.
index
=
index
;
...
...
@@ -350,6 +366,8 @@ const editTextScript = (item: any, index: number) => {
textScriptVisible
.
value
=
true
;
};
// 编辑音频脚本
// 删除文本脚本
const
deleteTextScript
=
(
index
:
number
)
=>
{
deleteTextId
.
value
=
index
;
...
...
@@ -367,11 +385,15 @@ const confirmDeleteText = () => {
const
textScriptSubmit
=
(
params
:
any
)
=>
{
if
(
params
.
title
&&
params
.
content
)
{
// 创建一个uuid
params
.
uuid
=
createLiveInfo
.
value
[
createLiveKeys
.
scriptUuid
]
;
params
.
uuid
=
v4
()
;
if
(
typeof
params
.
index
===
'number'
)
{
// 编辑
textScriptList
.
value
[
params
.
index
].
title
=
params
.
title
;
textScriptList
.
value
[
params
.
index
].
content
=
params
.
content
;
textScriptList
.
value
[
params
.
index
].
movement_id
=
params
.
movement_id
;
textScriptList
.
value
[
params
.
index
].
movement_type
=
params
.
movement_type
;
textScriptList
.
value
[
params
.
index
].
movement_name
=
params
.
movement_name
;
textScriptList
.
value
[
params
.
index
].
movement_url
=
params
.
movement_url
;
// 其他参数都要清掉
// 任务id
textScriptList
.
value
[
params
.
index
].
task_id
=
''
;
...
...
@@ -385,6 +407,18 @@ const textScriptSubmit = (params: any) => {
}
};
// 提交音频脚本
const
audioScriptSubmit
=
(
params
:
any
)
=>
{
console
.
log
(
params
);
if
(
typeof
params
.
index
===
'number'
)
{
// 编辑模式
audioScriptList
.
value
[
params
.
index
]
=
params
;
}
else
{
audioScriptList
.
value
.
push
(
params
);
}
uploadChange
();
};
// 文本脚本内容提交到store
const
submitTextScript
=
()
=>
{
commitInfo
({
...
...
@@ -439,7 +473,6 @@ const updateInfo = (info: any) => {
currentOption
.
value
=
scriptTypeText
;
if
(
type_content
)
{
// 内容
// textareaValue.value = type_content;
textScriptList
.
value
=
type_content
;
}
// 洗稿
...
...
@@ -457,16 +490,7 @@ const updateInfo = (info: any) => {
}
else
{
// 草稿
if
(
type_content
)
{
audioScriptList
.
value
=
type_content
.
map
((
item
:
any
)
=>
{
item
.
forEach
((
it
:
any
)
=>
{
it
.
audio_url
=
it
.
content
;
it
.
status
=
true
;
it
.
url
=
it
.
content
;
});
return
{
data
:
item
,
};
});
audioScriptList
.
value
=
type_content
;
}
else
{
audioScriptList
.
value
=
[];
}
...
...
@@ -722,6 +746,77 @@ onMounted(async () => {
.flex1
{
flex
:
1
1
auto
;
}
.script-template-body__text-add
{
height
:
100%
;
.dja();
flex-direction
:
column
;
cursor
:
pointer
;
img
{
width
:
40px
;
height
:
40px
;
margin-bottom
:
12px
;
}
.label
{
font-size
:
@
size-18
;
color
:
#b4b4b4
;
font-weight
:
600
;
}
}
.script-template-body__text
{
.dj();
flex-direction
:
column
;
height
:
100%
;
.title-box,
.content-box
{
font-size
:
@
size-14
;
display
:
flex
;
.label
{
white-space
:
nowrap
;
}
}
.action-box
{
color
:
#b4b4b4
;
margin-top
:
16px
;
.da();
.tag
{
margin-left
:
20px
;
border-radius
:
4px
;
background
:
#303030
;
.dja();
color
:
#04ae8a
;
font-size
:
@
size-12
;
font-weight
:
600
;
padding
:
3px
10px
3px
11px
;
}
}
.title-box
{
color
:
#fff
;
}
.content-box
{
color
:
#b4b4b4
;
margin-top
:
16px
;
flex
:
1
;
overflow
:
hidden
;
.value
{
width
:
100%
;
height
:
100%
;
word-break
:
break-all
;
overflow-y
:
auto
;
.uploaded-audio-list
{
width
:
100%
;
.da();
flex-wrap
:
wrap
;
row-gap
:
20px
;
margin-left
:
-20px
;
&
>
*
{
.dja();
flex-direction
:
column
;
margin-left
:
20px
;
}
}
}
}
}
.script-setting-text
{
overflow-y
:
auto
;
transition
:
0.3s
;
...
...
@@ -734,49 +829,6 @@ onMounted(async () => {
}
}
}
.script-template-body__text
{
.dj();
flex-direction
:
column
;
height
:
100%
;
.title-box,
.content-box
{
font-size
:
@
size-14
;
display
:
flex
;
.label
{
white-space
:
nowrap
;
}
}
.title-box
{
color
:
#fff
;
}
.content-box
{
color
:
#b4b4b4
;
margin-top
:
16px
;
flex
:
1
;
overflow
:
hidden
;
.value
{
height
:
100%
;
word-break
:
break-all
;
overflow-y
:
auto
;
}
}
}
.script-template-body__text-add
{
height
:
100%
;
.dja();
flex-direction
:
column
;
cursor
:
pointer
;
img
{
width
:
40px
;
height
:
40px
;
margin-bottom
:
12px
;
}
.label
{
font-size
:
@
size-18
;
color
:
#b4b4b4
;
font-weight
:
600
;
}
}
}
.script-setting-upload
{
overflow-y
:
auto
;
...
...
@@ -798,13 +850,6 @@ onMounted(async () => {
}
}
}
.custom-multiple-upload
{
height
:
100%
;
background
:
transparent
;
.custom-uploading-stauts
{
padding-top
:
12px
;
}
}
}
}
}
...
...
src/pages/createLive/index.vue
View file @
4bb22ea8
...
...
@@ -72,7 +72,7 @@ import ChoseDigitalPerson from './components/ChoseDigitalPerson.vue';
import
HomeSvg
from
'@/assets/svg/createLive/home.svg'
;
import
InteractSvg
from
'@/assets/svg/createLive/interact.svg'
;
import
ScriptsSvg
from
'@/assets/svg/createLive/scripts.svg'
;
import
{
computed
,
onBeforeMount
,
ref
,
onBeforeUnmount
,
onActivated
}
from
'vue'
;
import
{
computed
,
onBeforeMount
,
ref
,
onBeforeUnmount
,
onActivated
,
toRaw
}
from
'vue'
;
import
{
getElBounding
,
show_message
,
...
...
@@ -224,6 +224,12 @@ const getEditInfo = async (id: any, type: string) => {
[
createLiveKeys
.
interactiveLibrary
]:
res
.
data
.
interaction_ids
,
};
if
(
res
.
data
.
type
==
'2'
)
{
console
.
log
(
res
.
data
.
type_content
);
res
.
data
.
type_content
.
forEach
((
item
:
any
)
=>
{
item
.
movement_id
=
item
.
extend
.
movement_id
;
item
.
movement_type
=
item
.
extend
.
movement_type
;
item
.
movement_name
=
item
.
extend
.
movement_name
;
});
// 文本
params
[
createLiveKeys
.
textSoundColor
]
=
res
.
data
.
phonetic_timbres_id
;
params
[
createLiveKeys
.
textScriptList
]
=
[
res
.
data
.
type_content
];
...
...
@@ -232,7 +238,7 @@ const getEditInfo = async (id: any, type: string) => {
// 音频音色
params
[
createLiveKeys
.
phoneticsSoundColor
]
=
res
.
data
.
phonetic_timbres_id
;
params
[
createLiveKeys
.
phoneticsFile
]
=
res
.
data
.
type_content
;
params
[
createLiveKeys
.
audioScriptList
]
=
mergeSameAudio
(
res
.
data
.
type_content
);
params
[
createLiveKeys
.
audioScriptList
]
=
mergeSameAudio
(
ecursionDeepCopy
(
toRaw
(
res
.
data
.
type_content
))
);
}
// 更新标题
if
(
res
.
data
.
name
)
{
...
...
@@ -263,24 +269,7 @@ const getEditInfo = async (id: any, type: string) => {
// 音频音色
params
[
createLiveKeys
.
phoneticsSoundColor
]
=
content
.
phonetic_timbres_id
?
content
.
phonetic_timbres_id
:
''
;
if
(
content
.
type_content
)
{
let
newContent
=
ecursionDeepCopy
(
content
.
type_content
);
// 过滤出child
newContent
=
newContent
.
map
((
item
:
any
)
=>
{
item
.
forEach
((
it
:
any
)
=>
{
it
.
children
=
[];
let
children
=
it
.
content
.
split
(
'|'
);
children
.
forEach
((
child
)
=>
{
let
obj
=
{
audio_url
:
child
,
};
it
.
children
.
push
(
obj
);
});
});
return
{
data
:
item
,
};
});
params
[
createLiveKeys
.
audioScriptList
]
=
newContent
;
params
[
createLiveKeys
.
audioScriptList
]
=
content
.
type_content
;
}
}
// 更新标题
...
...
@@ -377,6 +366,8 @@ const onSave = () => {
// 保存为草稿
const
onSaveDrafts
=
async
()
=>
{
let
params
=
filterFiled
(
getCreateLiveInfo
());
// 单独修改草稿内容
params
.
type_content
=
createLiveInfo
.
value
[
createLiveKeys
.
audioScriptList
];
try
{
loading
.
value
=
true
;
let
res
:
any
=
await
createDrafts
(
params
);
...
...
@@ -415,13 +406,8 @@ const audioScriptEditSubmit = async () => {
const
editAudioSave
=
async
()
=>
{
try
{
loading
.
value
=
true
;
if
(
audioScriptVersion
==
'v1'
)
{
await
audioSplit
();
await
audioScriptEditSubmit
();
}
else
{
// v2
audioConvert
(
'update'
);
}
// v2
audioConvert
(
'update'
);
}
catch
(
e
)
{
writeLog
({
name
:
'createLive editAudioSave error'
,
...
...
@@ -447,7 +433,9 @@ const submitTaskAndConfuse = async (type: string) => {
// 音调
tone_id
:
item
[
createLiveKeys
.
textTones
],
content
:
row
.
content
,
uuid
:
item
[
createLiveKeys
.
scriptUuid
],
uuid
:
row
.
uuid
,
parent_uuid
:
item
[
createLiveKeys
.
scriptUuid
],
id
:
i
,
};
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
...
...
@@ -483,57 +471,6 @@ const onEditSave = async () => {
}
};
// 音频切割v1
const
audioSplit
=
async
()
=>
{
for
(
let
i
=
0
;
i
<
createLiveInfo
.
value
[
createLiveKeys
.
audioScriptList
].
length
;
i
++
)
{
let
item
=
createLiveInfo
.
value
[
createLiveKeys
.
audioScriptList
][
i
];
for
(
let
j
=
0
;
j
<
item
.
data
.
length
;
j
++
)
{
let
row
=
item
.
data
[
j
];
if
(
row
.
children
&&
row
.
children
.
length
>
1
)
{
// 编辑时没有修改参数
continue
;
}
if
(
row
.
duration
&&
row
.
duration
>
audioSplitNum
&&
row
.
content
&&
row
.
content
.
indexOf
(
'|'
)
==
-
1
&&
row
.
old_content
&&
!
row
.
file
?.
raw
)
{
console
.
log
(
'大于5分钟,开始下载文件'
);
// 没有文件时,下载
let
file
=
await
getFile
(
row
.
old_content
);
row
.
file
=
{};
row
.
file
.
raw
=
file
;
console
.
log
(
row
.
file
);
}
if
(
row
.
file
&&
row
.
file
.
raw
)
{
// 文件时长
let
fileDuration
=
await
getDurationOfAudioFile
(
row
.
file
.
raw
);
console
.
log
(
fileDuration
,
'文件时长'
);
if
(
fileDuration
>
audioSplitNum
)
{
// 开始切割前先判断文件类型
let
result
=
await
splitAudio
(
row
.
file
.
raw
,
audioSplitNum
);
if
(
result
.
length
)
{
// 上传阿里云--加个判断,没有长度抛出异常
let
alyList
=
await
uploadToAly
(
result
);
let
list
=
[];
alyList
.
forEach
((
aly
:
any
)
=>
{
aly
.
forEach
((
alyRow
:
any
)
=>
{
list
.
push
(
alyRow
.
content
);
});
});
// console.log(list, 'list');
// 一维数组
row
.
new_content
=
list
.
join
(
'|'
);
}
}
}
}
}
};
// python转换音频回调
const
convertCallback
=
(
convertInfo
:
any
)
=>
{
console
.
log
(
'转换回调'
,
convertInfo
);
...
...
@@ -542,9 +479,9 @@ const convertCallback = (convertInfo: any) => {
let
audioScriptList
=
createLiveInfo
.
value
[
createLiveKeys
.
audioScriptList
];
// 根据切割前的链接匹配更新
for
(
let
i
=
0
;
i
<
audioScriptList
.
length
;
i
++
)
{
let
item
=
audioScriptList
[
i
];
for
(
let
j
=
0
;
j
<
item
.
data
.
length
;
j
++
)
{
let
row
=
item
.
data
[
j
];
let
item
=
audioScriptList
[
i
]
.
audioList
;
for
(
let
j
=
0
;
j
<
item
.
length
;
j
++
)
{
let
row
=
item
[
j
];
if
(
getAudioUrl
(
row
)
==
convertInfo
.
url
)
{
// 更新url
let
key
=
getAudioUrlKey
(
row
);
...
...
@@ -579,9 +516,9 @@ const splitCallback = (splitInfo: any) => {
let
audioScriptList
=
createLiveInfo
.
value
[
createLiveKeys
.
audioScriptList
];
// 根据切割前的链接匹配更新
for
(
let
i
=
0
;
i
<
audioScriptList
.
length
;
i
++
)
{
let
item
=
audioScriptList
[
i
];
for
(
let
j
=
0
;
j
<
item
.
data
.
length
;
j
++
)
{
let
row
=
item
.
data
[
j
];
let
item
=
audioScriptList
[
i
]
.
audioList
;
for
(
let
j
=
0
;
j
<
item
.
length
;
j
++
)
{
let
row
=
item
[
j
];
if
(
getAudioUrl
(
row
)
==
splitInfo
.
url
)
{
row
.
new_content
=
splitInfo
.
list
.
join
(
'|'
);
row
.
py_split_status
=
true
;
...
...
@@ -639,9 +576,9 @@ const audioConvert = async (type: string) => {
// 清空总任务数
audioConvertTaskTotal
.
value
=
0
;
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
item
=
list
[
i
];
for
(
let
j
=
0
;
j
<
item
.
data
.
length
;
j
++
)
{
let
row
=
item
.
data
[
j
];
let
item
=
list
[
i
]
.
audioList
;
for
(
let
j
=
0
;
j
<
item
.
length
;
j
++
)
{
let
row
=
item
[
j
];
if
(
row
.
children
&&
row
.
children
.
length
>
1
)
{
// 编辑时没有修改参数
continue
;
...
...
@@ -651,12 +588,13 @@ const audioConvert = async (type: string) => {
let
suffix
=
getFileSuffixInUrl
(
audio_url
);
if
(
suffix
===
'wav'
)
{
console
.
log
(
'是wav文件,开始转换'
,
audio_url
);
audioConvertToPython
(
row
,
type
);
a
wait
a
udioConvertToPython
(
row
,
type
);
}
else
{
console
.
log
(
'不是wav'
,
audio_url
);
}
}
}
console
.
log
(
`共有
${
audioConvertTaskTotal
.
value
}
个文件要转换格式`
);
if
(
audioConvertTaskTotal
.
value
===
0
)
{
// 没有要转换的,直接切割
audioSplitV2
(
type
);
...
...
@@ -669,9 +607,9 @@ const audioSplitV2 = async (type: string) => {
// 清空总次数
audioSplitTaskTotal
.
value
=
0
;
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
item
=
list
[
i
];
for
(
let
j
=
0
;
j
<
item
.
data
.
length
;
j
++
)
{
let
row
=
item
.
data
[
j
];
let
item
=
list
[
i
]
.
audioList
;
for
(
let
j
=
0
;
j
<
item
.
length
;
j
++
)
{
let
row
=
item
[
j
];
if
(
row
.
children
&&
row
.
children
.
length
>
1
)
{
// 编辑时没有修改参数
continue
;
...
...
@@ -746,13 +684,8 @@ const audioScriptLiveTaskSubmit = async () => {
const
audioSubmit
=
async
()
=>
{
try
{
loading
.
value
=
true
;
if
(
audioScriptVersion
==
'v1'
)
{
await
audioSplit
();
await
audioScriptLiveTaskSubmit
();
}
else
{
// v2版本,提交到python处理
audioConvert
(
'create'
);
}
// v2版本,提交到python处理
audioConvert
(
'create'
);
}
catch
(
e
)
{
writeLog
({
name
:
'createLive audioSubmit error'
,
...
...
src/pages/home/index.vue
View file @
4bb22ea8
...
...
@@ -229,7 +229,9 @@ const startTest = async () => {
onMounted
(()
=>
{
// 发送token,即使重新登录也会回到首页再次发送
callPyjsInWindow
(
'setToken'
,
userToken
.
value
);
callPyjsInWindow
(
'setToken'
,
{
token
:
userToken
.
value
,
});
// 获取我的数字人
getList
();
startTest
();
...
...
src/pages/startLive/index.vue
View file @
4bb22ea8
...
...
@@ -281,12 +281,6 @@ const mergeCallback = (params: any) => {
onMounted
(
async
()
=>
{
// 将通知方法注入window
injectWindow
(
'mergeCallback'
,
mergeCallback
);
// 传递用户token
try
{
window
.
pyjs
.
setToken
(
getUserCookie
());
}
catch
(
e
)
{
console
.
error
(
'没有pyjs'
);
}
// if (isDev()) {
// mergeCallback({
...
...
src/service/Common.ts
View file @
4bb22ea8
...
...
@@ -169,13 +169,10 @@ export const audioStart = async (list: any[], dimensional: boolean = true) => {
// 合并后的文件上传
if
(
split_list
&&
split_list
.
length
)
{
let
result
=
await
uploadToAly
(
split_list
);
console
.
log
(
'上传完毕'
);
// 是否一维数组
if
(
dimensional
)
{
console
.
log
(
result
);
return
result
;
}
else
{
console
.
log
([
result
]);
return
[
result
];
}
}
...
...
@@ -236,10 +233,14 @@ export const uploadToAly = async (fileList: File[]) => {
};
// 获取动作列表
export
const
getLiveMovementList
=
async
()
=>
{
export
const
getLiveMovementList
=
async
(
filter
:
boolean
=
false
)
=>
{
try
{
let
res
:
any
=
await
getLiveMovement
();
if
(
res
.
code
==
0
)
{
if
(
filter
)
{
// 过滤出成功的
return
res
.
data
.
filter
((
item
:
any
)
=>
item
.
audit_status
==
LIVE_AUDIT_STATUS
.
LIVE_AUDIT_STATUS_FINISH
);
}
return
res
.
data
;
}
return
[];
...
...
src/service/CreateLive.ts
View file @
4bb22ea8
import
{
mergedArray
,
isDev
,
show_message
,
dimensionalConvert
,
DataType
}
from
'@/utils/tool'
;
import
{
mergedArray
,
isDev
,
show_message
,
dimensionalConvert
,
DataType
,
TableSortAsc
,
ecursionDeepCopy
,
}
from
'@/utils/tool'
;
import
{
liveContentRegenerateCallback
,
liveTts
,
getLiveTtsCallback
,
liveTaskRegenerate
}
from
'@/utils/api/userApi'
;
import
{
audioStart
}
from
'@/service/Common'
;
import
store
from
'@/store'
;
...
...
@@ -32,7 +40,7 @@ export const createLiveKeys = {
commentMethod
:
'commentMethod'
,
// 评论方式
interactiveLibrary
:
'interactiveLibrary'
,
// 互动库
isDisorganize
:
'is_disorganize'
,
// 是否洗稿
scriptUuid
:
'script_uuid'
,
// 文本脚本生成
是
的uuid
scriptUuid
:
'script_uuid'
,
// 文本脚本生成的uuid
};
// 脚本类型
...
...
@@ -53,19 +61,75 @@ export const scriptTypeList = [
export
const
typeTones
=
1
;
// 音调
export
const
typeSoundColor
=
2
;
// 音色
// 动作类型
export
const
movementTypeStart
=
1
;
// 开头插入
export
const
movementTypeEnd
=
2
;
// 结尾插入
// 合并同类项音频
export
const
mergeSameAudio
=
(
content
:
any
[])
=>
{
let
list
=
mergedArray
(
content
);
return
list
.
map
((
item
:
any
)
=>
{
let
list
=
[];
content
.
forEach
((
item
:
any
,
index
:
number
)
=>
{
let
title
=
''
;
let
url
=
''
;
let
movement_name
=
''
;
let
movement_type
=
null
;
let
movement_id
=
null
;
// 找到第一个old
let
oldList
=
item
.
filter
((
it
:
any
)
=>
it
.
is_old
);
if
(
oldList
.
length
)
{
title
=
oldList
[
0
].
extend
.
title
;
url
=
oldList
[
0
].
audio_url
;
movement_name
=
oldList
[
0
].
extend
.
movement_name
;
movement_type
=
oldList
[
0
].
extend
.
movement_type
;
movement_id
=
oldList
[
0
].
extend
.
movement_id
;
}
// 获取audioList
let
audioList
=
[];
oldList
.
forEach
((
it
:
any
)
=>
{
let
params
=
{
file
:
{
name
:
it
.
name
,
},
uuid
:
it
.
uuid
,
url
:
it
.
audio_url
,
duration
:
it
.
duration
,
status
:
true
,
};
audioList
.
push
(
params
);
});
// 找出所有 is_old == 0的,根据uuid存放到 is_old ==1的对象中
item
.
forEach
((
it
:
any
)
=>
{
if
(
it
.
audio_url
)
{
it
.
url
=
it
.
audio_url
;
for
(
let
i
=
0
;
i
<
audioList
.
length
;
i
++
)
{
let
audioRow
=
audioList
[
i
];
// 初始化children
if
(
!
audioRow
.
children
)
{
audioRow
.
children
=
[];
}
if
(
it
.
uuid
==
audioRow
.
uuid
&&
!
it
.
is_old
)
{
let
params
=
{
file
:
{
name
:
it
.
name
,
},
duration
:
it
.
duration
,
url
:
it
.
audio_url
,
};
audioRow
.
children
.
push
(
params
);
}
}
});
return
{
data
:
item
,
};
list
.
push
({
audioList
:
audioList
,
title
:
title
,
url
:
url
,
movement_name
:
movement_name
,
movement_type
:
movement_type
,
movement_id
:
movement_id
,
});
});
return
list
;
};
// 获取洗稿回调
...
...
@@ -91,23 +155,7 @@ export const onRewriteCallback = async (id: string) => {
//
res
.
data
=
[
{
content
:
`
大家好!欢迎来到今天的直播!我是你们的主持人,今天我将为大家带来一场精彩的直播节目。在这里,我们将分享一些有趣的内容,并回答你们的问题。
首先,让我们来聊一聊今天的主题。今天我们将重点聚焦在XX领域(根据直播主题填写),这是一个非常热门、有趣且前沿的领域。我们将了解最新的发展动态、分享一些实用的技巧,并回答你们提出的问题。
对于新加入直播的朋友,特别欢迎你们!如果你们有任何问题或者想要了解更多关于XX的信息,请随时在评论区留言,我将尽力回答你们的问题。
在这里,我们鼓励大家积极互动。请大家在评论区留下你们的想法、观点和问题。我会选择一些与主题相关的问题进行回答,在回答问题时我会尽量深入浅出,以确保每个人都能够理解。
也请大家相互尊重,遵守礼貌。如果有令人不舒服的言论或者不适当的内容,请及时举报,我们会及时处理。
接下来,让我们一起进入今天的正题吧!不管你是刚开始接触XX,还是已经有一定了解,请相信你们在这里能够获得更多知识、更多的收获。
再次感谢大家的到来和支持,让我们一起度过这个精彩的时刻!祝愿大家在本次直播中有所收获,也希望大家能够在评论区互相交流,共同进步。
谢谢大家!现在,让我们开始今天的直播吧!
`
,
content
:
`大家好!欢迎来到今天的直播!我是你们的主持人,今天我将为大家带来一场精彩的直播节目`
,
},
];
}
...
...
@@ -147,6 +195,7 @@ export const submitAudioTask = async (list: any[], item: any, uuid: string) => {
tone_id
:
item
[
createLiveKeys
.
textTones
],
content
:
list
[
i
].
content
,
uuid
:
uuid
,
id
:
i
,
};
// 生成音频
await
liveTts
(
params
);
...
...
@@ -208,25 +257,33 @@ export const filterFiled = (item: any, type: string = '') => {
// 脚本内容
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本
params
.
type_content
=
item
[
createLiveKeys
.
textScriptValue
];
// 转换格式
// 先二维转一维
params
.
type_content
=
dimensionalConvert
(
params
.
type_content
);
let
list
=
[];
params
.
type_content
.
forEach
((
item
:
any
)
=>
{
list
.
push
([
item
]);
// 文本内容--先转一维数组
let
newList
=
dimensionalConvert
(
item
[
createLiveKeys
.
textScriptList
]);
params
.
type_content
=
newList
.
map
((
row
:
any
)
=>
{
return
{
movement
:
{
id
:
row
.
movement_id
,
type
:
row
.
movement_type
,
name
:
row
.
movement_name
,
url
:
row
.
movement_url
,
},
// 提交的数组
list
:
row
.
newList
,
};
});
params
.
type_content
=
list
;
console
.
log
(
params
.
type_content
,
'文本 type_content'
);
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
textSoundColor
];
// 文本内容--先转一维数组
let
newList
=
dimensionalConvert
(
item
[
createLiveKeys
.
textScriptList
]);
params
.
content
=
newList
.
map
((
row
:
any
)
=>
{
params
.
content
=
newList
.
map
((
row
:
any
,
index
:
number
)
=>
{
return
{
title
:
row
.
title
,
content
:
row
.
content
,
movement_id
:
row
.
movement_id
,
movement_type
:
row
.
movement_type
,
movement_name
:
row
.
movement_name
,
movement_url
:
row
.
movement_url
,
};
});
}
else
{
...
...
@@ -241,7 +298,7 @@ export const filterFiled = (item: any, type: string = '') => {
// 音频
params
.
type_content
=
item
[
createLiveKeys
.
audioScriptList
].
map
((
audioScript
:
any
)
=>
{
let
list
=
[];
audioScript
.
data
.
forEach
((
it
:
any
)
=>
{
audioScript
.
audioList
.
forEach
((
it
:
any
)
=>
{
let
params
:
any
=
{
content
:
''
,
old_content
:
''
,
...
...
@@ -304,7 +361,19 @@ export const filterFiled = (item: any, type: string = '') => {
list
.
push
(
params
);
});
return
list
;
let
movement
:
any
=
{
id
:
audioScript
.
movement_id
,
type
:
audioScript
.
movement_type
,
name
:
audioScript
.
movement_name
,
url
:
audioScript
.
movement_url
,
};
return
{
movement
:
movement
,
list
:
list
,
extend
:
{
title
:
audioScript
.
title
,
},
};
});
console
.
log
(
params
.
type_content
,
'音频 type_content'
);
// 音色id
...
...
@@ -375,6 +444,45 @@ export const getAudioStartTimeAndEndTime = async (list: any[]) => {
}
};
// 洗稿音频回调处理
export
const
onAudioProcessed
=
async
(
res
:
any
,
liveInfo
:
any
)
=>
{
let
list
=
[];
for
(
let
i
=
0
;
i
<
res
.
data
.
length
;
i
++
)
{
let
item
=
res
.
data
[
i
];
let
data
=
item
.
data
;
if
(
data
&&
data
.
audio_address
)
{
let
resultList
=
await
audioStart
([
data
.
audio_address
],
true
);
// 转一维
resultList
=
dimensionalConvert
(
resultList
);
if
(
!
resultList
.
length
)
{
show_message
(
'洗稿失败'
);
writeLog
(
'洗稿回调中音频下载失败-audioStart'
);
return
;
}
let
textScriptList
=
dimensionalConvert
(
liveInfo
[
createLiveKeys
.
textScriptList
]);
list
.
push
({
movement
:
{
id
:
textScriptList
[
i
].
movement_id
,
type
:
textScriptList
[
i
].
movement_type
,
name
:
textScriptList
[
i
].
movement_name
,
url
:
textScriptList
[
i
].
movement_url
,
},
list
:
resultList
.
map
((
row
:
any
)
=>
{
return
{
content
:
row
.
content
,
movement_type
:
textScriptList
[
i
].
movement_type
,
movement_name
:
textScriptList
[
i
].
movement_name
,
};
}),
});
}
else
{
console
.
log
(
'洗稿缺少参数'
);
show_message
(
'洗稿缺少参数'
);
}
}
return
list
;
};
// 洗稿获取音频回调
export
const
getAudioCallback
=
(
audio_task_id
:
string
,
len
:
number
,
liveInfo
:
any
,
live_id
:
any
)
=>
{
let
interval
=
null
;
...
...
@@ -393,38 +501,28 @@ export const getAudioCallback = (audio_task_id: string, len: number, liveInfo: a
});
if
(
res
.
code
==
0
)
{
if
(
isDev
())
{
let
params
=
{
let
params
:
any
=
{
data
:
{
audio_address
:
'http://
nls-cloud-cn-shanghai.oss-cn-shanghai.aliyuncs.com/jupiter-flow/tmp/e56d8750eb3a44f9930f73703489acb1.wav?Expires=1692087730&OSSAccessKeyId=LTAIUpwNp2H7pBG5&Signature=FtKSld5Dn55po9GyTm%2BefRKmPqw%3D
'
,
'http://
yunyi-live.oss-cn-hangzhou.aliyuncs.com/upload/1/2023-08-16fcc74a89-d3f1-4545-a17c-d155dfa7978f.wav
'
,
task_id
:
0
,
},
};
for
(
let
i
=
0
;
i
<
3
;
i
++
)
{
for
(
let
i
=
0
;
i
<
1
;
i
++
)
{
params
.
data
.
id
=
i
;
res
.
data
.
push
(
params
);
}
}
if
(
res
.
data
.
length
)
{
// 根据id升序排列
res
.
data
=
TableSortAsc
(
res
.
data
,
'data.id'
);
console
.
log
(
'音频任务回调成功'
);
console
.
log
(
res
.
data
);
if
(
res
.
data
.
length
>=
len
)
{
closeInterval
();
let
audioList
=
[];
res
.
data
.
forEach
(
async
(
item
:
any
,
index
:
number
)
=>
{
let
data
=
item
.
data
;
if
(
data
&&
data
.
audio_address
)
{
audioList
.
push
(
data
.
audio_address
);
}
else
{
console
.
log
(
'洗稿缺少参数'
);
show_message
(
'洗稿缺少参数'
);
}
});
// 获取音频时长
let
durationList
=
await
getAudioStartTimeAndEndTime
(
res
.
data
);
console
.
log
(
durationList
,
'洗稿durationList'
);
let
resultList
=
await
audioStart
(
audioList
,
true
);
let
list
=
await
onAudioProcessed
(
res
,
liveInfo
);
// 提交
await
regenerate
(
resultL
ist
,
liveInfo
,
live_id
);
await
regenerate
(
l
ist
,
liveInfo
,
live_id
);
}
}
}
...
...
src/utils/tool.ts
View file @
4bb22ea8
...
...
@@ -81,10 +81,18 @@ export const TableSort = (list: any, field: string) => {
// 升序
export
const
TableSortAsc
=
(
list
:
any
,
field
:
string
)
=>
{
let
maxIndex
,
temp
;
const
getValue
=
(
obj
:
any
,
path
:
string
)
=>
{
const
keys
=
path
.
split
(
'.'
);
let
value
=
obj
;
for
(
const
key
of
keys
)
{
value
=
value
[
key
];
}
return
value
;
};
for
(
let
i
=
0
;
i
<
list
.
length
-
1
;
i
++
)
{
maxIndex
=
i
;
for
(
let
j
=
i
+
1
;
j
<
list
.
length
;
j
++
)
{
if
(
list
[
j
][
field
]
<
list
[
maxIndex
][
field
]
)
{
if
(
getValue
(
list
[
j
],
field
)
<
getValue
(
list
[
maxIndex
],
field
)
)
{
maxIndex
=
j
;
}
}
...
...
@@ -453,7 +461,7 @@ export const mergedArray = (arr: any[], key: string = 'uuid', first: string = 'i
result
.
push
(...
existingObj
);
}
newSubArray
.
forEach
((
obj
)
=>
{
const
existingIndex
=
result
.
findIndex
((
it
)
=>
it
.
uuid
===
obj
.
uuid
&&
!
obj
[
first
]
&&
!
obj
.
removed
);
const
existingIndex
=
result
.
findIndex
((
it
)
=>
it
[
key
]
===
obj
[
key
]
&&
!
obj
[
first
]
&&
!
obj
.
removed
);
if
(
existingIndex
!==
-
1
)
{
// 标记
obj
.
removed
=
true
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment