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
c7731fcb
Commit
c7731fcb
authored
Aug 03, 2023
by
haojie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
洗稿
parent
0d8701a5
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
766 additions
and
253 deletions
+766
-253
.eslintrc
+1
-0
src/components/AddVideoPlay.vue
+57
-7
src/components/MultipleUpload/index.tsx
+22
-16
src/hooks/useScript.ts
+126
-21
src/layouts/components/Content.vue
+1
-0
src/pages/OnlyVideoLive/components/video.vue
+0
-77
src/pages/OnlyVideoLive/index.vue
+290
-54
src/pages/createLive/components/ChoseDigitalPerson.vue
+43
-10
src/pages/createLive/components/scripts.vue
+53
-25
src/pages/createLive/index.vue
+119
-39
src/pages/home/components/digitalPeopleDiaog.vue
+1
-0
src/pages/home/index.vue
+1
-0
src/service/Common.ts
+1
-1
src/service/Live.ts
+9
-0
src/store/modules/live.ts
+5
-0
src/store/modules/navbar.ts
+5
-0
src/utils/api/userApi.ts
+2
-2
src/utils/audio.ts
+0
-1
src/utils/error.ts
+11
-0
src/utils/tool.ts
+19
-0
No files found.
.eslintrc
View file @
c7731fcb
...
...
@@ -25,6 +25,7 @@
"rules": {
// 禁止 || true ,关闭
"no-constant-condition": 0,
"no-empty": 0,
"vue/no-setup-props-destructure": 0,
"vue/no-v-model-argument": 0,
"vue/no-v-for-template-key": 0,
...
...
src/components/AddVideoPlay.vue
View file @
c7731fcb
...
...
@@ -6,9 +6,10 @@
:volume=
"firstVideoVolume"
ref=
"videoFirst"
class=
"video-default"
loop
:src=
"video1"
:loop=
"loop"
@
canplay=
"canplay"
@
ended=
"firstVideoEnded"
></video>
<video
v-show=
"!showFirstVideo"
...
...
@@ -16,7 +17,7 @@
:volume=
"secondVideoVolume"
class=
"video-default"
:src=
"video2"
@
ended=
"
on
VideoEnded"
@
ended=
"
second
VideoEnded"
@
canplay=
"canplay2"
></video>
<ConfirmDialog
v-model=
"confirmVisible"
:closeOnOverlayClick=
"false"
:footer=
"footerStatus"
@
confirm=
"confirm"
>
...
...
@@ -42,19 +43,35 @@ import { onBeforeRouteLeave } from 'vue-router';
import
{
injectWindow
}
from
'@/utils/pyqt'
;
import
{
show_message
}
from
'@/utils/tool'
;
const
props
=
defineProps
<
{
const
props
=
withDefaults
(
defineProps
<
{
video1
:
string
;
video2
:
string
;
playId
?:
any
;
progress
:
number
;
}
>
();
mainIndex
?:
number
|
null
;
totalTime
:
number
;
liveDetail
:
any
;
}
>
(),
{
mainIndex
:
null
,
},
);
const
emit
=
defineEmits
([
'playEnd'
,
'update:progress'
]);
const
emit
=
defineEmits
([
'update:totalTime'
,
'currentTime'
,
'playEnd'
,
'mainVideoStartPlay'
,
'mainVideoPlayEnd'
,
'update:progress'
,
]);
const
store
=
useStore
();
const
videoNum
=
computed
(()
=>
store
.
getters
[
'live/getVideoNum'
]);
const
liveVideoStatus
=
computed
(()
=>
store
.
getters
[
'live/getLiveVideoStatus'
]);
const
loop
=
ref
(
false
);
const
loading
=
ref
(
true
);
const
footerStatus
=
ref
(
false
);
const
showFirstVideo
=
ref
(
true
);
...
...
@@ -63,6 +80,9 @@ const videoSecondPlay = ref(false);
const
confirmVisible
=
ref
(
true
);
// 第一个视频是否首次播放
const
videoFirstPlay
=
ref
(
true
);
// 第二个视频是否首次播放
const
videoSecondFirstPlay
=
ref
(
true
);
...
...
@@ -98,18 +118,35 @@ const closeInterval = () => {
interval
=
null
;
};
// 确定播放
const
confirm
=
()
=>
{
openInterval
();
onPlay
();
videoFirstPlay
.
value
=
false
;
emit
(
'mainVideoStartPlay'
,
props
.
mainIndex
);
};
// 主视频可以播放
const
canplay
=
()
=>
{
// 获取视频总时长
total
.
value
=
videoFirst
.
value
.
duration
;
// onPlay();
emit
(
'update:totalTime'
,
total
.
value
);
if
(
!
videoFirstPlay
.
value
)
{
//
onPlay
();
emit
(
'mainVideoStartPlay'
,
props
.
mainIndex
);
}
};
// 主视频播放完毕
const
firstVideoEnded
=
()
=>
{
if
(
videoFirst
.
value
.
ended
)
{
emit
(
'mainVideoPlayEnd'
,
props
.
mainIndex
);
}
};
const
onVideoEnded
=
()
=>
{
// 互动视频播放完毕
const
secondVideoEnded
=
()
=>
{
if
(
videoSecond
.
value
?.
ended
)
{
emit
(
'playEnd'
,
props
.
playId
);
showFirstVideo
.
value
=
true
;
...
...
@@ -156,6 +193,17 @@ watch(
},
);
// 判断是否洗稿
watch
(
()
=>
props
.
liveDetail
,
(
v
)
=>
{
if
(
v
&&
v
.
is_disorganize
===
0
)
{
// 不洗稿,开启循环播放
loop
.
value
=
true
;
}
},
);
watch
(
()
=>
props
.
video1
,
(
v
)
=>
{
...
...
@@ -183,6 +231,8 @@ const updateTime = () => {
if
(
total
.
value
)
{
// 计算百分比
emit
(
'update:progress'
,
Math
.
floor
((
videoFirst
.
value
.
currentTime
/
total
.
value
)
*
100
));
// 提交当前进度
emit
(
'currentTime'
,
videoFirst
.
value
.
currentTime
);
}
};
// 减小正在播放的视频音量
...
...
src/components/MultipleUpload/index.tsx
View file @
c7731fcb
...
...
@@ -102,19 +102,21 @@ export default defineComponent({
// 文件是否上传过
const
fileHasUploaded
=
(
file
:
File
)
=>
{
for
(
let
i
=
0
;
i
<
fileList
.
value
.
length
;
i
++
)
{
let
item
=
fileList
.
value
[
i
].
file
;
if
(
item
===
file
||
(
item
.
lastModified
==
file
.
lastModified
&&
item
.
name
==
file
.
name
&&
item
.
size
==
file
.
size
&&
item
.
type
==
file
.
type
)
)
{
show_message
(
`
${
file
.
name
}
已经上传过了`
);
return
false
;
}
}
// for (let i = 0; i < fileList.value.length; i++) {
// let item = fileList.value[i].file;
// if (item) {
// if (
// item === file ||
// (item.lastModified == file.lastModified &&
// item.name == file.name &&
// item.size == file.size &&
// item.type == file.type)
// ) {
// show_message(`${file.name}已经上传过了`);
// return false;
// }
// }
// }
return
true
;
};
...
...
@@ -131,9 +133,11 @@ export default defineComponent({
return
false
;
}
// 文件后缀
cons
t
fileSuffix
=
getFileSuffix
(
file
);
le
t
fileSuffix
=
getFileSuffix
(
file
);
if
(
props
.
accept
)
{
if
(
props
.
accept
.
indexOf
(
fileSuffix
)
==
-
1
)
{
let
accept
=
props
.
accept
.
toLowerCase
();
fileSuffix
=
fileSuffix
.
toLowerCase
();
if
(
accept
.
indexOf
(
fileSuffix
)
==
-
1
)
{
show_message
(
`本次上传仅支持
${
props
.
accept
}
格式`
);
return
false
;
}
...
...
@@ -269,6 +273,8 @@ export default defineComponent({
fileList
.
value
.
forEach
((
item
:
any
)
=>
{
if
(
item
.
url
)
{
list
.
push
(
item
.
url
);
}
else
if
(
item
.
audio_url
)
{
list
.
push
(
item
.
audio_url
);
}
if
(
item
.
time
)
{
totalTime
+=
item
.
time
;
...
...
@@ -322,7 +328,7 @@ export default defineComponent({
</
span
>
</
div
>
)
}
<
div
class=
"file-name"
>
{
item
.
file
.
name
}
</
div
>
<
div
class=
"file-name"
>
{
item
.
file
?
.
name
}
</
div
>
{
computedTotalTime
()
?
(
<
audio
src=
{
item
.
url
}
...
...
src/
pages/createLive/hooks/scripts
.ts
→
src/
hooks/useScript
.ts
View file @
c7731fcb
import
{
computed
,
onBeforeUnmount
,
ref
,
watch
}
from
'vue'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
,
scriptTypeText
}
from
'@/service/CreateLive'
;
import
{
getLiveTtsCallback
,
createLiveTask
,
liveTts
}
from
'@/utils/api/userApi'
;
import
{
alyOssUpload
,
show_message
}
from
'@/utils/tool'
;
import
{
getLiveTtsCallback
,
createLiveTask
,
liveTts
,
liveTaskRegenerate
}
from
'@/utils/api/userApi'
;
import
{
alyOssUpload
,
dimensionalConvert
,
isDev
,
show_message
}
from
'@/utils/tool'
;
import
{
audioMerge
,
splitAudio
}
from
'@/utils/audio'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
getUploadConfig
}
from
'@/service/Common'
;
import
{
getUploadConfig
,
onUpdateLiveTask
}
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
}
from
'@/utils/pyqt'
;
// 轮询处理文本脚本语音生成回调
export
const
processTextCallback
=
()
=>
{
...
...
@@ -46,6 +48,7 @@ export const processTextCallback = () => {
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
if
(
res
.
code
==
0
)
{
console
.
log
(
'等待音频生成完成'
);
// 开始轮询
openInterval
(
true
);
}
...
...
@@ -57,6 +60,7 @@ export const processTextCallback = () => {
()
=>
confuseList
.
value
,
(
v
)
=>
{
if
(
v
.
length
)
{
console
.
log
(
'洗稿列表变化'
);
// 提交生成音频任务
submitAudioTask
(
v
);
}
...
...
@@ -81,25 +85,29 @@ export const processTextCallback = () => {
params
.
type_content
=
item
[
createLiveKeys
.
textScriptValue
];
// 音色id
params
.
phonetic_timbres_id
=
item
[
createLiveKeys
.
textSoundColor
];
// 文本内容
params
.
content
=
item
[
createLiveKeys
.
textScriptList
].
map
((
item
:
any
)
=>
{
// 文本内容--先转一维数组
let
newList
=
dimensionalConvert
(
item
[
createLiveKeys
.
textScriptList
]);
params
.
content
=
newList
.
map
((
row
:
any
)
=>
{
return
{
title
:
item
.
title
,
content
:
item
.
content
,
title
:
row
.
title
,
content
:
row
.
content
,
};
});
}
else
{
// 音频
params
.
type_content
=
item
[
createLiveKeys
.
audioScriptList
].
map
((
item
:
any
)
=>
{
console
.
log
(
item
[
createLiveKeys
.
audioScriptList
]);
params
.
type_content
=
item
[
createLiveKeys
.
audioScriptList
].
map
((
audioScript
:
any
)
=>
{
let
list
=
[];
item
.
data
.
forEach
((
it
:
any
)
=>
{
audioScript
.
data
.
forEach
((
it
:
any
)
=>
{
let
params
=
{
content
:
''
,
};
if
(
typeof
it
===
'string'
)
{
params
.
content
=
it
;
}
else
{
}
else
if
(
it
.
url
)
{
params
.
content
=
it
.
url
;
}
else
{
params
.
content
=
it
.
audio_url
;
}
list
.
push
(
params
);
});
...
...
@@ -134,7 +142,8 @@ export const processTextCallback = () => {
};
// 提交后台
const
submit
=
async
()
=>
{
const
submit
=
async
(
type
:
string
=
'create'
)
=>
{
if
(
type
===
'create'
)
{
try
{
let
res
:
any
=
await
createLiveTask
(
filterFiled
());
if
(
res
.
code
==
0
)
{
...
...
@@ -145,13 +154,40 @@ export const processTextCallback = () => {
console
.
log
(
e
);
return
false
;
}
}
else
{
// 更新
console
.
log
(
'更新'
);
try
{
let
params
=
filterFiled
();
loading
.
value
=
true
;
let
res
:
any
=
await
onUpdateLiveTask
(
route
.
query
.
id
,
params
);
if
(
res
)
{
if
(
route
.
query
.
type
===
'edit'
)
{
// 通知python删除对应的output.mp4
callPyjsInWindow
(
'deleteOutputVideo'
,
{
id
:
route
.
query
.
id
,
});
}
// 回首页
backHome
();
}
loading
.
value
=
false
;
}
catch
(
e
)
{
loading
.
value
=
false
;
console
.
log
(
e
);
}
}
};
// 任务提交成功后的回调
const
submitSuccessed
=
(
message
:
string
=
'创建成功'
)
=>
{
const
submitSuccessed
=
(
message
:
string
=
'创建成功'
,
back
:
boolean
=
true
)
=>
{
if
(
message
)
{
show_message
(
message
,
'success'
);
}
if
(
back
)
{
// 回首页
backHome
();
}
initCreateStore
();
// 通知三个模块清空自己的内容
initNum
.
value
+=
1
;
...
...
@@ -192,6 +228,10 @@ export const processTextCallback = () => {
// 循环上传阿里云
const
uploadToAly
=
async
(
fileList
:
File
[])
=>
{
// 每次上传前清空数组
alyList
.
value
=
[];
console
.
log
(
'任务数'
);
console
.
log
(
fileList
.
length
);
// 获取阿里云配置
let
config
=
await
getUploadConfig
();
for
(
let
i
=
0
;
i
<
fileList
.
length
;
i
++
)
{
...
...
@@ -232,6 +272,8 @@ export const processTextCallback = () => {
let
split_list
=
await
splitAudio
(
file
,
5
*
1024
*
1024
);
if
(
split_list
&&
split_list
.
length
)
{
let
result
=
await
uploadToAly
(
split_list
);
console
.
log
(
'上传完毕'
);
console
.
log
(
result
.
length
);
// 是否一维数组
if
(
dimensional
)
{
return
result
;
...
...
@@ -239,11 +281,32 @@ export const processTextCallback = () => {
return
[
result
];
}
}
}
else
{
}
};
// 重新生成直播
const
regenerate
=
async
(
list
:
any
[],
successCallback
:
boolean
)
=>
{
try
{
let
params
=
filterFiled
();
params
.
type_content
=
list
;
let
res
:
any
=
await
liveTaskRegenerate
(
route
.
query
.
id
,
params
);
if
(
res
.
code
==
0
)
{
if
(
successCallback
)
{
submitSuccessed
();
}
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 获取任务id
const
getTaskId
=
(
isConfuse
:
boolean
)
=>
{
const
getTaskId
=
(
isConfuse
:
boolean
,
uuid
:
string
=
''
)
=>
{
if
(
uuid
)
{
console
.
log
(
'自定义的uuid'
);
return
uuid
;
}
if
(
isConfuse
)
{
// 是洗稿任务
return
currentConfuseId
.
value
;
...
...
@@ -251,12 +314,30 @@ export const processTextCallback = () => {
return
createLiveInfo
.
value
[
createLiveKeys
.
scriptUuid
];
};
const
getTaskStatus
=
async
(
isConfuse
:
boolean
)
=>
{
const
getTaskStatus
=
async
(
isConfuse
:
boolean
,
type
:
string
=
'create'
,
successCallback
:
boolean
,
uuid
:
string
,
customRegenerate
:
any
=
false
,
)
=>
{
try
{
let
res
:
any
=
await
getLiveTtsCallback
({
task_id
:
getTaskId
(
isConfuse
),
task_id
:
getTaskId
(
isConfuse
,
uuid
),
});
if
(
res
.
code
==
0
)
{
if
(
isDev
())
{
let
params
=
{
data
:
{
audio_address
:
'http://nls-cloud-cn-shanghai.oss-cn-shanghai.aliyuncs.com/jupiter-flow/tmp/ed71050141c74954ac779cfbb9dd9604.wav?Expires=1691136228&OSSAccessKeyId=LTAIUpwNp2H7pBG5&Signature=jE01uOk8Vfa08ovlPbJYI2Bhwvs%3D'
,
task_id
:
0
,
},
};
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
res
.
data
.
push
(
params
);
}
}
if
(
res
.
data
.
length
>=
createLiveInfo
.
value
[
createLiveKeys
.
textScriptList
].
length
)
{
// 关闭定时器
closeInterval
();
...
...
@@ -267,7 +348,11 @@ export const processTextCallback = () => {
res
.
data
.
forEach
((
item
:
any
)
=>
{
// 根据task_id更新数组对象
let
data
=
item
.
data
;
if
(
data
&&
data
.
audio_address
&&
data
.
task_id
)
{
if
(
data
&&
data
.
audio_address
&&
(
typeof
data
.
task_id
===
'string'
||
typeof
data
.
task_id
===
'number'
)
)
{
audio_list
.
push
(
data
.
audio_address
);
let
index
=
list
.
findIndex
((
it
:
any
)
=>
it
.
task_id
==
data
.
task_id
);
if
(
index
!==
-
1
)
{
...
...
@@ -280,18 +365,23 @@ export const processTextCallback = () => {
show_message
(
'缺少音频或id'
);
}
});
if
(
!
audio_list
.
length
)
{
throw
new
CustomException
(
'没有要处理的音频'
);
}
let
resultList
=
await
audioStart
(
audio_list
,
false
);
// 修改store的type_content
commitInfo
({
[
createLiveKeys
.
textScriptValue
]:
resultList
,
});
// 提交
await
submit
();
await
submit
(
type
);
// 需要洗稿
if
(
createLiveInfo
.
value
[
createLiveKeys
.
isDisorganize
])
{
//
await
startConfuse
();
}
else
{
loading
.
value
=
false
;
submitSuccessed
();
}
}
else
{
...
...
@@ -305,19 +395,31 @@ export const processTextCallback = () => {
}
});
let
resultList
=
await
audioStart
(
audio_list
,
false
);
console
.
log
(
'提交的个数'
);
console
.
log
(
resultList
.
length
);
// 提交
if
(
customRegenerate
)
{
await
customRegenerate
(
resultList
);
}
else
{
await
regenerate
(
resultList
,
successCallback
);
}
loading
.
value
=
false
;
}
}
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
const
openInterval
=
(
isConfuse
:
boolean
)
=>
{
const
openInterval
=
(
isConfuse
:
boolean
,
type
:
string
=
'create'
,
successCallback
:
boolean
=
true
,
uuid
:
string
=
''
,
customRegenerate
:
any
=
false
,
)
=>
{
interval
.
value
=
window
.
setInterval
(()
=>
{
getTaskStatus
(
isConfuse
);
getTaskStatus
(
isConfuse
,
type
,
successCallback
,
uuid
,
customRegenerate
);
},
3000
);
};
...
...
@@ -341,5 +443,8 @@ export const processTextCallback = () => {
submit
,
submitSuccessed
,
backHome
,
currentConfuseId
,
confuseList
,
currentStartConfuse
,
};
};
src/layouts/components/Content.vue
View file @
c7731fcb
...
...
@@ -15,6 +15,7 @@
</
template
>
<
script
lang=
"ts"
setup
>
import
allRouter
from
'@/router'
;
import
{
useRoute
}
from
'vue-router'
;
const
route
=
useRoute
();
...
...
src/pages/OnlyVideoLive/components/video.vue
deleted
100644 → 0
View file @
0d8701a5
<
template
>
<div
class=
"start-only-video-live"
>
<!--
<Button
theme=
"green"
@
click=
"playVideo"
>
开始播放
</Button>
-->
<AddVideoPlay
v-model:progress=
"progress"
:playId=
"playId"
@
playEnd=
"playEnd"
:video1=
"video"
:video2=
"video2"
></AddVideoPlay>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
import
Button
from
'@/components/Button.vue'
;
import
{
onBeforeUnmount
,
ref
,
watch
}
from
'vue'
;
import
AddVideoPlay
from
'@/components/AddVideoPlay.vue'
;
const
props
=
withDefaults
(
defineProps
<
{
video
:
any
;
video2
:
any
;
playId
?:
any
;
modelValue
:
any
;
}
>
(),
{
playId
:
0
,
},
);
const
videoRef1
=
ref
<
HTMLVideoElement
>
();
let
interval1
=
null
;
const
progress
=
ref
(
0
);
const
emit
=
defineEmits
([
'update:modelValue'
,
'playEnd'
]);
watch
(
()
=>
progress
.
value
,
(
v
)
=>
{
emit
(
'update:modelValue'
,
v
);
},
);
const
playEnd
=
(
id
:
any
)
=>
{
emit
(
'playEnd'
,
id
);
};
const
closeInterval
=
()
=>
{
window
.
clearInterval
(
interval1
);
clearInterval
(
interval1
);
interval1
=
null
;
};
const
playVideo
=
()
=>
{
console
.
log
(
videoRef1
.
value
);
videoRef1
.
value
.
play
();
closeInterval
();
interval1
=
window
.
setInterval
(()
=>
{
// 播放结束
if
(
videoRef1
.
value
.
ended
)
{
closeInterval
();
}
},
100
);
};
onBeforeUnmount
(()
=>
{
closeInterval
();
});
</
script
>
<
style
lang=
"less"
>
.start-only-video-live
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
box-sizing
:
border-box
;
}
</
style
>
src/pages/OnlyVideoLive/index.vue
View file @
c7731fcb
<
template
>
<div
class=
"custom-start-only-video-page"
>
<Video
:video=
"realVideo"
v-model=
"progress"
:video2=
"addVideo"
:playId=
"addVideoId"
@
playEnd=
"playEnd"
></Video>
<div
class=
"start-only-video-live"
>
<AddVideoPlay
v-model:progress=
"progress"
v-model:totalTime=
"totalTime"
:mainIndex=
"mainVideoIndex"
:playId=
"addVideoId"
:video1=
"getCurrentMainVideo"
:liveDetail=
"liveDetail"
:video2=
"addVideo"
@
playEnd=
"playEnd"
@
mainVideoPlayEnd=
"mainVideoPlayEnd"
@
mainVideoStartPlay=
"mainVideoStartPlay"
@
currentTime=
"currentTimeChange"
></AddVideoPlay>
</div>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
onBeforeUnmount
,
onMounted
,
reactive
,
ref
}
from
'vue'
;
import
Video
from
'./components/video
.vue'
;
import
{
computed
,
onBeforeUnmount
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
AddVideoPlay
from
'@/components/AddVideoPlay
.vue'
;
import
{
getLiveDetail
}
from
'@/utils/api/userApi'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
import
{
show_message
,
isDev
}
from
'@/utils/tool'
;
import
{
callPyjsInWindow
,
injectWindow
}
from
'@/utils/pyqt'
;
import
{
getliveTaskReply
,
getUserCookie
}
from
'@/utils/api/userApi'
;
import
{
getliveTaskReply
,
getUserCookie
,
liveTts
,
getLiveTaskInfo
,
liveTaskRegenerate
}
from
'@/utils/api/userApi'
;
import
routerConfig
from
'@/router/tool'
;
import
{
useStore
}
from
'vuex'
;
import
{
v4
}
from
'uuid'
;
import
useConfuse
from
'@/hooks/useConfuse'
;
import
{
CONFUSE_STATUS
}
from
'@/service/Live'
;
import
{
processTextCallback
}
from
'@/hooks/useScript'
;
const
{
currentConfuseId
,
confuseList
,
currentStartConfuse
}
=
useConfuse
();
const
{
openInterval
:
confuseInterval
}
=
processTextCallback
();
const
store
=
useStore
();
const
route
=
useRoute
();
...
...
@@ -22,34 +42,150 @@ const routeQuery = route.query;
const
progress
=
ref
(
0
);
// 剩余多少时长时开始洗稿并获取下一个视频
const
esidueTime
=
60
*
10
;
// 当前播放的主视频的总视频时长
const
totalTime
=
ref
(
0
);
// 当前的播放进度
const
currentTime
=
ref
(
0
);
const
imgs
=
{
mp4
:
new
URL
(
'../../assets/img/1.mp4'
,
import
.
meta
.
url
).
href
,
mp3
:
new
URL
(
'../../assets/img/2.wav'
,
import
.
meta
.
url
).
href
,
};
const
liveInfo
=
reactive
({
// 原始链接
video
:
[],
content
:
''
,
type_content
:
''
,
});
// 定时检测python的方法是否注入成功
let
interval
=
null
;
// 定时获取直播互动内容
let
intervalLive
=
null
;
// 处理后的视频
const
realVideo
=
ref
(
''
);
// 新增视频(当前)
// 定时获取主视频任务
let
intervalMainVideo
=
null
;
// 主视频列表
const
realVideoList
=
ref
([]);
// 当前主视频的下标
const
mainVideoIndex
=
ref
();
// 当前洗稿的下标(在主视频列表中的下标)
const
confuseIndex
=
ref
();
// 互动视频
const
addVideo
=
ref
(
imgs
.
mp4
);
// 视频列表
//
互动
视频列表
const
addVideoList
=
ref
([]);
// 当前播放id
//
互动视频
当前播放id
const
addVideoId
=
ref
(
''
);
// 添加的视频播放结束
// 音调id
const
phoneticTimbresId
=
ref
();
// 音色id
const
toneId
=
ref
();
// 直播详情
const
liveDetail
=
ref
({});
const
submitAudioTask
=
async
(
list
:
any
[])
=>
{
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
params
=
{
// 音色
phonetic_timbres_id
:
phoneticTimbresId
.
value
,
// 音调
tone_id
:
toneId
.
value
,
content
:
list
[
i
].
content
,
uuid
:
currentConfuseId
.
value
,
};
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
if
(
res
.
code
==
0
)
{
console
.
log
(
'等待音频生成完成'
);
// 开始轮询
confuseInterval
(
true
,
''
,
false
,
currentConfuseId
.
value
,
regenerate
);
}
}
};
// 洗稿列表变化
watch
(
()
=>
confuseList
.
value
,
(
v
)
=>
{
if
(
v
.
length
)
{
console
.
log
(
'洗稿列表变化'
);
// 提交生成音频任务
submitAudioTask
(
v
);
}
},
);
// 当前主视频
const
getCurrentMainVideo
=
computed
(()
=>
{
if
(
typeof
mainVideoIndex
.
value
===
'number'
&&
realVideoList
.
value
[
mainVideoIndex
.
value
].
result
)
{
return
realVideoList
.
value
[
mainVideoIndex
.
value
].
result
;
}
return
''
;
});
// 提交洗稿
const
submitConfuse
=
async
()
=>
{
try
{
currentConfuseId
.
value
=
v4
();
let
content
=
''
;
let
contentList
=
realVideoList
.
value
[
mainVideoIndex
.
value
].
type_content
;
// 记录本次洗稿id
confuseIndex
.
value
=
mainVideoIndex
.
value
;
if
(
contentList
.
length
)
{
contentList
.
forEach
((
item
:
any
)
=>
{
content
+=
item
.
content
;
});
// 提交洗稿任务
currentStartConfuse
({
content
:
content
,
task_id
:
currentConfuseId
.
value
,
id
:
route
.
query
.
id
,
});
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 当前播放进度变化
const
currentTimeChange
=
(
value
:
number
)
=>
{
currentTime
.
value
=
value
;
// 剩余多少没有播放
let
currentEsidueTime
=
totalTime
.
value
-
value
;
let
currentVideoRow
=
realVideoList
.
value
[
mainVideoIndex
.
value
];
// 低于设置的值、没有开始洗稿、有文本内容
if
(
currentEsidueTime
<
esidueTime
&&
currentVideoRow
.
confuse
===
CONFUSE_STATUS
.
CONFUSE_STATUS_WAIT
&&
realVideoList
.
value
[
mainVideoIndex
.
value
].
type_content
.
length
&&
typeof
phoneticTimbresId
.
value
===
'number'
&&
typeof
toneId
.
value
===
'number'
&&
liveDetail
.
value
.
is_disorganize
)
{
currentVideoRow
.
confuse
=
CONFUSE_STATUS
.
CONFUSE_STATUS_PROGRESS
;
console
.
log
(
'开始洗稿'
);
// 开始洗稿
submitConfuse
();
}
};
// 主视频开始播放
const
mainVideoStartPlay
=
(
index
:
number
)
=>
{
realVideoList
.
value
[
index
].
play
=
true
;
};
// 主视频播放完毕
const
mainVideoPlayEnd
=
(
index
:
number
)
=>
{
realVideoList
.
value
[
index
].
status
=
true
;
// 找下一个
takeMainVideo
();
};
// 互动视频播放结束
const
playEnd
=
(
id
:
any
)
=>
{
if
(
id
)
{
//
...
...
@@ -63,6 +199,20 @@ const playEnd = (id: any) => {
}
};
// 开启主视频任务定时器
const
StartIntervalMainVideo
=
()
=>
{
intervalMainVideo
=
window
.
setInterval
(()
=>
{
getDetail
();
},
10000
);
};
// 关闭
const
closeIntervalMainVideo
=
()
=>
{
window
.
clearInterval
(
intervalMainVideo
);
clearInterval
(
intervalMainVideo
);
intervalMainVideo
=
null
;
};
const
stopInterval
=
()
=>
{
window
.
clearInterval
(
interval
);
clearInterval
(
interval
);
...
...
@@ -100,25 +250,6 @@ const getLive = async () => {
try
{
let
res
:
any
=
await
getliveTaskReply
(
route
.
query
.
id
);
if
(
res
.
code
==
0
&&
res
.
data
&&
res
.
data
.
length
)
{
// if (isDev()) {
// num += 1;
// res.data = [
// {
// id: num,
// reply_content:
// num % 2 == 1
// ? 'https://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/1.mp4'
// : 'http://yunyi-tiktok.oss-cn-shenzhen.aliyuncs.com/files/user/admin/5c8eeb9e-6a7b-45e6-85f9-1c75c945b8b1.mp4',
// },
// {
// id: num++,
// reply_content:
// num % 2 == 1
// ? 'https://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/1.mp4'
// : 'http://yunyi-tiktok.oss-cn-shenzhen.aliyuncs.com/files/user/admin/5c8eeb9e-6a7b-45e6-85f9-1c75c945b8b1.mp4',
// },
// ];
// }
res
.
data
.
forEach
((
item
:
any
)
=>
{
item
.
play_status
=
false
;
item
.
remove
=
false
;
...
...
@@ -132,6 +263,25 @@ const getLive = async () => {
console
.
log
(
e
);
}
};
// 重新生成直播
const
regenerate
=
async
(
list
:
any
[])
=>
{
try
{
let
params
=
{
digital_man_id
:
liveDetail
.
value
.
digital_man_id
,
name
:
liveDetail
.
value
.
name
,
phonetic_timbres_id
:
phoneticTimbresId
.
value
,
tone_id
:
toneId
.
value
,
type
:
liveDetail
.
value
.
type
,
};
params
.
type_content
=
list
;
let
res
:
any
=
await
liveTaskRegenerate
(
route
.
query
.
id
,
params
);
if
(
res
.
code
==
0
)
{
//
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
// 开启
const
startLiveInterval
=
()
=>
{
...
...
@@ -148,7 +298,7 @@ const closeLiveInterval = () => {
intervalLive
=
null
;
};
const
getDetail
=
async
()
=>
{
const
getDetail
=
async
(
type
:
string
=
''
)
=>
{
if
(
!
routeQuery
.
id
)
{
show_message
(
'禁止访问'
);
return
;
...
...
@@ -156,13 +306,56 @@ const getDetail = async () => {
try
{
let
res
:
any
=
await
getLiveDetail
(
routeQuery
.
id
);
if
(
res
.
code
==
0
)
{
liveInfo
.
video
=
res
.
data
.
url
;
liveInfo
.
content
=
res
.
data
.
content
;
if
(
res
.
data
.
type_content
)
{
liveInfo
.
content
=
res
.
data
.
type_content
;
if
(
isDev
())
{
// 创建url
res
.
data
=
{};
res
.
data
.
url
=
[
'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/87.mp4'
,
'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/87.mp4'
,
'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/87.mp4'
,
];
res
.
data
.
type_content
=
[
{
content
:
'测试文案提交'
,
},
];
}
if
(
res
.
data
.
url
.
length
)
{
if
(
typeof
confuseIndex
.
value
===
'number'
)
{
// 本次是洗稿回调
}
//
realVideoList
.
value
.
push
({
url
:
res
.
data
.
url
,
// 合并后的地址
result
:
''
,
// 是否播放完毕
status
:
false
,
// 是否取走
remove
:
false
,
// 是否正在播放
play
:
false
,
// 是否已经提交给python
submit
:
false
,
// 下一个视频的状态
confuse
:
CONFUSE_STATUS
.
CONFUSE_STATUS_WAIT
,
// 洗稿任务的uuid
uuid
:
v4
(),
type_content
:
res
.
data
.
type_content
?
res
.
data
.
type_content
:
[],
});
if
(
isDev
())
{
mergeCallback
({
// video: imgs.mp4,
video
:
'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/87.mp4'
,
index
:
realVideoList
.
value
.
length
-
1
,
});
}
else
{
// 通知python合并
submitVideo
();
}
if
(
type
===
'init'
)
{
// 通知python刷新所有首页的直播列表
callPyjsInWindow
(
'reloadLiveTaskList'
);
// 开播成功
...
...
@@ -175,6 +368,8 @@ const getDetail = async () => {
},
});
}
}
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
...
...
@@ -186,7 +381,12 @@ const submitVideo = () => {
if
(
window
.
pyjs
)
{
console
.
log
(
route
.
query
.
window_index
,
'窗口下标'
);
if
(
window
.
pyjs
.
run
)
{
window
.
pyjs
.
run
(
liveInfo
.
video
,
routeQuery
.
id
,
route
.
query
.
window_index
);
// 未取走且未提交过的视频
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
);
}
console
.
log
(
'执行了run方法'
);
}
else
{
console
.
log
(
'没有run方法'
);
...
...
@@ -199,14 +399,45 @@ const submitVideo = () => {
}
};
// 取主视频
const
takeMainVideo
=
()
=>
{
let
index
=
realVideoList
.
value
.
findIndex
((
item
:
any
)
=>
!
item
.
remove
&&
item
.
result
&&
!
item
.
status
);
if
(
index
!==
-
1
)
{
realVideoList
.
value
[
index
].
remove
=
true
;
mainVideoIndex
.
value
=
index
;
}
else
{
console
.
log
(
'没有要播放的视频'
);
// 手动重新开始播放
}
};
// python 回调
const
mergeCallback
=
(
params
:
any
)
=>
{
try
{
if
(
params
.
video
)
{
realVideo
.
value
=
params
.
video
;
if
(
typeof
params
.
index
===
'number'
&&
params
.
video
)
{
// 当前视频的返回结果
realVideoList
.
value
[
params
.
index
].
result
=
params
.
video
;
// 首次播放
let
list
=
realVideoList
.
value
.
filter
((
item
:
any
)
=>
item
.
remove
===
true
);
if
(
!
list
.
length
)
{
takeMainVideo
();
}
if
(
params
.
add_video
)
{
addVideo
.
value
=
params
.
add_video
;
}
else
{
console
.
log
(
'回调格式错误'
);
console
.
log
(
params
);
}
}
catch
(
e
)
{
console
.
log
(
e
);
}
};
const
getTone
=
async
()
=>
{
try
{
let
res
=
await
getLiveTaskInfo
(
route
.
query
.
id
);
if
(
res
.
code
==
0
)
{
phoneticTimbresId
.
value
=
res
.
data
.
phonetic_timbres_id
;
toneId
.
value
=
res
.
data
.
tone_id
;
liveDetail
.
value
=
res
.
data
;
}
}
catch
(
e
)
{
console
.
log
(
e
);
...
...
@@ -223,21 +454,20 @@ onMounted(async () => {
console
.
error
(
'没有pyjs'
);
}
// if (isDev()) {
// mergeCallback({
// // video: imgs.mp4,
// video: 'http://yunyi-live.oss-cn-hangzhou.aliyuncs.com/live/output/87.mp4',
// });
// }
// 打开定时任务
// 获取互动
startLiveInterval
();
// 获取主视频
StartIntervalMainVideo
();
openInterval
();
// 可以开播
await
getDetail
();
await
getDetail
(
'init'
);
// 获取音调和音色
getTone
();
});
onBeforeUnmount
(()
=>
{
closeLiveInterval
();
stopInterval
();
closeIntervalMainVideo
();
});
</
script
>
...
...
@@ -253,5 +483,11 @@ onBeforeUnmount(() => {
background
:
#303030
;
height
:
100%
;
}
.start-only-video-live
{
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
box-sizing
:
border-box
;
}
}
</
style
>
src/pages/createLive/components/ChoseDigitalPerson.vue
View file @
c7731fcb
...
...
@@ -12,7 +12,7 @@
maxHeight: maxHeight + 'px',
}"
>
<
Grid
:length=
"digitalList.list.length"
:rowGap=
"12"
:marginLeft=
"8
"
>
<
div
class=
"create-digital-person-grid
"
>
<template
v-for=
"item in digitalList.list"
:key=
"item.id"
>
<CardOne
:row=
"item"
...
...
@@ -23,7 +23,7 @@
@
change=
"onCardChange"
></CardOne>
</
template
>
</
Grid
>
</
div
>
</div>
</div>
</div>
...
...
@@ -31,10 +31,9 @@
<
script
lang=
"ts"
setup
>
import
Loading
from
'@/components/loading.vue'
;
import
Grid
from
'@/components/Grid.vue'
;
import
Select
from
'@/components/Select.vue'
;
import
CardOne
from
'@/components/cardOne.vue'
;
import
{
ref
,
onMounted
,
reactive
,
watch
,
computed
}
from
'vue'
;
import
{
ref
,
onMounted
,
reactive
,
watch
,
computed
,
onActivated
}
from
'vue'
;
import
{
getElBounding
,
getWindowClient
,
isDev
}
from
'@/utils/tool'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
}
from
'@/service/CreateLive'
;
...
...
@@ -84,12 +83,14 @@ const updateInfo = (info: any) => {
name
=
info
.
name
;
digital_man_id
=
info
.
digital_man_id
;
}
else
if
(
info
.
content
)
{
// 草稿
name
=
info
.
content
.
name
?
info
.
content
.
name
:
''
;
digital_man_id
=
info
.
content
.
digital_man_id
?
info
.
content
.
digital_man_id
:
''
;
}
if
(
name
)
{
// 更新标题
store
.
commit
(
'live/setName'
,
name
);
}
if
(
info
.
users_id
!==
0
)
{
// 我的数字人
currentOption
.
value
=
'2'
;
...
...
@@ -122,11 +123,13 @@ watch(
);
const
onSelectChange
=
(
value
:
string
)
=>
{
if
(
value
)
{
commitInfo
({
[
createLiveKeys
.
id_type
]:
value
,
});
currentOption
.
value
=
value
;
checkPerson
();
}
};
// 从python获取视频路径
...
...
@@ -158,6 +161,26 @@ const digitalList = reactive({
my
:
[],
});
const
findIdinList
=
()
=>
{
if
(
route
.
query
.
id
)
{
// 找到对应的id
let
index1
=
digitalList
.
my
.
findIndex
((
item
:
any
)
=>
item
.
id
==
route
.
query
.
id
);
if
(
index1
!==
-
1
)
{
currentCard
.
value
=
digitalList
.
my
[
index1
].
id
;
}
let
index2
=
digitalList
.
admin
.
findIndex
((
item
:
any
)
=>
item
.
id
==
route
.
query
.
id
);
if
(
index2
!==
-
1
)
{
currentCard
.
value
=
digitalList
.
admin
[
index2
].
id
;
}
if
(
currentCard
.
value
)
{
let
params
=
{
[
createLiveKeys
.
id
]:
currentCard
.
value
,
};
commitInfo
(
params
);
}
}
};
const
changeCurrentList
=
()
=>
{
if
(
currentCard
.
value
)
{
// 找到对应的库
...
...
@@ -189,6 +212,7 @@ const getList = async () => {
digitalList
.
admin
=
res
.
adminList
;
// digitalList.admin = digitalList.admin.concat(res.adminList);
digitalList
.
my
=
res
.
myList
;
findIdinList
();
changeCurrentList
();
checkPerson
();
loading
.
value
=
false
;
...
...
@@ -196,15 +220,18 @@ const getList = async () => {
loading
.
value
=
false
;
console
.
log
(
e
);
}
// 提交默认参数
if
(
currentOption
.
value
)
{
let
params
=
{
[
createLiveKeys
.
id_type
]:
currentOption
.
value
,
};
commitInfo
(
params
);
}
};
on
Moun
ted
(()
=>
{
on
Activa
ted
(()
=>
{
// 获取数字人列表
getList
();
// 提交默认参数
commitInfo
({
[
createLiveKeys
.
id_type
]:
currentOption
.
value
,
});
});
watch
(
...
...
@@ -250,6 +277,12 @@ watch(
height
:
150px
;
}
}
.create-digital-person-grid
{
display
:
grid
;
justify-content
:
space-between
;
grid-template-columns
:
repeat
(
auto-fill
,
150px
);
grid-gap
:
12px
;
}
.card-active
{
border
:
2px
solid
#00dfb0
;
}
...
...
src/pages/createLive/components/scripts.vue
View file @
c7731fcb
...
...
@@ -2,7 +2,9 @@
<div
class=
"create-live-script-setting"
>
<div
class=
"all-select"
>
<Select
:options=
"scriptTypeList"
v-model=
"currentOption"
@
change=
"scriptTypeChange"
></Select>
<template
v-if=
"currentOption == scriptTypeText"
>
<CheckBox
v-model=
"isDisorganize"
@
change=
"checkboxChange"
>
GPT洗稿
</CheckBox>
</
template
>
<
template
v-if=
"isDev()"
>
<Button
@
click=
"
...
...
@@ -152,6 +154,7 @@
v-model=
"item.data"
:config=
"ossConfig"
label=
"选择音频"
accept=
"wav"
@
change=
"uploadEdit"
></MultipleUpload>
</div>
...
...
@@ -191,7 +194,7 @@
</template>
<
script
lang=
"tsx"
setup
>
import
{
computed
,
onMounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
{
computed
,
on
Activated
,
on
Mounted
,
reactive
,
ref
,
watch
}
from
'vue'
;
import
Button
from
'@/components/Button.vue'
;
import
MultipleUpload
from
'@/components/MultipleUpload'
;
import
CheckBox
from
'@/components/CheckBox.vue'
;
...
...
@@ -423,6 +426,7 @@ const updateTonesInfo = (tone_id: any, phonetic_timbres_id: any) => {
};
const
updateInfo
=
(
info
:
any
)
=>
{
if
(
Object
.
keys
(
info
).
length
)
{
let
type
=
''
;
let
type_content
=
''
;
let
phonetic_timbres_id
=
''
;
...
...
@@ -433,6 +437,7 @@ const updateInfo = (info: any) => {
phonetic_timbres_id
=
info
.
phonetic_timbres_id
;
tone_id
=
info
.
tone_id
;
}
else
if
(
info
.
content
)
{
// 草稿
type
=
info
.
content
.
type
;
type_content
=
info
.
content
.
type_content
;
phonetic_timbres_id
=
info
.
content
.
phonetic_timbres_id
?
info
.
content
.
phonetic_timbres_id
:
''
;
...
...
@@ -442,12 +447,27 @@ const updateInfo = (info: any) => {
if
(
type
==
scriptTypeText
)
{
// 文本
currentOption
.
value
=
scriptTypeText
;
if
(
type_content
)
{
// 内容
textareaValue
.
value
=
type_content
;
// textareaValue.value = type_content;
textScriptList
.
value
=
type_content
;
}
// 洗稿
isDisorganize
.
value
=
info
.
is_disorganize
?
true
:
false
;
}
else
{
// 音频
currentOption
.
value
=
scriptTypePhonetics
;
mp3Url
.
value
=
type_content
;
// mp3Url.value = type_content;
if
(
type_content
)
{
audioScriptList
.
value
=
type_content
.
map
((
item
:
any
)
=>
{
return
{
data
:
item
,
};
});
}
else
{
audioScriptList
.
value
=
[];
}
if
(
phonetic_timbres_id
)
{
phoneticsValue
.
value
=
phonetic_timbres_id
;
}
...
...
@@ -459,6 +479,7 @@ const updateInfo = (info: any) => {
// 更新info
updateTonesInfo
(
tone_id
,
phonetic_timbres_id
);
}
};
watch
(
...
...
@@ -483,10 +504,32 @@ watch(
phoneticsInfo
.
value
=
{};
textareaValue
.
value
=
''
;
currentOption
.
value
=
scriptTypeText
;
audioScriptList
.
value
=
[];
textScriptList
.
value
=
[];
scriptTypeChange
(
scriptTypeText
+
''
);
},
);
watch
(
()
=>
soundColorValue
.
value
,
(
v
)
=>
{
if
(
!
v
)
{
soundColorItemChange
();
}
},
);
watch
(
()
=>
tonesValue
.
value
,
(
v
)
=>
{
if
(
v
)
{
disabled
.
value
=
false
;
}
else
{
disabled
.
value
=
true
;
}
},
);
const
openSoundColor
=
()
=>
{
if
(
tonesValue
.
value
)
{
// 允许打开
...
...
@@ -526,15 +569,6 @@ const soundColorItemChange = (item: any = false) => {
}
};
watch
(
()
=>
soundColorValue
.
value
,
(
v
)
=>
{
if
(
!
v
)
{
soundColorItemChange
();
}
},
);
// 音频 音色提交
const
phoneticsItemChange
=
(
item
:
any
)
=>
{
phoneticsInfo
.
value
=
item
;
...
...
@@ -557,17 +591,6 @@ const scriptTypeChange = (id: string | number) => {
});
};
watch
(
()
=>
tonesValue
.
value
,
(
v
)
=>
{
if
(
v
)
{
disabled
.
value
=
false
;
}
else
{
disabled
.
value
=
true
;
}
},
);
const
getList
=
async
()
=>
{
let
res
=
await
getTonesList
();
lists
.
tones
=
res
.
tones
;
...
...
@@ -591,13 +614,18 @@ onMounted(async () => {
// 提交默认脚本类型
commitInfo
({
[
createLiveKeys
.
scriptType
]:
currentOption
.
value
,
// 文本脚本的uuid
[
createLiveKeys
.
scriptUuid
]:
getUuid
(),
});
// 获取音色音调列表
getList
();
});
onActivated
(()
=>
{
commitInfo
({
// 文本脚本的uuid
[
createLiveKeys
.
scriptUuid
]:
getUuid
(),
});
});
</
script
>
<
style
lang=
"less"
>
...
...
src/pages/createLive/index.vue
View file @
c7731fcb
...
...
@@ -66,25 +66,26 @@ 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
,
onMounted
,
ref
,
onBeforeUnmount
,
onA
ctivated
}
from
'vue'
;
import
{
getElBounding
,
show_message
,
DataType
}
from
'@/utils/tool'
;
import
{
computed
,
onMounted
,
onBeforeMount
,
ref
,
onBeforeUnmount
,
onActivated
,
onDea
ctivated
}
from
'vue'
;
import
{
getElBounding
,
show_message
,
DataType
,
dimensionalConvert
}
from
'@/utils/tool'
;
import
{
useStore
}
from
'vuex'
;
import
{
createLiveKeys
,
scriptTypeText
,
scriptTypePhonetics
}
from
'@/service/CreateLive'
;
import
{
createLiveTask
,
getLiveTaskInfo
,
createDrafts
,
getDraftsDetail
,
liveTts
}
from
'@/utils/api/userApi'
;
import
{
useRoute
,
useRouter
}
from
'vue-router'
;
import
{
useRoute
,
useRouter
,
onBeforeRouteLeave
,
onBeforeRouteUpdate
}
from
'vue-router'
;
import
routerConfig
from
'@/router/tool'
;
import
{
onUpdateLiveTask
}
from
'@/service/Common'
;
import
{
createLiveRouteKey
}
from
'@/constants/token'
;
import
{
callPyjsInWindow
}
from
'@/utils/pyqt'
;
import
{
useLiveInfoSubmit
}
from
'@/hooks/useStoreCommit'
;
import
{
processTextCallback
}
from
'./hooks/scripts'
;
import
{
processTextCallback
}
from
'@/hooks/useScript'
;
import
CustomException
from
'@/utils/error'
;
const
{
loading
,
initNum
,
currentSetp
,
openInterval
,
filterFiled
,
backHome
,
submitSuccessed
,
submit
,
initCreateStore
}
=
processTextCallback
();
const
[
commitInfo
]
=
useLiveInfoSubmit
();
const
store
=
useStore
();
const
route
=
useRoute
();
const
routeQuery
=
route
.
query
;
// 离开页面前的query
const
currentQuery
=
ref
({});
const
router
=
useRouter
();
const
liveImage
=
computed
(()
=>
store
.
getters
[
'live/getLiveimage'
]);
// 创建直播的已有的字段
...
...
@@ -173,19 +174,29 @@ const getEditInfo = async (id: any, type: string) => {
store
.
commit
(
'live/setEditLive'
,
res
.
data
);
let
params
:
any
=
{
[
createLiveKeys
.
id
]:
res
.
data
.
digital_man_id
,
[
createLiveKeys
.
id_type
]:
''
,
[
createLiveKeys
.
scriptType
]:
res
.
data
.
type
+
''
,
[
createLiveKeys
.
textTones
]:
res
.
data
.
tone_id
,
[
createLiveKeys
.
commentMethod
]:
1
,
[
createLiveKeys
.
interactiveLibrary
]:
res
.
data
.
interaction_ids
,
};
if
(
res
.
data
.
type
==
'2'
)
{
// 文本
params
[
createLiveKeys
.
textSoundColor
]
=
res
.
data
.
phonetic_timbres_id
;
params
[
createLiveKeys
.
textScriptValue
]
=
res
.
data
.
type_content
;
params
[
createLiveKeys
.
textScriptList
]
=
[
res
.
data
.
type_content
];
params
[
createLiveKeys
.
isDisorganize
]
=
res
.
data
.
is_disorganize
?
true
:
false
;
}
else
{
// 音频音色
params
[
createLiveKeys
.
phoneticsSoundColor
]
=
res
.
data
.
phonetic_timbres_id
;
params
[
createLiveKeys
.
phoneticsFile
]
=
res
.
data
.
type_content
;
params
[
createLiveKeys
.
audioScriptList
]
=
res
.
data
.
type_content
.
map
((
item
:
any
)
=>
{
return
{
data
:
item
,
};
});
}
// 更新标题
if
(
res
.
data
.
name
)
{
store
.
commit
(
'live/setName'
,
res
.
data
.
name
);
}
commitInfo
(
params
);
}
...
...
@@ -197,19 +208,31 @@ const getEditInfo = async (id: any, type: string) => {
let
content
=
item
.
content
;
let
params
:
any
=
{
[
createLiveKeys
.
id
]:
content
.
digital_man_id
,
[
createLiveKeys
.
id_type
]:
''
,
[
createLiveKeys
.
scriptType
]:
content
.
type
+
''
,
[
createLiveKeys
.
textTones
]:
content
.
tone_id
,
[
createLiveKeys
.
commentMethod
]:
1
,
[
createLiveKeys
.
interactiveLibrary
]:
content
.
interaction_ids
,
};
if
(
res
.
data
.
type
==
'2'
)
{
// 文本
params
[
createLiveKeys
.
textSoundColor
]
=
content
.
phonetic_timbres_id
?
content
.
phonetic_timbres_id
:
''
;
params
[
createLiveKeys
.
textScriptValue
]
=
content
.
type_content
?
content
.
type_content
:
''
;
if
(
content
.
type_content
)
{
params
[
createLiveKeys
.
textScriptList
]
=
[
content
.
type_content
];
}
}
else
{
// 音频音色
params
[
createLiveKeys
.
phoneticsSoundColor
]
=
content
.
phonetic_timbres_id
?
content
.
phonetic_timbres_id
:
''
;
params
[
createLiveKeys
.
phoneticsFile
]
=
content
.
type_content
?
content
.
type_content
:
''
;
if
(
content
.
type_content
)
{
params
[
createLiveKeys
.
phoneticsFile
]
=
content
.
type_content
.
map
((
item
:
any
)
=>
{
return
{
data
:
item
,
};
});
}
}
// 更新标题
if
(
res
.
data
.
name
)
{
store
.
commit
(
'live/setName'
,
res
.
data
.
name
);
}
commitInfo
(
params
);
}
...
...
@@ -317,14 +340,12 @@ const onSaveDrafts = async () => {
}
};
// 编辑保存
const
onEditSave
=
async
()
=>
{
let
status
=
currentModuleField
();
if
(
status
)
{
// 可以提交
// 编辑时音频提交
const
editAudioSave
=
async
()
=>
{
try
{
let
params
=
filterFiled
();
loading
.
value
=
true
;
let
res
:
any
=
await
onUpdateLiveTask
(
route
.
query
.
id
,
filterFiled
()
);
let
res
:
any
=
await
onUpdateLiveTask
(
route
.
query
.
id
,
params
);
if
(
res
)
{
if
(
route
.
query
.
type
===
'edit'
)
{
// 通知python删除对应的output.mp4
...
...
@@ -340,44 +361,69 @@ const onEditSave = async () => {
loading
.
value
=
false
;
console
.
log
(
e
);
}
}
};
const
confirm
=
async
()
=>
{
// 确定生成
if
(
!
liveName
.
value
)
{
show_message
(
'请输入标题'
);
return
;
}
// 提交任务并洗稿
const
submitTaskAndConfuse
=
async
(
type
:
string
)
=>
{
let
item
=
createLiveInfo
.
value
;
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本脚本
loading
.
value
=
true
;
for
(
let
i
=
0
;
i
<
item
[
createLiveKeys
.
textScriptList
].
length
;
i
++
)
{
// 转一维数组
let
newList
=
dimensionalConvert
(
item
[
createLiveKeys
.
textScriptList
]);
for
(
let
i
=
0
;
i
<
newList
.
length
;
i
++
)
{
let
row
=
newList
[
i
];
let
params
=
{
// 音色
phonetic_timbres_id
:
item
[
createLiveKeys
.
textSoundColor
],
// 音调
tone_id
:
item
[
createLiveKeys
.
textTones
],
content
:
item
[
createLiveKeys
.
textScriptList
][
i
]
.
content
,
uuid
:
item
[
createLiveKeys
.
textScriptList
][
i
].
uuid
,
content
:
row
.
content
,
uuid
:
item
[
createLiveKeys
.
scriptUuid
]
,
};
// 生成音频
let
res
:
any
=
await
liveTts
(
params
);
if
(
res
.
code
==
0
)
{
// 通过uuid找到对应的对象
let
index
=
item
[
createLiveKeys
.
textScriptList
]
.
findIndex
((
it
:
any
)
=>
it
.
uuid
==
params
.
uuid
);
let
index
=
newList
.
findIndex
((
it
:
any
)
=>
it
.
uuid
==
params
.
uuid
);
if
(
index
!==
-
1
)
{
let
list
=
JSON
.
parse
(
JSON
.
stringify
(
item
[
createLiveKeys
.
textScriptList
]
));
let
list
=
JSON
.
parse
(
JSON
.
stringify
(
newList
));
list
[
i
].
task_id
=
res
.
data
.
task_id
;
commitInfo
({
[
createLiveKeys
.
textScriptList
]:
list
,
});
}
}
else
{
throw
new
CustomException
(
'音频任务提交失败'
);
}
}
// 开启轮询
openInterval
(
false
);
openInterval
(
false
,
type
);
};
// 编辑保存
const
onEditSave
=
async
()
=>
{
let
status
=
currentModuleField
();
if
(
status
)
{
// 判断脚本类型
if
(
createLiveInfo
.
value
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 文本脚本
submitTaskAndConfuse
(
'update'
);
}
else
{
editAudioSave
();
}
}
};
const
confirm
=
async
()
=>
{
// 确定生成
if
(
!
liveName
.
value
)
{
show_message
(
'请输入标题'
);
return
;
}
let
item
=
createLiveInfo
.
value
;
if
(
item
[
createLiveKeys
.
scriptType
]
==
scriptTypeText
)
{
// 提交并洗稿
submitTaskAndConfuse
(
'create'
);
}
else
{
// 音频脚本
try
{
...
...
@@ -394,26 +440,60 @@ const confirm = async () => {
}
};
onMounted
(()
=>
{
const
initPage
=
()
=>
{
let
type
=
route
.
query
.
type
;
// 清空缓存数据
if
(
type
===
'new'
)
{
submitSuccessed
(
''
,
false
);
}
};
onBeforeMount
(()
=>
{
initPage
();
});
const
enterPageEvent
=
()
=>
{
initPage
();
let
query
=
route
.
query
;
let
obj
=
getElBounding
(
publicTool
.
value
);
toolHeight
.
value
=
obj
.
height
;
if
(
routeQuery
.
id
&&
routeQ
uery
.
type
)
{
if
(
query
.
id
&&
q
uery
.
type
)
{
// 获取编辑数据
getEditInfo
(
routeQuery
.
id
,
routeQ
uery
.
type
);
getEditInfo
(
query
.
id
,
q
uery
.
type
);
}
store
.
commit
(
'live/setName'
,
route
.
query
.
title
?
route
.
query
.
title
:
''
);
// 记录本次路由
window
.
localStorage
.
setItem
(
createLiveRouteKey
,
JSON
.
stringify
(
route
.
query
));
// 添加导航
let
newQuery
=
JSON
.
parse
(
JSON
.
stringify
(
query
));
if
(
newQuery
.
type
===
'new'
)
{
delete
newQuery
.
type
;
}
store
.
commit
(
'navbar/setNavbar'
,
{
path
:
routerConfig
.
createLive
.
path
,
query
:
route
.
q
uery
,
query
:
newQ
uery
,
});
});
};
// 缓存进入
onActivated
(()
=>
{
store
.
commit
(
'live/setName'
,
route
.
query
.
title
?
route
.
query
.
title
:
''
);
// 初始化页面的参数
if
(
currentQuery
.
value
.
type
===
'new'
&&
route
.
query
.
type
===
'edit'
)
{
submitSuccessed
(
''
,
false
);
}
enterPageEvent
();
});
// 路由离开前保存query
onBeforeRouteLeave
(()
=>
{
currentQuery
.
value
=
route
.
query
;
let
type
=
currentQuery
.
value
.
type
;
if
(
type
===
'edit'
||
type
===
'edit_drafts'
)
{
submitSuccessed
(
''
,
false
);
}
});
// 缓存离开
// onDeactivated(() => {});
onBeforeUnmount
(()
=>
{
// 清空选择的数字人
store
.
commit
(
'live/setLiveImage'
,
''
);
...
...
src/pages/home/components/digitalPeopleDiaog.vue
View file @
c7731fcb
...
...
@@ -98,6 +98,7 @@ const confirm = () => {
query
:
{
id
:
currentCard
.
value
,
title
:
''
,
type
:
'new'
,
},
});
};
...
...
src/pages/home/index.vue
View file @
c7731fcb
...
...
@@ -158,6 +158,7 @@ const dialogConfirm = () => {
query
:
{
id
:
currentCard
.
value
,
title
:
liveName
.
value
,
type
:
'new'
,
},
});
};
...
...
src/service/Common.ts
View file @
c7731fcb
...
...
@@ -105,7 +105,7 @@ export const getLiveInteraction = async (select: boolean = false) => {
};
// 更新直播内容
export
const
onUpdateLiveTask
=
async
(
id
:
number
|
string
,
data
:
any
)
=>
{
export
const
onUpdateLiveTask
=
async
(
id
:
any
,
data
:
any
)
=>
{
try
{
let
res
:
any
=
await
updateLiveTask
(
id
,
data
);
if
(
res
.
code
==
0
)
{
...
...
src/service/Live.ts
View file @
c7731fcb
...
...
@@ -11,3 +11,12 @@ export const LIVE_AUDIT_STATUS = {
LIVE_AUDIT_STATUS_FINISH
:
3
,
// 己完成
LIVE_AUDIT_STATUS_ERROR
:
4
,
// 审核失败
};
/**
* 洗稿状态(直播页面下一个视频是否准备完毕)
*/
export
const
CONFUSE_STATUS
=
{
CONFUSE_STATUS_WAIT
:
1
,
// 未提交
CONFUSE_STATUS_PROGRESS
:
2
,
// 进行中
CONFUSE_STATUS_SUCCESS
:
3
,
// 已完成
};
src/store/modules/live.ts
View file @
c7731fcb
...
...
@@ -33,13 +33,18 @@ type StateType = typeof state;
const
mutations
=
{
setName
(
state
:
StateType
,
info
:
string
)
{
if
(
info
)
{
state
.
name
=
info
;
}
else
{
state
.
name
=
''
;
}
},
// 创建直播时的参数
setLiveInfo
(
state
:
StateType
,
info
:
any
)
{
Object
.
keys
(
info
).
forEach
((
item
:
any
)
=>
{
state
.
createLive
[
item
]
=
info
[
item
];
});
console
.
log
(
state
.
createLive
);
},
initLiveInfo
(
state
:
StateType
)
{
state
.
createLive
=
initParams
();
...
...
src/store/modules/navbar.ts
View file @
c7731fcb
import
routerConfig
from
'@/router/tool'
;
import
{
createLiveRouteKey
}
from
'@/constants/token'
;
const
imgs
=
{
home
:
new
URL
(
'../../assets/svg/home/home.svg'
,
import
.
meta
.
url
).
href
,
...
...
@@ -43,6 +44,10 @@ const mutations = {
}
state
.
navbarList
.
push
(
info
);
}
if
(
info
.
path
==
routerConfig
.
createLive
.
path
)
{
// 记录创建直播的参数
window
.
localStorage
.
setItem
(
createLiveRouteKey
,
JSON
.
stringify
(
info
.
query
));
}
},
};
...
...
src/utils/api/userApi.ts
View file @
c7731fcb
...
...
@@ -361,9 +361,9 @@ export const liveContentRegenerateCallback = (data: any) => {
};
// 重新生成直播
export
const
liveTaskRegenerate
=
()
=>
{
export
const
liveTaskRegenerate
=
(
id
:
any
,
data
:
any
)
=>
{
const
header
=
getHeader
();
return
request
.
post
(
`/api/live/task/
{id}/regenerate`
,
''
,
{
return
request
.
post
(
`/api/live/task/
${
id
}
/regenerate`
,
data
,
{
headers
:
{
...
header
,
},
...
...
src/utils/audio.ts
View file @
c7731fcb
...
...
@@ -68,7 +68,6 @@ export async function audioMerge(filePaths) {
}
offset
+=
Math
.
round
(
buffer
.
duration
*
sampleRate
);
});
// 导出合并后的音频数据为 WAV 文件
const
mergedData
=
exportBufferAsWav
(
mergedBuffer
);
const
blob
=
new
Blob
([
mergedData
],
{
type
:
'audio/wav'
});
...
...
src/utils/error.ts
0 → 100644
View file @
c7731fcb
import
{
show_message
}
from
'./tool'
;
class
CustomException
extends
Error
{
constructor
(
message
)
{
super
(
message
);
this
.
name
=
'CustomException'
;
show_message
(
message
,
'error'
);
}
}
export
default
CustomException
;
src/utils/tool.ts
View file @
c7731fcb
...
...
@@ -263,3 +263,22 @@ export const downloadBlobFile = (blob: Blob, name: string = 'test') => {
// 清理 Blob URL
URL
.
revokeObjectURL
(
url
);
};
// 二维数组转一维数组
export
const
dimensionalConvert
=
(
list
:
any
[])
=>
{
let
convertList
=
[];
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
let
items
=
list
[
i
];
if
(
DataType
(
items
,
'array'
))
{
// 是数组
for
(
let
j
=
0
;
j
<
items
.
length
;
j
++
)
{
let
item
=
items
[
j
];
convertList
.
push
(
item
);
}
}
else
{
// 子元素不是数组,直接返回
return
list
;
}
}
return
convertList
;
};
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