فهرست منبع

初始化:暨北内部-朵朵口播视频专用技能(固定OSS素材+百炼base_url,仅配key即可用)

zhengqi 2 هفته پیش
کامیت
2f54b7b699

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+# 密钥(含个人 API Key,严禁提交)
+.env
+
+# 本地生成产物(成片、中间素材)
+outputs/
+beauty-video-materials/
+
+# 系统文件
+.DS_Store
+__pycache__/
+*.pyc

+ 63 - 0
README.md

@@ -0,0 +1,63 @@
+# 美业口播科普视频脚本技能(百炼 wan3 直出版)
+
+把「美业口播科普短视频」从零散需求沉淀为一份**带固定品牌素材、可直接调用阿里云百炼 wan3(万相 3.0)生成视频**的结构化脚本。技能会像专业编导一样设计人物在门店场景里的动线、运镜、插画融入方式与门店丰富元素,确保成片真实、不站桩、不 AI 感。
+
+## 适用场景
+
+- 用户上传/指定人物五视角图、制服细节图、品牌立体 LOGO、指定音色,或要求生成可直出 wan3 的视频脚本与物料。
+- 典型触发:「帮我做一条美业口播视频(给 wan3 / 百炼)」「出个护肤科普短视频脚本并生成」。
+
+## 八大硬约束(贯穿全程)
+
+1. **人物**必须用指定人物五视角图(固定锁定,全片不变脸)。
+2. **制服**参考指定细节图(可换款式/颜色,**胸牌样式绝对不可变**)。
+3. **门店内景**必须有指定立体 LOGO(合成进参考图,前台必现)。
+4. **音色**必须用指定文件作 `reference_audio`。
+5. 口播文案由用户内容**转口语化**适合口播。
+6. 整段视频**一个片段、≤30 秒**(超了反馈精简,循环直到满足;绝不拆片段)。
+7. 确认后调用**百炼 wan3** 生成、轮询、下载本地、交付确认。
+8. **不支持二次创作**:任何元素修改都重新组装完整脚本、整段重发 wan3(不用编辑/延长模式)。
+
+## 首次配置(必做,只需一步)
+
+> 本技能为「暨北内部 - 朵朵」专用锁定版:人物五视角图、制服细节图、怡呵美立体 LOGO、朵朵音色、百炼工作空间与 base_url **均已固定在 `scripts/config.json` 中**,使用者无需修改。
+
+1. **API Key(唯一需要你提供的)**:登录百炼 / DashScope 控制台 → 切换到 **北京(cn-beijing)** 地域 → 创建 API Key(`sk-` 开头,只显示一次)。复制 `scripts/.env.example` 为 `scripts/.env`,填入 `DASHSCOPE_API_KEY=sk-...` 即可。
+   > ⚠️ `.env` 含你的密钥,**严禁提交 git 或随技能 zip 分发**;重新打包技能前请删除本地 `.env`。
+2. 固定品牌素材 / 工作空间 / base_url 均已预填,**无需任何改动**即可直接运行。
+
+## 运行
+
+对 WorkBuddy 说:「用美业口播科普视频脚本技能,做一条关于 *[选题]* 的口播视频」。技能按 `SKILL.md` 的 11 步流程执行:
+
+> 文字风格问卷 → 锁定固定素材 → 生成并确认物料(人物形象照 / 门店内景含 LOGO / 插画)→ 确认口播文案 → 确定插画插入点 → 组装编导分镜 Prompt → 逐步确认 → 调 wan3 生成 → 成片交付。
+
+也可手动驱动生成脚本:`python scripts/generate_video.py --help`。
+
+## 编导分镜要点(确保真实感)
+
+- **人物行为动线**:30 秒单段 ≤2 个动作、方向不反向(「走动→落座」则落座后不再起身;「坐姿→起身走动」则走动后不再落座);口播时不设计整理产品等手部摆弄动作,手部只用自然手势 / 点头。
+- **运镜组合**:2–3 种随机穿插(跟随 / 推近 / 拉远 / 横移 / 手持微晃)。
+- **插画展示方式**:全屏铺盖 / 圆形画中画 / 顶部或底部条状画中画 / 侧边画中画 / 人物画中画式全屏,随机混用不固化。
+- **门店丰富元素**:前台 / 美容床 / 沙发 / 桌椅 / 其他店员虚化走过,随机点缀 2–3 个增加景深。
+
+详细元素、wan3 工程要点、物料收集流程分别见 `references/elements.md`、`references/wan3-workflow.md`、`references/asset-collection.md`;单段脚本骨架见 `assets/script-template.md`。
+
+## 目录结构
+
+```
+beauty-talk-science-video-script/
+├── SKILL.md                  # 主流程与硬约束(11 步)
+├── README.md                 # 本文件(快速上手)
+├── references/
+│   ├── elements.md           # 全部可参数化元素与可选项
+│   ├── wan3-workflow.md       # 百炼 wan3 端点/鉴权/参考映射/编导分镜 prompt 范式
+│   └── asset-collection.md   # 固定 4 项素材 + 自动生成物料确认 + 物料登记
+├── assets/
+│   ├── script-template.md     # 单段结构化脚本骨架(交付物模板)
+│   └── brand/README.md        # 固定品牌素材包说明
+└── scripts/
+    ├── generate_video.py      # 解析素材 → 建任务 → 轮询 → 下载
+    ├── config.json            # region/workspace_id/model/分辨率/比例/品牌 URL(密钥走 .env)
+    └── .env.example           # API Key 模板(复制为 .env 填入真实 key)
+```

+ 149 - 0
SKILL.md

@@ -0,0 +1,149 @@
+---
+name: beauty-talk-science-video-script
+description: 生成「美业口播科普视频脚本」并直出视频的通用技能。面向阿里云百炼 wan3(万相3.0)文生/参考生视频,把选题/人设/画幅/时长/场景/服装/造型/画质/穿插/字幕/配乐等元素参数化;人物五视角图、制服细节图、立体LOGO、音色四项固定素材来自技能素材包(assets/brand/)或公网URL(config.brand_assets)并锁定作生成输入;据其生成人物完整形象照、门店内景(含LOGO)、插画供用户确认,确认后的物料作为参考图提交 wan3;口播转为口语化;整段视频一个片段、≤30秒;确认后调用 scripts/generate_video.py 提交 wan3 异步任务、轮询、下载本地;修改即整段重发(不支持二次创作)。
+agent_created: true
+---
+
+# 美业口播科普视频脚本生成技能(百炼 wan3 直出版)
+
+## Overview
+
+面向**阿里云百炼 · 万相 3.0(wan3.0-video)**,把"美业口播科普短视频"从零散需求沉淀为一份**带固定素材、可直接调用 wan3 生成视频**的结构化脚本。核心约束来自用户硬性要求:
+
+1. **人物**必须用指定的(素材包 `assets/brand/character_5view.*` 或公网 URL `config.brand_assets.character_5view.url`)人物五视角图(固定锁定)。
+2. **制服**必须参考指定的(素材包或 URL)制服细节图(可换款式/颜色,**胸牌绝对不变**)。
+3. **门店内景**前台或某场景必须有指定的(素材包或 URL)怡呵美立体 LOGO(合成进参考图)。
+4. **音色**必须用指定的(素材包或 URL)音色文件作 reference_audio。
+5. 口播文案由用户内容**转换为口语化适合口播**的文案。
+6. 整段视频**一个片段、≤30 秒**;超 30 秒则反馈用户精简、循环直到满足。
+7. 确认后调用 **百炼 wan3 API** 发起生成、轮询完成、存储本地、给用户确认。
+8. **不支持二次创作**:每次修改都重新组装完整脚本重发 wan3(不用编辑/延长模式)。
+
+## 跨团队复用说明
+
+- 技能**品牌/人设/视频工具三层解耦**:可变项参数化在 `references/elements.md`;固定品牌素材放在 `assets/brand/`(本地兜底)或 `scripts/config.json` 的 `brand_assets` 段(公网 URL,推荐);视频工具锁定百炼 wan3,工程要点全在 `references/wan3-workflow.md`。
+- **分发**:本技能为「暨北内部 - 朵朵」专用锁定版,OSS 素材 URL、百炼 base_url、workspace_id 均已固定在 `scripts/config.json`;其他同事把 git 仓库 clone 到 `~/.workbuddy/skills/beauty-talk-science-video-duoduo/`(个人级)或项目 `.workbuddy/skills/`(团队级),**复制 `.env.example` 为 `.env` 填入自己的 `DASHSCOPE_API_KEY`** 即可启用,无需改任何配置。详见 `docs/暨北内部-朵朵口播视频专用技能.md`。
+
+## 凭证准备(首次运行前必做)
+
+百炼 wan3 视频生成需要 **北京地域的 DashScope / 百炼 API Key**(以 `sk-` 开头)。你之前看到的 `sk-xxx` 只是占位符,必须替换成在控制台创建的**真实 Key**。操作如下:
+
+1. **获取真实 Key**:登录阿里云百炼控制台([Model Studio](https://bailian.console.aliyun.com) 或 [DashScope 控制台](https://dashscope.console.aliyun.com))→ 右上角头像 → **API Key 管理 / API-KEY** → 切换地域到 **北京(cn-beijing)** → **创建 API Key**(权限选"全部",归属工作空间默认)→ 复制 `sk-` 开头的串(只显示一次,立即保存)。
+   - ⚠️ 每个地域的 Key 独立、不能跨地域使用;你的工作空间在 `cn-beijing`,**必须创建北京地域的 Key**,否则调用直接失败。
+2. **填入 Key(脚本自动识别,二选一)**:
+   - 方式 A(单次,推荐调试):运行生成脚本的命令前加前缀,例如 `DASHSCOPE_API_KEY=sk-真实key python scripts/generate_video.py ...`(仅本次进程生效,适合 WorkBuddy 终端环境)。
+   - 方式 B(持久):复制 `scripts/.env.example` 为 `scripts/.env`,写入一行 `DASHSCOPE_API_KEY=sk-真实key`;脚本优先读环境变量、其次读 `.env`。
+   - ⚠️ `.env` 含密钥,**严禁提交 git 或随技能 zip 分发**;重新打包技能前请删除本地 `.env`。
+3. **确认地域一致**:`config.json` 的 `region=cn-beijing` 与 Key 地域必须一致,`workspace_id=gxuwdo0w0g13zbax` 已填好。
+
+## 何时使用
+
+- "帮我做一条美业口播视频(给 wan3/百炼)" / "出个护肤科普短视频脚本并生成"
+- 用户上传/指定人物五视角图、制服细节图、LOGO、音色,或要求生成可直出的视频脚本与物料
+
+## 资源引用
+
+- `references/elements.md` — 全部可参数化元素与可选项(含门店风格/插画风格/整体色调)。
+- `references/wan3-workflow.md` — 百炼 wan3 端点/鉴权/参考映射/单段 prompt 范式/LOGO 合成/不二次创作。
+- `references/asset-collection.md` — 固定 4 项素材包清单 + 自动生成门店3/插画2确认 + LOGO 合成 + 物料登记 + wan3 映射。
+- `assets/script-template.md` — 单段结构化 Markdown 脚本骨架(含物料清单与 wan3 请求段),填充后即为交付物。
+- `scripts/generate_video.py` — 解析素材(公网URL直传 / 本地图base64直传)→建任务→轮询→下载本地。
+- `scripts/config.json` — region / workspace_id / model / resolution / ratio / output_dir(密钥走环境变量)。
+
+## 执行流程
+
+### Step 1 — 收集基础输入(提示词优先,缺失交互补全)
+
+1. 解析用户提示词,提取已指定元素:选题/口播素材、画幅、平台、人设、目标人群、场景、机位、运镜、造型、画质、穿插类型、字幕、配乐、情绪、品牌露出、门店/插画/色调风格、自带素材包路径。
+2. 对照 `references/elements.md`,将**未指定**的基础元素用一次交互式问答(AskUserQuestion,批量提问,每题给可选项+默认标注)补全;具体值不在可选项内时以用户值为准。
+
+### Step 2 — 文字版风格问卷(流程最前端)
+
+生成任何图之前,用一次交互式问答询问用户对以下**元素风格**的文字偏好(选项见 `references/elements.md`):
+- 门店/场景风格(元素 22)|插画风格(元素 23)|整体色调(元素 24)|画质质感(元素 15)|情绪基调(元素 20)
+
+- 用户逐条给出 → 后续按这些风格自动生成物料图。
+- 用户答"无特别要求/你定" → 进入**自动模式**,按默认风格生成示例图,让用户在看图时再挑(见 Step 4)。
+
+### Step 3 — 锁定固定品牌素材(URL 优先,本地文件兜底,校验存在)
+
+按 `references/asset-collection.md` 第一节,逐项解析并校验 4 个固定素材(**它们在本流程中是"生成输入",用于生成最终确认物料,默认不直接提交 wan3**):
+- 每项优先读 `scripts/config.json` 的 `brand_assets.<key>.url`(公网 URL,调用 wan3 时固定素材可直接透传);若留空则回退读取 `assets/brand/` 本地文件。
+- 人物五视角(`character_5view`)、制服细节(`uniform_detail`)、立体 LOGO(`logo_3d`)、音色(`voice_ref`,≤15s)。
+- **每项都必须有来源(URL 或本地文件),二者皆无 → 主动提示用户填 URL 或放文件,不进入后续生成**。
+- 锁定后:人物五视角 + 制服细节用于生成「人物完整形象照」、LOGO 用于生成「门店内景照片」、音色直接作 Audio 1;胸牌样式在锁定时即标注"不可变更"。
+
+### Step 4 — 生成最终确认物料(人物形象照 + 门店内景 + 插画)并确认
+
+按 `references/asset-collection.md` 第二节,用图像生成工具基于锁定素材生成并展示,请用户确认后才作为 wan3 参考图:
+1. **人物完整形象照 — 1 张(可生成 2–3 张供选)**:以 `character_5view` 为人物参考、`uniform_detail` 为制服参考,合成「人物身穿制服的完整形象照」;胸牌样式与 `uniform_detail` 完全一致、不可变更。→ 确认后作为 **Image 1**。
+2. **门店内景照片(含怡呵美 LOGO)— 3 张位置供选**:以 `logo_3d` 为 LOGO 参考生成门店内景(位置1 面诊桌正对面 / 位置2 前台侧含 LOGO / 位置3 产品护理区),确保前台出现立体 LOGO。→ 用户确认采用哪张作为主场景,记为 `门店_内景_采用.jpg`,作为 **Image 2**。
+3. **内容插入插画参考图 — 2 张**(抽象可视化风格启发,无真人皮肤/血液/文字)→ **Image 3 / Image 4**。
+
+展示后请用户**逐类挑选/确认**;若用户**未做任何选择** → 系统**自动随机指定**一组(记录"已自动随机指定")继续。确认后的物料登记进脚本「物料清单」。
+
+### Step 5 — 处理口播文案(转口语化 + 30 秒硬卡)
+
+- **用户自带内容/口播** → 转换为口语化、适合口播的文案(自然亲和、带 `/` `//` 停顿符号、科普准确)。
+- **用户只给选题/知识点** → 技能生成口语化口播文案。
+- **30 秒硬卡循环**:按"30 秒 ≈ 120–150 字"估算字数;若 >150 字 → **反馈用户精简,等用户回精简版后重新估算**,循环直到 ≤150 字(对应 ≤30 秒)才继续。绝不为凑时长拆分片段。
+
+### Step 6 — 确认口播文案(用户确认后才进下一步)
+
+- 把 Step 5 产出的口语化口播文案(含字数校验)**单独呈现**给用户,请用户确认或修订。
+- 用户未明确确认(或提出修改)→ 回到 Step 5 重做,循环直到用户确认。
+- 此步确保「口播文案已确定」,是 Step 7 插画插入点确认的两大前置之一(另一前置是 Step 4 已确认插画)。
+
+### Step 7 — 确定插画插入点(插画 + 口播都确认后)
+
+- **前置**:Step 4 已确认插画(Image 3/4)、Step 6 已确认口播文案。两者缺一不进本步。
+- **请用户确定:插画(抽象可视化)从口播文案的哪一句话开始融入画面作为起始点。**
+  1. 把已确认的口播文案按停顿(`/` 短停、`//` 长停)切分为带编号的分句,逐句列出(① / ② / ③ …)供用户点选。
+  2. 询问用户:插画从哪一句开始?(若有多张插画 Image 3 / Image 4,可一并确认各自对应哪一句;默认从同一句起连续融入)。
+  3. 用户选定第 N 句 → 记录「插画起始句:第 N 句「原文」」写入脚本「插画插入点」字段(见 `assets/script-template.md` 第四节补)。
+  4. 用户无偏好 → 系统按语义建议一个起始句(通常选「讲到核心知识点那句」),标注"已自动建议"并请用户最终确认,**不默认静默落定**。
+- 该插入点直接决定 Step 8 单段 Prompt 中"画面融入插画"的时机,必须显式写进 prompt。
+
+### Step 8 — 组装单段 30 秒脚本(编导分镜级)
+
+用 `assets/script-template.md` 填充,产出**单份结构化 Markdown**:
+一、角色定义 → 二、固定品牌素材 → 三、自动生成素材 → 四、口播文案(口语化,字数校验)→ **四-补、插画插入点** → 五、单段视频 Prompt(整段 30 秒,**编导分镜版**,含 Image 1–5 / Audio 1 引用)→ 六、保留分析 → 七、硬性禁令 → 八、AI 口令(wan3 请求:命令 + JSON)。
+- 第五节单段 Prompt **必须按 `wan3-workflow.md` 第四节「编导分镜版」范式写**,像专业编导一样覆盖四块:
+  1. **人物行为动线**(元素 25):30 秒单段内 **≤2 个动作切换**,且方向不反向("走动→落座"则落座后不再起身;"坐姿→起身走动"则走动后不再落座);**口播时不设计"整理产品"等手部摆弄动作**,手部只用自然手势 / 点头;全程在门店场景里与场景互动,**绝不全程正对镜头站桩**。
+  2. **运镜组合**(元素 12):每条约 2–3 种手法按时间轴穿插(跟随 / 推近 / 拉远 / 横移 / 手持微晃),随机组合、不全程单一机位。
+  3. **插画展示方式**(元素 26):在「插画插入点」处触发,随机选用全屏铺盖 / 圆形画中画 / 顶部或底部条状画中画 / 侧边 PiP,**同一视频多次出现可轮换方式,不固化一种**。
+  4. **门店丰富元素**(元素 27):在门店场景里随机点缀 2–3 个道具 / 人物(前台 / 美容床 / 沙发 / 桌椅 / 其他店员虚化走过),增加景深与真实感。
+- 口播全文直接写进 prompt 作对白;在「插画插入点」指定句处明确写"讲到[第 N 句:原文]时,画面以[某展示方式]融入 Image 3 / Image 4 风格的抽象可视化";音色用 Audio 1 引用。
+- 引用的是**确认后的生成物料**:Image 1 = 人物完整形象照、Image 2 = 门店内景照片(含 LOGO)、Image 3/4 = 插画;LOGO 已在 Step 4 生成门店内景时落位,无需单独合成。
+
+### Step 9 — 逐步确认后交付(贴合"逐步确认"习惯)
+
+1. 呈现「已确定元素清单」+「口语化口播文案(含字数校验)」+「插画插入点:第 N 句」+「固定素材(URL/本地,生成输入)」+「生成并确认的最终物料(人物完整形象照 / 门店内景照片 / 插画,含自动随机指定的项)」+「单段 Prompt / wan3 请求」。请用户确认或修正。
+2. 用户确认后,将完整脚本写入工作区(如 `美业口播科普视频脚本_[主题].md`)并 present;参考物料图一并随交付提供。
+3. 确认无误后再进入 Step 10 实际调用 API(避免浪费生成额度)。
+
+### Step 10 — 调用百炼 wan3 生成视频 + 下载 + 确认
+
+1. 确保 `DASHSCOPE_API_KEY` 环境变量(或同目录 `.env`)已设置;`scripts/config.json` 的 workspace_id / base_url / `brand_assets` URL 为固定预填(暨北内部朵朵专用),无需改动。
+2. 执行 `scripts/generate_video.py`(参数见脚本模板第八节):提交**确认后的生成物料**(人物完整形象照 / 门店内景照片 / 插画,本地图编码 base64 直传;音色 voice_ref 按 URL 直传或本地 base64 直传)→ 建任务 → 轮询 → 下载到 `output_dir`。
+3. 捕获脚本 stdout 的 `VIDEO_PATH=...`,把生成的视频 present 给用户确认。
+4. 若生成失败/不满意 → 回到 Step 8 修改脚本,整段重发(见 Step 11)。
+
+### Step 11 — 修改即整段重生成(不支持二次创作)
+
+- 任何元素变更(口播、服装颜色、场景、插画风格、**插画插入点**等)→ **重新组装完整脚本(Step 8)→ 重新确认(Step 9)→ 重新调用 wan3(Step 10)**。
+- **严禁使用 wan3 的视频编辑/延长模式**(对应第 8 条)。每次都是一条全新的整段生成。
+
+## 关键约束(贯穿全程)
+
+- **固定 4 项永远锁定(作生成输入)**:人物五视角/制服细节/LOGO/音色来自素材包(`assets/brand/`)或公网 URL(`config.brand_assets`),不可被自动生成覆盖;制服胸牌样式绝对不可变。
+- **提交的是确认后的生成物料**:wan3 实际接收 Image 1=人物完整形象照、Image 2=门店内景照片(含 LOGO)、Image 3/4=插画、Audio 1=音色;原始 4 项仅用于生成这些物料,不直接提交。
+- **风格先确认后出图**:发起任务先文字版问风格,再生成「人物完整形象照 + 门店内景(含 LOGO)+ 插画」示例图供确认。
+- **单片段 ≤30 秒**:口播超 150 字必须反馈精简、循环直到满足;不拆分片段。
+- **LOGO 必现**:在生成门店内景照片时以 `logo_3d` 为参考落位(Image 2),确保成片前台有怡呵美立体 LOGO。
+- **原生音视频**:口播写进 prompt 作对白,音色作 reference_audio,wan3 一次性生成画面+对白+口型+环境音。
+- **插画插入点确认**:插画与口播文案都确认后,必须请用户指定插画从口播哪一句开始融入,再组装 prompt(见 Step 7);不静默默认。
+- **编导分镜(不站桩)**:单段 Prompt 必须像专业编导覆盖四块——人物行为动线(按内容长短设计走动/坐/起/落座,不全程正对镜头)、运镜组合(2–3 种随机穿插)、插画展示方式(全屏/圆形PiP/条状PiP/侧边PiP 随机混用不固化)、门店丰富元素(前台/美容床/沙发/其他人物虚化走过随机点缀);详见 `wan3-workflow.md` 第四节与 `elements.md` 元素 12/25/26/27。
+- **口型对齐**由 wan3 原生完成,脚本只保证口播文案与停顿完整。
+- **硬性禁令**优先级最高,必须写入脚本第七节,口播文字绝不转化为屏幕文字(LOGO 视觉露出除外)。
+- **真实质感**:避免卡通化、塑料皮肤、夸张嘴型、场景跳变、AI 痕迹过重。

+ 14 - 0
assets/brand/README.md

@@ -0,0 +1,14 @@
+# 固定品牌素材包(brand assets)
+
+把以下 4 个固定素材放入本目录,技能每次运行会**直接读取并锁定**(不会自动生成、不会随机替换):
+
+| 文件名(可改名,改名后在提示词/配置声明) | 作用 | wan3 角色 | 硬约束 |
+|---|---|---|---|
+| `character_5view.*`(png/jpg) | 人物五视角图 | `reference_image` = Image 1 | 全片同一人,脸/发型/年龄感不变 |
+| `uniform_detail.*` | 制服细节图 | `reference_image` = Image 2 | 可换款式/颜色;**胸牌样式必须完全一致、绝对不可变** |
+| `logo_3d.*` | 怡呵美立体 LOGO 源文件 | 合成进门店内景参考图(Image 2) | 必须出现在门店前台/某场景墙面 |
+| `voice_ref.*`(mp3/wav,≤15s) | 指定音色 | `reference_audio` = Audio 1 | 作为口播音色参考;超 15s 先裁剪一段 |
+
+跨团队:替换这 4 个文件即可复用技能,无需改流程。
+
+> 注意:技能启动时会校验这 4 个文件是否存在;缺失任一项会提示你补充,不会进入后续生成。

+ 153 - 0
assets/script-template.md

@@ -0,0 +1,153 @@
+# 美业口播科普视频脚本(单段 · 百炼 wan3):【主题】
+
+> 本模板由 `beauty-talk-science-video-script` 技能填充。下方所有 `[ ]` 占位项按用户确定的元素与 wan3 工作流生成。整段视频**一个片段、≤30 秒**,不支持二次创作(每次修改整段重发 wan3)。
+> 关键链路:原始固定素材(人物五视角图/制服细节图/LOGO/音色)是**生成输入**;最终提交 wan3 的是**经用户确认的生成物料**(人物完整形象照 / 门店内景照片 / 插画 / 音色)。
+
+---
+
+## 一、角色定义(Subject)
+
+- **人设 / 身份**:[皮肤知识科普博主 / 医美咨询师 / …]
+- **面部形象**:由 `character_5view.*`(固定素材)生成,全片同一人、不变脸。
+- **服装**:由 `uniform_detail.*`(固定素材)生成,可换款式/颜色;**胸牌样式必须完全一致、不可变更**。
+- **造型**:[深栗色半扎长发 + 斜刘海 / 与人物五视角图一致]
+- **音色**:`voice_ref.*`(作 Audio 1 音色参考,wan3 原生生成对白并对口型)
+
+---
+
+## 二、固定品牌素材(生成输入,素材包/URL 锁定,不可覆盖)
+
+> 以下 4 项用于**生成**第三节的最终物料,默认不直接提交 wan3(voice_ref 作音色直接提交)。
+
+- `character_5view.*`(URL 或本地)→ 生成「人物完整形象照」的人物参考
+- `uniform_detail.*`(URL 或本地)→ 生成「人物完整形象照」的制服参考(胸牌锁死)
+- `logo_3d.*`(URL 或本地)→ 生成「门店内景照片」的 LOGO 落位参考
+- `voice_ref.*`(URL 或本地)→ Audio 1(直接提交,≤15s)
+
+---
+
+## 三、生成并确认的最终物料(用户确认后才提交)
+
+- **人物完整形象照(Image 1)**:由 character_5view + uniform_detail 生成,`人物_完整形象照.jpg`(胸牌与 uniform_detail 一致、不可变更)。
+  - 确认状态:[用户挑选 / 已自动随机指定:人物_形象_X]
+- **门店内景照片(Image 2,含怡呵美 LOGO)**:由 logo_3d 生成含 LOGO,`门店_内景_采用.jpg`(确认采用的位置)。
+  - 候选:`门店_内景_1.jpg`(面诊桌正对面)/ `_2.jpg`(前台侧含 LOGO)/ `_3.jpg`(产品/护理区)
+  - 确认状态:[用户挑选 / 已自动随机指定:门店_内景_X]
+- **插画参考图(Image 3 / Image 4,抽象可视化风格启发)**:`插画_参考1.jpg` / `插画_参考2.jpg`,无真人皮肤/血液/文字。
+  - 确认状态:[用户挑选 / 已自动随机指定:插画_参考_X]
+
+---
+
+## 四、口播文案(口语化,≤150 字 / 30 秒)
+
+> 由用户内容转换而来,自然亲和、适合口播;`/` 短停、`//` 长停不读出。
+
+[口语化口播全文:……(示例)"很多姐妹分不清泛红和红血丝 / 其实它俩真不是一回事 // 泛红是一过性的、受刺激就红 / 红血丝是毛细血管扩张、常年挂在那 // 搞清楚了,护肤才不踩坑。"]
+
+字数校验:[N] 字 ≤150 → 满足 30 秒约束。
+
+---
+
+## 四-补、插画插入点(用户确认,提交前必填)
+
+> 在口播文案(第四节)与插画(第三节 Image 3/4)都确认后,由用户指定插画从哪一句开始融入画面作为起始点(见技能 Step 7)。
+
+- **口播分句(按停顿切分,带编号)**:
+  ① [句1] ② [句2] ③ [句3] ④ [句4] …(以用户确认稿为准逐句拆出)
+- **插画起始句**:第 [N] 句「[原文]」——Image 3 / Image 4 从该句起连续融入画面;若多图各自对应不同句,逐图标注(如 Image 3→句②、Image 4→句③)。
+- 确认状态:[用户点选 / 已自动建议:第 N 句]
+
+---
+
+## 五、单段视频 Prompt(整段 30 秒 · 编导分镜版,含参考引用)
+
+> 一段连续 prompt 描述整段画面(不拆分请求),wan3 原生生成画面 + 对白 + 环境音。引用的 Image 1/2/3/4 即第三节**确认后的物料**。写这条 prompt 要像专业编导:**人物必须在门店场景里"活"起来,不站桩;运镜/插画展示/门店丰富元素按下面四块随机组合设计**(对应 `elements.md` 元素 25/26/27/12)。
+
+```
+Image 1 中的女性(即这张已确认的人物完整形象照:与图中面孔、[深栗色半扎长发 + 斜刘海]、身穿[米白]美容师制服完全一致;
+胸牌样式与确认稿一致、不可更改),
+身处 Image 2 的怡呵美门店内(墙面有怡呵美立体 LOGO,背景虚化;
+店内可见[门店丰富元素:前台 / 美容床 / 沙发 / 产品陈列架,可选其他店员从画面边缘虚化走过])。
+
+[人物行为动线 · 按口播长短设计,全程与场景互动、不站桩]
+开场她[从走动中入画 / 端坐于面诊桌前]自然引入[主题];讲到中段[起身缓步走向产品架 / 从走动落座于沙发]边走边说;
+结尾[回到中近景、手势收束]。说话间伴随[整理产品 / 手势比划 / 轻微点头]等真实肢体动作。
+
+[运镜组合 · 随机穿插 2–3 种]
+开场[中近景固定 / 极轻微横摇]→ 人物走动时[跟随拍摄]→ 讲到核心点时[缓慢推近]→ 结尾[缓慢拉远]收束;
+整体[手持微晃]保留真实手机拍摄质感。
+
+她自然亲和地讲解[主题]:
+"[第四节口语化口播全文]"
+
+[插画展示方式 · 随机使用,不固化一种](在[插画插入点:第 N 句「原文」]处触发,对应 Image 3 / Image 4)
+方式示例:[全屏铺盖插画] / [画面右侧圆形画中画嵌入插画] / [顶部条状画中画展示插画] / [侧边圆角区域 PiP] /
+[人物画中画式全屏:插画铺满整屏、口播人物以圆形或正方形 PiP 出现在画面某区域];
+同一视频多次出现插画时可轮换不同方式。
+(插画为抽象皮肤结构可视化:透明表皮层、缓慢流动光点、柔和结构变化,无真人皮肤、无血液、无文字)
+
+原生生成清晰女声普通话对白(音色参考 Audio 1)、轻微环境音、无背景音乐。
+绝对禁止:字幕/任何文字/卡通化/塑料皮肤/变脸/服装漂移/场景跳变/其他清晰正脸人物抢镜。
+```
+
+---
+
+## 六、保留分析(Retention,一致性)
+
+- **人物**:与 Image 1(确认的人物完整形象照)同脸 / 同发型 / 同年龄感 / 同制服(胸牌尤甚),全片不变。
+- **场景**:门店前台(含怡呵美 LOGO)与 Image 2 一致,光线方向一致。
+- **音色**:同一 Audio 1 音色。
+- **插画风格**:与 Image 3 / Image 4 一致(抽象可视化)。
+
+---
+
+## 七、硬性禁令(Hard Bans,优先级最高)
+
+- 绝对禁止字幕、标题、Logo、品牌字样、任何可读或不可读文字(用户指定 LOGO 视觉露出除外)。
+- 绝对禁止把口播文字转化为屏幕文字;对白只通过人物声音表达。
+- 禁止人物变脸 / 换人 / 服装漂移(胸牌尤甚)/ 场景跳变 / 卡通化 / 塑料皮肤 / 夸张嘴型。
+- 抽象画面禁止真实血液、伤口、恐怖皮肤、医学 UI、文字、箭头、图例。
+- 人物皮肤、脸部、颈部、手臂与服装表面禁止任何 Logo、文字、字母、数字、纹身字样、标签、水印(胸牌为指定样式,不含额外文字)。
+- 全片真实拍摄质感,不生成失真或 AI 痕迹过重画面。
+
+---
+
+## 八、AI 口令(wan3 请求,含参考物料引用)
+
+> 组装为 `scripts/generate_video.py` 的实际调用参数。提交的是**第三节确认后的物料**。
+
+**命令**:
+```bash
+export DASHSCOPE_API_KEY="sk-xxx"
+python scripts/generate_video.py \
+  --config scripts/config.json \
+  --prompt "[第五节整段 prompt]" \
+  --media \
+    人物_完整形象照.jpg:reference_image \
+    门店_内景_采用.jpg:reference_image \
+    插画_参考1.jpg:reference_image \
+    插画_参考2.jpg:reference_image \
+    "https://cdn.x/voice_ref.mp3:reference_audio" \
+  --duration 30 --ratio 9:16 --resolution 720P \
+  --output 成片_[主题].mp4
+```
+
+**等价于请求体(JSON)**:
+```json
+{
+  "model": "wan3.0-video",
+  "input": {
+    "prompt": "[第五节整段 prompt]",
+    "media": [
+      {"type": "reference_image", "url": "<人物_完整形象照 上传URL>"},
+      {"type": "reference_image", "url": "<门店_内景_采用 上传URL>"},
+      {"type": "reference_image", "url": "<插画_参考1 上传URL>"},
+      {"type": "reference_image", "url": "<插画_参考2 上传URL>"},
+      {"type": "reference_audio", "url": "<voice_ref URL 或 上传URL>"}
+    ]
+  },
+  "parameters": {"resolution": "720P", "ratio": "9:16", "duration": 30, "audio": true, "prompt_extend": false, "watermark": false}
+}
+```
+
+> 修改任何元素都**整段重发本请求**(不用 wan3 编辑/延长),见技能第 9 步。

+ 158 - 0
docs/暨北内部-朵朵口播视频专用技能.md

@@ -0,0 +1,158 @@
+# 暨北内部 - 朵朵口播视频专用技能
+
+> 本技能是「暨北内部 - 朵朵」品牌口播短视频的**专用锁定版**,基于 WorkBuddy 的 `beauty-talk-science-video-script` 技能收口而成。
+> 它把人物、制服、门店 LOGO、朵朵音色、百炼工作空间与模型接口**全部固定**,使用者**只需填入自己的 API Key** 即可一键生成可直接用于抖音 / 视频号的美业科普口播成片。
+>
+> 本质:把一条「美业口播科普短视频」从零散需求,沉淀为一份**带固定品牌素材、由 AI 像专业编导一样分镜、并直出阿里云百炼 wan3(万相 3.0)视频**的结构化脚本与成片。
+
+---
+
+## 一、已经固定的元素与物料(使用者不可改)
+
+以下内容已写死在 `scripts/config.json` 与技能流程中,使用者无需也不会去改。
+
+### 1. 固定品牌素材(4 项,公网 OSS URL 已预填)
+| 素材 | 含义 | 固定 URL |
+| --- | --- | --- |
+| 人物五视角图 | 朵朵固定形象(全片不变脸) | `https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/duoduo-demo.jpg` |
+| 制服细节图 | 美容师制服(胸牌样式**绝对不可变**,仅可换款式/颜色) | `https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/zhifu-demo.png` |
+| 怡呵美立体 LOGO | 合成进门店内景,前台墙面**必现** | `https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/yihemei-logo.jpeg` |
+| 朵朵音色 | 口播对白音色(`reference_audio`,Audio 1 引用) | `https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/voice-demo.mp3` |
+
+### 2. 固定工程配置(百炼 wan3)
+| 配置 | 固定值 |
+| --- | --- |
+| 工作空间 workspace_id | `gxuwdo0w0g13zbax` |
+| 模型接口 base_url | `https://llm-gxuwdo0w0g13zbax.cn-beijing.maas.aliyuncs.com` |
+| 地域 region | `cn-beijing` |
+| 模型 model | `wan3.0-video`(万相 3.0 视频) |
+| 画幅 ratio | `9:16`(竖屏) |
+| 分辨率 resolution | `720P` |
+
+### 3. 固定编导规则(确保真实感、不 AI 感)
+- **单段时长**:整段一个片段、**≤30 秒**(超字数自动反馈精简,绝不拆片段)。
+- **人物动线**:30 秒内动作**≤2 个、方向不反向**——「走动→落座」则落座后不再起身;「坐姿→起身走动」则走动后不再落座;**口播中不设计整理产品等手部摆弄动作**,手部只用自然手势 / 点头。
+- **运镜组合**:2–3 种随机穿插(跟随 / 推近 / 拉远 / 横移 / 手持微晃)。
+- **插画展示方式**:全屏铺盖 / 圆形画中画 / 顶部或底部条状画中画 / 侧边画中画 / 人物画中画式全屏,随机混用、不固化一种。
+- **门店丰富元素**:前台 / 美容床 / 沙发 / 桌椅 / 其他店员虚化走过,随机点缀 2–3 个增加景深。
+- **插画插入点**:插画与口播文案都确认后,必须指定插画从口播**哪一句**开始融入(见第二节「用户可指定」)。
+- **硬性禁令**:无字幕 / 无文字 / 无卡通化 / 无塑料皮肤 / 无变脸 / 无服装漂移 / 无场景跳变。
+
+### 4. 固定的生产原则
+- **不支持二次创作**:任何元素修改(口播、服装、场景、插画、运镜)都重新组装完整脚本、整段重发 wan3,绝不使用视频编辑 / 延长模式。
+- **逐步确认**:物料、口播、插画插入点、最终分镜方案都需使用者确认后再提交生成,避免浪费生成额度。
+
+---
+
+## 二、用户可指定配置的选择(使用者能填 / 选的)
+
+除「固定配置」外,使用者只需提供以下内容,其余由技能自动编排:
+
+| 可指定项 | 说明 | 是否必填 | 备注 |
+| --- | --- | --- | --- |
+| **API Key** | 自己的百炼 / DashScope Key(`sk-` 开头) | ✅ 必填 | 写入 `.env`,不进 git |
+| **选题 / 知识点** | 这条视频讲什么(如「敏感肌能不能用功效型护肤品」) | ✅ 必填 | 触发即提供 |
+| **口播文案** | 自带底稿,或让技能生成 | 可选 | 自带则转口语化;不给则技能写 |
+| **风格偏好问卷** | 门店调性 / 插画风格 / 色调等 | 可选 | 无要求→系统自动生成物料 |
+| **插画插入点** | 插画从口播第几句开始融入 | 需确认 | 默认技能按语义建议,使用者最终拍板 |
+| **人物动线路径** | 走动→落座 / 坐→起身走动 | 可选 | 默认技能选,可指定 |
+| **插画展示方式偏好** | 5 种方式中的偏好 | 可选 | 默认随机混用,可指定 |
+| **门店丰富元素偏好** | 想要哪些道具 / 路人 | 可选 | 默认随机 2–3 个,可指定 |
+| **物料选材确认** | 门店内景 3 张选哪张 / 插画 2 张选哪张 / 人物确认 | 需确认 | 生成后逐步确认 |
+
+---
+
+## 三、使用方法(安装 + 使用)
+
+### 1. 安装(拿到 git 地址即可)
+```bash
+# 个人级(推荐):放进用户级 skills 目录
+git clone https://p-git-work.hzbeautybox.com/zhengqi/yhm-ai-video-duoduo.git \
+  ~/.workbuddy/skills/beauty-talk-science-video-duoduo
+
+# 或团队级:放进项目级 skills 目录(团队共享)
+git clone https://p-git-work.hzbeautybox.com/zhengqi/yhm-ai-video-duoduo.git \
+  <你的项目>/.workbuddy/skills/beauty-talk-science-video-duoduo
+```
+克隆后即启用,无需改任何配置。
+
+### 2. 配置自己的 Key(唯一一步)
+```bash
+cd ~/.workbuddy/skills/beauty-talk-science-video-duoduo/scripts
+cp .env.example .env
+# 编辑 .env,把 DASHSCOPE_API_KEY 改成你自己的 sk-... key
+```
+> ⚠️ `.env` 含你的密钥,**切勿提交 git**;本仓库已将其加入忽略。
+
+### 3. 触发使用
+对 WorkBuddy 说:
+> 「用美业口播科普视频脚本技能,做一条关于 *[你的选题]* 的口播视频」
+
+技能会按下方流程图走完整 11 步,并在每个确认点停下来等你拍板,最后把成片(MP4)交给你本地预览。
+
+### 4. 手动生成(可选)
+```bash
+python scripts/generate_video.py --help   # 查看参数
+```
+
+---
+
+## 四、生产视频流程图
+
+```mermaid
+flowchart TD
+    A[用户触发:用本技能做「选题」口播视频] --> B[Step1 文字风格问卷<br/>无要求则系统自动生成物料]
+    B --> C[Step2 锁定4项固定品牌素材<br/>朵朵人物 / 制服 / LOGO / 音色]
+    C --> D[Step3 生成确认物料<br/>人物形象照 / 门店内景含LOGO / 插画]
+    D --> E[Step4 用户确认物料选材]
+    E --> F[Step5 口播转口语化 + 30秒字数硬卡]
+    F --> G[Step6 用户确认口播文案]
+    G --> H[Step7 确定插画插入点<br/>指定从哪句开始融入]
+    H --> I[Step8 编导分镜级 Prompt 组装<br/>动线 + 运镜 + 插画展示 + 门店元素]
+    I --> J[Step9 逐步确认全部方案]
+    J --> K[Step10 调用百炼 wan3 生成<br/>建任务 → 轮询 → 下载]
+    K --> L[Step11 成片交付确认]
+    L --> M{满意?}
+    M -->|是| N[✅ 交付成片 MP4]
+    M -->|否| I
+```
+
+**流程要点**
+- **物料确认(Step4)**:系统先用固定素材生成「人物形象照 / 门店内景(含 LOGO)/ 插画」,你确认选材后才往下。
+- **口播 + 插画插入点(Step6–7)**:口播文案确认后,再确认插画从哪句开始融入。
+- **编导分镜(Step8)**:AI 像专业编导一样设计人物动线、运镜、插画展示、门店丰富元素,全部落在单段 Prompt 里。
+- **整段重发(Step11→Step8)**:不满意则整段重发,不做局部二次创作。
+
+---
+
+## 五、固定配置说明(config.json 已含)
+
+`scripts/config.json` 已直接写死以下固定值,使用者**不要改动**:
+
+```json
+{
+  "region": "cn-beijing",
+  "workspace_id": "gxuwdo0w0g13zbax",
+  "model": "wan3.0-video",
+  "resolution": "720P",
+  "ratio": "9:16",
+  "api_base": "https://llm-gxuwdo0w0g13zbax.cn-beijing.maas.aliyuncs.com",
+  "brand_assets": {
+    "character_5view": { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/duoduo-demo.jpg", "name": "朵朵" },
+    "uniform_detail":   { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/zhifu-demo.png" },
+    "logo_3d":          { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/yihemei-logo.jpeg" },
+    "voice_ref":        { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/voice-demo.mp3" }
+  }
+}
+```
+
+唯一需要你提供的是 `.env` 里的 `DASHSCOPE_API_KEY`。
+
+---
+
+## 六、注意事项
+
+1. **密钥安全**:`.env` 含个人 Key,已加入 `.gitignore`,切勿手动提交;重新打包技能前请删除本地 `.env`。
+2. **整段重发**:本技能不支持二次创作,任何修改都整段重生成(对应品牌硬需求)。
+3. **逐步确认**:每个确认点请认真看,避免浪费百炼生成额度。
+4. **画质**:成片为 9:16 竖屏 720P、单段 ≤30 秒,适合短视频平台直接发布。

+ 71 - 0
references/asset-collection.md

@@ -0,0 +1,71 @@
+# 素材收集、生成、确认与登记参考
+
+本文件定义技能在"用户发起口播视频任务"时如何**锁定固定品牌素材(生成输入)**、**生成最终确认物料并让用户确认**、**登记物料清单**,最终把确认后的物料映射为 wan3 的参考素材。目标:调用视频接口前,人物形象与场景风格全部锁定且经用户确认,成片一致、可直出。
+
+## 一、固定品牌素材(生成输入,永远锁定,不可被自动生成覆盖)
+
+以下 4 项是**生成输入**,由用户提前以「公网 URL(config.brand_assets,推荐)」或「本地文件(assets/brand/,兜底)」提供,技能每次运行直接读取并锁定:
+
+| 素材 | config 字段(url) | 本地兜底文件名 | 角色 | 硬约束 |
+|---|---|---|---|---|
+| 人物五视角图 | `brand_assets.character_5view.url` | `character_5view.*`(png/jpg) | 生成「人物完整形象照」的输入 | 全片同一人:脸型/五官/发型/年龄感一致 |
+| 制服细节图 | `brand_assets.uniform_detail.url` | `uniform_detail.*` | 生成「人物完整形象照」的输入 | 可换款式/颜色;**胸牌样式必须完全一致、绝对不可变更** |
+| 立体 LOGO 源文件 | `brand_assets.logo_3d.url` | `logo_3d.*` | 生成「门店内景照片」的输入(LOGO 落位) | 必须出现在门店前台或某场景墙面 |
+| 音色文件 | `brand_assets.voice_ref.url` | `voice_ref.*`(mp3/wav,单段 ≤15s) | `reference_audio` = Audio 1(直接提交) | 作为口播音色参考;超 15s 先裁剪一段代表音色 |
+
+- 这 4 项**默认不直接提交 wan3**——它们是用来生成「第二节最终确认物料」的输入;只有 `voice_ref` 作为音色直接提交。
+- 技能启动时**校验这 4 项**:每项要么 `config.brand_assets.<key>.url` 非空,要么 `assets/brand/` 存在对应本地文件;**两项皆无 → 主动提示用户(填 URL 或放文件),不进入后续生成**。
+- 跨团队复用:给团队「URL 列表」或「4 个文件」其一即可,无需改流程。
+
+## 二、生成最终确认物料(核心:先出图确认,再提交)
+
+固定 4 项之外/之上,按用户选题/知识点**生成以下最终物料**,展示给用户确认后,这些确认稿才作为 wan3 的 `reference_image` 提交:
+
+### 1. 人物完整形象照 — 1 张(可生成 2–3 张供选)
+- **来源**:以 `character_5view`(人物五官/发型/年龄感)为人物参考、以 `uniform_detail`(制服款式/颜色、胸牌样式)为服装参考,用图像生成能力**合成 1 张「人物身穿制服的完整形象照」**。
+- **硬约束**:胸牌样式与 `uniform_detail` 完全一致、不可变更;脸型/发型/年龄感与 `character_5view` 一致、不可变脸。
+- 文件名:`人物_完整形象照.jpg`(若多张候选:`人物_形象_1.jpg` …)。
+- 这是最终提交 wan3 的 **Image 1**(不再是原始五视角图本身)。
+
+### 2. 门店内景照片(含怡呵美 LOGO)— 3 张(多位置供选)
+- **来源**:以 `logo_3d` 作 LOGO 参考,生成门店内景,确保前台/墙面出现怡呵美立体 LOGO(单靠文字描述不可靠,必须靠 LOGO 参考落位)。
+- 位置 1:面诊桌正对面(主角主讲机位);位置 2:前台侧(LOGO 主展示);位置 3:产品陈列 / 护理区。
+- 文件名:`门店_内景_1.jpg` / `门店_内景_2.jpg` / `门店_内景_3.jpg`。
+- 用户确认采用哪张作为视频主场景 → 记为 `门店_内景_采用.jpg`,这是最终提交 wan3 的 **Image 2**。
+
+### 3. 内容插入插画参考图 — 2 张(抽象可视化风格启发)
+- 风格来自元素 25(插画风格);内容提炼自知识点(如"屏障受损示意""红血丝 vs 泛红对比")。
+- 约束:无真人皮肤 / 无血液 / 无伤口 / 无文字 / 无医学 UI。
+- 文件名:`插画_参考1.jpg` / `插画_参考2.jpg`。
+- 单段 30 秒视频内,插画以"抽象皮肤科普可视化"呈现(见元素 17),这两张图作**风格启发 / 参考图**,不单独生成插画视频段。提交为 **Image 3 / Image 4**。
+
+## 三、确认与自动随机指定
+
+- 展示:人物完整形象照(1–3 张)、门店内景(3 张)、插画(2 张),请用户**逐类挑选/确认**。
+- 用户**未做任何选择** → 系统**自动随机指定**一组(记录"已自动随机指定:人物_形象_X / 门店_内景_X / 插画_参考_X"),继续组装,不阻塞流程。
+- 固定 4 项不进入"随机",始终用用户提供的素材(作生成输入)。
+
+## 四、物料清单登记(写入脚本「物料清单」段)
+
+- 人物完整形象照:`人物_完整形象照.jpg`(由 character_5view + uniform_detail 生成、确认,Image 1)
+- 门店内景照片:`门店_内景_采用.jpg`(由 logo_3d 生成含 LOGO、确认,Image 2)
+- 插画参考图:`插画_参考1.jpg` / `插画_参考2.jpg`(自动生成,Image 3 / Image 4)
+- 音色文件:`voice_ref.*`(确认,Audio 1,≤15s)
+- 原始输入(不提交):`character_5view.*` / `uniform_detail.*` / `logo_3d.*`
+
+## 五、映射为 wan3 参考素材(供 generate_video.py)
+
+media 数组顺序 = prompt 中 Image/Audio 编号。**提交的是确认后的生成物料,不是原始 4 项文件本身**:
+
+```
+--media \
+  人物_完整形象照.jpg:reference_image \   # Image 1(由 character_5view + uniform_detail 生成、确认)
+  门店_内景_采用.jpg:reference_image \    # Image 2(由 logo_3d 生成含 LOGO、确认)
+  插画_参考1.jpg:reference_image \        # Image 3
+  插画_参考2.jpg:reference_image \        # Image 4
+  https://cdn.x/voice_ref.mp3:reference_audio   # Audio 1(config URL 透传,或 assets/brand 本地文件)
+```
+
+prompt 中相应使用 `Image 1`…`Image 4` / `Audio 1` 引用(详见 `wan3-workflow.md` 第四节)。
+
+> 注:若 wan3 对一致性要求极高、希望额外锚定人物基准,可把 `character_5view` 也作为附加 `reference_image` 传入(Image 5),但默认流程仅提交上述确认物料。

+ 166 - 0
references/elements.md

@@ -0,0 +1,166 @@
+# 可参数化元素与选项目录
+
+本目录汇总「美业口播科普视频脚本」所有可参数化元素。技能在执行时:
+1. 先从用户提示词中解析已指定的元素;
+2. 未指定的元素,按下方「可选项」用交互式问答补全(批量提问,避免逐个打断);
+3. 解析到的具体值若不在可选项内,以用户给定值为准(自定义)。
+
+每个元素的「默认」用于用户完全没有提及时自动采用。
+
+> **目标工具**:百炼 wan3(万相 3.0)。单条视频**一个片段、≤30 秒**,不支持二次创作(每次修改整段重发)。详见 `references/wan3-workflow.md`。
+
+---
+
+## 1. 视频画幅(Aspect Ratio)
+- 默认:9:16 竖屏
+- 可选项:9:16 竖屏(视频号 / 抖音 / 小红书 主流)|16:9 横屏|1:1 方形|4:5 竖方
+- 说明:wan3 `ratio` 参数支持 16:9 / 4:3 / 1:1 / 3:4 / 9:16 / adaptive。
+
+## 2. 视频时长(Duration,单段)
+- 默认:30 秒
+- 硬约束:**整段 ≤30 秒**(wan3 上限)。技能在口播文案阶段按"30 秒 ≈ 120–150 字"估算,超了**反馈用户精简、循环直到 ≤30 秒**才继续(见 SKILL.md 第 5 步)。
+- 可选项:15 秒 / 30 秒(不提供分片段;若内容过多请精简而非延长)
+
+## 3. 发布平台(Platform)
+- 默认:视频号
+- 可选项:视频号 / 抖音 / 小红书 / 通用·不限
+
+## 4. 人设 / 形象(Persona)
+- 默认:皮肤知识科普博主
+- 可选项:皮肤知识科普博主|医美咨询师|美容院主理人 / 老板娘|护肤达人 / 成分党|皮肤科医师(科普向,非诊疗)|自定义
+
+## 5. 目标人群(Target Audience)
+- 默认:女性问题皮肤群体
+- 可选项:女性问题皮肤群体|敏感肌人群|抗初老女性(25–35 岁)|护肤新手 / 学生党|医美意向用户|自定义
+
+## 6. 视频主题 / 选题(Topic)
+- 默认:无(必须由用户提供,或仅给知识点由技能生成)
+- 说明:如「泛红和红血丝是一回事吗?」「刷酸后爆皮怎么办」。
+
+## 7. 口播文案(Oral Script)
+- 默认:技能生成(当用户只给选题/知识点时)
+- 可选项:
+  - 用户自带完整口播(含 / 短停、// 长停 符号)
+  - 技能生成(把用户给的内容**转换为口语化、适合口播**的文案;自然亲和、带停顿符号、科普准确)
+- 停顿符号约定(不读出):`/` 短停(换口气) `//` 长停(段落 / 情绪切换)
+- 字数硬约束:≤150 字(对应 30 秒)。
+
+## 8. 角色面部素材(Character Reference Image)【固定素材包】
+- 默认:素材包 `assets/brand/character_5view.*`(用户指定五视角图,**固定锁定**)
+- 说明:作为 wan3 `reference_image` = Image 1。全片同一人,脸/发型/年龄感不变。用户须把文件放入素材包;缺失则提示补充,不自动生成。
+
+## 9. 音色素材(Voice Reference)【固定素材包】
+- 默认:素材包 `assets/brand/voice_ref.*`(用户指定音色,**固定锁定**,作 reference_audio)
+- 硬约束:单段 ≤15s;超长先裁剪一段代表音色。作为口播音色参考,wan3 原生生成对白并对口型。
+
+## 10. 场景(Scene)
+- 默认:美容店前台 / 面诊房间(含怡呵美 LOGO)
+- 可选项:美容店前台(背景含品牌 LOGO 立体标识,虚化)|美容店面诊房间|居家梳妆台|专业护肤工作室|医美机构大厅|自定义
+- 说明:门店外观由自动生成示例图确认(见 asset-collection.md),LOGO 由 `logo_3d` 合成进选定门店图。
+
+## 11. 机位(Camera Position)
+- 默认:主角正对面、隔桌相对
+- 可选项:正对面、隔桌相对|侧面 45°|过肩|微俯 / 微仰|自定义
+
+## 12. 运镜(Camera Movement)
+- 默认:跟随拍摄 + 极轻微横摇
+- 可选项:固定机位|极轻微横摇|缓慢推近(Dolly In)|缓慢拉远(Dolly Out)|镜头横移(Pan)|跟随拍摄(跟人物走动)|手持微晃(真实手机感)|环绕微移(Orbit)|变焦(Zoom)
+- **随机组合**:每条约 2–3 种运镜手法按时间轴穿插,不全程单一机位;如"开场中近景固定 → 人物走动时跟随 → 讲到核心点时缓慢推近 → 结尾拉远收束"。
+
+## 13. 服装(Costume)【参考固定素材包】
+- 默认:参考素材包 `uniform_detail.*` 的米白美容师制服
+- 可选项(在制服细节图基础上):保持原款|换颜色(同款不同色)|换款式(胸牌不变)
+- 硬约束:**胸牌样式必须完全一致、绝对不可变更**;服装表面不得出现任何其他 Logo / 文字 / 水印。
+
+## 14. 造型(Styling)
+- 默认:深栗色半扎长发 + 斜刘海(与人物五视角图一致)
+- 可选项:深栗色半扎长发 + 斜刘海|利落低马尾|自然披发(微卷)|自定义
+- 硬约束:不戴帽子、不戴夸张饰品;全片发型 / 年龄感保持一致(与 Image 1 一致)。
+
+## 15. 画质基调(Quality)
+- 默认:真实手机拍摄画质
+- 可选项:真实手机拍摄画质|真实相机 / 电影感(浅景深)|高清写实(棚拍)|自定义
+
+## 16. 表情与肢体(Expression & Body Language)
+- 默认:表情丰富但克制、嘴巴小幅自然开合、身体语言随内容延展
+- 硬约束:不夸张嘴型、不变脸、不卡通化;口型由 wan3 原生生成对齐。
+
+## 17. 穿插画面(B-roll / Inserts)
+- 默认:抽象皮肤科普可视化(单段内)
+- 可选项:
+  - 抽象皮肤科普可视化(透明表皮层 / 光点 / 缓慢结构变化;无真人皮肤、无血液、无文字;由自动生成的插画参考图作风格启发,呈现在单条视频内,不切分段)
+  - 产品 / 成分特写
+  - 无穿插
+  - 自定义
+- 说明:严格"插画风独立片段"会破坏"一个片段",故默认以抽象可视化呈现(用户上一轮选定)。
+
+## 18. 字幕 / 文字(Text & Subtitle)
+- 默认:绝对无字幕、无标题、无 Logo、无品牌字样、无任何可读文字
+- 可选项:绝对无文字|含口播字幕(下三分之一)|含标题卡片|自定义
+
+## 19. 配乐 / 环境音(Music & Ambience)
+- 默认:无背景音乐 + 轻微环境音(由 wan3 原生生成)
+- 可选项:无背景音乐 + 轻微环境音|轻背景音乐(舒缓)|纯口播无环境音|自定义
+
+## 20. 情绪基调(Tone)
+- 默认:专业可信
+- 可选项:专业可信 / 温暖亲和 / 犀利直接 / 轻松幽默 / 焦虑安抚 / 自定义
+
+## 21. 品牌露出(Brand Exposure)【固定素材包】
+- 默认:怡呵美 LOGO(来自素材包 `logo_3d.*`,合成进门店参考图)
+- 可选项:指定品牌 logo 立体标识(前台墙面,背景虚化)|全程无品牌词 / 店名(仅 LOGO 视觉)
+- 硬约束:除用户明确指定的品牌露出外,人物、服装、场景表面不得出现任何 Logo / 文字 / 水印。
+
+## 22. 门店 / 场景风格(Store / Scene Style)【自动生成确认用】
+- 默认:现代简约轻奢(干净明亮、浅木 / 白调)
+- 可选项:现代简约轻奢 / 日式原木 / 科技感冷调 / 暖白诊所风 / 法式优雅 / 自定义
+- 说明:驱动"门店内景示例图"的生成风格(含品牌 LOGO)。品牌来自元素 21。
+
+## 23. 插画风格(Illustration Style)【自动生成确认用】
+- 默认:扁平插画(干净、专业)
+- 可选项:扁平插画 / 手绘水彩 / 线条极简 / 治愈系 / 科技蓝 / 噪点质感 / 自定义
+- 说明:驱动"内容插入插画参考图"的生成风格,作为单段视频内抽象可视化的风格启发。
+
+## 24. 整体色调(Color Tone)【自动生成确认用】
+- 默认:暖白(品牌亲和)
+- 可选项:暖白 / 冷调(蓝灰)/ 品牌色(怡呵美色系)/ 莫兰迪 / 自定义
+- 说明:统管门店、插画的配色走向。
+
+---
+
+## 25. 人物行为动线(Blocking / 肢体调度,按内容长短设计)
+- 默认:技能按口播内容自动设计 **≤2 个动作切换**(不全程正对镜头站桩)
+- 可选项(导演按需组合,且选定一条路径后全程不回头):
+  - 缓慢走动(在门店里踱步讲解,像真人在店里拍)
+  - 端坐讲解(坐于面诊桌 / 沙发,自然面对镜头)
+  - 从走动到落座(走动引入后坐下,落座后全程保持坐姿)
+  - 从坐姿站起走动(开场坐着,讲到重点起身走动,走动后全程保持站立走动)
+- **硬要求**:
+  - 30 秒单段内人物动作路线 **不超过 2 个**;一旦选定"走动→落座",落座后 **不再起身走动**;一旦选定"坐姿→起身走动",走动后 **不再落座**(动作方向不反向,节奏清晰)。
+  - **口播讲解时不设计"整理产品 / 轻触产品 / 翻阅资料"等无意义手部摆弄动作**(用户明确要求去掉),手部只用自然手势比划 / 轻微点头等微动作。
+  - 每段口播都要有人物与门店场景的互动行为,避免"一直正对镜头不动"的死板站桩。
+  - 手势比划 / 轻微点头等微动作不算独立动线,可全程保留,不计入 2 个上限。
+- 说明:这是导演级分镜设计,由技能在组装单段 Prompt 时按内容自动编排,不进用户风格问卷。
+
+## 26. 插画展示方式(Illustration Presentation,随机使用不固化)
+- 默认:技能在单次内随机选用,不恒定为一种
+- 可选项(一场视频内可混用):
+  - 全屏铺盖(插画整屏铺开,口播人物退为背景或短暂隐去)
+  - 圆形画中画(在口播画面的某 1–2 个区域嵌入圆形 PiP 展示插画)
+  - 条状画中画(在口播画面底部 / 顶部拿一条区域展示插画 PiP)
+  - 侧边画中画(画面一侧矩形 / 圆角区域嵌入插画)
+  - **人物画中画式全屏**(插画铺满整屏,口播人物以圆形 / 正方形画中画出现在画面某区域内,即"插画主、人物 PiP"的反向构图)
+- **随机组合**:同一视频里插画出现多次时,可轮换不同展示方式(如首次全屏、二次圆形 PiP),不要全部按一种方式来;与第三节「插画插入点」配合。
+- 说明:抽象可视化插画(Image 3/4)以这些方式融入单段画面,不切分段。
+
+## 27. 门店丰富元素(Scene Ambience / 道具与群演,增加画面丰富性)
+- 默认:技能在门店场景里随机点缀 2–3 个丰富元素
+- 可选项:
+  - 前台(与 LOGO 同框,自然出现在背景)
+  - 美容床 / 护理床
+  - 沙发 / 休息区座椅
+  - 桌椅 / 茶几 / 产品陈列架
+  - 其他人物(店员 / 顾客)从画面边缘走过、虚化处理
+  - 绿植 / 灯光氛围
+- **随机点缀**:除口播主角外,画面里适当出现上述道具 / 人物,增加真实门店的丰富度与景深;其他人物一律虚化、不抢主角、不出现清晰正脸文字。
+- 说明:这些元素在生成门店内景照片(Image 2)与单段 Prompt 描述中体现;与元素 10/22 场景风格一致。

+ 114 - 0
references/wan3-workflow.md

@@ -0,0 +1,114 @@
+# 百炼 wan3(万相3.0)视频生成工作流参考
+
+本文件取代原 `jimeng-workflow.md`,定义技能对接**阿里云百炼 · 万相 3.0(wan3.0-video)**的工程要点。技能所有"调用 AI 视频接口"的步骤都以本文件为准。
+
+## 一、模型与能力边界(决定技能流程)
+
+- **模型**:`wan3.0-video`(标准版)/ `wan3.0-video-prime`(高速版)。All-in-One,按 `input.media` 的 type 与 prompt 意图自动路由任务类型。
+- **单段时长上限 30 秒 / 30fps**:直接满足技能"一个片段 ≤30 秒"的硬约束。
+- **原生音视频**:一次调用即生成"画面 + 原生语音对白 + BGM + 音效",且原生对口型。因此口播无需单独 TTS 再对口型——把口播写进 prompt 作为对白,音色文件作为 `reference_audio` 传入即可。
+- **多模态参考(最多 20 个素材)**:图片 ≤10 张(单张 ≤20MB)、音频 ≤5 段(单段 ≤15s、≤15MB)、视频 ≤5 段。本技能只用"图片参考 + 音频参考"。
+- **参考引用语法**:prompt 中用 `Image 1` / `Image 2` / `Audio 1` 按 `media` 数组顺序引用素材。例如 media[0]=人物五视角图 → prompt 里写"Image 1 中的女性"。
+- **不支持二次创作**:wan3 虽有视频编辑 / 延长模式,但技能第 8 条要求"每次修改都重新组装完整脚本重发",故**只用文生/参考生视频一种模式,禁用 edit / extend**。
+
+## 二、接口与鉴权
+
+- **异步调用**:HTTP 仅支持异步,必须带请求头 `X-DashScope-Async: enable`。
+- **端点**(注意 `{WorkspaceId}` 与 `region`):
+  - 北京:`https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis`
+  - 新加坡:`https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/...`
+  - 任务查询:`GET https://{WorkspaceId}.{region}.maas.aliyuncs.com/api/v1/tasks/{task_id}`
+- **视频主机不带 `llm-` 前缀**:用户从百炼控制台拿到的 `…maas.aliyuncs.com/compatible-mode/v1` 是 **LLM 对话网关**(OpenAI 兼容模式),**视频生成不使用它**。视频主机为 `https://{WorkspaceId}.{region}.maas.aliyuncs.com`(无 `llm-` 前缀、`/api/v1` 之后才是视频路径)。脚本按 `config.workspace_id` + `config.region` 自动拼,或显式覆盖 `config.api_base`。
+- **鉴权**:`Authorization: Bearer $DASHSCOPE_API_KEY`。**密钥必须走环境变量,禁止写死**。
+- **地域一致**:模型、Endpoint、API Key 必须同地域,跨地域调用会失败(本片 workspace 在 cn-beijing,Key 也须为 cn-beijing 地域)。
+- **流程**:创建任务 → 拿 `task_id`(24h 有效)→ 轮询 `tasks/{task_id}` 至 `SUCCEEDED` → 取 `output.video_url` → 下载。
+
+## 三、素材 → wan3 参考映射(技能固定 4 项 + 自动 2 类)
+
+| 素材 | 来源 | media type | prompt 引用 | 约束 |
+|---|---|---|---|---|
+| 人物完整形象照 | **生成物料**:以 `character_5view` + `uniform_detail`(固定素材)为参考生成并确认(见 `asset-collection.md` 第二节) | `reference_image` | `Image 1` | 全片同脸/同发型/同年龄感/同制服;**胸牌样式与确认稿一致、不可变更** |
+| 门店内景照片(含 LOGO) | **生成物料**:以 `logo_3d`(固定素材)为 LOGO 参考生成含 LOGO 并确认(见第二节) | `reference_image` | `Image 2` | 前台墙面须出现怡呵美立体 LOGO |
+| 插画参考图 1/2 | 自动生成(抽象可视化风格启发) | `reference_image` | `Image 3` / `Image 4` | 无真人皮肤/血液/文字 |
+| 音色文件 | 公网 URL `config.brand_assets.voice_ref.url`(优先)或本地 `assets/brand/voice_ref.*`(兜底) | `reference_audio` | `Audio 1` | 单段 ≤15s;超长则裁剪一段代表音色 |
+| (生成输入,不提交)人物五视角图 / 制服细节图 / 立体 LOGO | 固定素材,仅用于生成 Image 1 / Image 2,本身不提交 wan3 | — | — | 锁死、不可被自动生成覆盖 |
+
+> media 数组顺序即 prompt 中 Image/Audio 编号顺序,组装时务必对应。提交的是**确认后的生成物料**,不是原始 4 项文件本身。
+
+> media 数组顺序即 prompt 中 Image/Audio 编号顺序,组装时务必对应。
+
+## 四、单段 30 秒 prompt 范式(编导分镜版)
+
+一个 prompt 描述**整段 30 秒**的连续画面(不要拆成多个 Shot 分开发请求)。要把它当作一条**专业编导分镜**来写——人物必须在门店场景里"活"起来,不能一直正对镜头站桩。必须覆盖四块:**人物行为动线 / 运镜组合 / 插画展示方式 / 门店丰富元素**(对应 `elements.md` 元素 25/26/27/12)。结构范式:
+
+```
+Image 1 中的女性(即这张已确认的人物完整形象照:与图中面孔、深栗色半扎长发、斜刘海一致,
+身穿[米白]美容师制服,胸牌样式与确认稿一致、不可更改),
+身处 Image 2 的怡呵美门店内(墙面有怡呵美立体 LOGO,背景虚化;店内可见[门店丰富元素:
+前台 / 美容床 / 沙发 / 产品陈列架,可选其他店员从画面边缘虚化走过])。
+
+[人物行为动线 · 按口播长短设计,全程与场景互动、不站桩]:
+开场她[从走动中入画 / 端坐于面诊桌前]自然引入[主题];讲到中段时[起身缓步走向产品架 /
+从走动落座于沙发]边走边说;结尾[回到中近景、手势收束]。说话间伴随[整理产品 / 手势比划 /
+轻微点头]等真实肢体动作。
+
+[运镜组合 · 随机穿插 2–3 种]:
+开场[中近景固定 / 极轻微横摇]→ 人物走动时[跟随拍摄]→ 讲到核心点时[缓慢推近]→
+结尾[缓慢拉远]收束。整体[手持微晃]保留真实手机拍摄质感。
+
+她自然亲和地讲解[主题]:
+"[口语化口播全文,含自然停顿]"
+
+[插画展示方式 · 随机使用,不固化一种](在[插画插入点:第 N 句]处触发,对应 Image 3 / Image 4):
+- 方式示例:[全屏铺盖插画] / [画面右侧圆形画中画嵌入插画] / [顶部条状画中画展示插画] /
+  [侧边圆角区域 PiP] / [人物画中画式全屏:插画铺满整屏、口播人物以圆形或正方形 PiP 出现在画面某区域];
+  同一视频多次出现插画时可轮换不同方式。
+(插画为抽象皮肤结构可视化:透明表皮层、缓慢流动光点、柔和结构变化,无真人皮肤、无血液、无文字)
+
+原生生成清晰女声普通话对白(音色参考 Audio 1)、轻微环境音、无背景音乐。
+绝对禁止:字幕/任何文字/卡通化/塑料皮肤/变脸/服装漂移/场景跳变/其他清晰正脸人物抢镜。
+```
+
+- 口播全文直接写进 prompt(作为对白台词),wan3 原生生成语音并对口型。
+- **人物行为动线**按口播时长设计:≤15 秒用 1–2 个动作切换,30 秒用 3–4 个动线(走动/坐/起/落座/整理)。
+- **运镜**每条约 2–3 种按时间轴穿插,不全程单一机位;**插画展示方式**一场内可混用多种,不恒定为一种;**门店丰富元素**随机点缀 2–3 个,增加景深与真实感。
+- 时长参数 `duration=30`,`ratio=9:16`,`resolution` 按 config。
+- 反向约束(硬性禁令)也写进 prompt 负向描述:无字幕/无文字/无卡通化/无塑料皮肤/无变脸/无服装漂移/无场景跳变。
+
+## 五、LOGO 落位(保证成片一定出现 LOGO)
+
+只靠 prompt 文字描述"前台有 LOGO"不可靠,必须在**生成门店内景照片**时就把 LOGO 锚定:
+
+1. 在 `asset-collection.md` 第二节第 2 步生成门店内景照片时,把固定素材 `logo_3d.*`(立体 LOGO 源文件,来自 URL 或本地)作为**图像生成参考**,要求模型在前台/墙面生成与参考一致的怡呵美立体 LOGO。
+2. 若生成模型对 LOGO 还原仍不精确,可在生成后对采用稿做图像贴图精修(PIL 合成),确保 LOGO 清晰一致。
+3. 确认后的门店内景照片(含 LOGO)作为 **Image 2** 传入 wan3;原始 `logo_3d` 本身不单独提交。
+
+## 六、调用脚本
+
+技能在用户确认脚本后,调用 `scripts/generate_video.py`:
+
+```bash
+export DASHSCOPE_API_KEY="sk-xxx"
+python scripts/generate_video.py \
+  --config scripts/config.json \
+  --prompt "<脚本模板第五节:整段 prompt>" \
+  --media \
+    /abs/人物_完整形象照.jpg:reference_image \   # Image 1(由 character_5view + uniform_detail 生成、确认)
+    /abs/门店_内景_采用.jpg:reference_image \     # Image 2(由 logo_3d 生成含 LOGO、确认)
+    /abs/插画_参考1.jpg:reference_image \        # Image 3
+    /abs/插画_参考2.jpg:reference_image \        # Image 4
+    "https://cdn.x/voice_ref.mp3:reference_audio" \  # Audio 1(config URL 透传,或本地路径)
+  --duration 30 --ratio 9:16 --resolution 720P \
+  --output /abs/成片.mp4
+```
+
+脚本会自动:公网 URL 素材直接透传(config.reupload_external_urls=true 时先下载再编码 base64 直传)、本地生成素材(人物形象照/门店内景/插画)读取后编码 base64 直传→建任务→轮询→下载到 `output_dir`,并把结果打印到 stdout(`VIDEO_PATH=...`)。技能捕获后把视频 present 给用户确认。
+
+## 七、常见坑
+
+- 模型/Endpoint/Key 跨地域 → 直接失败,务必同地域。本片 workspace 在 cn-beijing,Key 也须 cn-beijing 地域。
+- `media[].url` 支持**公网 URL 直传**,也支持**图像 base64 直传**(`data:{mime};base64,{b64}`)。固定 4 项若填了公网 URL(config.brand_assets),脚本默认直接透传;若 wan3 不接受站外 URL,把 `config.reupload_external_urls` 设为 `true`,脚本会先下载再编码 base64 直传。本地生成的图(人物形象照/门店内景/插画)一律编码 base64 直传,无需文件上传端点。
+- 用户所给 `llm-….maas.aliyuncs.com/compatible-mode/v1` 是 LLM 网关,**视频端点主机不带 `llm-` 前缀**。若视频调用报 404,确认 `config.workspace_id`/`region` 是否拼出 `https://{ws}.{region}.maas.aliyuncs.com`;可显式填 `config.api_base` 覆盖。
+- `reference_audio` 单段 ≤15s、≤15MB;音色样本过长先裁剪。
+- `duration` 必须 ≤30,超了先在技能侧精简口播(见 SKILL.md 第 5 步硬卡循环)。
+- 不传 `X-DashScope-Async: enable` 会报"current user api does not support synchronous calls"。

+ 4 - 0
scripts/.env.example

@@ -0,0 +1,4 @@
+# 百炼 / DashScope API Key 模板(北京地域创建,sk- 开头)
+# 用法:复制本文件为 .env(同目录),把下面的值换成你的真实 key,然后运行脚本。
+# 警告:.env 含密钥,切勿提交到 git 或随技能 zip 分发;重新打包技能前请删除本地 .env。
+DASHSCOPE_API_KEY=sk-your-real-key-here

+ 17 - 0
scripts/config.json

@@ -0,0 +1,17 @@
+{
+  "region": "cn-beijing",
+  "workspace_id": "gxuwdo0w0g13zbax",
+  "model": "wan3.0-video",
+  "resolution": "720P",
+  "ratio": "9:16",
+  "output_dir": "outputs",
+  "api_base": "https://llm-gxuwdo0w0g13zbax.cn-beijing.maas.aliyuncs.com",
+  "reupload_external_urls": false,
+  "llm_base_url": "https://llm-gxuwdo0w0g13zbax.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
+  "brand_assets": {
+    "character_5view": { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/duoduo-demo.jpg", "type": "reference_image", "name": "朵朵" },
+    "uniform_detail":   { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/zhifu-demo.png", "type": "reference_image" },
+    "logo_3d":          { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/yihemei-logo.jpeg", "type": "reference_image" },
+    "voice_ref":        { "url": "https://jibei-open-oss.oss-cn-hangzhou.aliyuncs.com/ai-video-assets/duoduo/voice-demo.mp3", "type": "reference_audio" }
+  }
+}

+ 308 - 0
scripts/generate_video.py

@@ -0,0 +1,308 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+百炼 wan3(万相3.0)视频生成调用脚本
+====================================
+仅供 beauty-talk-science-video-script 技能在「用户确认脚本后」调用。
+
+流程:
+  1. 解析参考素材(人物完整形象照 / 门店内景照 / 插画参考图 / 音色文件)。
+     - 公网 URL(--media 'https://...:类型'):默认直接透传,wan3 原生支持公网 URL。
+       若 config 的 reupload_external_urls=true(wan3 拒收站外 URL 时),先下载再编码 base64 直传。
+     - 本地文件(生成的人物形象照 / 门店内景 / 插画):读取后编码为
+       data:{mime};base64,{b64} 直接放入 media[].url(wan3 原生支持 base64 图像,免去文件上传端点)。
+  2. 组装 video-synthesis 异步请求(model / prompt / media / parameters),提交任务拿 task_id。
+  3. 轮询任务状态,直到 SUCCEEDED。
+  4. 下载生成的视频到本地 output_dir。
+
+端点(与用户所给 LLM base_url 不同,视频服务走同 workspace、同地域、但**不带 llm- 前缀**的主机):
+  POST https://{WorkspaceId}.{region}.maas.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis
+  GET  https://{WorkspaceId}.{region}.maas.aliyuncs.com/api/v1/tasks/{task_id}
+用户所给 "https://llm-xxxx.cn-beijing.maas.aliyuncs.com/compatible-mode/v1" 是 **LLM 对话网关**
+(OpenAI 兼容模式),视频生成不使用它;脚本按 workspace_id + region 自动拼视频主机,
+也可在 config.api_base 显式覆盖。
+
+凭证:
+  - DASHSCOPE_API_KEY 必须存在于环境变量(不写死在代码/配置里)。
+  - region / workspace_id / model / resolution / ratio / output_dir 写在同目录 config.json。
+  - 模型 / Endpoint / Key 必须同地域,跨地域调用会失败。
+
+注意:
+  - 本脚本只做「整段重新生成」,不使用 wan3 的视频编辑 / 延长模式(对应技能第 8 条:不支持二次创作)。
+  - 单次生成时长上限 30 秒(wan3.0 限制)。超过 30 秒的脚本请在技能侧先拆分/精简,本脚本强制 duration≤30。
+"""
+
+import os
+import sys
+import json
+import time
+import base64
+import argparse
+import mimetypes
+
+import requests
+
+# --------------------------------------------------------------------------- #
+# 配置与端点
+# --------------------------------------------------------------------------- #
+
+def load_config(path):
+    with open(path, "r", encoding="utf-8") as f:
+        return json.load(f)
+
+
+def api_base(cfg):
+    """视频服务主机:优先用 config.api_base;否则按 workspace_id + region 拼(不带 llm- 前缀)。"""
+    if cfg.get("api_base"):
+        return cfg["api_base"].rstrip("/")
+    ws = cfg["workspace_id"]
+    region = cfg["region"]
+    return f"https://{ws}.{region}.maas.aliyuncs.com"
+
+
+def auth_headers(key):
+    return {
+        "Authorization": f"Bearer {key}",
+        "Content-Type": "application/json",
+    }
+
+
+def resolve_key(here):
+    """解析百炼 / DashScope API Key。
+    优先级:环境变量 DASHSCOPE_API_KEY > 脚本同目录 .env(DASHSCOPE_API_KEY=...)。
+    注意:.env 含密钥,禁止随技能分发;重新打包技能前请删除本地 .env。
+    """
+    env = os.environ.get("DASHSCOPE_API_KEY")
+    if env and env.strip():
+        return env.strip()
+    env_path = os.path.join(here, ".env")
+    if os.path.exists(env_path):
+        try:
+            with open(env_path, "r", encoding="utf-8") as f:
+                for line in f:
+                    line = line.strip()
+                    if not line or line.startswith("#"):
+                        continue
+                    if line.startswith("DASHSCOPE_API_KEY="):
+                        v = line.split("=", 1)[1].strip().strip('"').strip("'")
+                        if v:
+                            return v
+        except Exception:
+            pass
+    sys.exit(
+        "未找到 DASHSCOPE_API_KEY:\n"
+        "  (1) 运行前 export DASHSCOPE_API_KEY=sk-真实key(当前 shell 生效);或\n"
+        "  (2) 在脚本同目录创建 .env,写入一行 DASHSCOPE_API_KEY=sk-真实key(详见 .env.example)。\n"
+        "注意:北京地域创建、sk- 开头;密钥严禁提交或分发。"
+    )
+
+
+# --------------------------------------------------------------------------- #
+# 素材 -> URL(公网URL直传 / 本地文件 base64 直传)
+# --------------------------------------------------------------------------- #
+
+def local_file_to_data_uri(filepath):
+    """读取本地文件,编码为 data:{mime};base64,{b64},wan3 原生支持图像 base64 直传。"""
+    mime = mimetypes.guess_type(filepath)[0] or "application/octet-stream"
+    with open(filepath, "rb") as f:
+        b64 = base64.b64encode(f.read()).decode("ascii")
+    return f"data:{mime};base64,{b64}"
+
+
+def download_to_temp(url, suffix=".tmp"):
+    """把公网 URL 下载到临时文件,返回本地路径(用于 reupload_external_urls)。"""
+    import tempfile
+    fd, tmppath = tempfile.mkstemp(suffix=suffix)
+    os.close(fd)
+    try:
+        resp = requests.get(url, timeout=300, stream=True)
+        resp.raise_for_status()
+        with open(tmppath, "wb") as f:
+            for chunk in resp.iter_content(8192):
+                f.write(chunk)
+    except Exception:
+        if os.path.exists(tmppath):
+            os.remove(tmppath)
+        raise
+    return tmppath
+
+
+# --------------------------------------------------------------------------- #
+# 任务创建与轮询
+# --------------------------------------------------------------------------- #
+
+def create_task(base, key, payload):
+    url = base + "/api/v1/services/aigc/video-generation/video-synthesis"
+    headers = auth_headers(key)
+    headers["X-DashScope-Async"] = "enable"
+    resp = requests.post(url, headers=headers, json=payload, timeout=120)
+    if resp.status_code not in (200, 202):
+        raise RuntimeError(f"建任务失败:HTTP {resp.status_code} {resp.text[:500]}")
+    return resp.json()
+
+
+def poll_task(base, key, task_id, interval, timeout):
+    url = base + f"/api/v1/tasks/{task_id}"
+    headers = {"Authorization": f"Bearer {key}"}
+    waited = 0
+    while waited < timeout:
+        try:
+            resp = requests.get(url, headers=headers, timeout=60)
+            if resp.status_code == 200:
+                data = resp.json()
+                status = (
+                    (data.get("output", {}) or {}).get("task_status")
+                    or data.get("task_status")
+                )
+                if status == "SUCCEEDED":
+                    return data
+                if status in ("FAILED", "UNKNOWN"):
+                    raise RuntimeError(f"任务失败:{json.dumps(data, ensure_ascii=False)[:800]}")
+        except requests.RequestException:
+            pass
+        time.sleep(interval)
+        waited += interval
+    raise RuntimeError("轮询超时(视频生成可能仍在后台,请用 task_id 手动查询)")
+
+
+def extract_video_url(data):
+    out = data.get("output", {}) or {}
+    for k in ("video_url", "videoUrl", "url"):
+        if out.get(k):
+            return out[k]
+    for r in out.get("results") or []:
+        if r.get("url"):
+            return r["url"]
+    raise RuntimeError("任务成功但未找到视频 URL")
+
+
+def download(url, out_path):
+    resp = requests.get(url, timeout=300, stream=True)
+    resp.raise_for_status()
+    with open(out_path, "wb") as f:
+        for chunk in resp.iter_content(8192):
+            f.write(chunk)
+    return out_path
+
+
+# --------------------------------------------------------------------------- #
+# 入口
+# --------------------------------------------------------------------------- #
+
+def main():
+    here = os.path.dirname(os.path.abspath(__file__))
+    ap = argparse.ArgumentParser(description="百炼 wan3 视频生成(单段,≤30s)")
+    ap.add_argument("--config", default=os.path.join(here, "config.json"))
+    ap.add_argument("--prompt", required=True, help="单段视频提示词(含口播对白与 Image 1 / Audio 1 引用)")
+    ap.add_argument(
+        "--media",
+        nargs="*",
+        default=[],
+        help="参考素材,格式 '路径或URL:类型'。类型:reference_image / reference_audio。"
+             "如 /abs/char.jpg:reference_image 或 https://cdn.x/char.jpg:reference_image;"
+             "公网 URL 默认直接透传;本地文件编码 base64 直传;详见 config.reupload_external_urls。",
+    )
+    ap.add_argument("--duration", type=int, default=30, help="时长(秒),≤30")
+    ap.add_argument("--ratio", default=None, help="画幅,如 9:16")
+    ap.add_argument("--resolution", default=None, help="分辨率,如 720P")
+    ap.add_argument("--model", default=None)
+    ap.add_argument("--output", default=None, help="输出视频本地路径")
+    ap.add_argument("--poll-interval", type=int, default=10)
+    ap.add_argument("--timeout", type=int, default=1200)
+    args = ap.parse_args()
+
+    if args.duration > 30:
+        sys.exit("wan3 单次生成上限 30 秒,duration 必须 ≤30。请先在技能侧精简口播。")
+    if args.duration < 2:
+        sys.exit("duration 必须 ≥2 秒。")
+
+    key = resolve_key(here)
+
+    cfg = load_config(args.config)
+    base = api_base(cfg)
+    model = args.model or cfg.get("model", "wan3.0-video")
+    resolution = args.resolution or cfg.get("resolution", "720P")
+    ratio = args.ratio or cfg.get("ratio", "9:16")
+    out_dir = os.path.join(here, cfg.get("output_dir", "outputs"))
+    os.makedirs(out_dir, exist_ok=True)
+
+    # 1) 解析素材 -> URL(公网URL直传 / 本地文件base64直传)
+    reupload = bool(cfg.get("reupload_external_urls"))
+    media = []
+    for m in args.media:
+        raw = m.strip()
+        if "://" in raw:
+            # 公网 URL 形式:'https://...:reference_image|reference_audio'(类型可选)
+            head, sep, tail = raw.rpartition(":")
+            if sep and tail in ("reference_image", "reference_audio"):
+                raw, mtype = head, tail
+            else:
+                mtype = "reference_image"
+        else:
+            raw, _, mtype = raw.partition(":")
+            mtype = (mtype or "reference_image").strip()
+        raw = raw.strip()
+        if "://" in raw:
+            if reupload:
+                print(f"[下载并base64] {raw} ({mtype}) ...", file=sys.stderr)
+                tmp = download_to_temp(raw)
+                u = local_file_to_data_uri(tmp)
+                try:
+                    os.remove(tmp)
+                except OSError:
+                    pass
+            else:
+                print(f"[透传URL] {raw} ({mtype})", file=sys.stderr)
+                u = raw
+            media.append({"type": mtype, "url": u})
+            continue
+        fpath = os.path.expanduser(raw)
+        if not os.path.exists(fpath):
+            sys.exit(f"素材不存在:{fpath}")
+        print(f"[base64直传] {fpath} ({mtype}) ...", file=sys.stderr)
+        u = local_file_to_data_uri(fpath)
+        media.append({"type": mtype, "url": u})
+
+    # 2) 组装请求
+    payload = {
+        "model": model,
+        "input": {"prompt": args.prompt},
+        "parameters": {
+            "resolution": resolution,
+            "ratio": ratio,
+            "duration": args.duration,
+            "audio": True,
+            "prompt_extend": False,
+            "watermark": False,
+        },
+    }
+    if media:
+        payload["input"]["media"] = media
+
+    print("[提交] 创建视频生成任务 ...", file=sys.stderr)
+    created = create_task(base, key, payload)
+    task_id = (created.get("output", {}) or {}).get("task_id") or created.get("task_id")
+    if not task_id:
+        sys.exit(f"未返回 task_id:{json.dumps(created, ensure_ascii=False)[:500]}")
+    print(f"[轮询] task_id={task_id}", file=sys.stderr)
+
+    # 3) 轮询
+    result = poll_task(base, key, task_id, args.poll_interval, args.timeout)
+
+    # 4) 下载
+    vurl = extract_video_url(result)
+    out_path = args.output or os.path.join(out_dir, f"video_{int(time.time())}.mp4")
+    out_path = os.path.abspath(out_path)
+    print(f"[下载] {vurl} -> {out_path}", file=sys.stderr)
+    download(vurl, out_path)
+
+    # 仅供技能解析的结构化结果(走 stdout)
+    print("VIDEO_PATH=" + out_path)
+    print("RESULT_JSON=" + json.dumps(
+        {"task_id": task_id, "video_path": out_path, "video_url": vurl},
+        ensure_ascii=False,
+    ))
+
+
+if __name__ == "__main__":
+    main()