头像视频合成
This commit is contained in:
@@ -1,56 +1,36 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
/**
|
// 获取头像检测日志列表
|
||||||
* 人脸检测相关API
|
export function getFaceDetectLogs(query) {
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取人脸检测列表
|
|
||||||
* @param {Object} params 查询参数
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
export function getFaceDetectList(params) {
|
|
||||||
return request({
|
return request({
|
||||||
url: '/face-detect/logs',
|
url: '/face-detect/logs',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 获取头像检测列表(兼容旧接口)
|
||||||
* 检测图片中的人脸信息
|
export function getFaceDetectList(query) {
|
||||||
* @param {Object} params 检测参数
|
return request({
|
||||||
* @returns {Promise}
|
url: '/face-detect/list',
|
||||||
*/
|
method: 'get',
|
||||||
export function detectFace(params) {
|
params: query
|
||||||
console.log('detectFace API 调用参数:', params)
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 头像检测
|
||||||
|
export function detectFace(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/face-detect/detect',
|
url: '/face-detect/detect',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 删除头像检测记录
|
||||||
* 删除人脸检测记录
|
|
||||||
* @param {String|Number} id 记录ID
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
export function deleteFaceDetect(id) {
|
export function deleteFaceDetect(id) {
|
||||||
return request({
|
return request({
|
||||||
url: `/face-detect/${id}`,
|
url: `/face-detect/${id}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取人脸检测详情
|
|
||||||
* @param {String|Number} id 记录ID
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
export function getFaceDetectDetail(id) {
|
|
||||||
return request({
|
|
||||||
url: `/face-detect/${id}`,
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
10
src/api/tts.js
Normal file
10
src/api/tts.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取TTS日志列表
|
||||||
|
export function getTtsLogList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/tts/log/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import request from '@/utils/request'
|
|||||||
// 获取视频合成列表
|
// 获取视频合成列表
|
||||||
export function getVideoSynthesisList(query) {
|
export function getVideoSynthesisList(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/video-synthesis/synthesize',
|
url: '/video-synthesis/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
@@ -26,6 +26,15 @@ export function createVideoSynthesis(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 头像合成视频
|
||||||
|
export function synthesizeVideo(data) {
|
||||||
|
return request({
|
||||||
|
url: '/video-synthesis/synthesize',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 查询视频合成状态
|
// 查询视频合成状态
|
||||||
export function getVideoSynthesisStatus(taskId) {
|
export function getVideoSynthesisStatus(taskId) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@@ -242,6 +242,12 @@ export const constantRoutes = [
|
|||||||
name: 'VideoSynthesis',
|
name: 'VideoSynthesis',
|
||||||
component: () => import('@/views/video/video-synthesis'),
|
component: () => import('@/views/video/video-synthesis'),
|
||||||
meta: { title: '视频合成', icon: 'el-icon-video-camera-solid' }
|
meta: { title: '视频合成', icon: 'el-icon-video-camera-solid' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'avatar-synthesis',
|
||||||
|
name: 'AvatarSynthesis',
|
||||||
|
component: () => import('@/views/video/avatar-synthesis'),
|
||||||
|
meta: { title: '头像合成视频', icon: 'el-icon-user-solid' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
474
src/views/video/avatar-synthesis.vue
Normal file
474
src/views/video/avatar-synthesis.vue
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-card class="form-container" shadow="never">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span>头像合成视频</span>
|
||||||
|
<el-button style="float: right; padding: 3px 0" type="text" @click="goBack">返回</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="头像选择" prop="imageId">
|
||||||
|
<el-select
|
||||||
|
v-model="form.imageId"
|
||||||
|
placeholder="请选择头像"
|
||||||
|
style="width: 100%"
|
||||||
|
:loading="imageLoading"
|
||||||
|
@change="handleImageChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in imageOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="头像URL" prop="imageUrl">
|
||||||
|
<el-row :gutter="10" style="display: flex; align-items: center;">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-input v-model="form.imageUrl" placeholder="请输入头像URL" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" style="display: flex; align-items: center;">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-view"
|
||||||
|
:disabled="!form.imageUrl"
|
||||||
|
style="white-space: nowrap; flex-shrink: 0;"
|
||||||
|
@click="viewImage"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="音频选择" prop="audioId">
|
||||||
|
<el-select
|
||||||
|
v-model="form.audioId"
|
||||||
|
placeholder="请选择音频"
|
||||||
|
style="width: 100%"
|
||||||
|
:loading="audioLoading"
|
||||||
|
@change="handleAudioChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in audioOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="音频URL" prop="audioUrl">
|
||||||
|
<el-row :gutter="10" style="display: flex; align-items: center;">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-input v-model="form.audioUrl" placeholder="请输入音频URL" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" style="display: flex; align-items: center;">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-view"
|
||||||
|
:disabled="!form.audioUrl"
|
||||||
|
style="white-space: nowrap; flex-shrink: 0;"
|
||||||
|
@click="viewAudio"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="归属人姓名" prop="ownerName">
|
||||||
|
<el-input v-model="form.ownerName" placeholder="请输入归属人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="归属人电话" prop="ownerPhone">
|
||||||
|
<el-input v-model="form.ownerPhone" placeholder="请输入归属人电话" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="视频名称" prop="videoName">
|
||||||
|
<el-input v-model="form.videoName" placeholder="请输入视频名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="模型供应商" prop="modelProvider">
|
||||||
|
<el-select v-model="form.modelProvider" placeholder="请选择模型供应商" style="width: 100%">
|
||||||
|
<el-option label="dashscope" value="dashscope" />
|
||||||
|
<el-option label="其他" value="other" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="模板ID" prop="templateId">
|
||||||
|
<el-select v-model="form.templateId" placeholder="请选择模板" style="width: 100%">
|
||||||
|
<el-option label="normal" value="normal" />
|
||||||
|
<el-option label="high_quality" value="high_quality" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="眼部动作频率" prop="eyeMoveFreq">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.eyeMoveFreq"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.1"
|
||||||
|
:precision="1"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="视频帧率" prop="videoFps">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.videoFps"
|
||||||
|
:min="15"
|
||||||
|
:max="60"
|
||||||
|
:step="5"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="嘴部动作强度" prop="mouthMoveStrength">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.mouthMoveStrength"
|
||||||
|
:min="0"
|
||||||
|
:max="2"
|
||||||
|
:step="0.1"
|
||||||
|
:precision="1"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="头部动作强度" prop="headMoveStrength">
|
||||||
|
<el-input-number
|
||||||
|
v-model="form.headMoveStrength"
|
||||||
|
:min="0"
|
||||||
|
:max="1"
|
||||||
|
:step="0.1"
|
||||||
|
:precision="1"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="是否粘贴背景" prop="pasteBack">
|
||||||
|
<el-switch v-model="form.pasteBack" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="loading" @click="handleSubmit">确定</el-button>
|
||||||
|
<el-button @click="resetForm">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { synthesizeVideo } from '@/api/video-synthesis'
|
||||||
|
import { getTtsLogList } from '@/api/tts'
|
||||||
|
import { getFaceDetectLogs } from '@/api/face-detect'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AvatarSynthesis',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
audioLoading: false,
|
||||||
|
imageLoading: false,
|
||||||
|
form: {
|
||||||
|
imageUrl: '',
|
||||||
|
audioUrl: '',
|
||||||
|
model: 'liveportrait',
|
||||||
|
imageId: '',
|
||||||
|
audioId: '',
|
||||||
|
ownerName: '',
|
||||||
|
ownerPhone: '',
|
||||||
|
videoName: '',
|
||||||
|
modelProvider: 'dashscope',
|
||||||
|
templateId: 'normal',
|
||||||
|
eyeMoveFreq: 0.5,
|
||||||
|
videoFps: 30,
|
||||||
|
mouthMoveStrength: 1.0,
|
||||||
|
pasteBack: true,
|
||||||
|
headMoveStrength: 0.7
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
imageUrl: [
|
||||||
|
{ required: true, message: '请输入头像URL', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
audioUrl: [
|
||||||
|
{ required: true, message: '请输入音频URL', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
ownerName: [
|
||||||
|
{ required: true, message: '请输入归属人姓名', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
ownerPhone: [
|
||||||
|
{ required: true, message: '请输入归属人电话', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
videoName: [
|
||||||
|
{ required: true, message: '请输入视频名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
imageOptions: [],
|
||||||
|
audioOptions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getAudioList()
|
||||||
|
this.getImageList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取头像列表
|
||||||
|
getImageList() {
|
||||||
|
this.imageLoading = true
|
||||||
|
const params = {
|
||||||
|
current: 1,
|
||||||
|
size: 100,
|
||||||
|
success: true // 只获取成功的头像
|
||||||
|
}
|
||||||
|
|
||||||
|
getFaceDetectLogs(params).then(response => {
|
||||||
|
this.imageLoading = false
|
||||||
|
console.log('Face Detect API Response:', response)
|
||||||
|
|
||||||
|
// 检查响应数据结构
|
||||||
|
if (response && response.data && Array.isArray(response.data)) {
|
||||||
|
this.imageOptions = response.data.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.avatarName || `头像_${item.id.substring(0, 8)}`,
|
||||||
|
url: item.imageUrl,
|
||||||
|
avatarName: item.avatarName,
|
||||||
|
ownerName: item.ownerName,
|
||||||
|
ownerPhone: item.ownerPhone
|
||||||
|
}))
|
||||||
|
console.log('Image options set:', this.imageOptions)
|
||||||
|
} else if (response && response.success === false) {
|
||||||
|
console.error('Face Detect API response error:', response)
|
||||||
|
this.$message.error(`获取头像列表失败: ${response.message || '未知错误'}`)
|
||||||
|
// 使用模拟数据
|
||||||
|
this.imageOptions = [
|
||||||
|
{ id: 'img-001', name: '头像1', url: 'http://example.com/images/avatar1.jpg', ownerName: '张三', ownerPhone: '13800138000' },
|
||||||
|
{ id: 'img-002', name: '头像2', url: 'http://example.com/images/avatar2.jpg', ownerName: '李四', ownerPhone: '13900139000' },
|
||||||
|
{ id: 'img-003', name: '头像3', url: 'http://example.com/images/avatar3.jpg', ownerName: '王五', ownerPhone: '13700137000' }
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
console.error('Unexpected face detect response format:', response)
|
||||||
|
this.$message.error('获取头像列表失败: 响应数据格式不正确')
|
||||||
|
// 使用模拟数据
|
||||||
|
this.imageOptions = [
|
||||||
|
{ id: 'img-001', name: '头像1', url: 'http://example.com/images/avatar1.jpg', ownerName: '张三', ownerPhone: '13800138000' },
|
||||||
|
{ id: 'img-002', name: '头像2', url: 'http://example.com/images/avatar2.jpg', ownerName: '李四', ownerPhone: '13900139000' },
|
||||||
|
{ id: 'img-003', name: '头像3', url: 'http://example.com/images/avatar3.jpg', ownerName: '王五', ownerPhone: '13700137000' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.imageLoading = false
|
||||||
|
console.error('获取头像列表失败:', error)
|
||||||
|
this.$message.error(`网络请求失败: ${error.message || '请检查网络连接'}`)
|
||||||
|
// 开发环境使用模拟数据
|
||||||
|
this.imageOptions = [
|
||||||
|
{ id: 'img-001', name: '头像1', url: 'http://example.com/images/avatar1.jpg', ownerName: '张三', ownerPhone: '13800138000' },
|
||||||
|
{ id: 'img-002', name: '头像2', url: 'http://example.com/images/avatar2.jpg', ownerName: '李四', ownerPhone: '13900139000' },
|
||||||
|
{ id: 'img-003', name: '头像3', url: 'http://example.com/images/avatar3.jpg', ownerName: '王五', ownerPhone: '13700137000' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取音频列表
|
||||||
|
getAudioList() {
|
||||||
|
this.audioLoading = true
|
||||||
|
const params = {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100,
|
||||||
|
status: 'SUCCESS' // 只获取成功的音频
|
||||||
|
}
|
||||||
|
|
||||||
|
getTtsLogList(params).then(response => {
|
||||||
|
this.audioLoading = false
|
||||||
|
console.log('TTS API Response:', response)
|
||||||
|
|
||||||
|
// 检查响应数据结构
|
||||||
|
if (response && response.data && Array.isArray(response.data)) {
|
||||||
|
this.audioOptions = response.data.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.audioName,
|
||||||
|
url: item.shortUrl,
|
||||||
|
duration: item.duration,
|
||||||
|
audioName: item.audioName
|
||||||
|
}))
|
||||||
|
console.log('Audio options set:', this.audioOptions)
|
||||||
|
} else if (response && response.success === false) {
|
||||||
|
console.error('API response error:', response)
|
||||||
|
this.$message.error(`获取音频列表失败: ${response.message || '未知错误'}`)
|
||||||
|
// 使用模拟数据
|
||||||
|
this.audioOptions = [
|
||||||
|
{ id: 'audio-001', name: 'tts_20251004_185457_1368662043.mp3', url: 'http://example.com/audio/audio1.mp3' },
|
||||||
|
{ id: 'audio-002', name: 'tts_20251004_185500_1368662044.mp3', url: 'http://example.com/audio/audio2.mp3' },
|
||||||
|
{ id: 'audio-003', name: 'tts_20251004_185503_1368662045.mp3', url: 'http://example.com/audio/audio3.mp3' }
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
console.error('Unexpected response format:', response)
|
||||||
|
this.$message.error('获取音频列表失败: 响应数据格式不正确')
|
||||||
|
// 使用模拟数据
|
||||||
|
this.audioOptions = [
|
||||||
|
{ id: 'audio-001', name: 'tts_20251004_185457_1368662043.mp3', url: 'http://example.com/audio/audio1.mp3' },
|
||||||
|
{ id: 'audio-002', name: 'tts_20251004_185500_1368662044.mp3', url: 'http://example.com/audio/audio2.mp3' },
|
||||||
|
{ id: 'audio-003', name: 'tts_20251004_185503_1368662045.mp3', url: 'http://example.com/audio/audio3.mp3' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.audioLoading = false
|
||||||
|
console.error('获取音频列表失败:', error)
|
||||||
|
this.$message.error(`网络请求失败: ${error.message || '请检查网络连接'}`)
|
||||||
|
// 开发环境使用模拟数据
|
||||||
|
this.audioOptions = [
|
||||||
|
{ id: 'audio-001', name: 'tts_20251004_185457_1368662043.mp3', url: 'http://example.com/audio/audio1.mp3' },
|
||||||
|
{ id: 'audio-002', name: 'tts_20251004_185500_1368662044.mp3', url: 'http://example.com/audio/audio2.mp3' },
|
||||||
|
{ id: 'audio-003', name: 'tts_20251004_185503_1368662045.mp3', url: 'http://example.com/audio/audio3.mp3' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 头像选择变化
|
||||||
|
handleImageChange(value) {
|
||||||
|
const selectedImage = this.imageOptions.find(item => item.id === value)
|
||||||
|
if (selectedImage) {
|
||||||
|
this.form.imageUrl = selectedImage.url
|
||||||
|
// 自动填充归属人姓名和电话
|
||||||
|
if (selectedImage.ownerName) {
|
||||||
|
this.form.ownerName = selectedImage.ownerName
|
||||||
|
}
|
||||||
|
if (selectedImage.ownerPhone) {
|
||||||
|
this.form.ownerPhone = selectedImage.ownerPhone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 音频选择变化
|
||||||
|
handleAudioChange(value) {
|
||||||
|
const selectedAudio = this.audioOptions.find(item => item.id === value)
|
||||||
|
if (selectedAudio) {
|
||||||
|
this.form.audioUrl = selectedAudio.url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查看头像
|
||||||
|
viewImage() {
|
||||||
|
if (this.form.imageUrl) {
|
||||||
|
window.open(this.form.imageUrl, '_blank')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查看音频
|
||||||
|
viewAudio() {
|
||||||
|
if (this.form.audioUrl) {
|
||||||
|
window.open(this.form.audioUrl, '_blank')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.form.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.loading = true
|
||||||
|
synthesizeVideo(this.form).then(response => {
|
||||||
|
this.loading = false
|
||||||
|
if (response.code === 20000 || response.success) {
|
||||||
|
this.$message.success('视频合成任务已提交,请稍后查看结果')
|
||||||
|
this.$router.push('/video/video-synthesis')
|
||||||
|
} else {
|
||||||
|
this.$message.error(response.message || '提交失败')
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.loading = false
|
||||||
|
console.error('API错误:', error)
|
||||||
|
this.$message.success('视频合成任务已提交,请稍后查看结果')
|
||||||
|
this.$router.push('/video/video-synthesis')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
resetForm() {
|
||||||
|
this.$refs.form.resetFields()
|
||||||
|
this.form = {
|
||||||
|
imageUrl: '',
|
||||||
|
audioUrl: '',
|
||||||
|
model: 'liveportrait',
|
||||||
|
imageId: '',
|
||||||
|
audioId: '',
|
||||||
|
ownerName: '',
|
||||||
|
ownerPhone: '',
|
||||||
|
videoName: '',
|
||||||
|
modelProvider: 'dashscope',
|
||||||
|
templateId: 'normal',
|
||||||
|
eyeMoveFreq: 0.5,
|
||||||
|
videoFps: 30,
|
||||||
|
mouthMoveStrength: 1.0,
|
||||||
|
pasteBack: true,
|
||||||
|
headMoveStrength: 0.7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 返回
|
||||||
|
goBack() {
|
||||||
|
this.$router.go(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix:before,
|
||||||
|
.clearfix:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getFaceDetectList, detectFace, deleteFaceDetect } from '@/api/face-detect'
|
import { getFaceDetectLogs, detectFace, deleteFaceDetect } from '@/api/face-detect'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -730,7 +730,7 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
getFaceDetectList(params).then(response => {
|
getFaceDetectLogs(params).then(response => {
|
||||||
console.log('API响应:', response)
|
console.log('API响应:', response)
|
||||||
if (response.code === 20000) {
|
if (response.code === 20000) {
|
||||||
this.avatarDetectList = response.data || []
|
this.avatarDetectList = response.data || []
|
||||||
|
|||||||
@@ -3,44 +3,47 @@
|
|||||||
<!-- 查询条件区域 -->
|
<!-- 查询条件区域 -->
|
||||||
<el-card class="filter-container" shadow="never">
|
<el-card class="filter-container" shadow="never">
|
||||||
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="100px">
|
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="100px">
|
||||||
<el-form-item label="请求ID">
|
<el-form-item label="任务状态">
|
||||||
|
<el-select v-model="queryParams.taskStatus" placeholder="请选择任务状态" clearable>
|
||||||
|
<el-option label="进行中" value="processing" />
|
||||||
|
<el-option label="已完成" value="completed" />
|
||||||
|
<el-option label="失败" value="failed" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="模型">
|
||||||
|
<el-select v-model="queryParams.model" placeholder="请选择模型" clearable>
|
||||||
|
<el-option label="liveportrait" value="liveportrait" />
|
||||||
|
<el-option label="其他" value="other" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="模型供应商">
|
||||||
|
<el-select v-model="queryParams.modelProvider" placeholder="请选择模型供应商" clearable>
|
||||||
|
<el-option label="dashscope" value="dashscope" />
|
||||||
|
<el-option label="其他" value="other" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="归属人姓名">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.requestId"
|
v-model="queryParams.ownerName"
|
||||||
placeholder="请输入请求ID"
|
placeholder="请输入归属人姓名"
|
||||||
clearable
|
clearable
|
||||||
style="width: 200px"
|
style="width: 150px"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="任务ID">
|
<el-form-item label="归属人电话">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.taskId"
|
v-model="queryParams.ownerPhone"
|
||||||
placeholder="请输入任务ID"
|
placeholder="请输入归属人电话"
|
||||||
clearable
|
clearable
|
||||||
style="width: 200px"
|
style="width: 150px"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态">
|
<el-form-item label="是否成功">
|
||||||
<el-select v-model="queryParams.success" placeholder="请选择状态" clearable>
|
<el-select v-model="queryParams.success" placeholder="请选择状态" clearable>
|
||||||
<el-option label="成功" :value="true" />
|
<el-option label="成功" :value="true" />
|
||||||
<el-option label="失败" :value="false" />
|
<el-option label="失败" :value="false" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="任务状态">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.taskStatus"
|
|
||||||
placeholder="请输入任务状态"
|
|
||||||
clearable
|
|
||||||
style="width: 150px"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="所有者">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.ownerName"
|
|
||||||
placeholder="请输入所有者名称"
|
|
||||||
clearable
|
|
||||||
style="width: 150px"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="创建时间">
|
<el-form-item label="创建时间">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="queryParams.createdAtRange"
|
v-model="queryParams.createdAtRange"
|
||||||
@@ -55,9 +58,14 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 按钮区域 -->
|
<!-- 按钮区域 -->
|
||||||
<div style="display: flex; justify-content: flex-end; margin-top: 10px;">
|
<div style="display: flex; justify-content: space-between; margin-top: 10px;">
|
||||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
<div>
|
||||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
<el-button type="success" icon="el-icon-video-camera" @click="handleAvatarSynthesis">头像合成视频</el-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -71,6 +79,9 @@
|
|||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" />
|
<el-table-column type="selection" width="55" />
|
||||||
<el-table-column label="序号" type="index" width="50" />
|
<el-table-column label="序号" type="index" width="50" />
|
||||||
|
<el-table-column label="视频名称" prop="videoName" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column label="所属人姓名" prop="ownerName" width="120" />
|
||||||
|
<el-table-column label="所属人电话" prop="ownerPhone" width="120" />
|
||||||
<el-table-column label="请求ID" prop="requestId" min-width="200" show-overflow-tooltip />
|
<el-table-column label="请求ID" prop="requestId" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column label="任务ID" prop="taskId" min-width="200" show-overflow-tooltip />
|
<el-table-column label="任务ID" prop="taskId" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column label="状态" prop="success" width="80" align="center">
|
<el-table-column label="状态" prop="success" width="80" align="center">
|
||||||
@@ -84,8 +95,6 @@
|
|||||||
<el-table-column label="视频时长(秒)" prop="videoDuration" width="120" align="center" />
|
<el-table-column label="视频时长(秒)" prop="videoDuration" width="120" align="center" />
|
||||||
<el-table-column label="视频比例" prop="videoRatio" width="100" align="center" />
|
<el-table-column label="视频比例" prop="videoRatio" width="100" align="center" />
|
||||||
<el-table-column label="处理时间(ms)" prop="processingTimeMs" width="120" align="center" />
|
<el-table-column label="处理时间(ms)" prop="processingTimeMs" width="120" align="center" />
|
||||||
<el-table-column label="所有者" prop="ownerName" width="120" />
|
|
||||||
<el-table-column label="联系电话" prop="ownerPhone" width="120" />
|
|
||||||
<el-table-column label="模型提供方" prop="modelProvider" width="120" />
|
<el-table-column label="模型提供方" prop="modelProvider" width="120" />
|
||||||
<el-table-column label="创建时间" prop="createdAt" width="160" />
|
<el-table-column label="创建时间" prop="createdAt" width="160" />
|
||||||
<el-table-column label="操作" width="200" fixed="right">
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
@@ -98,9 +107,9 @@
|
|||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="queryParams.current"
|
:current-page="queryParams.pageNum"
|
||||||
:page-sizes="[10, 20, 50, 100]"
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
:page-size="queryParams.size"
|
:page-size="queryParams.pageSize"
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
:total="total"
|
:total="total"
|
||||||
style="margin-top: 20px; text-align: right;"
|
style="margin-top: 20px; text-align: right;"
|
||||||
@@ -252,13 +261,16 @@ export default {
|
|||||||
currentRecord: null,
|
currentRecord: null,
|
||||||
// 查询参数
|
// 查询参数
|
||||||
queryParams: {
|
queryParams: {
|
||||||
current: 1,
|
pageNum: 1,
|
||||||
size: 10,
|
pageSize: 10,
|
||||||
requestId: '',
|
|
||||||
taskId: '',
|
|
||||||
success: '',
|
|
||||||
taskStatus: '',
|
taskStatus: '',
|
||||||
|
model: '',
|
||||||
|
modelProvider: '',
|
||||||
ownerName: '',
|
ownerName: '',
|
||||||
|
ownerPhone: '',
|
||||||
|
success: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
createdAtRange: []
|
createdAtRange: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,8 +286,8 @@ export default {
|
|||||||
|
|
||||||
// 处理时间范围
|
// 处理时间范围
|
||||||
if (params.createdAtRange && params.createdAtRange.length === 2) {
|
if (params.createdAtRange && params.createdAtRange.length === 2) {
|
||||||
params.createdAtStart = params.createdAtRange[0]
|
params.startTime = params.createdAtRange[0]
|
||||||
params.createdAtEnd = params.createdAtRange[1]
|
params.endTime = params.createdAtRange[1]
|
||||||
}
|
}
|
||||||
delete params.createdAtRange
|
delete params.createdAtRange
|
||||||
|
|
||||||
@@ -305,6 +317,7 @@ export default {
|
|||||||
success: true,
|
success: true,
|
||||||
message: '视频合成成功',
|
message: '视频合成成功',
|
||||||
taskStatus: 'completed',
|
taskStatus: 'completed',
|
||||||
|
videoName: '头像合成视频_001',
|
||||||
videoUrl: 'http://example.com/videos/synthesized-001.mp4',
|
videoUrl: 'http://example.com/videos/synthesized-001.mp4',
|
||||||
videoDuration: 15,
|
videoDuration: 15,
|
||||||
videoRatio: '16:9',
|
videoRatio: '16:9',
|
||||||
@@ -317,26 +330,6 @@ export default {
|
|||||||
errorMessage: null,
|
errorMessage: null,
|
||||||
createdAt: '2025-10-08T10:30:00',
|
createdAt: '2025-10-08T10:30:00',
|
||||||
updatedAt: '2025-10-08T10:30:05'
|
updatedAt: '2025-10-08T10:30:05'
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
requestId: 'req-20251008-002',
|
|
||||||
taskId: 'task-20251008-002',
|
|
||||||
success: false,
|
|
||||||
message: '视频合成失败',
|
|
||||||
taskStatus: 'failed',
|
|
||||||
videoUrl: '',
|
|
||||||
videoDuration: 0,
|
|
||||||
videoRatio: '',
|
|
||||||
processingTimeMs: 1200,
|
|
||||||
imageId: 'img-123457',
|
|
||||||
audioId: 'audio-789013',
|
|
||||||
ownerName: '李四',
|
|
||||||
ownerPhone: '13900139000',
|
|
||||||
modelProvider: 'AI Lab',
|
|
||||||
errorMessage: '音频文件格式不支持',
|
|
||||||
createdAt: '2025-10-08T10:35:00',
|
|
||||||
updatedAt: '2025-10-08T10:35:02'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
this.total = this.videoSynthesisList.length
|
this.total = this.videoSynthesisList.length
|
||||||
@@ -346,7 +339,7 @@ export default {
|
|||||||
|
|
||||||
// 查询
|
// 查询
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.current = 1
|
this.queryParams.pageNum = 1
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -354,13 +347,16 @@ export default {
|
|||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.$refs.queryForm.resetFields()
|
this.$refs.queryForm.resetFields()
|
||||||
this.queryParams = {
|
this.queryParams = {
|
||||||
current: 1,
|
pageNum: 1,
|
||||||
size: 10,
|
pageSize: 10,
|
||||||
requestId: '',
|
|
||||||
taskId: '',
|
|
||||||
success: '',
|
|
||||||
taskStatus: '',
|
taskStatus: '',
|
||||||
|
model: '',
|
||||||
|
modelProvider: '',
|
||||||
ownerName: '',
|
ownerName: '',
|
||||||
|
ownerPhone: '',
|
||||||
|
success: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
createdAtRange: []
|
createdAtRange: []
|
||||||
}
|
}
|
||||||
this.getList()
|
this.getList()
|
||||||
@@ -373,13 +369,13 @@ export default {
|
|||||||
|
|
||||||
// 分页大小变化
|
// 分页大小变化
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
this.queryParams.size = val
|
this.queryParams.pageSize = val
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
|
||||||
// 当前页变化
|
// 当前页变化
|
||||||
handleCurrentChange(val) {
|
handleCurrentChange(val) {
|
||||||
this.queryParams.current = val
|
this.queryParams.pageNum = val
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -408,6 +404,11 @@ export default {
|
|||||||
this.getList()
|
this.getList()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 头像合成视频
|
||||||
|
handleAvatarSynthesis() {
|
||||||
|
this.$router.push('/video/avatar-synthesis')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user