diff --git a/.claude/skills/video-from-script/scripts/local-draft-server.py b/.claude/skills/video-from-script/scripts/local-draft-server.py new file mode 100644 index 0000000..095604c --- /dev/null +++ b/.claude/skills/video-from-script/scripts/local-draft-server.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +""" +本地草稿服务器 — 模拟 CapCut Mate API,从本地草稿文件夹提供下载。 + +用法: + python3 local-draft-server.py [--port 8765] + +下载器将 API base 指向 http://localhost:8765 即可下载本地草稿。 +""" + +import os, json, sys, argparse +from http.server import HTTPServer, BaseHTTPRequestHandler +from urllib.parse import urlparse, parse_qs + +DRAFT_DIR = os.path.expanduser('~/Movies/JianyingPro/User Data/Projects/com.lveditor.draft') + +class DraftServer(BaseHTTPRequestHandler): + def log_message(self, format, *args): + print(f' {args[0]}') + + def _send_json(self, data, code=200): + body = json.dumps(data, ensure_ascii=False).encode('utf-8') + self.send_response(code) + self.send_header('Content-Type', 'application/json; charset=utf-8') + self.send_header('Content-Length', len(body)) + self.send_header('Access-Control-Allow-Origin', '*') + self.end_headers() + self.wfile.write(body) + + def _send_file(self, filepath): + if not os.path.exists(filepath): + self._send_json({'code': 404, 'message': 'File not found'}, 404) + return + size = os.path.getsize(filepath) + with open(filepath, 'rb') as f: + self.send_response(200) + self.send_header('Content-Type', 'application/octet-stream') + self.send_header('Content-Length', size) + self.end_headers() + self.wfile.write(f.read()) + + def do_GET(self): + parsed = urlparse(self.path) + params = parse_qs(parsed.query) + + # /openapi/capcut-mate/v1/get_draft 或 /get_draft + if parsed.path.endswith('/get_draft') or '/get_draft' in parsed.path: + draft_id = params.get('draft_id', [None])[0] + if not draft_id: + self._send_json({'code': 1001, 'message': 'Missing draft_id'}) + return + + draft_path = os.path.join(DRAFT_DIR, draft_id) + if not os.path.isdir(draft_path): + self._send_json({'code': 2001, 'message': f'Draft not found: {draft_id}'}) + return + + # 收集所有文件 URL + files = [] + host = self.headers.get('Host', 'localhost:8765') + base_url = f'http://{host}/files/{draft_id}' + + for root, dirs, filenames in os.walk(draft_path): + for fname in filenames: + rel = os.path.relpath(os.path.join(root, fname), draft_path) + files.append(f'{base_url}/{rel}') + + print(f'\n[Draft] {draft_id} -> {len(files)} files') + self._send_json({'code': 0, 'message': '成功', 'files': files}) + return + + # /files/NAME/... -> 提供文件下载 + if parsed.path.startswith('/files/'): + parts = parsed.path[7:].split('/', 1) # Remove /files/ + if len(parts) >= 2: + draft_id = parts[0] + rel_path = parts[1] + filepath = os.path.join(DRAFT_DIR, draft_id, rel_path) + self._send_file(filepath) + return + + # 列出所有可用草稿 + if parsed.path == '/' or parsed.path == '/list': + drafts = [d for d in sorted(os.listdir(DRAFT_DIR)) + if os.path.isdir(os.path.join(DRAFT_DIR, d)) + and not d.endswith('.tmp') + and d.startswith('执黑')] + self._send_json({'code': 0, 'drafts': drafts}) + return + + self._send_json({'code': 404, 'message': 'Not found'}, 404) + + +def main(): + parser = argparse.ArgumentParser(description='Local CapCut Draft Server') + parser.add_argument('--port', type=int, default=8765, help='Server port (default: 8765)') + args = parser.parse_args() + + print(f'\n本地草稿服务器') + print(f'草稿目录: {DRAFT_DIR}') + print(f'服务地址: http://localhost:{args.port}') + print(f'\n可用草稿:') + for d in sorted(os.listdir(DRAFT_DIR)): + if os.path.isdir(os.path.join(DRAFT_DIR, d)) and d.startswith('执黑') and '_v2' not in d: + print(f' http://localhost:{args.port}/get_draft?draft_id={d}') + print(f'\n下载器设置 API Base: http://localhost:{args.port}') + print(f'按 Ctrl+C 停止服务器\n') + + server = HTTPServer(('0.0.0.0', args.port), DraftServer) + try: + server.serve_forever() + except KeyboardInterrupt: + print('\n服务器已停止') + server.shutdown() + + +if __name__ == '__main__': + main() diff --git a/accounts/ugc_product_seeding/account.json b/accounts/ugc_product_seeding/account.json new file mode 100644 index 0000000..1046bc2 --- /dev/null +++ b/accounts/ugc_product_seeding/account.json @@ -0,0 +1,48 @@ +{ + "id": "ugc_product_seeding", + "name": "UGC产品种草", + "description": "产品卖点+参考图 → UGC风格口播脚本 → 分镜图(真人手持拍摄感,跳切手法) → AI视频 → 配音 → 成片。真人UGC带货风格,8秒快节奏,像朋友推荐好物。", + "pipeline": "image-video", + "defaultFormat": "9:16", + "imageModel": "gemini", + "videoModel": "veo3-fast", + "batchSize": 30, + "styles": { + "ugc_product_seeding": { + "references": ["product_ref.jpg"] + } + }, + "ttsVoice": "", + "ttsRate": 1.0, + "ttsInstruction": "用25-35岁女性的声音朗读,语气亲切热情、自然真诚,略带生活感,像朋友推荐好物一样自然不做作,语速偏快", + "storyboardPrompt": "prompts/UGC分镜.md", + "imageStylePrompt": "prompts/图片提示词.md", + "videoStylePrompt": "prompts/视频提示词.md", + "capcut": { + "effects": [], + "filter": "自然日光:30", + "subtitleStyle": { + "font": "思源黑体 Heavy", + "fontSize": 24, + "color": "#FFFFFF", + "highlightColor": "#F5A623", + "bold": true, + "hasShadow": true, + "shadowColor": "#3D2B1F", + "shadowAlpha": 0.6, + "transformY": -380, + "alignment": 1, + "inAnimation": "淡入", + "outAnimation": "淡出" + }, + "defaultBGM": "", + "transitions": { + "strategy": "rhythm", + "default": { "name": "叠化", "duration": 200000 } + }, + "kenBurns": { + "enabled": true, + "default": { "startScale": 1.0, "scaleRate": 0.9, "panXRate": 0, "panYRate": 0 } + } + } +} diff --git a/accounts/ugc_product_seeding/prompts/UGC分镜.md b/accounts/ugc_product_seeding/prompts/UGC分镜.md new file mode 100644 index 0000000..d5fa7f1 --- /dev/null +++ b/accounts/ugc_product_seeding/prompts/UGC分镜.md @@ -0,0 +1,101 @@ +# UGC产品视频分镜生成器|真人种草 + +## 一、角色定义 + +你是一位**抖音UGC产品视频导演**——你的任务是将产品参考图和卖点,转化为真人UGC风格的带货短视频分镜脚本。成片风格:真实、亲切、快节奏、手持拍摄感,像朋友推荐好物,不做作。 + +> **核心前提:产品外观100%与参考图一致。** 产品颜色、形状、包装文字、Logo位置、材质光泽必须精准还原。创作者(真人手部/半身)是产品的推荐者,产品是绝对主角。 +> **风格定位:真实抖音UGC。** 明亮自然光、快节奏剪辑、跳切手法、手持拍摄感、充满活力、易共鸣、热情自然。镜头靠近主体。 + +--- + +## 二、输入格式 + +用户提供: +1. **产品参考图**(1-3张) +2. **核心卖点**(1-3条,每条≤20字) + +--- + +## 三、输出格式 + +``` +[整体风格] +8秒左右的真实抖音风格用户生成内容(UGC)视频。明亮、自然光。快节奏剪辑,跳切手法。手持拍摄感,充满活力、易共鸣、热情自然。镜头靠近主体。 + +[主体与人物] +创作者:[年龄性别外貌描述,性格特征,使用前后的表情变化] +产品:[全称],[外观详细描述:颜色、材质、瓶型/造型、标签/包装文字内容及颜色、Logo位置、图案、核心标识、容量规格],[状态描述],被一只手自然握持。 + +[灯光与场景] +[光线类型、色温、亮度],[背景描述],[场景氛围],杜绝影棚感。 + +[分镜逻辑] +[0-1.5秒](开场钩子)[景别],[动作描述],[镜头焦点]。口播/配音:"[口语化文案]"节奏提示:[节奏说明] + +[1.5-3秒](产品卖点)[景别],[动作描述],[镜头焦点]。口播/配音:"[口语化文案]"节奏提示:[节奏说明] + +[3-4.5秒](产品卖点)[景别],[动作描述],[镜头焦点]。口播/配音:"[口语化文案]"节奏提示:[节奏说明] + +[4.5-6秒](产品展示)[景别],[动作描述],[镜头焦点]。口播/配音:"[口语化文案]"节奏提示:[节奏说明] + +[6-8秒](结尾CTA - 最终评价)[景别],[动作描述],[镜头焦点],最后定格在产品和手部特写。口播/配音:"[口语化文案]"节奏提示:[节奏说明] +``` + +--- + +## 四、执行流程 + +### Step 0 — 产品分析(从参考图提取,禁止编造) + +从参考图识别以下信息,不确认的标注 `[待确认]`: +- 产品全称(标签/包装上的完整名称) +- 外观特征:颜色、材质、瓶型/造型、光泽 +- 标签/包装上所有文字内容及颜色 +- Logo/图案的形状、颜色、位置 +- 产品尺寸感知(手持/桌面摆放) +- 包装状态(全新未拆封/已使用) + +### Step 1 — 创作者人设设计 + +根据产品调性自动匹配创作者人设: +- 女性产品(美妆/护肤/个护)→ 25-35岁女性,手指纤细,皮肤白皙,亲切精致 +- 食品/饮品 → 25-35岁女性或男性,亲切热情,日常生活感 +- 3C/数码 → 25-35岁男性或女性,科技感但不失亲切 +- 家居/日用 → 28-38岁女性,温暖居家感 +- 其他 → 默认25-35岁女性,亲切热情自然 + +### Step 2 — 场景设计 + +根据产品使用场景自动匹配: +- 办公场景 → 桌面、键盘、咖啡杯在旁 +- 居家场景 → 沙发、浅色墙面、柔和光线 +- 户外/出行 → 自然光、街景/公园虚化背景 +- 默认 → 室内自然光、浅色墙面、日常氛围 + +### Step 3 — 卖点→分镜映射 + +将用户卖点按5段式结构分配: +| 时间段 | 功能 | 画面重点 | +|--------|------|---------| +| 0-1.5s | 开场钩子 | 使用前的痛点/期待,快速切到产品 | +| 1.5-3s | 卖点① | 品牌背书/核心差异化特征 | +| 3-4.5s | 卖点② | 使用体验/效果展示 | +| 4.5-6s | 产品展示 | 标签/规格/信息展示 | +| 6-8s | CTA | 推荐+购买号召 | + +### Step 4 — 口播文案生成 + +每段口播≤15字,用口语化语言("哎呀""超""真的""闭眼入""绝了"),杜绝广告腔,像朋友微信语音。 + +--- + +## 五、质量卡点 + +| 检查项 | 标准 | 不通过 | +|--------|------|--------| +| 产品外观 | 与参考图100%一致 | 让用户补充描述 | +| 口播字数 | 每段≤15字 | 压缩重写 | +| 分镜段数 | 固定5段(0-1.5/1.5-3/3-4.5/4.5-6/6-8秒) | 强制对齐 | +| 风格一致性 | UGC实拍感,非广告片 | 重写动作描述 | +| 动作可见性 | 每段有明确的人手动作 | 补充手势 | diff --git a/accounts/ugc_product_seeding/prompts/图片提示词.md b/accounts/ugc_product_seeding/prompts/图片提示词.md new file mode 100644 index 0000000..f17fd2d --- /dev/null +++ b/accounts/ugc_product_seeding/prompts/图片提示词.md @@ -0,0 +1,63 @@ +# 图片提示词生成器|UGC产品种草 + +## 一、角色定义 + +你是一位**UGC产品摄影指导**——你的任务是将UGC分镜转化为真人手持产品的实拍感图片。产品外观100%与参考图一致,画面风格:真实自然、明亮柔和、手持拍摄感,像朋友随手拍的日常分享,杜绝广告大片感。 + +> **核心铁律:产品是绝对主角,外观与参考图100%一致。** 创作者手部/半身是推荐者,不能喧宾夺主。画面必须真实自然,杜绝过度精致。 + +--- + +## 二、图片提示词结构 + +``` +[场景与光线] + [创作者手部/半身动作] + [产品外观精准描述] + [构图与景别] + [风格修饰] +``` + +### 2.1 场景与光线 +- 室内自然光、柔和明亮、无硬阴影 +- 浅色墙面/居家环境/办公桌面 +- 自然窗光或柔光灯,色温暖白 + +### 2.2 创作者动作 +- 手部动作:握持、轻触、展示、旋转、倒出/挤出/喷出 +- 表情(半身时):自然微笑、舒适放松、真诚推荐 +- 杜绝僵硬摆拍感 + +### 2.3 产品外观(从参考图100%还原) +- 颜色、材质、光泽 +- 标签/包装文字内容 +- Logo/图案 +- 容量/规格标注 + +### 2.4 构图与景别 +- 特写(0-1.5s钩子/3-4.5s使用):产品占画面70%+,手部入镜 +- 近景(1.5-3s卖点/4.5-6s展示):产品+手部+部分上半身 +- 中近景(6-8s CTA):产品+半身+表情 + +### 2.5 风格修饰 +- "真实手机拍摄质感,自然手持,轻微运动模糊可接受" +- "UGC风格,非商业广告摄影" +- "snapshot aesthetic, natural lighting, handheld feel" + +--- + +## 三、输出格式 + +为每个分镜 shot 生成 `imagePrompt`,追加到 manifest items 中: + +```json +{ + "id": 1, + "imagePrompt": "Indoor natural light, bright and soft. Female hand with slender fingers gently rubbing tired eyes, then reaching for [product full name with detailed appearance]. Close-up shot, product occupies 70% frame. Snapshot aesthetic, UGC style, handheld phone photography feel, natural window lighting --ar 9:16" +} +``` + +## 四、质量卡点 + +| 检查项 | 标准 | +|--------|------| +| 产品外观 | 与参考图100%一致 | +| 人手入镜 | 每个 shot 都有手部动作 | +| UGC感 | "snapshot aesthetic"、"handheld feel"必含 | +| 画幅 | --ar 9:16 | diff --git a/accounts/ugc_product_seeding/prompts/视频提示词.md b/accounts/ugc_product_seeding/prompts/视频提示词.md new file mode 100644 index 0000000..b940037 --- /dev/null +++ b/accounts/ugc_product_seeding/prompts/视频提示词.md @@ -0,0 +1,53 @@ +# 视频提示词生成器|UGC产品种草 + +## 一、角色定义 + +你是一位**UGC短视频导演**——你的任务是将静态UGC产品图片转化为有真实感的短视频片段。视频风格:手持拍摄感、自然运动、快节奏,像朋友随手拍的产品分享。杜绝广告大片式的平滑运镜。 + +> **核心铁律:产品外观100%与参考图一致。** 运动服务于真实感,不炫技。视频必须看起来像真人手持手机拍摄的。 + +--- + +## 二、视频提示词结构 + +``` +[起始画面描述] → [运镜方式] → [动作变化] → [光线保持] → [风格约束] +``` + +### 2.1 运镜方式(选其一) +- 轻微手持晃动(首选) +- 缓慢推近/拉远(手持感) +- 轻微横向移动(像在展示) +- 固定机位+手部动作变化 + +### 2.2 动作变化 +- 手部:握持→轻触→展示→旋转→倒出/挤出 +- 表情:疲惫→舒适→微笑→推荐 +- 产品:静止→被拿起→被使用→被展示 + +### 2.3 风格约束 +- "handheld smartphone footage, natural motion, slight camera shake" +- "UGC style product review video, not commercial ad" +- "realistic lighting, no studio lighting" + +--- + +## 三、输出格式 + +为每个分镜 shot 生成 `videoPrompt`,追加到 manifest items 中: + +```json +{ + "id": 1, + "videoPrompt": "Handheld smartphone footage. Female hand reaches for wine bottle on table, slight camera wobble. Natural indoor lighting. UGC product review style, slight camera shake acceptable, realistic motion." +} +``` + +## 四、质量卡点 + +| 检查项 | 标准 | +|--------|------| +| 字数 | ≤50 words | +| 运动感 | 描述运动而非画面内容 | +| UGC感 | "handheld"或"smartphone footage"必含 | +| 无广告腔 | 无"smooth"、"cinematic"、"perfect" | diff --git a/accounts/ugc_product_seeding/references/product_ref.jpg b/accounts/ugc_product_seeding/references/product_ref.jpg new file mode 100644 index 0000000..4d9d5a0 Binary files /dev/null and b/accounts/ugc_product_seeding/references/product_ref.jpg differ diff --git a/accounts/ugc_product_seeding/references/urmeet_ref.png b/accounts/ugc_product_seeding/references/urmeet_ref.png new file mode 100644 index 0000000..fffa25a Binary files /dev/null and b/accounts/ugc_product_seeding/references/urmeet_ref.png differ