Picasso TikTok 🎨
Genera videos 9:16 para TikTok/Reels combinando un video fuente + avatar HeyGen + subtítulos sincronizados.
⚠️ FLUJO OBLIGATORIO — paso a paso con validación
NUNCA correr el pipeline completo de una sola vez. Siempre:
- 1. Descargar + analizar video → mostrar duración e info
- Escribir guión → mostrar a Paul, esperar OK
- Generar audio → enviar para escuchar, esperar OK
- Preguntar configuración del video (layout, música fuente) → esperar OK
- Generar avatar HeyGen
- Transcribir + corregir subtítulos contra guión original
- Componer video final
Paso 1: Descargar video
Google Drive
pip install gdown -q
gdown "https://drive.google.com/uc?id=FILE_ID&confirm=t" -O output.mp4
Si falla (permisos): pedir a Paul que comparta "cualquier persona con el link" o mande por Telegram.
TikTok / YouTube
CODEBLOCK1
Telegram (archivo adjunto)
Los archivos adjuntos llegan a INLINECODE0
Verificar
ffprobe video.mp4 2>&1 | grep -E "Duration|Video:|Audio:"
Paso 2: Guión
Reglas:
- - Español argentino rioplatense (voseo: "grabás", "actualizás", "imaginá")
- Hook fuerte en los primeros 3 segundos
- Dinámico, sin relleno
- Sin notas de dirección, solo el texto que se lee
- CTA al final (ej: "sumate a Morfeo Labs")
- Duración objetivo: igual o levemente mayor que el video fuente
Mostrar guión y esperar aprobación antes de generar audio.
Paso 3: Audio — TTS
✅ DEFAULT: ElevenLabs Paul Pro
SIEMPRE generar 3 variaciones de voz y enviar para que Paul elija antes de continuar.
CODEBLOCK3
Trucos de puntuación para controlar ritmo:
- - Frases separadas en párrafos propios → pausas naturales largas (VA)
- Guiones largos
— dentro de frases → pausa dramática mid-sentence (VB, ganador) - Todo junto sin cortes → fluido tipo documental (VC)
⚠️ IMPORTANTE:
- - Modelo:
eleven_multilingual_v2 — NUNCA eleven_v3 (cambia el acento) - Voice ID Paul Pro: INLINECODE4
- API Key: INLINECODE5
Backup: Cartesia sonic-3
CODEBLOCK4
Enviar audio para escuchar y esperar OK antes de continuar.
Paso 4: Preguntar configuración
Antes de generar avatar y componer, confirmar:
- - Layout: 60/40 (source top), 50/50, 40/60 (avatar top)
- Subtítulos: sí/no
- Audio fuente: ¿mezclar música original? Si sí, ¿a qué volumen? (típico: 30%)
- Título para primeros segundos (ej: "Esta chica no existe 👁️")
- Caption TikTok con hashtags
Paso 5: Avatar HeyGen
Subir audio a uguu.se (requerido por HeyGen)
CODEBLOCK5
Generar video
CODEBLOCK6
Poll hasta completar (~2-4 min)
CODEBLOCK7
Descargar y cropdetect
curl -sL "$AVATAR_URL" -o avatar.mp4
# Auto-detect crop (quita padding negro de HeyGen)
ffmpeg -ss 2 -i avatar.mp4 -vframes 10 -vf cropdetect=24:2:0 -f null - 2>&1 | grep crop= | tail -2
# Típico resultado: crop=432:244:0:262
Paso 6: Subtítulos — SIEMPRE contrastar con guión original
Transcribir con Whisper
CODEBLOCK9
⚠️ SIEMPRE revisar y corregir contra el guión original
Whisper comete errores frecuentes en español/rioplatense + términos técnicos:
| Whisper escribe | Correcto |
|---|
| Cling | KLING |
| Confi / Confy |
COMFY |
| Imagina | IMAGINÁ |
| Grabas | GRABÁS |
| Actualizas | ACTUALIZÁS |
| Buscas | BUSCÁS |
| Preparas | PREPARÁS |
| I A | IA |
| cualquier nombre de marca | verificar siempre |
Corregir en el .ass antes de renderizar:
CODEBLOCK10
Generar .ass
CODEBLOCK11
MarginV según layout
| Layout | Top px | Bot px | MarginV recomendado |
|---|
| 60/40 | 1152 | 768 | 720 |
| 50/50 |
960 | 960 | 880 |
| 40/60 | 768 | 1152 | ~1000 |
Parchear en el .ass:
import re
ass = re.sub(
r'(Style: Word,\S+,\d+,\S+,\S+,\S+,\S+,-?\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,[\d.]+,[\d.]+,\d+,\d+,\d+,)\d+,',
lambda m: m.group(1) + str(MARGIN_V) + ',', ass)
Paso 7: Componer video final
Splits de altura
| Layout | toph | both |
|---|
| 60/40 | 1152 | 768 |
| 50/50 |
960 | 960 |
| 40/60 | 768 | 1152 |
Filter chain base (sin mezcla de audio)
CODEBLOCK13
Con mezcla de audio (música fuente al X%)
CODEBLOCK14
⚠️ NUNCA estirar el avatar
CODEBLOCK15
Output final
- - Resolución: 1080x1920
- Codec: H.264 high profile level 4.0
- Audio: AAC 192k
- INLINECODE6
Layouts adicionales
2/3 top + 1/3 bottom (Chiqui Tapia, Claude Opus style)
top_h=1280, bot_h=640, MarginV=640
CODEBLOCK17
Video fuente que debe verse ENTERO (letterbox, sin recorte)
CODEBLOCK18
Loop de video fuente cuando el audio es más largo
CODEBLOCK19
Recorte del inicio del video fuente
# Agregar -ss SEGUNDOS antes del -i source.mp4 en el loop
ffmpeg -y -ss 1.25 -stream_loop 3 -i source.mp4 -t $AUDIO_DUR ...
B-roll generado con IA — Runway Gen-4.5
Cuando no hay video fuente real, generar B-roll con Runway Gen-4.5 via Replicate.
Variables:
- -
prompt — descripción cinematográfica del clip - INLINECODE8 — frame inicial opcional (para image-to-video)
- INLINECODE9 — segundos (default 5, máximo 10)
- INLINECODE10 — default
16:9; usar 768:1344 para 9:16 vertical
Costo: ~$0.05 por clip de 10s
CODEBLOCK21
Workflow para videos con guión largo:
- 1. Generar audio TTS primero → obtener duración total
- Dividir guión en segmentos temáticos con timestamps aproximados
- Asignar duración a cada clip de Runway (suma debe cubrir la duración total)
- Generar todos los clips en paralelo (lanzar predicciones, luego poll)
- Concatenar clips con ffmpeg, usar como source en Picasso
Checklist antes de entregar
- - [ ] Guión aprobado por Paul
- [ ] 3 variaciones de audio enviadas — Paul elige antes de continuar
- [ ] Layout confirmado por Paul
- [ ] Subtítulos corregidos contra guión original (errores de Whisper fixeados)
- [ ] Avatar sin deformación (AR mantenido)
- [ ] Audio fuente mezclado al volumen correcto (si aplica)
- [ ] Video es 1080x1920 verificado con ffprobe
Picasso TikTok 🎨
为TikTok/Reels生成9:16视频,结合源视频 + HeyGen头像 + 同步字幕。
⚠️ 强制流程 — 带验证的逐步操作
绝不要一次性运行完整管道。始终:
- 1. 下载 + 分析视频 → 显示时长和信息
- 撰写脚本 → 展示给Paul,等待确认
- 生成音频 → 发送试听,等待确认
- 询问视频配置(布局、源音乐) → 等待确认
- 生成HeyGen头像
- 转录 + 对照原始脚本修正字幕
- 合成最终视频
步骤1:下载视频
Google Drive
bash
pip install gdown -q
gdown https://drive.google.com/uc?id=FILE_ID&confirm=t -O output.mp4
如果失败(权限问题):请Paul将分享权限设为任何拥有链接的人或通过Telegram发送。
TikTok / YouTube
bash
yt-dlp -o output.mp4 URL
Telegram(附件)
附件会到达 ~/.openclaw/media/inbound/
验证
bash
ffprobe video.mp4 2>&1 | grep -E Duration|Video:|Audio:
步骤2:脚本
规则:
- - 阿根廷拉普拉塔河西班牙语(voseo:如grabás、actualizás、imaginá)
- 前3秒要有强力钩子
- 动态,无填充内容
- 无导演注释,仅朗读文本
- 结尾CTA(例如:加入Morfeo Labs)
- 目标时长:等于或略长于源视频
展示脚本并在生成音频前等待批准。
步骤3:音频 — TTS
✅ 默认:ElevenLabs Paul Pro
始终生成3种语音变体并发送给Paul选择,然后再继续。
python
import requests, time
CACHE = /home/ubuntu/clawd/projects/picasso-tiktok/cache/JOB_NAME
BASEURL = https://api.elevenlabs.io/v1/text-to-speech/$ELEVENLABSVOICE_ID
HEADERS = {xi-api-key: $ELEVENLABSAPIKEY, Content-Type: application/json}
变体A — 富有表现力,强停顿
变体B — 默认获胜者:长破折号用于戏剧性停顿(stability 0.45)
变体C — 流畅新闻风格,无中断(stability 0.62)
configs = [
(A, scripta, {stability: 0.35, similarityboost: 0.80, style: 0.25}),
(B, scriptb, {stability: 0.45, similarityboost: 0.82, style: 0.15}), # ← 常胜将军
(C, scriptc, {stability: 0.62, similarityboost: 0.78, style: 0.05}),
]
for ver, text, settings in configs:
r = requests.post(BASE_URL, headers=HEADERS,
json={text: text, modelid: elevenmultilingualv2, voicesettings: settings})
with open(f{CACHE}/audio_{ver}.mp3, wb) as f:
f.write(r.content)
print(f✅ V{ver} {len(r.content)//1024}KB)
time.sleep(1)
标点技巧控制节奏:
- - 独立段落分隔的短语 → 自然长停顿(VA)
- 句内长破折号 — → 句中戏剧性停顿(VB,获胜者)
- 全部连在一起无中断 → 纪录片式流畅(VC)
⚠️ 重要:
- - 模型:elevenmultilingualv2 — 绝不用 elevenv3(会改变口音)
- Paul Pro语音ID:$ELEVENLABSVOICEID
- API密钥:$ELEVENLABSAPI_KEY
备用:Cartesia sonic-3
python
r = requests.post(https://api.cartesia.ai/tts/bytes,
headers={X-API-Key: $CARTESIA
APIKEY,
Cartesia-Version: 2025-04-16, Content-Type: application/json},
json={model_id: sonic-3, # 始终用 sonic-3,绝不用 sonic-2
transcript: SCRIPT,
voice: {mode: id, id: $CARTESIA
VOICEID},
language: es,
output
format: {container: mp3, samplerate: 44100, bit_rate: 128000}})
发送音频试听并在继续前等待确认。
步骤4:询问配置
在生成头像和合成前,确认:
- - 布局: 60/40(源在上方)、50/50、40/60(头像在上方)
- 字幕: 是/否
- 源音频: 是否混合原始音乐?如果是,音量多少?(通常:30%)
- 前几秒标题(例如:这个女孩不存在 👁️)
- TikTok标题带话题标签
步骤5:HeyGen头像
上传音频到uguu.se(HeyGen要求)
python
import requests
with open(audio.mp3, rb) as f:
r = requests.post(https://uguu.se/upload,
files={files[]: (audio.mp3, f.read(), audio/mpeg)}, timeout=30)
audio_url = r.json()[files][0][url]
生成视频
python
HEYGEN
KEY = $HEYGENAPI_KEY
AVATAR_ID = aa7ca06de7454b9caa147b97a534e813 # Paul默认
r = requests.post(https://api.heygen.com/v2/video/generate,
headers={X-Api-Key: HEYGEN_KEY, Content-Type: application/json},
json={
video_inputs: [{
character: {type: avatar, avatarid: AVATARID, avatar_style: normal},
voice: {type: audio, audiourl: audiourl},
background: {type: color, value: #000000}
}],
dimension: {width: 432, height: 768}, # 小9:16,缩放效果更好
aspect_ratio: 9:16
})
videoid = r.json()[data][videoid]
轮询直到完成(约2-4分钟)
python
import time
while True:
r = requests.get(fhttps://api.heygen.com/v1/video
status.get?videoid={video_id},
headers={X-Api-Key: HEYGEN_KEY})
data = r.json().get(data) or {}
if data.get(status) == completed:
avatar
url = data[videourl]
break
time.sleep(15)
下载和cropdetect
bash
curl -sL $AVATAR_URL -o avatar.mp4
自动检测裁剪(去除HeyGen的黑色填充)
ffmpeg -ss 2 -i avatar.mp4 -vframes 10 -vf cropdetect=24:2:0 -f null - 2>&1 | grep crop= | tail -2
典型结果:crop=432:244:0:262
步骤6:字幕 — 始终对照原始脚本
用Whisper转录
python
import requests, os
with open(audio.mp3, rb) as f:
r = requests.post(https://api.openai.com/v1/audio/transcriptions,
headers={Authorization: fBearer {os.environ[OPENAIAPIKEY]}},
files={file: (audio.mp3, f, audio/mpeg)},
data={model: whisper-1, responseformat: verbosejson,
timestamp_granularities[]: word, language: es})
words = r.json()[words]
⚠️ 始终对照原始脚本检查并修正
Whisper在西班牙语/拉普拉塔语+技术术语上常犯错误:
| Whisper写的 | 正确 |
|---|
| Cling | KLING |
| Confi / Confy |
COMFY |
| Imagina | IMAGINÁ |
| Grabas | GRABÁS |
| Actualizas | ACTUALIZÁS |
| Buscas | BUSCÁS |
| Preparas | PRE