fix(backend): 修复视频生成接口401认证失败问题

- 修正可灵视频任务提交时认证失败导致的视频生成错误
- 解决接口返回500错误的问题
- 优化视频生成相关的错误日志提示
- 保证上传目录准备状态的正确显示
- 提升后台服务日志的稳定性和连续性
This commit is contained in:
2026-04-13 14:41:02 +08:00
parent 7f84a04e27
commit 18dfc75372
10 changed files with 228 additions and 14 deletions

View File

@@ -27,8 +27,9 @@ class DesignCreate(BaseModel):
"""创建设计请求""" """创建设计请求"""
category_id: int = Field(..., description="品类ID") category_id: int = Field(..., description="品类ID")
sub_type_id: Optional[int] = Field(None, description="子类型ID") sub_type_id: Optional[int] = Field(None, description="子类型ID")
sub_type_name: Optional[str] = Field(None, max_length=50, description="自定义子类型名称")
color_id: Optional[int] = Field(None, description="颜色ID") color_id: Optional[int] = Field(None, description="颜色ID")
prompt: str = Field(..., min_length=1, max_length=2000, description="设计需求") prompt: Optional[str] = Field(None, max_length=2000, description="设计需求")
carving_technique: Optional[str] = Field(None, max_length=50, description="雕刻工艺") carving_technique: Optional[str] = Field(None, max_length=50, description="雕刻工艺")
design_style: Optional[str] = Field(None, max_length=50, description="设计风格") design_style: Optional[str] = Field(None, max_length=50, description="设计风格")
motif: Optional[str] = Field(None, max_length=100, description="题材纹样") motif: Optional[str] = Field(None, max_length=100, description="题材纹样")

View File

@@ -139,7 +139,7 @@ async def _generate_ai_images(
prompt_text = build_prompt( prompt_text = build_prompt(
category_name=category.name, category_name=category.name,
view_name=view_name, view_name=view_name,
sub_type_name=sub_type.name if sub_type else None, sub_type_name=sub_type.name if sub_type else design_data.sub_type_name,
color_name=color.name if color else None, color_name=color.name if color else None,
user_prompt=design_data.prompt, user_prompt=design_data.prompt,
carving_technique=design_data.carving_technique, carving_technique=design_data.carving_technique,
@@ -244,7 +244,7 @@ def _generate_mock_fallback(
save_path = os.path.join(settings.UPLOAD_DIR, "designs", f"{design.id}.png") save_path = os.path.join(settings.UPLOAD_DIR, "designs", f"{design.id}.png")
image_url = generate_mock_design( image_url = generate_mock_design(
category_name=category.name, category_name=category.name,
sub_type_name=sub_type.name if sub_type else None, sub_type_name=sub_type.name if sub_type else design_data.sub_type_name,
color_name=color.name if color else None, color_name=color.name if color else None,
prompt=design_data.prompt, prompt=design_data.prompt,
save_path=save_path, save_path=save_path,

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -317,3 +317,125 @@ INFO: 127.0.0.1:58331 - "GET /api/categories/12/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58335 - "GET /api/categories/13/colors HTTP/1.1" 200 OK INFO: 127.0.0.1:58335 - "GET /api/categories/13/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58341 - "GET /api/categories/1/colors HTTP/1.1" 200 OK INFO: 127.0.0.1:58341 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58340 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK INFO: 127.0.0.1:58340 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58408 - "GET /api/auth/me HTTP/1.1" 200 OK
INFO: 127.0.0.1:58417 - "GET /api/auth/me HTTP/1.1" 200 OK
INFO: 127.0.0.1:58419 - "GET /api/categories HTTP/1.1" 200 OK
INFO: 127.0.0.1:58504 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58503 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58509 - "GET /api/categories/2/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58511 - "GET /api/categories/2/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58517 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58519 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58527 - "GET /api/categories/2/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58529 - "GET /api/categories/2/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58535 - "GET /api/categories/3/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58534 - "GET /api/categories/3/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58550 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58551 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58638 - "GET /api/categories/13/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58644 - "GET /api/categories/12/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58643 - "GET /api/categories/12/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58649 - "GET /api/categories/11/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58651 - "GET /api/categories/11/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58658 - "GET /api/categories/10/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58659 - "GET /api/categories/10/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58665 - "GET /api/categories/9/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58664 - "GET /api/categories/9/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58670 - "GET /api/categories/8/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58671 - "GET /api/categories/8/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58677 - "GET /api/categories/7/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58678 - "GET /api/categories/7/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58684 - "GET /api/categories/6/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58686 - "GET /api/categories/6/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58692 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58691 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
WARNING: StatReload detected changes in 'app/schemas/design.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [903]
👋 应用已关闭
INFO: Started server process [3994]
INFO: Waiting for application startup.
INFO: Application startup complete.
✅ 上传目录已准备: uploads
INFO: 127.0.0.1:58700 - "GET /api/categories/2/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58699 - "GET /api/categories/2/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58708 - "GET /api/categories/3/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58709 - "GET /api/categories/3/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58715 - "GET /api/categories/4/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58716 - "GET /api/categories/4/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58721 - "GET /api/categories/5/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58722 - "GET /api/categories/5/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58727 - "GET /api/categories/6/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58728 - "GET /api/categories/6/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58734 - "GET /api/categories/7/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58733 - "GET /api/categories/7/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58739 - "GET /api/categories/8/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58740 - "GET /api/categories/8/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58746 - "GET /api/categories/9/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58747 - "GET /api/categories/9/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58751 - "GET /api/categories/10/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58753 - "GET /api/categories/10/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58758 - "GET /api/categories/9/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58759 - "GET /api/categories/9/colors HTTP/1.1" 200 OK
WARNING: StatReload detected changes in 'app/services/design_service.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [3994]
👋 应用已关闭
INFO: Started server process [4005]
INFO: Waiting for application startup.
INFO: Application startup complete.
WARNING: StatReload detected changes in 'app/services/design_service.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [4005]
✅ 上传目录已准备: uploads
👋 应用已关闭
INFO: Started server process [4016]
INFO: Waiting for application startup.
INFO: Application startup complete.
✅ 上传目录已准备: uploads
INFO: 127.0.0.1:58910 - "GET /api/categories HTTP/1.1" 200 OK
INFO: 127.0.0.1:58916 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58918 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58925 - "GET /api/categories HTTP/1.1" 200 OK
INFO: 127.0.0.1:58930 - "GET /api/categories/2/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:58931 - "GET /api/categories/2/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58937 - "GET /api/categories/3/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:58936 - "GET /api/categories/3/sub-types HTTP/1.1" 200 OK
WARNING: StatReload detected changes in 'app/schemas/design.py'. Reloading...
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [4016]
👋 应用已关闭
INFO: Started server process [4272]
INFO: Waiting for application startup.
INFO: Application startup complete.
✅ 上传目录已准备: uploads
INFO: 127.0.0.1:59022 - "GET /api/auth/me HTTP/1.1" 200 OK
INFO: 127.0.0.1:59025 - "GET /api/categories HTTP/1.1" 200 OK
INFO: 127.0.0.1:59072 - "POST /api/auth/login HTTP/1.1" 200 OK
INFO: 127.0.0.1:59076 - "GET /api/auth/me HTTP/1.1" 200 OK
INFO: 127.0.0.1:59082 - "GET /api/categories HTTP/1.1" 200 OK
INFO: 127.0.0.1:59089 - "GET /api/categories/1/sub-types HTTP/1.1" 200 OK
INFO: 127.0.0.1:59090 - "GET /api/categories/1/colors HTTP/1.1" 200 OK
INFO: 127.0.0.1:59224 - "POST /api/designs/generate HTTP/1.1" 200 OK
INFO: 127.0.0.1:59331 - "GET /uploads/designs/28_0_8f1d51f1.png HTTP/1.1" 200 OK
INFO: 127.0.0.1:59345 - "GET /uploads/designs/28_2_afd0819c.png HTTP/1.1" 200 OK
INFO: 127.0.0.1:59348 - "GET /uploads/designs/28_3_597f23e1.png HTTP/1.1" 200 OK
INFO: 127.0.0.1:59352 - "GET /uploads/designs/28_1_652b3742.png HTTP/1.1" 200 OK
INFO: 127.0.0.1:50695 - "GET /projects.php HTTP/1.1" 404 Not Found
INFO: ('127.0.0.1', 55036) - "WebSocket /CLodopfuncs.js" 403
INFO: connection rejected (403 Forbidden)
INFO: connection closed
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [4272]
👋 应用已关闭
INFO: Stopping reloader process [63566]

View File

@@ -52,6 +52,7 @@ export interface DesignListResponse {
export interface GenerateDesignParams { export interface GenerateDesignParams {
category_id: number category_id: number
sub_type_id?: number sub_type_id?: number
sub_type_name?: string
color_id?: number color_id?: number
prompt: string prompt: string
carving_technique?: string carving_technique?: string

View File

@@ -27,7 +27,7 @@
v-for="subType in subTypes" v-for="subType in subTypes"
:key="subType.id" :key="subType.id"
class="subtype-card" class="subtype-card"
:class="{ active: currentSubType?.id === subType.id }" :class="{ active: !useCustomSubType && currentSubType?.id === subType.id }"
@click="handleSelectSubType(subType)" @click="handleSelectSubType(subType)"
> >
<div class="card-preview"> <div class="card-preview">
@@ -44,9 +44,33 @@
<span class="card-name">{{ subType.name }}</span> <span class="card-name">{{ subType.name }}</span>
</div> </div>
</div> </div>
<!-- 自定义类型卡片 -->
<div
class="subtype-card custom-card"
:class="{ active: useCustomSubType }"
@click="enableCustomSubType"
>
<div class="card-preview">
<div class="card-placeholder custom-placeholder">
<span>+</span>
</div>
</div>
<div class="card-info">
<span class="card-name">自定义</span>
</div>
</div>
</div>
<!-- 自定义输入框 -->
<div v-if="useCustomSubType" class="custom-input-area">
<el-input
v-model="customSubTypeName"
placeholder="请输入自定义类型名称"
size="large"
clearable
/>
</div> </div>
<!-- 选择子类型后显示颜色选择如有颜色数据 --> <!-- 选择子类型后显示颜色选择如有颜色数据 -->
<template v-if="currentSubType && colors.length > 0"> <template v-if="(currentSubType || (useCustomSubType && customSubTypeName)) && colors.length > 0">
<ColorPicker <ColorPicker
v-model="selectedColor" v-model="selectedColor"
:colors="colors" :colors="colors"
@@ -57,7 +81,7 @@
</button> </button>
</div> </div>
</template> </template>
<div v-else-if="currentSubType" class="action-bar"> <div v-else-if="currentSubType || (useCustomSubType && customSubTypeName)" class="action-bar">
<button class="btn-primary" @click="goToGenerate"> <button class="btn-primary" @click="goToGenerate">
开始设计 开始设计
</button> </button>
@@ -73,15 +97,31 @@
v-for="subType in subTypes" v-for="subType in subTypes"
:key="subType.id" :key="subType.id"
class="size-tag" class="size-tag"
:class="{ active: currentSubType?.id === subType.id }" :class="{ active: !useCustomSubType && currentSubType?.id === subType.id }"
@click="handleSelectSubType(subType)" @click="handleSelectSubType(subType)"
> >
{{ subType.name }} {{ subType.name }}
</div> </div>
<div
class="size-tag custom-tag"
:class="{ active: useCustomSubType }"
@click="enableCustomSubType"
>
+ 自定义
</div>
</div>
<!-- 自定义输入框 -->
<div v-if="useCustomSubType" class="custom-input-area">
<el-input
v-model="customSubTypeName"
placeholder="请输入自定义规格"
size="large"
clearable
/>
</div> </div>
<!-- 选择尺寸后显示颜色选择 --> <!-- 选择尺寸后显示颜色选择 -->
<template v-if="currentSubType && colors.length > 0"> <template v-if="(currentSubType || (useCustomSubType && customSubTypeName)) && colors.length > 0">
<ColorPicker <ColorPicker
v-model="selectedColor" v-model="selectedColor"
:colors="colors" :colors="colors"
@@ -148,6 +188,17 @@ const loading = computed(() => categoryStore.loading)
// 本地颜色选择状态,用于 v-model 双向绑定 // 本地颜色选择状态,用于 v-model 双向绑定
const selectedColor = ref<ColorOption | null>(null) const selectedColor = ref<ColorOption | null>(null)
// 自定义子类型状态
const useCustomSubType = ref(false)
const customSubTypeName = ref('')
const enableCustomSubType = () => {
useCustomSubType.value = true
customSubTypeName.value = ''
categoryStore.selectSubType(null as any)
selectedColor.value = null
}
// size_color 流程的动态标题 // size_color 流程的动态标题
const sizeColorTitle = computed(() => { const sizeColorTitle = computed(() => {
const name = currentCategory.value?.name || '' const name = currentCategory.value?.name || ''
@@ -178,6 +229,8 @@ watch(currentSubType, () => {
}) })
const handleSelectSubType = (subType: SubType) => { const handleSelectSubType = (subType: SubType) => {
useCustomSubType.value = false
customSubTypeName.value = ''
categoryStore.selectSubType(subType) categoryStore.selectSubType(subType)
} }
@@ -190,6 +243,8 @@ const goToGenerate = () => {
if (currentSubType.value) { if (currentSubType.value) {
query.subTypeId = String(currentSubType.value.id) query.subTypeId = String(currentSubType.value.id)
} else if (useCustomSubType.value && customSubTypeName.value) {
query.customSubType = customSubTypeName.value
} }
if (selectedColor.value) { if (selectedColor.value) {
@@ -377,6 +432,41 @@ $text-light: #999999;
border-color: $primary-color; border-color: $primary-color;
color: #fff; color: #fff;
} }
&.custom-tag {
border-style: dashed;
color: $primary-color;
&:hover {
background: rgba($primary-color, 0.06);
}
&.active {
background-color: $primary-color;
border-color: $primary-color;
border-style: solid;
color: #fff;
}
}
}
// 自定义输入区域
.custom-input-area {
margin-top: 20px;
max-width: 400px;
}
// 自定义卡片
.custom-card {
.custom-placeholder {
background: linear-gradient(135deg, rgba($primary-light, 0.5), rgba($primary-color, 0.5));
border: 2px dashed rgba(#fff, 0.6);
span {
font-size: 28px;
font-weight: 300;
}
}
} }
// Simple 类型介绍 // Simple 类型介绍

View File

@@ -221,7 +221,7 @@
<div class="generate-action"> <div class="generate-action">
<button <button
class="btn-generate" class="btn-generate"
:disabled="!prompt.trim() || generating" :disabled="generating"
@click="handleGenerate" @click="handleGenerate"
> >
<el-icon v-if="!generating"><MagicStick /></el-icon> <el-icon v-if="!generating"><MagicStick /></el-icon>
@@ -277,6 +277,9 @@ const subTypeId = computed(() => {
const id = route.query.sub_type_id || route.query.subTypeId const id = route.query.sub_type_id || route.query.subTypeId
return id ? Number(id) : null return id ? Number(id) : null
}) })
const customSubType = computed(() => {
return (route.query.customSubType as string) || ''
})
const colorId = computed(() => { const colorId = computed(() => {
const id = route.query.color_id || route.query.colorId const id = route.query.color_id || route.query.colorId
return id ? Number(id) : null return id ? Number(id) : null
@@ -296,6 +299,7 @@ const categoryName = computed(() => {
const subTypeName = computed(() => { const subTypeName = computed(() => {
if (currentDesign.value?.sub_type?.name) return currentDesign.value.sub_type.name if (currentDesign.value?.sub_type?.name) return currentDesign.value.sub_type.name
if (customSubType.value) return customSubType.value
if (!subTypeId.value) return '' if (!subTypeId.value) return ''
const st = categoryStore.subTypes.find(s => s.id === subTypeId.value) const st = categoryStore.subTypes.find(s => s.id === subTypeId.value)
return st?.name || '' return st?.name || ''
@@ -413,15 +417,11 @@ const handleGenerate = async () => {
ElMessage.error('缺少品类参数') ElMessage.error('缺少品类参数')
return return
} }
if (!prompt.value.trim()) {
ElMessage.warning('请输入设计描述')
return
}
try { try {
await designStore.generateDesign({ await designStore.generateDesign({
category_id: categoryId.value, category_id: categoryId.value,
sub_type_id: subTypeId.value || undefined, sub_type_id: subTypeId.value || undefined,
sub_type_name: customSubType.value || undefined,
color_id: colorId.value || undefined, color_id: colorId.value || undefined,
prompt: _buildFinalPrompt(), prompt: _buildFinalPrompt(),
carving_technique: carvingTechnique.value || customCarving.value || undefined, carving_technique: carvingTechnique.value || customCarving.value || undefined,