flow2 / moldovan-qwen /scripts /generate_moldovan_video_scripts.py
AndrianBalanescu
fix: require auth only when FLOW_API_KEY is explicitly set
434c049
Raw
History Blame Contribute Delete
8.05 kB
#!/usr/bin/env python3
"""
generate_moldovan_video_scripts.py — Moldovan Viral Video & Short-Form Comedy Studio
Generates 30-60s viral video concepts for TikTok, Instagram Reels, and YouTube Shorts.
Includes scene-by-scene storyboard prompts for FLUX.1 / Sora, voiceover scripts (Kokoro TTS),
on-screen text hooks, and comedy timing.
"""
import os
import sys
import re
import json
import argparse
from typing import List, Dict
SKETCH_CONCEPTS = [
{
"title": "Moldoveanul la Vama Leușeni — Bagajul Secret",
"category": "Satiră Socială & Diasporă",
"duration_seconds": 45,
"hook_text": "Băi, ce găsește vameșul în portbagaj când zici 'n-am nimic de declarat'?!",
"hashtags": ["#moldova", "#chisinau", "#vama", "#leuseni", "#moldoveniinitalia", "#comedy", "#prikol"],
"scenes": [
{
"scene_num": 1,
"time_range": "0:00 - 0:05",
"visual_prompt": "Cinematic close-up of a nervous Moldovan driver sitting in a dusty Volkswagen Passat B5 at the Leuseni border checkpoint, wearing a dark leather jacket, night atmosphere with fluorescent border lights.",
"voiceover": "Ora 3 dimineața la vama Leușeni. Vameșul vine tacticos la geam și întreabă: 'Ceva interzis aveți?'",
"on_screen_text": "POV: Treci vama la 3 dimineața 🛂",
"sound_effect": "Tension build-up, car engine idling"
},
{
"scene_num": 2,
"time_range": "0:05 - 0:15",
"visual_prompt": "Open trunk of the car packed to the brim with giant woven plastic market bags (kuleoace), a 20-liter glass demijohn wrapped in wicker full of red wine, and foil-wrapped packages.",
"voiceover": "Și tu zici: 'Doamne ferește, dom' șef, două kuleoace cu haine și-o sticluță de apă!'... Între timp în portbagaj: 30 de litri de vin de casă, 4 găini tăiate de mama, 15 borcane de compot de cireșe și o găleată de brânză de oi!",
"on_screen_text": "'Doar 2 kuleoace cu haine, dom' șef!' 😂",
"sound_effect": "Record scratch, comedic dramatic brass"
},
{
"scene_num": 3,
"time_range": "0:15 - 0:30",
"visual_prompt": "Close-up of the border guard smiling knowingly while tapping the demijohn of red wine with his pen.",
"voiceover": "Vameșul se uită lung la damigeană, o bate ușor cu pixul și zice: 'Măi băiatule, asta-i apă sfințită sau e cabernet din '22?'",
"on_screen_text": "Vameșul expert în vinuri 🍷",
"sound_effect": "Clinking glass sound"
},
{
"scene_num": 4,
"time_range": "0:30 - 0:45",
"visual_prompt": "The driver quickly offering a warm wrapped placinta with homemade cheese from the glove box with a huge friendly smile.",
"voiceover": "Koroce, n-ai cum să nu scoți o plăcintă caldă cu brânză de oi pe loc! 'Hai davai, dom' vameș, luați o plăcintă și drum bun să avem!' Niciun scanner din lume nu rezistă la plăcinta moldovenească!",
"on_screen_text": "Plăcinta rezolvă orice problemă! 🥧✨",
"sound_effect": "Fast energetic Moldovan accordion festive outro"
}
]
},
{
"title": "Babușca la Chișinău — 'De ce ești așa slab, maică?!'",
"category": "Familie & Gastronomie",
"duration_seconds": 40,
"hook_text": "Ai slăbit 100 de grame? Babușca de la sat intră în alertă de gradul 0!",
"hashtags": ["#moldova", "#babusca", "#zeama", "#sat", "#chisinau", "#mamaia", "#relatable"],
"scenes": [
{
"scene_num": 1,
"time_range": "0:00 - 0:05",
"visual_prompt": "Traditional Moldovan grandmother wearing a floral headscarf (batic) looking with utter shock and concern through a wooden village gate.",
"voiceover": "Ai venit la sat după o lună de stat la Chișinău. Babușca te vede la poartă și-și pune mâinile-n cap!",
"on_screen_text": "Când ajungi la sat după o lună 👵🏻🚨",
"sound_effect": "Dramatic soap-opera zoom sound"
},
{
"scene_num": 2,
"time_range": "0:05 - 0:20",
"visual_prompt": "Steaming hot bowl of chicken noodle soup (zeama) with fresh dill and hot chili pepper on a rustic embroidered tablecloth, accompanied by huge chunks of homemade bread.",
"voiceover": "'Doamne, maică, numai os și piele ai rămas! Ce vă dau ăștia la Chișinău să mâncați, pietre?' În fix 4 minute pe masă apare un lighean de zeamă fierbinte, o mămăligă cât roata carului și-un castron de friptură!",
"on_screen_text": "Tratamentul de urgență: ZEAMĂ + MĂMĂLIGĂ 🍲",
"sound_effect": "Sizzling meat in cast iron cauldron"
},
{
"scene_num": 3,
"time_range": "0:20 - 0:40",
"visual_prompt": "Young guy sitting at the table unable to move, while grandmother holds another plate of 5 giant cheese pies (placinte) trying to force-feed him.",
"voiceover": "Zici: 'Babușcă, gata, nu mai pot, crap!'. Iar ea: 'Mai mănâncă 3 plăcinte că te ia vântul pe stradă!'... Pleci de la sat cu 8 kile în plus și 4 pungi de mâncare în portbagaj!",
"on_screen_text": "Nu există 'm-am săturat' la sat! 😂",
"sound_effect": "Belly full groan, comedic folk trumpet"
}
]
}
]
def generate_video_scripts(output_dir: str):
"""Generate structured viral script files."""
os.makedirs(output_dir, exist_ok=True)
for idx, sketch in enumerate(SKETCH_CONCEPTS, 1):
file_slug = sketch["title"].lower().replace(" ", "_").replace("—", "").replace("-", "_").replace("'", "").replace("ș", "s").replace("ț", "t").replace("ă", "a").replace("î", "i").replace("?", "")
file_slug = re.sub(r'[^a-z0-9_]', '', file_slug)
md_content = f"# 🎬 {sketch['title']}\n\n"
md_content += f"**Categorie:** {sketch['category']} | **Durată:** ~{sketch['duration_seconds']} secunde\n\n"
md_content += f"### 🔥 Hook (Primele 3 secunde):\n> \"{sketch['hook_text']}\"\n\n"
md_content += f"### 🏷️ Hashtags:\n`{' '.join(sketch['hashtags'])}`\n\n"
md_content += "---\n\n## 🎥 Storyboard & Script Scenă cu Scenă\n\n"
for sc in sketch["scenes"]:
md_content += f"### Scena {sc['scene_num']} ({sc['time_range']})\n"
md_content += f"* **Visual Prompt (FLUX.1 / Sora):** `{sc['visual_prompt']}`\n"
md_content += f"* **Voiceover (Kokoro TTS):** \"{sc['voiceover']}\"\n"
md_content += f"* **On-Screen Text:** `{sc['on_screen_text']}`\n"
md_content += f"* **Sound Effect:** *{sc['sound_effect']}*\n\n"
md_path = os.path.join(output_dir, f"{file_slug}.md")
with open(md_path, 'w', encoding='utf-8') as f:
f.write(md_content)
json_path = os.path.join(output_dir, f"{file_slug}.json")
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(sketch, f, ensure_ascii=False, indent=2)
print(f"[✓] Generated Video Concept: {sketch['title']} -> {md_path}")
def main():
default_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data/generated_video_scripts")
parser = argparse.ArgumentParser(description="Generate Moldovan Short-Form Video Scripts")
parser.add_argument("--output-dir", default=default_dir, help="Output directory")
args = parser.parse_args()
generate_video_scripts(args.output_dir)
if __name__ == "__main__":
main()