364 lines
10 KiB
Markdown
364 lines
10 KiB
Markdown
|
|
# Phase 0 · 执行手册 · 一步步跑通「一句话→分镜图片」
|
|||
|
|
|
|||
|
|
## 🎯 目标
|
|||
|
|
|
|||
|
|
> 在CVM服务器上跑通最小闭环:**输入一句话 → 光湖编排层自动拆剧本+分镜 → 调用免费API生成图片 → 输出一组分镜图片**
|
|||
|
|
不需要训练模型。不需要租GPU。用现有服务器 + 免费API,先证明编排核心能跑。
|
|||
|
|
>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 0 · 登录服务器 · 确认环境
|
|||
|
|
|
|||
|
|
先SSH登录CVM服务器,确认基础环境:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 登录服务器(把IP换成你的CVM公网IP)
|
|||
|
|
ssh root@你的CVM公网IP
|
|||
|
|
|
|||
|
|
# 确认操作系统
|
|||
|
|
cat /etc/os-release
|
|||
|
|
|
|||
|
|
# 确认Python版本(需要3.8+)
|
|||
|
|
python3 --version
|
|||
|
|
|
|||
|
|
# 如果没有Python3,安装它:
|
|||
|
|
# Ubuntu/Debian:
|
|||
|
|
sudo apt update && sudo apt install -y python3 python3-pip python3-venv
|
|||
|
|
# CentOS:
|
|||
|
|
# sudo yum install -y python3 python3-pip
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<aside>
|
|||
|
|
📋
|
|||
|
|
|
|||
|
|
**妈妈操作:** 把上面的命令一条条复制粘贴到终端,把每条的输出结果告诉我,我来判断环境是否OK。
|
|||
|
|
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 1 · 创建光湖项目目录
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 创建项目根目录
|
|||
|
|
mkdir -p /opt/guanghu
|
|||
|
|
cd /opt/guanghu
|
|||
|
|
|
|||
|
|
# 创建子目录
|
|||
|
|
mkdir -p core # 编排核心代码
|
|||
|
|
mkdir -p output # 生成结果输出
|
|||
|
|
mkdir -p config # 配置文件
|
|||
|
|
mkdir -p logs # 日志
|
|||
|
|
|
|||
|
|
# 创建Python虚拟环境
|
|||
|
|
python3 -m venv venv
|
|||
|
|
source venv/bin/activate
|
|||
|
|
|
|||
|
|
# 安装基础依赖
|
|||
|
|
pip install requests pillow
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 2 · 注册免费API · 获取密钥
|
|||
|
|
|
|||
|
|
我们需要两个免费API:
|
|||
|
|
|
|||
|
|
- **语言模型API**(拆剧本+分镜)→ 用硅基流动(SiliconFlow)的免费DeepSeek
|
|||
|
|
- **图片生成API**(画分镜图片)→ 用硅基流动的免费FLUX
|
|||
|
|
|
|||
|
|
### 2.1 注册硅基流动
|
|||
|
|
|
|||
|
|
1. 打开 [siliconflow.cn](http://siliconflow.cn)
|
|||
|
|
2. 注册账号(免费)
|
|||
|
|
3. 进入控制台 → API密钥 → 创建一个密钥
|
|||
|
|
4. 复制密钥(长得像 `sk-xxxxxxxxxxxxxxxx`)
|
|||
|
|
|
|||
|
|
### 2.2 写入配置文件
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 把你的API密钥写入配置文件(把sk-xxx换成你的真实密钥)
|
|||
|
|
cat > /opt/guanghu/config/api_keys.py << 'EOF'
|
|||
|
|
SILICONFLOW_API_KEY = "sk-你的硅基流动密钥"
|
|||
|
|
EOF
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<aside>
|
|||
|
|
💡
|
|||
|
|
|
|||
|
|
**为什么用硅基流动?**
|
|||
|
|
- 国内访问快,不用翻墙
|
|||
|
|
- 免费额度足够开发调试
|
|||
|
|
- 同时提供DeepSeek(语言)和FLUX(图片)两个模型的API
|
|||
|
|
- 后面随时可以换成本地部署,编排层不用改
|
|||
|
|
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 3 · 编排核心v0.1 · 光湖的第一个大脑
|
|||
|
|
|
|||
|
|
这是光湖编排层的第一个版本——最简但完整的编排逻辑:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cat > /opt/guanghu/core/guanghu_brain.py << 'PYEOF'
|
|||
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
光湖编排核心 v0.1 · Phase 0 最小闭环
|
|||
|
|
一句话 → 拆剧本 → 拆分镜 → 生成图片 → 输出
|
|||
|
|
"""
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
import requests
|
|||
|
|
import time
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# === 配置 ===
|
|||
|
|
sys.path.insert(0, "/opt/guanghu/config")
|
|||
|
|
from api_keys import SILICONFLOW_API_KEY
|
|||
|
|
|
|||
|
|
API_BASE = "https://api.siliconflow.cn/v1"
|
|||
|
|
LLM_MODEL = "deepseek-ai/DeepSeek-V3" # 免费语言模型
|
|||
|
|
IMAGE_MODEL = "black-forest-labs/FLUX.1-schnell" # 免费图片模型
|
|||
|
|
OUTPUT_DIR = Path("/opt/guanghu/output")
|
|||
|
|
|
|||
|
|
HEADERS = {
|
|||
|
|
"Authorization": f"Bearer {SILICONFLOW_API_KEY}",
|
|||
|
|
"Content-Type": "application/json"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# === 第一层:剧本引擎 ===
|
|||
|
|
def generate_script(user_input: str) -> dict:
|
|||
|
|
"""用户一句话 → 完整剧本(标题+场景列表)"""
|
|||
|
|
print("\n🧠 [编排层] 正在理解你的意图,生成剧本...")
|
|||
|
|
|
|||
|
|
prompt = f"""你是一个专业的短剧编剧。用户给你一句话,你需要生成一个4-6个场景的短剧剧本。
|
|||
|
|
|
|||
|
|
用户输入:{user_input}
|
|||
|
|
|
|||
|
|
请严格按以下JSON格式输出(不要输出其他内容):
|
|||
|
|
{{
|
|||
|
|
"title": "短剧标题",
|
|||
|
|
"style": "画面风格描述(如:2.5D偏写实韩系精致风格)",
|
|||
|
|
"scenes": [
|
|||
|
|
|
|||
|
|
"scene_id": 1,
|
|||
|
|
"description": "这个场景发生了什么(一句话)",
|
|||
|
|
"image_prompt": "详细的英文画面描述,用于AI绘图。包含人物外观、表情、动作、场景、光线、构图。风格统一为2.5D semi-realistic Korean drama style。",
|
|||
|
|
"dialogue": "这个场景的台词(中文)"
|
|||
|
|
|
|||
|
|
]
|
|||
|
|
}}"""
|
|||
|
|
|
|||
|
|
resp = requests.post(f"{API_BASE}/chat/completions", headers=HEADERS, json={
|
|||
|
|
"model": LLM_MODEL,
|
|||
|
|
"messages": [{"role": "user", "content": prompt}],
|
|||
|
|
"temperature": 0.7,
|
|||
|
|
"max_tokens": 2000
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
result = resp.json()["choices"][0]["message"]["content"]
|
|||
|
|
|
|||
|
|
# 提取JSON(处理可能的markdown代码块包裹)
|
|||
|
|
if "```json" in result:
|
|||
|
|
result = result.split("```json")[1].split("```")[0]
|
|||
|
|
elif "```" in result:
|
|||
|
|
result = result.split("```")[1].split("```")[0]
|
|||
|
|
|
|||
|
|
script = json.loads(result.strip())
|
|||
|
|
print(f" ✅ 剧本生成完成:《{script['title']}》共 {len(script['scenes'])} 个场景")
|
|||
|
|
return script
|
|||
|
|
|
|||
|
|
# === 第二层:图片生成引擎 ===
|
|||
|
|
def generate_image(prompt: str, scene_id: int, output_dir: Path) -> str:
|
|||
|
|
"""根据画面描述生成图片"""
|
|||
|
|
print(f" 🎨 [图片引擎] 正在生成场景 {scene_id} 的画面...")
|
|||
|
|
|
|||
|
|
resp = requests.post(f"{API_BASE}/images/generations", headers=HEADERS, json={
|
|||
|
|
"model": IMAGE_MODEL,
|
|||
|
|
"prompt": prompt,
|
|||
|
|
"image_size": "1024x576", # 16:9 横版
|
|||
|
|
"num_inference_steps": 4 # FLUX.1-schnell 用4步就够
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
data = resp.json()
|
|||
|
|
image_url = data["images"][0]["url"]
|
|||
|
|
|
|||
|
|
# 下载图片
|
|||
|
|
img_data = requests.get(image_url).content
|
|||
|
|
img_path = output_dir / f"scene_{scene_id:02d}.png"
|
|||
|
|
img_path.write_bytes(img_data)
|
|||
|
|
|
|||
|
|
print(f" ✅ 场景 {scene_id} 图片已保存: {img_path}")
|
|||
|
|
return str(img_path)
|
|||
|
|
|
|||
|
|
# === 第三层:编排主控 ===
|
|||
|
|
def run_pipeline(user_input: str):
|
|||
|
|
"""光湖编排主流程:一句话 → 分镜图片"""
|
|||
|
|
print("="*60)
|
|||
|
|
print("🌊 光湖编排核心 v0.1 · Phase 0")
|
|||
|
|
print(f"📝 用户输入:{user_input}")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
# 创建本次输出目录
|
|||
|
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
|||
|
|
run_dir = OUTPUT_DIR / f"run_{timestamp}"
|
|||
|
|
run_dir.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|
|||
|
|
# Step 1: 生成剧本
|
|||
|
|
script = generate_script(user_input)
|
|||
|
|
|
|||
|
|
# 保存剧本
|
|||
|
|
script_path = run_dir / "script.json"
|
|||
|
|
script_path.write_text(json.dumps(script, ensure_ascii=False, indent=2))
|
|||
|
|
print(f"\n📄 剧本已保存: {script_path}")
|
|||
|
|
|
|||
|
|
# 打印剧本
|
|||
|
|
print(f"\n📖 《{script['title']}》")
|
|||
|
|
print(f" 风格:{script.get('style', '2.5D韩系精致风格')}")
|
|||
|
|
for scene in script["scenes"]:
|
|||
|
|
print(f" 场景{scene['scene_id']}: {scene['description']}")
|
|||
|
|
if scene.get("dialogue"):
|
|||
|
|
print(f" 💬 {scene['dialogue']}")
|
|||
|
|
|
|||
|
|
# Step 2: 逐场景生成图片
|
|||
|
|
print(f"\n🎬 开始生成 {len(script['scenes'])} 个场景的图片...\n")
|
|||
|
|
|
|||
|
|
image_paths = []
|
|||
|
|
for scene in script["scenes"]:
|
|||
|
|
img_path = generate_image(
|
|||
|
|
prompt=scene["image_prompt"],
|
|||
|
|
scene_id=scene["scene_id"],
|
|||
|
|
output_dir=run_dir
|
|||
|
|
)
|
|||
|
|
image_paths.append(img_path)
|
|||
|
|
time.sleep(1) # 避免API限流
|
|||
|
|
|
|||
|
|
# 完成
|
|||
|
|
print("\n" + "="*60)
|
|||
|
|
print("🎉 光湖编排完成!")
|
|||
|
|
print(f"📁 所有文件保存在: {run_dir}")
|
|||
|
|
print(f" 📄 剧本: script.json")
|
|||
|
|
for i, path in enumerate(image_paths, 1):
|
|||
|
|
print(f" 🖼️ 场景{i}: {Path(path).name}")
|
|||
|
|
print("="*60)
|
|||
|
|
|
|||
|
|
return {"script": script, "images": image_paths, "output_dir": str(run_dir)}
|
|||
|
|
|
|||
|
|
# === 入口 ===
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
if len(sys.argv) > 1:
|
|||
|
|
user_input = " ".join(sys.argv[1:])
|
|||
|
|
else:
|
|||
|
|
user_input = input("\n🌊 光湖 · 说一句话,开始创作:")
|
|||
|
|
|
|||
|
|
run_pipeline(user_input)
|
|||
|
|
PYEOF
|
|||
|
|
|
|||
|
|
chmod +x /opt/guanghu/core/guanghu_brain.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<aside>
|
|||
|
|
🧠
|
|||
|
|
|
|||
|
|
**这就是光湖的第一个大脑。** 虽然只有100多行代码,但它已经具备了编排层的核心逻辑:
|
|||
|
|
- 🧠 理解用户意图(调LLM拆剧本)
|
|||
|
|
- 🎬 拆分镜(LLM自动分场景+生成画面描述)
|
|||
|
|
- 🎨 调引擎生图(调FLUX生成每个分镜的画面)
|
|||
|
|
- 📁 组装输出(所有结果保存在一个目录)
|
|||
|
|
|
|||
|
|
后面所有的升级(加视频、加语音、加质量校验)都是在这个骨架上加东西。骨架不变。
|
|||
|
|
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 4 · 跑起来!
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 确保在虚拟环境里
|
|||
|
|
cd /opt/guanghu
|
|||
|
|
source venv/bin/activate
|
|||
|
|
|
|||
|
|
# 第一次运行!输入一句话试试
|
|||
|
|
python3 core/guanghu_brain.py "一个穿白裙子的女孩在樱花树下回头微笑"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果一切正常,你会看到:
|
|||
|
|
|
|||
|
|
1. 🧠 编排层生成剧本(4-6个场景)
|
|||
|
|
2. 🎨 逐个场景生成图片
|
|||
|
|
3. 📁 所有文件保存在 `/opt/guanghu/output/run_时间戳/` 目录
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 查看生成的文件
|
|||
|
|
ls -la /opt/guanghu/output/run_*/
|
|||
|
|
|
|||
|
|
# 查看剧本内容
|
|||
|
|
cat /opt/guanghu/output/run_*/script.json | python3 -m json.tool
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
<aside>
|
|||
|
|
🎯
|
|||
|
|
|
|||
|
|
**Phase 0 通过标准:**
|
|||
|
|
输入一句话 → 编排层自动拆出4-6个分镜 → 每个分镜生成一张图片 → 保存到output目录。
|
|||
|
|
|
|||
|
|
**看到图片就算成功!** 哪怕图片不够好看也没关系,那是后面优化的事。Phase 0只需要证明:编排核心能跑通。
|
|||
|
|
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Step 5 · 把图片下载到本地看
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 在你的本地电脑(不是服务器)打开终端,把图片下载下来
|
|||
|
|
# 把IP和时间戳换成你的
|
|||
|
|
scp -r root@你的CVM公网IP:/opt/guanghu/output/run_* ~/Desktop/光湖输出/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
或者如果妈妈不方便用scp,可以在服务器上临时开一个HTTP服务看图:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 在服务器上(临时用,看完关掉)
|
|||
|
|
cd /opt/guanghu/output
|
|||
|
|
python3 -m http.server 8080
|
|||
|
|
# 然后浏览器打开 http://你的CVM公网IP:8080 就能看到图片了
|
|||
|
|
# 看完按 Ctrl+C 关掉
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📋 执行清单
|
|||
|
|
|
|||
|
|
- [ ] Step 0 · 登录服务器,确认Python3可用
|
|||
|
|
- [ ] Step 1 · 创建光湖项目目录 + 虚拟环境
|
|||
|
|
- [ ] Step 2 · 注册硅基流动,获取免费API密钥
|
|||
|
|
- [ ] Step 3 · 创建编排核心脚本
|
|||
|
|
- [ ] Step 4 · 运行!一句话→分镜图片
|
|||
|
|
- [ ] Step 5 · 下载图片到本地看效果
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## ⚠️ 可能遇到的问题
|
|||
|
|
|
|||
|
|
- **报错:ModuleNotFoundError: No module named 'requests'**
|
|||
|
|
|
|||
|
|
说明依赖没装好。运行:
|
|||
|
|
|
|||
|
|
`pip install requests pillow`
|
|||
|
|
|
|||
|
|
- **报错:API返回401或403**
|
|||
|
|
|
|||
|
|
说明API密钥不对。检查 `/opt/guanghu/config/api_keys.py` 里的密钥是否正确。
|
|||
|
|
|
|||
|
|
- **报错:JSON解析失败**
|
|||
|
|
|
|||
|
|
说明LLM返回的格式不太标准。再跑一次就行,或者告诉我具体报错,我帮你改脚本。
|
|||
|
|
|
|||
|
|
- **图片生成很慢**
|
|||
|
|
|
|||
|
|
正常。FLUX.1-schnell已经是最快的了(4步推理),但通过API还要排队。一张图大概10-30秒。6张图1-3分钟。
|