Files
YuShiSheJiShi/docs/多视角一致性与3D视频生成技术文档.md
2ef126e445 feat: 强化多视角图片一致性 + 修复下载逻辑 + 技术文档
- 新增品类专属背面/侧面描述(BACK_VIEW_HINTS/SIDE_VIEW_HINTS)
- 强化一致性前缀策略,按视角定制相机位置描述
- 更新视角映射提示词为纯摄影术语
- 修复前端下载逻辑:改用fetch直接下载当前视角图片
- HTTPS改HTTP修复外网URL访问
- 新增多视角一致性与3D视频生成技术文档
2026-03-28 19:51:08 +08:00

21 KiB
Raw Blame History

多视角图片一致性 & 3D/视频生成 技术文档

一、系统概述

玉宗珠宝 AI 设计系统支持根据用户选择的品类、颜色、工艺等参数,自动生成多视角设计图(效果图、正面图、侧面图、背面图),并基于这些图片进一步生成 3D 模型和 360 度旋转展示视频。

核心挑战AI 生图模型(如 Seedream 5.0 lite的"参考图"参数本质上是风格参考,而非"同一物体不同角度"的语义理解。因此需要通过多层提示词策略来约束 AI 保持多视角图片的一致性。


二、整体架构

用户提交设计请求
       │
       ▼
┌──────────────────────────────────────────────────────────────┐
│  design_service.py - create_design_async()                   │
│                                                              │
│  1. 获取品类视角列表prompt_builder.get_views_for_category │
│  2. 循环每个视角:                                             │
│     ├── prompt_builder.build_prompt() → 构建英文提示词         │
│     ├── 添加一致性前缀(相机位置描述)                          │
│     ├── ai_generator.generate_image() → 调用AI生图API         │
│     ├── 下载图片到本地持久化                                   │
│     └── 创建 DesignImage 记录                                 │
│  3. 第一张图的 seed/URL 传给后续视角复用                       │
└──────────────────────────────────────────────────────────────┘
       │
       ▼ 用户手动触发
┌──────────────┐    ┌──────────────────┐
│ 生成3D模型    │    │ 生成旋转视频      │
│ ai_3d_       │    │ ai_video_        │
│ generator.py │    │ generator_       │
│              │    │ kling.py         │
│ 腾讯混元3D    │    │ 可灵AI多图参考    │
│ 专业版        │    │ 生视频            │
└──────────────┘    └──────────────────┘

三、涉及文件清单

文件路径 职责
backend/app/services/design_service.py 设计生成主流程,多视角循环、一致性策略协调
backend/app/services/prompt_builder.py 提示词构建器,品类视角配置、品类专属背面/侧面描述
backend/app/services/ai_generator.py AI 生图服务,支持 SiliconFlow Kolors 和 Seedream 双模型
backend/app/services/ai_3d_generator.py 腾讯混元3D 模型生成服务多视角→3D
backend/app/services/ai_video_generator_kling.py 可灵 AI 多图参考生视频服务
backend/app/routers/designs.py REST API 路由,收集多视角图片调用 3D/视频服务
backend/app/models/design_image.py DesignImage 数据模型
backend/app/services/config_service.py 配置服务AI Key 等从数据库优先读取
init_data.sql 数据库初始化,包含 prompt_mappings 视角映射
frontend/src/components/DesignPreview.vue 前端多视角展示与下载

四、品类视角配置

不同品类生成的视角数量和种类不同,定义在 prompt_builder.pyCATEGORY_VIEWS 字典中:

品类 视角列表 视角数
牌子 效果图、正面图、背面图 3
珠子 效果图、正面图 2
手把件 效果图、正面图、侧面图、背面图 4
雕刻件 效果图、正面图、侧面图、背面图 4
摆件 效果图、正面图、侧面图、背面图 4
随形 效果图、正面图、侧面图、背面图 4
手镯 效果图、正面图、侧面图 3
戒指 效果图、正面图、侧面图 3
耳钉/耳饰/手链/项链/表带 效果图、正面图 2

生成顺序:严格按列表顺序,第一张始终是"效果图"45度英雄镜头后续视角依次生成。


五、多视角图片一致性策略(四层保障)

第一层AI 模型级参考机制

位置:design_service.py_generate_ai_images() 第 134-183 行

两种模型的不同一致性方式:

模型 一致性机制 参数 说明
SiliconFlow Kolors seed 复用 seed 第一张图返回的 seed 值传给后续视角,确保随机过程相同
Seedream 5.0 lite 参考图 ref_image_urlimage: [url] 第一张图的远程 URL 作为风格参考传入后续视角

代码流程:

shared_seed = None       # Kolors 用: 第一张图的 seed
first_remote_url = None  # Seedream 用: 第一张图的远程 URL

for idx, view_name in enumerate(views):
    # 后续视角传入 seed 或参考图 URL
    ref_url = first_remote_url if idx > 0 else None
    
    remote_url, returned_seed = await ai_generator.generate_image(
        final_prompt, model, seed=shared_seed, ref_image_url=ref_url
    )
    
    # 第一张图保存信息供后续复用
    if idx == 0:
        first_remote_url = remote_url
        if returned_seed is not None:
            shared_seed = returned_seed

关键限制Seedream 的 image 参数本质上是风格参考AI 不能直接理解为"同一个物体的不同角度",所以需要第二、三、四层提示词来补充约束。


第二层:一致性前缀(相机位置描述)

位置:design_service.py 第 159-172 行

从第 2 张图起idx > 0在提示词最前面拼接一段一致性约束前缀,按视角名称定制相机位置描述:

view_angle_map = {
    "正面图": "moving the camera to face the object directly from the front",
    "侧面图": "moving the camera 90 degrees to the left side of the object",
    "背面图": "moving the camera 180 degrees to see the reverse/back side of the object",
}

consistency_prefix = (
    f"Photograph the EXACT SAME jade object from the reference image, {angle_desc}. "
    "The object does NOT move or change - only the camera position changes. "
    "The shape, size, color, material texture, and all physical features must remain IDENTICAL. "
)

final_prompt = consistency_prefix + prompt_text

设计思路

  • 强调"EXACT SAME"和"IDENTICAL"强制 AI 保持物体一致
  • 用"相机移动"的摄影术语描述视角变化,而非"生成另一张图"
  • 明确"物体不动,只有相机位置改变"

第三层:品类专属视角描述

位置:prompt_builder.py 第 35-65 行 & 第 197-201 行

不同品类的背面特征差异极大,需要品类专属描述来避免 AI 产生错误理解。

背面描述BACK_VIEW_HINTS

品类 背面特征 核心约束
牌子 光滑平面,可能有题款,绝对没有雕刻图案 "Do NOT mirror or duplicate the front carving on the back"
手把件 同一件三维雕塑的背面,自然延续 "natural continuation of the carving from the rear angle"
雕刻件 三维雕塑的背面,雕刻自然延续 "not a separate or different design"
摆件 三维陈列品的背面 "form and carving continue naturally"
随形 天然石料表面的背面 "may show more of the raw jade texture"

侧面描述SIDE_VIEW_HINTS

品类 侧面特征
牌子 薄片轮廓5-10mm 厚度

解决的核心问题 牌子品类出现"双面佛"效果 —— 背面也有雕刻图案。真实的玉雕牌子背面是光滑平面。通过 BACK_VIEW_HINTS["牌子"] 强制约束 AI

"The reverse/back side of a jade pendant plaque is traditionally a smooth, flat, polished surface. It may have a brief inscription or seal mark, but it must NOT have any carved figure, face, or decorative relief pattern."

应用时机:在 build_prompt() 构建提示词时,根据视角名称和品类名称自动追加:

if view_name == "背面图" and category_name in BACK_VIEW_HINTS:
    parts.append(BACK_VIEW_HINTS[category_name])
elif view_name == "侧面图" and category_name in SIDE_VIEW_HINTS:
    parts.append(SIDE_VIEW_HINTS[category_name])

第四层:数据库视角映射提示词

位置:prompt_mappingsmapping_type='view'

每个视角有标准化的英文摄影术语描述,存储在数据库中,支持后台热更新:

视角 英文描述
效果图 three-quarter view at 45-degree angle, hero shot showing the complete jade artwork with depth and dimension, single object on pure white background
正面图 front view, camera positioned directly in front of the object facing it straight-on, showing only the front carved surface, single object on pure white background
侧面图 side view, camera positioned at exactly 90 degrees to the left of the object, showing the edge profile and thickness, single object on pure white background
背面图 back view, camera positioned directly behind the object at 180 degrees, showing the reverse side, single object on pure white background

设计特点

  • 使用纯摄影术语camera positioned, facing, straight-on
  • 精确的角度度数45°、90°、180°
  • 统一的纯白背景要求pure white background
  • 强调单一物体single object避免生成多个物体

四层策略的组合效果

以"牌子"品类的背面图为例,最终提示词结构:

[第二层:一致性前缀]
Photograph the EXACT SAME jade object from the reference image, 
moving the camera 180 degrees to see the reverse/back side of the object. 
The object does NOT move or change - only the camera position changes. 
The shape, size, color, material texture, and all physical features must remain IDENTICAL.

[常规提示词内容]
Chinese Hetian nephrite jade pendant plaque, 
natural Hetian nephrite jade with warm luster, 
featuring dragon-phoenix auspicious pattern, 
relief carving with raised design emerging from surface, 
...

[第四层:视角映射]
back view, camera positioned directly behind the object at 180 degrees, 
showing the reverse side, single object on pure white background,

[第三层:品类专属背面描述]
IMPORTANT: The reverse/back side of a jade pendant plaque is traditionally 
a smooth, flat, polished surface. It may have a brief inscription or seal mark, 
but it must NOT have any carved figure, face, or decorative relief pattern. 
The back is plain and minimalist. Do NOT mirror or duplicate the front carving on the back.

[质量后缀]
professional jewelry product photography, studio lighting setup, 
pure white background, ultra-detailed, sharp focus, 8K resolution, 
photorealistic rendering, high-end commercial quality

加上 [第一层] Seedream API 的 image 参数传入第一张效果图作为风格参考。


六、3D 模型生成

6.1 技术方案

  • 服务腾讯混元3D 专业版Hunyuan3D Pro
  • API 认证TC3-HMAC-SHA256 签名
  • 输入:主图 + 多视角图片
  • 输出ZIP 包(包含 GLB/OBJ/FBX/STL 多种格式)

6.2 多视角图片收集

位置:designs.pygenerate_3d_model() 第 329-339 行

# 收集所有多视角图片 URL 和视角名称
image_urls = []
view_names = []
if design.images:
    for img in sorted(design.images, key=lambda x: x.sort_order):
        if img.image_url:
            image_urls.append(img.image_url)
            view_names.append(img.view_name or "效果图")

6.3 视角映射

位置:ai_3d_generator.py 第 121-126 行

混元3D API 的 MultiViewImages 参数支持指定每张图的视角类型:

_VIEW_NAME_MAP = {
    "侧面图": "left",
    "背面图": "back",
}

主图选择逻辑:正面图优先 → 效果图次之 → 否则取第一张

for url, name in zip(image_urls, view_names):
    if name == "正面图" and not main_url:
        main_url = url                    # 正面图作为主图
    elif name in _VIEW_NAME_MAP:
        multi_views.append({              # 侧面/背面作为辅助视角
            "ViewType": _VIEW_NAME_MAP[name], 
            "ViewImageUrl": url
        })
    elif not main_url:
        main_url = url                    # 效果图或其他作为备选主图

6.4 URL 转换

位置:ai_3d_generator.py_to_public_url() 第 129-138 行

第三方 API 需要外网可访问的完整 URL本地存储路径/uploads/xxx需要拼接域名

def _to_public_url(url: str) -> str:
    if url and url.startswith("/uploads/"):
        base_domain = get_config_value("SITE_DOMAIN", "http://c02.wsg.plus")
        return f"{base_domain}{url}"
    return url

注意:服务器仅支持 HTTP不支持 HTTPSHTTPS 会 ERR_CONNECTION_REFUSED

6.5 生成流程

收集多视角图片 → 转换为外网URL → 选择主图/辅助视角
    → 提交 SubmitHunyuanTo3DProJob (ImageUrl + MultiViewImages)
    → 轮询 QueryHunyuanTo3DProJob (每5秒最多120次≈10分钟)
    → 下载 ZIP 解压提取 .glb → 保存到 /uploads/models/

6.6 结果存储

3D 模型 URL 保存到第一张 DesignImagemodel_3d_url 字段。同时保留 ZIP 包(包含 GLB/OBJ/FBX/STL供用户完整下载。


七、视频生成

7.1 技术方案

  • 服务:可灵 AIKling多图参考生视频
  • API 端点https://api-beijing.klingai.com/v1/videos/multi-image2video
  • API 认证JWTHS256Access Key + Secret Key 签发30 分钟有效期)
  • 输入1-4 张参考图片 + 提示词
  • 输出MP4 视频

7.2 多视角图片收集

位置:designs.pygenerate_video() 第 273-280 行

# 收集多视角图片 URL
image_urls = []
if design.images:
    for img in sorted(design.images, key=lambda x: x.sort_order):
        if img.image_url:
            image_urls.append(img.image_url)
if not image_urls and design.image_url:
    image_urls.append(design.image_url)  # 兼容旧数据:只有 design.image_url

7.3 核心优势

可灵 AI 的多图参考生视频 API 原生支持传入 1-4 张参考图AI 会理解为同一物体的多个角度参考,生成单品旋转展示视频。这是选择可灵 AI 的核心原因。

7.4 视频提示词

默认提示词(可通过数据库 VIDEO_PROMPT 配置覆盖):

精美玉雕工艺品在专业珠宝摄影棚内展示,
纯白色背景,柔和的珠宝摄影灯光,
玉石作品放在旋转展台上缓慢平稳地旋转360度
展示正面、侧面、背面全貌,
展现玉石温润的质感、细腻的雕刻纹理和通透的光泽,
电影级画质,微距细节感,平稳流畅的转台旋转

7.5 API 参数

payload = {
    "model_name": "kling-v1-6",      # 可灵 v1.6 模型
    "image_list": image_list,          # [{"image": "url"}, ...]最多4张
    "prompt": prompt,                  # 视频提示词
    "mode": "pro",                     # 高品质模式Pro
    "duration": "5",                   # 视频时长5秒或10秒
    "aspect_ratio": "1:1",            # 正方形比例
}

7.6 生成流程

收集多视角图片(最多4张) → 转换为外网URL → 构建image_list
    → 提交 POST /v1/videos/multi-image2video
    → 轮询 GET /v1/videos/multi-image2video/{task_id} (每5秒最多120次)
    → 下载 MP4 → 保存到 /uploads/videos/

7.7 JWT 认证细节

headers = {"alg": "HS256", "typ": "JWT"}
payload = {
    "iss": access_key,        # 签发者 = Access Key
    "exp": now + 1800,        # 30 分钟过期
    "nbf": now - 5,           # 允许 5 秒时钟偏差
    "iat": now,               # 签发时间(必须包含!)
}
token = jwt.encode(payload, secret_key, algorithm="HS256", headers=headers)

踩坑记录headers 中的 typpayload 中的 iat 字段缺一不可,否则返回 401 认证失败。


八、图片持久化存储

8.1 问题背景

第三方 AI 服务(火山引擎 Seedream生成的图片 URL 是临时链接,一段时间后会过期失效(返回 NoSuchKey 错误)。

8.2 解决方案

生成图片后立即下载到本地 uploads/designs/ 目录持久化存储:

async def _download_image_to_local(remote_url, design_id, idx):
    filename = f"{design_id}_{idx}_{uuid.uuid4().hex[:8]}.png"
    local_path = os.path.join(designs_dir, filename)
    # 下载远程图片
    async with httpx.AsyncClient(timeout=60, follow_redirects=True) as client:
        resp = await client.get(remote_url)
        with open(local_path, "wb") as f:
            f.write(resp.content)
    return f"/uploads/designs/{filename}"

8.3 URL 格式

  • 本地存储路径/uploads/designs/{design_id}_{idx}_{随机8位}.png
  • 外网访问 URLhttp://c02.wsg.plus/uploads/designs/{design_id}_{idx}_{随机8位}.png

九、前端展示与下载

9.1 多视角切换

前端 DesignPreview.vue 通过 Tab 栏展示多视角图片,用户点击不同视角 Tab 切换显示。

9.2 图片下载

前端直接通过 fetch() 下载当前视角图片(不走后端 download 接口),确保下载的是当前展示的视角图片:

const handleDownload = async () => {
  const imgUrl = currentImageUrl.value  // 当前视角的图片URL
  const res = await fetch(imgUrl)
  const blob = await res.blob()
  // 创建 <a> 标签触发下载
  _downloadBlob(blob, downloadFilename.value)
}

踩坑记录:之前使用后端 /api/designs/{id}/download 接口,该接口只返回 design.image_url(第一张效果图),导致所有视角下载的都是效果图。


十、数据模型

DesignImage 表

字段 类型 说明
id Integer 主键
design_id Integer 关联设计 ID
view_name String(20) 视角名称:效果图/正面图/侧面图/背面图
image_url String(500) 图片 URL本地路径或远程链接
model_used String(50) AI 模型标识seedream-5.0 / kolors
prompt_used Text 实际使用的英文提示词
sort_order Integer 视角排序0=效果图, 1=正面图, 2=侧面图, 3=背面图)
model_3d_url String(500) 对应的 3D 模型 URL

Design 表(关键字段)

字段 说明
image_url 第一张效果图 URL兼容旧逻辑
video_url 生成的视频 URL
images 关联的 DesignImage 列表

十一、API 接口

方法 路径 说明
POST /api/designs/generate 创建设计AI 多视角生图
GET /api/designs 分页查询设计历史
GET /api/designs/{id} 设计详情(含 images 数组)
DELETE /api/designs/{id} 删除设计及所有图片
GET /api/designs/{id}/download 下载效果图(兼容旧逻辑)
POST /api/designs/{id}/generate-video 生成旋转视频
POST /api/designs/{id}/generate-3d 生成 3D 模型

十二、成本估算

服务 单价 说明
Seedream 5.0 lite 生图 ≈ 0.22 元/张 4 个视角 ≈ 0.88 元
腾讯混元3D 专业版 按量计费 单次 3D 生成
可灵 AI 视频 Pro 5s ≈ 7 元/次 Pro 模式5 秒时长

单次完整设计成本4视角品类≈ 0.88(生图)+ 混元3D + 7视频


十三、已知问题与踩坑记录

问题 原因 解决方案
背面图出现"双面佛" Seedream 参考图是风格参考AI 把正面图案复制到背面 品类专属 BACK_VIEW_HINTS + 一致性前缀
图片过期 404 (NoSuchKey) 火山引擎临时链接过期 生成后立即下载到本地持久化
HTTPS 连接被拒绝 服务器未配置 HTTPS _to_public_url 使用 http://
下载所有视角都是效果图 后端 download 接口只返回 image_url 前端改用 fetch 直接下载当前视角 URL
可灵 AI 401 认证失败 JWT 缺少 typ header 和 iat 字段 显式传入 headers={typ:JWT} 和 iat
混元3D 字段名错误 ViewImage 应为 ViewImageUrl 使用正确的 ViewImageUrl 字段
前端更新不生效 只上传了 .vue 源文件 前端是编译型项目,需上传编译后的 dist/

十四、配置项

以下配置通过数据库 system_configs 表管理,支持后台热更新:

配置键 说明 默认值
VOLCENGINE_API_KEY 火山引擎 Seedream API Key -
SILICONFLOW_API_KEY SiliconFlow Kolors API Key -
AI_IMAGE_MODEL 生图模型选择 flux-dev
AI_IMAGE_SIZE 图片尺寸 1024
TENCENT_SECRET_ID 腾讯云 SecretId混元3D -
TENCENT_SECRET_KEY 腾讯云 SecretKey混元3D -
KLING_ACCESS_KEY 可灵 AI Access Key -
KLING_SECRET_KEY 可灵 AI Secret Key -
SITE_DOMAIN 站点域名外网URL拼接 http://c02.wsg.plus
VIDEO_PROMPT 视频生成提示词 内置默认值
VIDEO_DURATION 视频时长(秒) 5