Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-dml
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-dml
Commits
46c835f3
提交
46c835f3
authored
12月 01, 2025
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 优化直播记录的AI分析
上级
3a747802
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
164 行增加
和
1 行删除
+164
-1
Live.vue
src/modules/live/test/components/Live.vue
+82
-1
RecordView.vue
src/modules/live/test/components/RecordView.vue
+0
-0
prompt.ts
src/modules/live/test/composables/prompt.ts
+0
-0
useLiveRecord.ts
src/modules/live/test/composables/useLiveRecord.ts
+82
-0
没有找到文件。
src/modules/live/test/components/Live.vue
浏览文件 @
46c835f3
...
...
@@ -13,6 +13,8 @@ import dayjs from 'dayjs'
import
{
useLiveChat
}
from
'../composables/useLiveChat'
import
{
useSpeechTranscriber
}
from
'../composables/useSpeechTranscriber'
import
{
appendUpload
}
from
'@/utils/oss'
import
{
useLiveRecord
}
from
'../composables/useLiveRecord'
import
{
Check
}
from
'@element-plus/icons-vue'
const
props
=
defineProps
({
orderCount
:
{
type
:
Number
,
default
:
0
},
...
...
@@ -22,7 +24,8 @@ const props = defineProps({
onSentenceEnd
:
{
type
:
Function
,
default
:
()
=>
{}
},
onStatsChange
:
{
type
:
Function
,
default
:
()
=>
{}
},
})
const
dialogVisible
=
ref
(
false
)
const
{
statusText
,
startPolling
,
isPolling
}
=
useLiveRecord
()
const
{
messages
,
viewers
,
stats
,
currentTime
,
start
:
startChat
,
stop
:
stopChat
}
=
useLiveChat
()
watch
(
()
=>
[
stats
,
viewers
],
...
...
@@ -149,6 +152,9 @@ const handleUpdateRecord = async (params) => {
if
(
!
requestParams
.
live_practice_id
)
return
const
res
=
await
saveTestRecord
(
requestParams
)
recordId
.
value
=
res
?.
data
.
id
// 开始AI评分轮询
startPolling
(
recordId
.
value
)
dialogVisible
.
value
=
true
}
// 上传视频
...
...
@@ -234,6 +240,32 @@ defineExpose({ enabled, start, stop })
>
</div>
</div>
<el-dialog
title=
"提示"
:model-value=
"dialogVisible"
:showClose=
"false"
width=
"500px"
>
<div
class=
"modal-content"
>
<template
v-if=
"isPolling"
>
<div
class=
"progress-circle"
>
<div
class=
"spinner"
></div>
</div>
<div
class=
"progress-text"
>
{{
statusText
}}
</div>
</
template
>
<
template
v-else
>
<div
class=
"success-icon"
>
<el-icon><Check
/></el-icon>
</div>
<div
class=
"progress-text"
>
AI评价完成
</div>
</
template
>
</div>
<
template
#
footer
>
<el-button
auto-insert-space
@
click=
"$router.push(
{ path: '/live/test' })">确定
</el-button>
<el-button
type=
"primary"
auto-insert-space
@
click=
"$router.push(
{ path: '/live/test/view', query: { ...$route.query, record_id: recordId } })"
v-if="!isPolling
&&
recordId"
>查看AI评价
</el-button
>
</
template
>
</el-dialog>
</template>
<
style
lang=
"scss"
>
...
...
@@ -268,4 +300,53 @@ defineExpose({ enabled, start, stop })
text-align
:
center
;
}
}
.modal-content
{
text-align
:
center
;
padding
:
1rem
;
}
.progress-circle
{
width
:
80px
;
height
:
80px
;
margin
:
0
auto
2rem
;
position
:
relative
;
}
.spinner
{
width
:
100%
;
height
:
100%
;
border
:
8px
solid
#f5f7fa
;
border-top-color
:
#d91f5d
;
border-radius
:
50%
;
animation
:
spin
1s
linear
infinite
;
}
@keyframes
spin
{
to
{
transform
:
rotate
(
360deg
);
}
}
.progress-text
{
font-size
:
1rem
;
color
:
#333
;
margin-bottom
:
1rem
;
text-align
:
center
;
}
.success-icon
{
width
:
100px
;
height
:
100px
;
background
:
#ba003f
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
margin
:
0
auto
2rem
;
i
{
font-size
:
3rem
;
color
:
white
;
}
}
</
style
>
src/modules/live/test/components/RecordView.vue
浏览文件 @
46c835f3
差异被折叠。
点击展开。
src/modules/live/test/composables/prompt.ts
0 → 100644
浏览文件 @
46c835f3
差异被折叠。
点击展开。
src/modules/live/test/composables/useLiveRecord.ts
0 → 100644
浏览文件 @
46c835f3
import
{
getRecord
,
updateRecord
}
from
'../api'
import
{
useChat
}
from
'@ezijing/ai-vue'
import
{
systemPrompt
,
getUserPrompt
}
from
'./prompt'
export
function
useLiveRecord
({
id
=
''
,
immediate
=
false
}:
{
id
?:
string
;
immediate
?:
boolean
}
=
{})
{
const
{
isLoading
,
generateText
}
=
useChat
({
provider
:
'volcano'
})
const
recordId
=
ref
(
id
)
const
liveRecord
=
ref
<
any
>
(
null
)
const
statusText
=
ref
(
''
)
const
isPolling
=
ref
(
false
)
let
pollingTimer
:
ReturnType
<
typeof
setTimeout
>
|
null
=
null
const
fetchLiveRecord
=
async
()
=>
{
if
(
!
recordId
.
value
)
return
const
res
=
await
getRecord
({
id
:
recordId
.
value
})
const
resDetail
=
res
.
data
.
detail
liveRecord
.
value
=
{
...
resDetail
,
live_info
:
JSON
.
parse
(
resDetail
.
live_info
)
}
return
liveRecord
.
value
}
onMounted
(()
=>
{
if
(
immediate
&&
recordId
.
value
)
{
fetchLiveRecord
().
then
(()
=>
{
if
(
!
liveRecord
.
value
?.
ai_analyze
)
handleAIScore
()
})
}
})
const
handleAIScore
=
async
()
=>
{
const
messages
=
[
{
role
:
'system'
,
content
:
systemPrompt
},
{
role
:
'user'
,
content
:
getUserPrompt
(
liveRecord
.
value
)
},
]
const
result
=
await
generateText
({
messages
,
response_format
:
{
type
:
'json_object'
}
}
as
any
)
if
(
!
result
)
return
const
aiAnalyze
=
result
.
content
.
replaceAll
(
'卖点讲解覆盖情况'
,
''
)
.
replaceAll
(
'违禁词分析报告'
,
''
)
.
replaceAll
(
'直播优化建议'
,
''
)
.
replaceAll
(
'语速分析报告'
,
''
)
await
updateRecord
({
id
:
recordId
.
value
,
ai_analyze
:
aiAnalyze
})
if
(
immediate
)
fetchLiveRecord
()
}
const
startPolling
=
(
id
=
''
,
interval
=
3000
)
=>
{
if
(
isPolling
.
value
)
return
if
(
id
)
recordId
.
value
=
id
isPolling
.
value
=
true
const
poll
=
async
()
=>
{
if
(
!
isPolling
.
value
)
return
statusText
.
value
=
'口播内容识别中,请稍后...'
const
record
=
await
fetchLiveRecord
()
if
(
record
?.
subtitle
)
{
statusText
.
value
=
'AI分析中,大约需要1分钟,请耐心等待...'
await
handleAIScore
()
stopPolling
()
}
else
{
pollingTimer
=
setTimeout
(
poll
,
interval
)
}
}
poll
()
}
const
stopPolling
=
()
=>
{
isPolling
.
value
=
false
statusText
.
value
=
''
if
(
pollingTimer
)
{
clearTimeout
(
pollingTimer
)
pollingTimer
=
null
}
}
onUnmounted
(()
=>
{
stopPolling
()
})
return
{
liveRecord
,
fetchLiveRecord
,
handleAIScore
,
startPolling
,
stopPolling
,
isPolling
,
isLoading
,
statusText
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论