feat(design): 添加360视频和3D模型生成功能支持
- 在Design模型中新增video_url字段用于存储360度展示视频URL - 在DesignImage模型中新增model_3d_url字段用于存储3D模型URL - 设计路由新增生成视频接口,调用火山引擎即梦3.0 Pro API生成展示视频 - 设计路由新增生成3D模型接口,调用腾讯混元3D服务生成.glb格式3D模型 - 新增本地文件删除工具,支持强制重新生成时清理旧文件 - 设计响应Schema中添加video_url和model_3d_url字段支持前后端数据传递 - 前端设计详情页新增360度旋转3D模型展示区,支持生成、重新生成和下载3D模型 - 实现录制3D模型展示视频功能,支持捕获model-viewer旋转画面逐帧合成WebM文件下载 - 引入@google/model-viewer库作为3D模型Web组件展示支持 - 管理后台新增即梦视频生成和腾讯混元3D模型生成配置界面,方便服务密钥管理 - 前端API增加生成视频和生成3D模型接口请求方法,超时设置为10分钟以支持长时间处理 - 优化UI交互提示,新增生成中状态显示和错误提示,提升用户体验和操作反馈
This commit is contained in:
@@ -97,6 +97,103 @@
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 即梦视频生成配置卡片 -->
|
||||
<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 }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<p class="card-desc">火山引擎即梦 3.0 Pro 图生视频 API,将设计图生成 360 度旋转展示视频。需要火山引擎 Access Key 和 Secret Key(非 API Key)</p>
|
||||
</div>
|
||||
<el-form label-width="120px" class="config-form">
|
||||
<el-form-item label="Access Key">
|
||||
<el-input
|
||||
v-model="volcAccessKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入火山引擎 Access Key"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key">
|
||||
<el-input
|
||||
v-model="volcSecretKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入火山引擎 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>
|
||||
</el-form-item>
|
||||
<el-form-item label="视频提示词">
|
||||
<el-input
|
||||
v-model="videoPrompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="玉雕作品在摄影棚内缓慢旋转360度展示全貌..."
|
||||
/>
|
||||
<span class="form-tip">用于控制视频生成效果,尽情描述旋转展示方式、灯光、背景等</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 腾讯混元3D 配置卡片 -->
|
||||
<div class="section-card">
|
||||
<div class="card-header">
|
||||
<div class="card-title-row">
|
||||
<h3 class="section-title">腾讯混元3D 模型生成</h3>
|
||||
<el-tag :type="hunyuan3dStatus" size="small">
|
||||
{{ hunyuan3dStatusText }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<p class="card-desc">腾讯混元3D 图生 3D 模型 API,将设计图转换为可交互的 3D 模型(.glb 格式)</p>
|
||||
</div>
|
||||
<el-form label-width="120px" class="config-form">
|
||||
<el-form-item label="SecretId">
|
||||
<el-input
|
||||
v-model="tencentSecretId"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入腾讯云 SecretId"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="SecretKey">
|
||||
<el-input
|
||||
v-model="tencentSecretKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="请输入腾讯云 SecretKey"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<span class="form-tip">获取方式:访问 <a href="https://console.cloud.tencent.com/cam/capi" target="_blank">https://console.cloud.tencent.com/cam/capi</a> 创建密钥,并在 <a href="https://console.cloud.tencent.com/ai3d" target="_blank">混元3D控制台</a> 开通服务</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="3D提示词">
|
||||
<el-input
|
||||
v-model="model3dPrompt"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="可选,用于控制3D模型生成效果"
|
||||
/>
|
||||
<span class="form-tip">可选,用于描述3D模型的生成效果要求</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 通用设置 -->
|
||||
<div class="section-card">
|
||||
<h3 class="section-title">通用设置</h3>
|
||||
@@ -133,12 +230,23 @@ 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 tencentSecretId = ref('')
|
||||
const tencentSecretKey = ref('')
|
||||
const videoPrompt = ref('')
|
||||
const videoFrames = ref('121')
|
||||
const model3dPrompt = ref('')
|
||||
const imageSize = ref('1024')
|
||||
const saving = ref(false)
|
||||
|
||||
// 后端是否已配置 API Key(脱敏值也算已配置)
|
||||
const siliconflowConfigured = ref(false)
|
||||
const volcengineConfigured = ref(false)
|
||||
const volcAccessKeyConfigured = ref(false)
|
||||
const volcSecretKeyConfigured = ref(false)
|
||||
const tencentSecretIdConfigured = ref(false)
|
||||
const tencentSecretKeyConfigured = ref(false)
|
||||
|
||||
// 测试状态
|
||||
const testingSiliconflow = ref(false)
|
||||
@@ -151,6 +259,10 @@ 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 hunyuan3dStatus = computed(() => ((tencentSecretId.value || tencentSecretIdConfigured.value) && (tencentSecretKey.value || tencentSecretKeyConfigured.value)) ? 'success' : 'info')
|
||||
const hunyuan3dStatusText = computed(() => ((tencentSecretId.value || tencentSecretIdConfigured.value) && (tencentSecretKey.value || tencentSecretKeyConfigured.value)) ? '已配置' : '未配置')
|
||||
|
||||
// 加载配置
|
||||
const loadConfigs = async () => {
|
||||
@@ -176,6 +288,28 @@ 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']
|
||||
}
|
||||
if (map['VOLC_SECRET_KEY'] && !map['VOLC_SECRET_KEY'].includes('****')) {
|
||||
volcSecretKey.value = map['VOLC_SECRET_KEY']
|
||||
}
|
||||
// 腾讯云 SecretId / SecretKey
|
||||
tencentSecretIdConfigured.value = !!map['TENCENT_SECRET_ID']
|
||||
tencentSecretKeyConfigured.value = !!map['TENCENT_SECRET_KEY']
|
||||
if (map['TENCENT_SECRET_ID'] && !map['TENCENT_SECRET_ID'].includes('****')) {
|
||||
tencentSecretId.value = map['TENCENT_SECRET_ID']
|
||||
}
|
||||
if (map['TENCENT_SECRET_KEY'] && !map['TENCENT_SECRET_KEY'].includes('****')) {
|
||||
tencentSecretKey.value = map['TENCENT_SECRET_KEY']
|
||||
}
|
||||
// 提示词配置
|
||||
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) {
|
||||
console.error('加载配置失败', e)
|
||||
@@ -204,6 +338,22 @@ const handleSave = async () => {
|
||||
if (volcengineKey.value) {
|
||||
configs['VOLCENGINE_API_KEY'] = volcengineKey.value
|
||||
}
|
||||
if (volcAccessKey.value) {
|
||||
configs['VOLC_ACCESS_KEY'] = volcAccessKey.value
|
||||
}
|
||||
if (volcSecretKey.value) {
|
||||
configs['VOLC_SECRET_KEY'] = volcSecretKey.value
|
||||
}
|
||||
if (tencentSecretId.value) {
|
||||
configs['TENCENT_SECRET_ID'] = tencentSecretId.value
|
||||
}
|
||||
if (tencentSecretKey.value) {
|
||||
configs['TENCENT_SECRET_KEY'] = tencentSecretKey.value
|
||||
}
|
||||
// 提示词始终提交(包括空值,允许清空)
|
||||
configs['VIDEO_PROMPT'] = videoPrompt.value
|
||||
configs['VIDEO_FRAMES'] = videoFrames.value
|
||||
configs['MODEL3D_PROMPT'] = model3dPrompt.value
|
||||
await updateConfigsBatch(configs)
|
||||
ElMessage.success('配置已保存')
|
||||
await loadConfigs()
|
||||
|
||||
Reference in New Issue
Block a user