@fifine/aim-studio 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/commands/init.d.ts.map +1 -1
  2. package/dist/commands/init.js +123 -101
  3. package/dist/commands/init.js.map +1 -1
  4. package/dist/configurators/workflow.d.ts.map +1 -1
  5. package/dist/configurators/workflow.js +91 -65
  6. package/dist/configurators/workflow.js.map +1 -1
  7. package/dist/templates/aim/scripts/common/paths.py +3 -2
  8. package/dist/templates/aim/scripts/export.py +427 -0
  9. package/dist/templates/claude/commands/aim/export.md +89 -115
  10. package/dist/templates/claude/commands/aim/onboard.md +10 -8
  11. package/dist/templates/claude/commands/aim/start.md +104 -37
  12. package/dist/templates/claude/hooks/inject-subagent-context.py +6 -10
  13. package/dist/templates/claude/hooks/session-start.py +134 -24
  14. package/dist/templates/markdown/index.d.ts +5 -0
  15. package/dist/templates/markdown/index.d.ts.map +1 -1
  16. package/dist/templates/markdown/index.js +6 -0
  17. package/dist/templates/markdown/index.js.map +1 -1
  18. package/dist/templates/markdown/spec/cli/directory-structure.md.txt +71 -0
  19. package/dist/templates/markdown/spec/cli/error-handling.md.txt +91 -0
  20. package/dist/templates/markdown/spec/cli/index.md.txt +37 -0
  21. package/dist/templates/markdown/spec/cli/options-flags.md.txt +71 -0
  22. package/dist/templates/markdown/spec/cli/output-formatting.md.txt +93 -0
  23. package/dist/utils/project-detector.d.ts +1 -1
  24. package/dist/utils/project-detector.d.ts.map +1 -1
  25. package/dist/utils/project-detector.js +20 -0
  26. package/dist/utils/project-detector.js.map +1 -1
  27. package/package.json +1 -1
  28. package/dist/templates/claude/commands/trellis/before-backend-dev.md +0 -13
  29. package/dist/templates/claude/commands/trellis/before-frontend-dev.md +0 -13
  30. package/dist/templates/claude/commands/trellis/break-loop.md +0 -125
  31. package/dist/templates/claude/commands/trellis/check-backend.md +0 -13
  32. package/dist/templates/claude/commands/trellis/check-cross-layer.md +0 -153
  33. package/dist/templates/claude/commands/trellis/check-frontend.md +0 -13
  34. package/dist/templates/claude/commands/trellis/create-command.md +0 -154
  35. package/dist/templates/claude/commands/trellis/finish-work.md +0 -129
  36. package/dist/templates/claude/commands/trellis/integrate-skill.md +0 -219
  37. package/dist/templates/claude/commands/trellis/onboard.md +0 -358
  38. package/dist/templates/claude/commands/trellis/parallel.md +0 -193
  39. package/dist/templates/claude/commands/trellis/record-session.md +0 -62
  40. package/dist/templates/claude/commands/trellis/start.md +0 -280
  41. package/dist/templates/claude/commands/trellis/update-spec.md +0 -285
  42. package/dist/templates/trellis/gitignore.txt +0 -29
  43. package/dist/templates/trellis/index.d.ts +0 -49
  44. package/dist/templates/trellis/index.d.ts.map +0 -1
  45. package/dist/templates/trellis/index.js +0 -92
  46. package/dist/templates/trellis/index.js.map +0 -1
  47. package/dist/templates/trellis/scripts/__init__.py +0 -5
  48. package/dist/templates/trellis/scripts/add_session.py +0 -392
  49. package/dist/templates/trellis/scripts/common/__init__.py +0 -80
  50. package/dist/templates/trellis/scripts/common/cli_adapter.py +0 -435
  51. package/dist/templates/trellis/scripts/common/developer.py +0 -190
  52. package/dist/templates/trellis/scripts/common/git_context.py +0 -383
  53. package/dist/templates/trellis/scripts/common/paths.py +0 -347
  54. package/dist/templates/trellis/scripts/common/phase.py +0 -253
  55. package/dist/templates/trellis/scripts/common/registry.py +0 -366
  56. package/dist/templates/trellis/scripts/common/task_queue.py +0 -255
  57. package/dist/templates/trellis/scripts/common/task_utils.py +0 -178
  58. package/dist/templates/trellis/scripts/common/worktree.py +0 -219
  59. package/dist/templates/trellis/scripts/create_bootstrap.py +0 -290
  60. package/dist/templates/trellis/scripts/get_context.py +0 -16
  61. package/dist/templates/trellis/scripts/get_developer.py +0 -26
  62. package/dist/templates/trellis/scripts/init_developer.py +0 -51
  63. package/dist/templates/trellis/scripts/multi_agent/__init__.py +0 -5
  64. package/dist/templates/trellis/scripts/multi_agent/cleanup.py +0 -403
  65. package/dist/templates/trellis/scripts/multi_agent/create_pr.py +0 -329
  66. package/dist/templates/trellis/scripts/multi_agent/plan.py +0 -233
  67. package/dist/templates/trellis/scripts/multi_agent/start.py +0 -461
  68. package/dist/templates/trellis/scripts/multi_agent/status.py +0 -817
  69. package/dist/templates/trellis/scripts/task.py +0 -1056
  70. package/dist/templates/trellis/scripts-shell-archive/add-session.sh +0 -384
  71. package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +0 -129
  72. package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +0 -263
  73. package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +0 -208
  74. package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +0 -150
  75. package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +0 -247
  76. package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +0 -142
  77. package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +0 -151
  78. package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +0 -128
  79. package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +0 -299
  80. package/dist/templates/trellis/scripts-shell-archive/get-context.sh +0 -7
  81. package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +0 -15
  82. package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +0 -34
  83. package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +0 -396
  84. package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +0 -241
  85. package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +0 -207
  86. package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +0 -317
  87. package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +0 -828
  88. package/dist/templates/trellis/scripts-shell-archive/task.sh +0 -1204
  89. package/dist/templates/trellis/tasks/.gitkeep +0 -0
  90. package/dist/templates/trellis/workflow.md +0 -416
  91. package/dist/templates/trellis/worktree.yaml +0 -47
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Export script for generating Seedance-ready prompts
5
+
6
+ Usage:
7
+ python export.py --ep 1 # Export episode 1
8
+ python export.py --ep 1-3 # Export episodes 1-3
9
+ python export.py --all # Export all episodes
10
+ python export.py --scene 1 # Export scene 1 of current episode
11
+ python export.py --format seedance # Seedance format (default)
12
+ python export.py --format simple # Simple format for quick copy
13
+ """
14
+
15
+ import argparse
16
+ import json
17
+ import os
18
+ import sys
19
+ from pathlib import Path
20
+ from datetime import datetime
21
+
22
+ # Add parent directory to path for imports
23
+ sys.path.insert(0, str(Path(__file__).parent))
24
+ from common.paths import get_project_root, get_tasks_dir
25
+
26
+
27
+ def read_file(file_path: Path) -> str:
28
+ """Read file content."""
29
+ try:
30
+ return file_path.read_text(encoding="utf-8")
31
+ except (FileNotFoundError, PermissionError):
32
+ return ""
33
+
34
+
35
+ def get_character_prompt(character_name: str, spec_dir: Path) -> str:
36
+ """Generate character prompt for Seedance."""
37
+ character_file = spec_dir / "story" / "character.md"
38
+ if not character_file.exists():
39
+ return ""
40
+
41
+ content = read_file(character_file)
42
+
43
+ # Extract character section
44
+ lines = content.split("\n")
45
+ in_character = False
46
+ character_lines = []
47
+
48
+ for line in lines:
49
+ if f"## {character_name}" in line or f"## {character_name}:" in line:
50
+ in_character = True
51
+ continue
52
+ if in_character:
53
+ if line.startswith("## "):
54
+ break
55
+ character_lines.append(line)
56
+
57
+ if character_lines:
58
+ # Extract key information: appearance, personality, clothing
59
+ prompt_parts = []
60
+
61
+ # Extract appearance
62
+ for line in character_lines:
63
+ if "外观" in line or "外貌" in line or "Appearance" in line:
64
+ prompt_parts.append(line.split(":", 1)[-1].strip())
65
+
66
+ if "服装" in line or "Clothing" in line:
67
+ prompt_parts.append(line.split(":", 1)[-1].strip())
68
+
69
+ return ", ".join(prompt_parts) if prompt_parts else ""
70
+
71
+ return ""
72
+
73
+
74
+ def get_world_prompt(spec_dir: Path) -> str:
75
+ """Generate world prompt for Seedance."""
76
+ world_file = spec_dir / "story" / "world.md"
77
+ if not world_file.exists():
78
+ return ""
79
+
80
+ content = read_file(world_file)
81
+
82
+ # Extract style keywords
83
+ keywords = []
84
+
85
+ # Look for style/tone keywords
86
+ for line in content.split("\n"):
87
+ if "风格" in line or "Style" in line or "视觉" in line or "Visual" in line:
88
+ # Extract keywords after colon
89
+ if ":" in line:
90
+ keywords.append(line.split(":", 1)[-1].strip())
91
+
92
+ return ", ".join(keywords)[:200] if keywords else "cinematic, high quality"
93
+
94
+
95
+ def parse_scene_file(scene_path: Path) -> dict:
96
+ """Parse scene file and extract Seedance-relevant content."""
97
+ content = read_file(scene_path)
98
+
99
+ if not content:
100
+ return {}
101
+
102
+ scene_data = {
103
+ "content": content,
104
+ "has_seedance_format": False,
105
+ }
106
+
107
+ # Check for Seedance 2.0 format (六要素)
108
+ required_elements = ["主体描述", "动作", "环境", "镜头", "音频", "风格"]
109
+ if any(elem in content for elem in required_elements):
110
+ scene_data["has_seedance_format"] = True
111
+
112
+ return scene_data
113
+
114
+
115
+ def generate_seedance_prompt(
116
+ scene_content: str,
117
+ character_prompts: dict,
118
+ world_prompt: str,
119
+ scene_name: str,
120
+ previous_context: str = "",
121
+ ) -> str:
122
+ """
123
+ Generate a clean, copy-paste ready prompt for Seedance.
124
+
125
+ Format: Pure text, no markdown, ready for video generation.
126
+ """
127
+
128
+ # Extract key information from scene content
129
+ lines = scene_content.split("\n")
130
+
131
+ output = []
132
+
133
+ # Scene header
134
+ output.append(f"=== {scene_name} ===")
135
+ output.append("")
136
+
137
+ # Character prompts
138
+ if character_prompts:
139
+ output.append("[CHARACTERS]")
140
+ for name, prompt in character_prompts.items():
141
+ if prompt:
142
+ output.append(f"{name}: {prompt}")
143
+ output.append("")
144
+
145
+ # Environment
146
+ output.append("[ENVIRONMENT]")
147
+ # Extract environment description
148
+ for line in lines:
149
+ if "环境" in line or "场景" in line:
150
+ env_text = line.split(":", 1)[-1].strip() if ":" in line else line
151
+ if env_text:
152
+ output.append(env_text)
153
+ break
154
+ output.append("")
155
+
156
+ # Previous context
157
+ if previous_context:
158
+ output.append("[PREVIOUS CONTEXT]")
159
+ output.append(previous_context[:200])
160
+ output.append("")
161
+
162
+ # Main content - extract the actual scene description
163
+ output.append("[SCENE]")
164
+
165
+ # Extract main scene content (skip headers and metadata)
166
+ in_main_content = False
167
+ for line in lines:
168
+ # Skip metadata lines
169
+ if any(marker in line for marker in ["#", "##", "---", "**", "日期", "时间", "时长"]):
170
+ continue
171
+
172
+ # Skip empty lines at start
173
+ if not in_main_content and not line.strip():
174
+ continue
175
+
176
+ # Start main content
177
+ if line.strip() and not in_main_content:
178
+ in_main_content = True
179
+
180
+ if in_main_content:
181
+ # Clean the line - remove markdown
182
+ cleaned_line = line.strip()
183
+ cleaned_line = cleaned_line.replace("**", "").replace("*", "")
184
+ cleaned_line = cleaned_line.replace("[", "").replace("]", "")
185
+
186
+ if cleaned_line:
187
+ output.append(cleaned_line)
188
+
189
+ output.append("")
190
+
191
+ # Style prompt
192
+ if world_prompt:
193
+ output.append("[STYLE]")
194
+ output.append(world_prompt)
195
+
196
+ # Return as pure text
197
+ return "\n".join(output)
198
+
199
+
200
+ def generate_simple_prompt(scene_content: str, scene_name: str) -> str:
201
+ """
202
+ Generate a simple, minimal prompt for quick copy.
203
+ Just the essential scene description.
204
+ """
205
+
206
+ lines = scene_content.split("\n")
207
+ output = []
208
+
209
+ output.append(f"Scene: {scene_name}")
210
+ output.append("")
211
+
212
+ # Extract just the dialogue and action
213
+ for line in lines:
214
+ # Skip headers and metadata
215
+ if line.startswith("#") or line.startswith("##"):
216
+ continue
217
+ if "日期" in line or "时间" in line or "时长" in line:
218
+ continue
219
+ if "主体描述" in line or "动作" in line:
220
+ continue
221
+
222
+ # Clean and add
223
+ cleaned = line.strip().replace("**", "").replace("*", "")
224
+ if cleaned:
225
+ output.append(cleaned)
226
+
227
+ return "\n".join(output)
228
+
229
+
230
+ def find_episodes(tasks_dir: Path) -> list:
231
+ """Find all episode directories."""
232
+ episodes = []
233
+
234
+ if not tasks_dir.exists():
235
+ return episodes
236
+
237
+ for item in tasks_dir.iterdir():
238
+ if item.is_dir() and "EP" in item.name.upper():
239
+ episodes.append((item.name, item))
240
+
241
+ # Sort by episode number
242
+ episodes.sort(key=lambda x: x[0])
243
+ return episodes
244
+
245
+
246
+ def find_scenes(episode_dir: Path) -> list:
247
+ """Find all scene files in an episode directory."""
248
+ scenes = []
249
+
250
+ if not episode_dir.exists():
251
+ return scenes
252
+
253
+ for item in episode_dir.iterdir():
254
+ if item.is_file() and (item.suffix == ".md" or item.suffix == ".txt"):
255
+ if "task.json" in item.name or "prd" in item.name:
256
+ continue
257
+ scenes.append(item)
258
+
259
+ scenes.sort(key=lambda x: x.name)
260
+ return scenes
261
+
262
+
263
+ def export_episode(
264
+ episode_name: str,
265
+ episode_dir: Path,
266
+ spec_dir: Path,
267
+ output_dir: Path,
268
+ format_type: str = "seedance",
269
+ ) -> list:
270
+ """Export a single episode."""
271
+
272
+ # Get character and world prompts
273
+ world_prompt = get_world_prompt(spec_dir)
274
+
275
+ # Find scenes
276
+ scenes = find_scenes(episode_dir)
277
+
278
+ output_files = []
279
+
280
+ for scene_file in scenes:
281
+ scene_name = scene_file.stem
282
+ content = read_file(scene_file)
283
+
284
+ # Get character prompts for this scene (simplified - use all characters)
285
+ character_prompts = {}
286
+ character_file = spec_dir / "story" / "character.md"
287
+ if character_file.exists():
288
+ char_content = read_file(character_file)
289
+ # Extract character names from ## headers
290
+ for line in char_content.split("\n"):
291
+ if line.startswith("## ") and not line.startswith("###"):
292
+ char_name = line.replace("##", "").strip()
293
+ # Generate prompt for this character
294
+ char_prompt = get_character_prompt(char_name, spec_dir)
295
+ if char_prompt:
296
+ character_prompts[char_name] = char_prompt
297
+
298
+ # Generate prompt based on format
299
+ if format_type == "simple":
300
+ prompt = generate_simple_prompt(content, scene_name)
301
+ else:
302
+ prompt = generate_seedance_prompt(
303
+ content,
304
+ character_prompts,
305
+ world_prompt,
306
+ scene_name,
307
+ )
308
+
309
+ # Write to output directory
310
+ output_file = output_dir / f"{episode_name}_{scene_name}.txt"
311
+ output_file.write_text(prompt, encoding="utf-8")
312
+ output_files.append(output_file)
313
+
314
+ return output_files
315
+
316
+
317
+ def main():
318
+ parser = argparse.ArgumentParser(
319
+ description="Export script for Seedance video generation"
320
+ )
321
+ parser.add_argument(
322
+ "--ep",
323
+ type=str,
324
+ help="Episode number(s). Examples: 1, 1-3, all",
325
+ )
326
+ parser.add_argument(
327
+ "--scene",
328
+ type=int,
329
+ help="Scene number within episode",
330
+ )
331
+ parser.add_argument(
332
+ "--format",
333
+ type=str,
334
+ default="seedance",
335
+ choices=["seedance", "simple"],
336
+ help="Export format: seedance (full) or simple (minimal)",
337
+ )
338
+ parser.add_argument(
339
+ "--output",
340
+ type=str,
341
+ default="export",
342
+ help="Output directory name",
343
+ )
344
+ parser.add_argument(
345
+ "--open",
346
+ action="store_true",
347
+ help="Open output directory after export",
348
+ )
349
+
350
+ args = parser.parse_args()
351
+
352
+ # Get project paths
353
+ project_root = get_project_root()
354
+ tasks_dir = get_tasks_dir(project_root)
355
+ spec_dir = project_root / ".aim-studio" / "spec"
356
+
357
+ # Check if story project
358
+ if not (spec_dir / "story").exists():
359
+ print("Error: This is not a story project. No spec/story/ directory found.")
360
+ sys.exit(1)
361
+
362
+ # Create output directory
363
+ output_dir = project_root / args.output
364
+ output_dir.mkdir(exist_ok=True)
365
+
366
+ print(f"Exporting to: {output_dir}")
367
+ print(f"Format: {args.format}")
368
+ print("")
369
+
370
+ exported_files = []
371
+
372
+ # Determine which episodes to export
373
+ if args.ep == "all":
374
+ episodes = find_episodes(tasks_dir)
375
+ for ep_name, ep_dir in episodes:
376
+ print(f"Exporting {ep_name}...")
377
+ files = export_episode(ep_name, ep_dir, spec_dir, output_dir, args.format)
378
+ exported_files.extend(files)
379
+ elif "-" in str(args.ep):
380
+ # Range like 1-3
381
+ start, end = map(int, args.ep.split("-"))
382
+ for ep_num in range(start, end + 1):
383
+ ep_name = f"EP{ep_num:02d}"
384
+ ep_dir = tasks_dir / ep_name
385
+ if ep_dir.exists():
386
+ print(f"Exporting {ep_name}...")
387
+ files = export_episode(ep_name, ep_dir, spec_dir, output_dir, args.format)
388
+ exported_files.extend(files)
389
+ elif args.ep:
390
+ # Single episode
391
+ ep_num = int(args.ep)
392
+ ep_name = f"EP{ep_num:02d}"
393
+ ep_dir = tasks_dir / ep_name
394
+
395
+ if ep_dir.exists():
396
+ print(f"Exporting {ep_name}...")
397
+ exported_files = export_episode(ep_name, ep_dir, spec_dir, output_dir, args.format)
398
+ else:
399
+ print(f"Error: Episode {ep_name} not found in {tasks_dir}")
400
+ sys.exit(1)
401
+ else:
402
+ print("Error: Please specify --ep or --all")
403
+ parser.print_help()
404
+ sys.exit(1)
405
+
406
+ print("")
407
+ print(f"Exported {len(exported_files)} files:")
408
+ for f in exported_files:
409
+ print(f" - {f.relative_to(project_root)}")
410
+
411
+ # Optionally open output directory
412
+ if args.open:
413
+ import subprocess
414
+
415
+ if sys.platform == "win32":
416
+ os.startfile(output_dir)
417
+ elif sys.platform == "darwin":
418
+ subprocess.run(["open", str(output_dir)])
419
+ else:
420
+ subprocess.run(["xdg-open", str(output_dir)])
421
+
422
+ print("")
423
+ print("Done! Files are ready for Seedance.")
424
+
425
+
426
+ if __name__ == "__main__":
427
+ main()
@@ -1,187 +1,161 @@
1
1
  ---
2
2
  name: export
3
- description: 导出剧本用于AI视频生成
3
+ description: 导出剧本用于AI视频生成(纯文本格式)
4
4
  ---
5
5
 
6
6
  # 导出剧本
7
7
 
8
- 将剧本导出为可直接粘贴到 AI 视频生成工具(如 Seedance)的格式。
8
+ 将剧本导出为可直接粘贴到 AI 视频生成工具(如 Seedance)的**纯文本格式**。
9
9
 
10
- ## 导出流程
10
+ ---
11
+
12
+ ## 核心功能
13
+
14
+ 本命令生成**不带任何 Markdown 符号**的纯文本文件,可直接复制粘贴到 Seedance 的视频生成输入框。
15
+
16
+ ---
11
17
 
12
- ### 1. 选择导出范围
18
+ ## 使用方法
19
+
20
+ ### 基本用法
13
21
 
14
22
  ```bash
15
- # 导出单集
16
- /aim:export --ep 1
23
+ # 导出第1集
24
+ python3 .aim-studio/scripts/export.py --ep 1
17
25
 
18
26
  # 导出多集
19
- /aim:export --ep 1-5
27
+ python3 .aim-studio/scripts/export.py --ep 1-3
28
+
29
+ # 导出全部集数
30
+ python3 .aim-studio/scripts/export.py --all
20
31
 
21
- # 导出全部
22
- /aim:export --all
32
+ # 导出后打开文件夹
33
+ python3 .aim-studio/scripts/export.py --ep 1 --open
23
34
  ```
24
35
 
25
- ### 2. 选择导出格式
36
+ ### 导出格式
26
37
 
27
- | 格式 | 用途 | 说明 |
38
+ | 格式 | 说明 | 用途 |
28
39
  |------|------|------|
29
- | `seedance` | Seedance Web 端 | 单场次独立 prompt,包含上下文 |
30
- | `batch` | 批量生成 | 所有场次合并,适合批量处理 |
31
- | `review` | 预览检查 | 带注释格式,便于检查 |
32
- | `text` | 纯文本发布 | 去除备注,统一标点 |
40
+ | `seedance` | 完整格式,包含角色、环境、上下文(默认) | 推荐用于 Seedance |
41
+ | `simple` | 极简格式,只有场景描述和对话 | 快速复制 |
33
42
 
34
- ### 3. 导出内容结构
43
+ ```bash
44
+ # 使用简单格式
45
+ python3 .aim-studio/scripts/export.py --ep 1 --format simple
46
+ ```
35
47
 
36
- 每次导出会生成以下文件:
48
+ ---
49
+
50
+ ## 输出文件
51
+
52
+ 导出会生成纯文本文件到 `export/` 目录:
37
53
 
38
54
  ```
39
55
  export/
40
- ├── EP01/
41
- ├── scene_01.txt # 场次1 - 可直接粘贴
42
- ├── scene_02.txt # 场次2 - 可直接粘贴
43
- │ ├── context.txt # 本集上下文摘要
44
- │ └── characters.txt # 本集角色参考
45
- ├── EP02/
46
- │ └── ...
47
- └── global_context.txt # 全局设定(角色、世界观)
56
+ ├── EP01_场景1.txt # 可直接粘贴
57
+ ├── EP01_场景2.txt # 可直接粘贴
58
+ ├── EP02_场景1.txt
59
+ └── ...
48
60
  ```
49
61
 
50
62
  ---
51
63
 
52
- ## Seedance 导出格式
53
-
54
- ### 单场次 Prompt 模板
64
+ ## Seedance 纯文本格式
55
65
 
56
- 每个场次文件包含完整的上下文信息,可直接粘贴:
66
+ 导出的文件内容示例(无任何 Markdown 符号):
57
67
 
58
68
  ```
59
- 【角色设定】
60
- [角色名]:[外貌描述],[性格关键词]
61
- (如有多位角色,逐一列出)
69
+ === 场景1: 青云峰主殿 ===
62
70
 
63
- 【场景设定】
64
- [场景名称]:[环境描述],[氛围]
71
+ [CHARACTERS]
72
+ 沈安在: 白衣中年男子, 两鬓霜白, 面容俊俏
73
+ 慕容天: 少年身形, 目光坚定
65
74
 
66
- 【前情提要】(如适用)
67
- [上一场次的关键事件,1-2句话]
75
+ [ENVIRONMENT]
76
+ 青云峰主殿: 破旧大殿, 阳光洒落, 萧条冷清
68
77
 
69
- 【本场次剧本】
70
- 场次 X:[场景] - [时间] - [气氛] - [时长]
78
+ [PREVIOUS CONTEXT]
79
+ 慕容天决定下山离开
71
80
 
72
- [画面描述]
81
+ [SCENE]
82
+ 场次 1: 青云峰主殿内 - 清晨 - 萧条落寞 - 30秒
73
83
 
74
- [角色名]:(情绪) 台词
84
+ 白衣中年沈安在瘫坐在太师椅上,神情苦涩。
75
85
 
76
- [画面描述]
86
+ 慕容天:(低沉) 师父,弟子不孝,今日便要下山!
77
87
 
78
- ...
79
-
80
- 【视觉风格】
81
- [风格关键词,如:xianxia, fantasy, cinematic lighting]
82
- ```
83
-
84
- ### 示例输出
88
+ 沈安在听到声音,却懒得出门。镜头推进他的脸,苦涩中带着自嘲。
85
89
 
90
+ [STYLE]
91
+ xianxia, chinese fantasy, cinematic lighting, melancholic atmosphere
86
92
  ```
87
- 【角色设定】
88
- 沈安在:白衣中年男子,两鬓霜白,面容俊俏,气质高深莫测。性格:腹黑、护短、爱演。
89
- 慕容天:少年身形,目光从落寞到坚定。性格:勤奋、尊师重道、意志坚定。
90
93
 
91
- 【场景设定】
92
- 青云峰主殿:破旧的大殿,阳光透过残破窗棂洒落,萧条冷清的氛围。
94
+ ---
93
95
 
94
- 【前情提要】
95
- 慕容天决定下山离开,沈安在内心吐槽自己的穿越遭遇。
96
+ ## 快速使用流程
96
97
 
97
- 【本场次剧本】
98
- 场次 1:青云峰主殿内 - 清晨 - 萧条落寞 - 30秒
98
+ ### 步骤 1:导出
99
99
 
100
- 白衣中年沈安在瘫坐在太师椅上,神情苦涩。殿外,少年慕容天背着大包小包,站在门口。
100
+ ```bash
101
+ python3 .aim-studio/scripts/export.py --ep 1 --open
102
+ ```
101
103
 
102
- 慕容天:(低沉) 师父,弟子不孝,今日便要下山继承家业,还望师父珍重!
104
+ ### 步骤 2:复制
103
105
 
104
- 沈安在听到声音,却懒得出门。镜头推进他的脸,苦涩中带着自嘲。
106
+ 打开 `export/` 文件夹,选择对应场次的 `.txt` 文件,**直接全选复制**。
105
107
 
106
- 沈安在:(内心独白) 老天啊,你是让我来这边受折磨的吗?
108
+ ### 步骤 3:粘贴到 Seedance
107
109
 
108
- 【视觉风格】
109
- xianxia, chinese fantasy, cinematic lighting, melancholic atmosphere
110
- ```
110
+ 将复制的内容**直接粘贴**到 Seedance 的 prompt 输入框中,点击生成。
111
111
 
112
112
  ---
113
113
 
114
- ## 保持一致性的策略
114
+ ## 保持一致性的技巧
115
115
 
116
- ### 1. 全局上下文文件
116
+ ### 1. 角色描述一致性
117
117
 
118
- `global_context.txt` 包含:
119
- - 核心角色设定(外貌、性格、说话风格)
120
- - 世界观设定(力量体系、地理环境)
121
- - 视觉风格关键词
118
+ 每次导出时,脚本会自动从 `spec/story/character.md` 提取角色信息。确保角色设定文件中的描述保持一致。
122
119
 
123
- **使用方式**:
124
- - 首次使用时,先粘贴全局上下文
125
- - 或将全局上下文保存为 Seedance 的"项目设定"
120
+ ### 2. 视觉风格关键词
126
121
 
127
- ### 2. 集间上下文文件
122
+ 在世界观文件 `spec/story/world.md` 中定义统一的视觉风格关键词,导出会自动包含这些关键词。
128
123
 
129
- 每集的 `context.txt` 包含:
130
- - 本集角色状态快照
131
- - 本集关键事件摘要
132
- - 上一集结尾状态
124
+ ### 3. 上下文衔接
133
125
 
134
- ### 3. 角色参考文件
135
-
136
- 每集的 `characters.txt` 包含:
137
- - 本集出场角色的完整设定
138
- - SD Prompt 片段
139
- - 服装变化记录
126
+ 每集导出时会包含 `[PREVIOUS CONTEXT]` 部分,帮助 Seedance 理解剧情连续性。
140
127
 
141
128
  ---
142
129
 
143
- ## 执行方式
130
+ ## 常见问题
144
131
 
145
- ```bash
146
- # 交互式导出
147
- /aim:export
132
+ ### Q: 导出文件有乱码?
148
133
 
149
- # 快速导出(使用默认设置)
150
- /aim:export --ep 1 --format seedance
134
+ 确保使用 `--format seedance`(默认)格式,这是为 Seedance 优化的纯文本格式。
151
135
 
152
- # 导出纯文本格式
153
- /aim:export --ep 1 --format text
136
+ ### Q: 如何只导出一个场景?
154
137
 
155
- # 导出并打开目录
156
- /aim:export --ep 1 --open
157
- ```
158
-
159
- ---
138
+ 目前脚本按集导出。如果需要单场景,可以手动编辑导出的文件。
160
139
 
161
- ## 导出后检查清单
140
+ ### Q: 导出的内容太长?
162
141
 
163
- - [ ] 每个场次文件是否可独立使用?
164
- - [ ] 角色设定是否完整?
165
- - [ ] 前情提要是否准确?
166
- - [ ] 视觉风格是否一致?
167
- - [ ] 时长是否符合配置?
142
+ Seedance prompt 长度有限制。可以使用 `--format simple` 获得更简洁的版本。
168
143
 
169
144
  ---
170
145
 
171
- ## 注意事项
146
+ ## 与其他命令配合
172
147
 
173
- 1. **首次使用**:建议先粘贴 `global_context.txt` 到 Seedance,建立项目基准
174
- 2. **连续剧**:每集开始前,先粘贴上一集的 `context.txt`
175
- 3. **角色一致性**:使用相同的角色描述和 SD Prompt 片段
176
- 4. **时长控制**:根据视频格式配置,调整每场次的字数
148
+ ```
149
+ 1. /aim:story → 创作剧本
150
+ 2. /aim:check-story → 检查剧情一致性
151
+ 3. /aim:export --ep 1 → 导出第1集
152
+ 4. 复制到 Seedance → 生成视频
153
+ ```
177
154
 
178
155
  ---
179
156
 
180
- ## 纯文本导出(传统格式)
181
-
182
- 如需导出为传统发布格式,直接读取当前剧本并整理为适合发布的格式:
183
- - 去除构建过程中的备注
184
- - 统一标点符号
185
- - 优化段落间距
157
+ ## 注意事项
186
158
 
187
- 输出目标:纯文本 / 长图文案 / 剧本杀格式(请根据用户需求调整)
159
+ 1. **纯文本格式**:导出的文件不包含任何 `#`、`*`、`[]` Markdown 符号
160
+ 2. **字符编码**:文件使用 UTF-8 编码,确保 Seedance 能正确识别
161
+ 3. **首次使用**:建议先导出单集测试,确认格式符合预期