feat(video): 集成可灵AI多图参考生视频生成服务

- 替换视频生成服务为可灵AI多图参考生视频API,支持1-4张多视角图片输入
- 调整图片拼接逻辑,生成横向长图传入即梦API备用
- 实现基于JWT认证的可灵API请求和轮询机制,支持高品质1:1正方形视频生成
- 在设计详情页新增视频展示区域及生成、重新生成和下载视频操作
- 更新后台系统配置,支持配置可灵AI Access Key和Secret Key
- 删除即梦视频相关配置及逻辑,所有视频生成功能切换到可灵AI实现
- 优化视频生成提示词,提升视频质感和展示效果
- 增加视频文件本地存储和路径管理,保证视频可访问和下载
- 前端增加视频生成状态管理和用户界面交互提示
- 后端添加PyJWT依赖,支持JWT认证流程
This commit is contained in:
2026-03-28 00:20:48 +08:00
parent 8f5a86418e
commit 1d94ec114a
9 changed files with 596 additions and 95 deletions

View File

@@ -97,45 +97,38 @@
</el-form>
</div>
<!-- 即梦视频生成配置卡片 -->
<!-- 可灵AI 视频生成配置卡片 -->
<div class="section-card">
<div class="card-header">
<div class="card-title-row">
<h3 class="section-title">即梦 3.0 Pro 视频生成</h3>
<el-tag :type="volcVideoStatus" size="small">
{{ volcVideoStatusText }}
<h3 class="section-title">可灵 AI 视频生成</h3>
<el-tag :type="klingVideoStatus" size="small">
{{ klingVideoStatusText }}
</el-tag>
</div>
<p class="card-desc">火山引擎即梦 3.0 Pro 图生视频 API将设计图生成 360 度旋转展示视频需要火山引擎 Access Key Secret Key API Key</p>
<p class="card-desc">可灵 AI 多图参考生视频 API支持传入多张参考图1-4AI 理解为同一物体多角度参考生成单品 360 度旋转展示视频</p>
</div>
<el-form label-width="120px" class="config-form">
<el-form-item label="Access Key">
<el-input
v-model="volcAccessKey"
v-model="klingAccessKey"
type="password"
show-password
placeholder="请输入火山引擎 Access Key"
placeholder="请输入可灵 AI Access Key"
clearable
/>
</el-form-item>
<el-form-item label="Secret Key">
<el-input
v-model="volcSecretKey"
v-model="klingSecretKey"
type="password"
show-password
placeholder="请输入火山引擎 Secret Key"
placeholder="请输入可灵 AI Secret Key"
clearable
/>
</el-form-item>
<el-form-item>
<span class="form-tip">获取方式火山引擎控制台 右上角头像 API访问密钥或访问 https://console.volcengine.com/iam/keymanage/</span>
</el-form-item>
<el-form-item label="视频时长">
<el-select v-model="videoFrames" style="width: 200px">
<el-option label="2 秒(快速预览)" value="49" />
<el-option label="5 秒(完整展示)" value="121" />
</el-select>
<span class="form-tip">推荐 5 足够展示完整 360 度旋转</span>
<span class="form-tip">获取方式访问 <a href="https://klingai.com" target="_blank">可灵AI开放平台</a> 注册/登录 控制台 API密钥管理</span>
</el-form-item>
<el-form-item label="视频提示词">
<el-input
@@ -144,7 +137,7 @@
:rows="3"
placeholder="玉雕作品在摄影棚内缓慢旋转360度展示全貌..."
/>
<span class="form-tip">用于控制视频生成效果尽情描述旋转展示方式灯光背景等</span>
<span class="form-tip">用于控制视频生成效果留空使用默认提示词</span>
</el-form-item>
</el-form>
</div>
@@ -230,12 +223,11 @@ const siliconflowKey = ref('')
const siliconflowUrl = ref('https://api.siliconflow.cn/v1')
const volcengineKey = ref('')
const volcengineUrl = ref('https://ark.cn-beijing.volces.com/api/v3')
const volcAccessKey = ref('')
const volcSecretKey = ref('')
const klingAccessKey = ref('')
const klingSecretKey = ref('')
const tencentSecretId = ref('')
const tencentSecretKey = ref('')
const videoPrompt = ref('')
const videoFrames = ref('121')
const model3dPrompt = ref('')
const imageSize = ref('1024')
const saving = ref(false)
@@ -243,8 +235,8 @@ const saving = ref(false)
// 后端是否已配置 API Key脱敏值也算已配置
const siliconflowConfigured = ref(false)
const volcengineConfigured = ref(false)
const volcAccessKeyConfigured = ref(false)
const volcSecretKeyConfigured = ref(false)
const klingAccessKeyConfigured = ref(false)
const klingSecretKeyConfigured = ref(false)
const tencentSecretIdConfigured = ref(false)
const tencentSecretKeyConfigured = ref(false)
@@ -259,8 +251,8 @@ const siliconflowStatus = computed(() => (siliconflowKey.value || siliconflowCon
const siliconflowStatusText = computed(() => (siliconflowKey.value || siliconflowConfigured.value) ? '已配置' : '未配置')
const volcengineStatus = computed(() => (volcengineKey.value || volcengineConfigured.value) ? 'success' : 'info')
const volcengineStatusText = computed(() => (volcengineKey.value || volcengineConfigured.value) ? '已配置' : '未配置')
const volcVideoStatus = computed(() => ((volcAccessKey.value || volcAccessKeyConfigured.value) && (volcSecretKey.value || volcSecretKeyConfigured.value)) ? 'success' : 'info')
const volcVideoStatusText = computed(() => ((volcAccessKey.value || volcAccessKeyConfigured.value) && (volcSecretKey.value || volcSecretKeyConfigured.value)) ? '已配置' : '未配置')
const klingVideoStatus = computed(() => ((klingAccessKey.value || klingAccessKeyConfigured.value) && (klingSecretKey.value || klingSecretKeyConfigured.value)) ? 'success' : 'info')
const klingVideoStatusText = computed(() => ((klingAccessKey.value || klingAccessKeyConfigured.value) && (klingSecretKey.value || klingSecretKeyConfigured.value)) ? '已配置' : '未配置')
const hunyuan3dStatus = computed(() => ((tencentSecretId.value || tencentSecretIdConfigured.value) && (tencentSecretKey.value || tencentSecretKeyConfigured.value)) ? 'success' : 'info')
const hunyuan3dStatusText = computed(() => ((tencentSecretId.value || tencentSecretIdConfigured.value) && (tencentSecretKey.value || tencentSecretKeyConfigured.value)) ? '已配置' : '未配置')
@@ -288,14 +280,14 @@ const loadConfigs = async () => {
volcengineKey.value = map['VOLCENGINE_API_KEY']
}
volcengineUrl.value = map['VOLCENGINE_BASE_URL'] || 'https://ark.cn-beijing.volces.com/api/v3'
// 即梦视频 Access Key / Secret Key
volcAccessKeyConfigured.value = !!map['VOLC_ACCESS_KEY']
volcSecretKeyConfigured.value = !!map['VOLC_SECRET_KEY']
if (map['VOLC_ACCESS_KEY'] && !map['VOLC_ACCESS_KEY'].includes('****')) {
volcAccessKey.value = map['VOLC_ACCESS_KEY']
// 可灵 AI Access Key / Secret Key
klingAccessKeyConfigured.value = !!map['KLING_ACCESS_KEY']
klingSecretKeyConfigured.value = !!map['KLING_SECRET_KEY']
if (map['KLING_ACCESS_KEY'] && !map['KLING_ACCESS_KEY'].includes('****')) {
klingAccessKey.value = map['KLING_ACCESS_KEY']
}
if (map['VOLC_SECRET_KEY'] && !map['VOLC_SECRET_KEY'].includes('****')) {
volcSecretKey.value = map['VOLC_SECRET_KEY']
if (map['KLING_SECRET_KEY'] && !map['KLING_SECRET_KEY'].includes('****')) {
klingSecretKey.value = map['KLING_SECRET_KEY']
}
// 腾讯云 SecretId / SecretKey
tencentSecretIdConfigured.value = !!map['TENCENT_SECRET_ID']
@@ -308,7 +300,6 @@ const loadConfigs = async () => {
}
// 提示词配置
videoPrompt.value = map['VIDEO_PROMPT'] || ''
videoFrames.value = map['VIDEO_FRAMES'] || '121'
model3dPrompt.value = map['MODEL3D_PROMPT'] || ''
imageSize.value = map['AI_IMAGE_SIZE'] || '1024'
} catch (e) {
@@ -338,11 +329,11 @@ const handleSave = async () => {
if (volcengineKey.value) {
configs['VOLCENGINE_API_KEY'] = volcengineKey.value
}
if (volcAccessKey.value) {
configs['VOLC_ACCESS_KEY'] = volcAccessKey.value
if (klingAccessKey.value) {
configs['KLING_ACCESS_KEY'] = klingAccessKey.value
}
if (volcSecretKey.value) {
configs['VOLC_SECRET_KEY'] = volcSecretKey.value
if (klingSecretKey.value) {
configs['KLING_SECRET_KEY'] = klingSecretKey.value
}
if (tencentSecretId.value) {
configs['TENCENT_SECRET_ID'] = tencentSecretId.value
@@ -352,7 +343,6 @@ const handleSave = async () => {
}
// 提示词始终提交(包括空值,允许清空)
configs['VIDEO_PROMPT'] = videoPrompt.value
configs['VIDEO_FRAMES'] = videoFrames.value
configs['MODEL3D_PROMPT'] = model3dPrompt.value
await updateConfigsBatch(configs)
ElMessage.success('配置已保存')