History Buffer

How prompts and videos are built

Cursor is the editor this app was written in. It does not generate scripts at runtime. Keep this page in sync with README.md when the pipeline changes.

What AI is used

Optional Groq (default qwen/qwen3.8-27b), Gemini, OpenAI, NVIDIA, or local Ollama from Admin/New prompt. Claude is disabled in the picker (paid). By default they only rewrite the topic brief (hooks, topics, facts) — spoken script, scenes, and InVideo text stay Python templates in prompts.py. Exception: Mode 2 Build auto-writes a finished spoken voiceover with the same Script / LLM (then templates split it into scenes). Needs the provider key (or Ollama up). Agnes is motion only: image→video or text→video. Voice defaults to Edge TTS (Antonio / Francisca / Thalita on PT-BR; Andrew / Jenny / … on EN; roles Male / Female / Warrior / Ancient). Optional ElevenLabs · … voices appear in the same Voice dropdown when ELEVENLAB_API_KEY1 is set in .env (KEY2 failover on quota/auth/rate limits). Free-tier keys only get premade voices (Adam, Antoni, Brian, Daniel, Will, George, Callum, Sarah, Matilda, Lily, Jessica, Alice) — library voices need a paid plan and are not offered. Optional Fish Audio · … voices use FISHAUDIO_API_KEY1 / FISHAUDIO_API_KEY2 (s2.1-pro-free A/B lab; equal-time captions).

PythonScripts and InVideo prompt
Script LLMBrief rewrite or finished VO
Agnes I2V / T2VMotion from still or text

Runtime path

  1. Source (no writing AI)

    Wikipedia fetch, topic search, or a pasted script. Python only. If Britannica or another allowlisted host returns 403, Build uses the English Wikipedia page from the URL slug.

  2. Brief or finished VO (optional OpenAI, Gemini, Groq, Claude, or Ollama)

    Python extracts sentences. By default the script model for this Build rewrites hooks and topics toward what/why/wow (not the same establishment year restated), and for listicle topics it should name several list items — not only the survivor. New prompt is pre-filled from Admin; changing it does not save Admin. Default is Groq qwen/qwen3.8-27b (free-tier) when GROQ_API_KEY is set (also openai/gpt-oss-20b, openai/gpt-oss-120b). Gemini is free-tier cloud (not local GPU). Gemini uses generateContent when GEMINI_API_KEY is set (GOOGLE_API_KEY also works): default gemini-3.5-flash-lite (free-tier), plus gemini-3.6-flash, gemini-3.5-flash, and gemini-3.1-flash-lite. Get a Gemini key at https://aistudio.google.com/apikey. Groq is console.groq.com (not xAI Grok). Get a Groq key at https://console.groq.com → sign in → API Keys → Create API Key. OpenAI is paid (gpt-4o-mini etc.; needs credits). Claude is disabled in Admin/Build pickers (paid / not free). Grok (xAI) is paid backlog when XAI_API_KEY (or GROK_API_KEY) is set, via https://api.x.ai/v1/chat/completions (default grok-4-fast; also grok-4.6, grok-4.5, grok-3-mini). Hugging Face is credit-limited (~$0.10/mo free then paid — not unlimited free) when HF_TOKEN / HF_API_KEY (or HF_key) is set, via https://router.huggingface.co/v1/chat/completions (default meta-llama/Llama-3.1-8B-Instruct:fastest). OpenRouter is free-tier cloud when OPEN_ROUTER_KEY is set, via https://openrouter.ai/api/v1/chat/completions (default openrouter/free; also specific :free models — ~50 RPD without purchased credits; upstream 429s common). Mistral is Experiment/free rate-limited when MISTRAL_API_KEY is set, via https://api.mistral.ai/v1/chat/completions (default mistral-small-latest). NVIDIA is free preview NIM (not paid enterprise containers) when NVIDIA_API_KEY is set, via https://integrate.api.nvidia.com/v1/chat/completions. The model list is free preview chat NIMs (live catalog, with a small fallback). Restart uvicorn after adding a key. Ollama is free-local but can freeze this machine; it uses a model already pulled (OLLAMA_HOST, default http://127.0.0.1:11434). Admin default is auto start/stop: the app starts an owned ollama serve only when a local LLM call needs it, then stops it (no prompts). Choose manual to leave a daemon you started alone. One-time: disable the system unit with systemctl disable --now ollama so boot does not keep it up. Claude uses the Anthropic Messages API when CLAUDE_API_KEY is set (claude-sonnet-5 for everyday scripts; claude-haiku-4-5-20251001 is cheaper; claude-opus-5 is expensive). A selected provider never silently calls another. If it is not ready, Build keeps the extractive brief and shows a warning. New Ollama models need ollama pull <name> — this app will not pull for you. Wikidata/Grokipedia stay on the brief, not in voice or burned-in captions. Mode 1 refine may also invent a punchy pack/display title (like Mode 2 VO titles); the Wikipedia page name stays in source_title for stills, stock, and Agnes subject lock. If refine is skipped or omits a title, the wiki name stays. Mode 2 VO titles follow the same rule (punchy pack title, not the bare wiki name); if the model echoes the topic, Build derives a distinctive title from the VO hook. Spoken VO (Mode 1 and Mode 2) strips archaeology catalog / tomb codes (e.g. KV62) and beat clocks / duration tokens (3s, [0:04], — 3 seconds) so they are not TTS'd or burned into captions. New Builds ask the scriptwriter to vary cold opens (Imagine / Imagina / Picture this / Feche os olhos are fine sometimes, not every script); VO and brief prompts share a History Buffer (EN) and Revisitando (PT-BR) hook-shape bank in vo_hooks.py. A shared name-collision rule (name_collisions.py) keeps Wikipedia myth/history subjects off Hollywood/game namesakes (Pandora is the Greek myth, not Avatar). Saved jobs are not rewritten. Scene seconds stay metadata only.

    Mode 2 — Text → video (New prompt Mode dropdown): topic/phrase plus optional Wikipedia search (same as Mode 1). Build always auto-writes a finished VO (editable VO instructions; default craft from mode2_vo_prompt.py); never TTS the scriptwriter instructions. If a weak model (e.g. NVIDIA GPT-OSS or some Groq tags) echoes the template into script, Build strips a clear leading dump when possible and auto-retries the VO write once before refusing TTS. No separate Write VO click. Queue is locked to Agnes text→video. T2V prompts add a WARDROBE line when people are likely on screen: period-accurate clothing for historical recreations. When VO mentions a kid/boy/child in a historical narrative (birth, boy king, Egypt pack), lock to a period Egyptian / era child — never a modern-day kid in a gold tee. Modern kid clothes only for explicit present-day visitors/tourists/museum beats. Similes like "more gold than a modern stadium" do not flip wardrobe by themselves.

    (hard-fail after retries; no still hydrate / Ken Burns fallback). Each clip locks to that beat’s spoken nouns and scene visual intent — not the pack title on every beat — with anti-repeat shot roles; on-screen FOLLOW FOR MORE is last-beat only. (720×1280 / 1280×720, resolution-capped num_frames, paid plan by default). No still hydrate and no Ken Burns fallback — clip failures retry then hard-fail. Short platforms are independent: TikTok master ~90–110s (~225–275 spoken words; never under 65s / ~163 words; soft max rewrite/trim keeps the ending) and/or Meta short ≤60s (~45–55s / ~112–137 words; hard ceiling ≤150 spoken words, re-clipped after the Mode 5.01 end question; compressed punch + spoken CTA, not a mid-conquest cut); medium (mixed single-write) ~350s (~800–950); YouTube-only ~700s (~1600–1900). Checking both Shorts boxes dual-writes TikTok + Meta VOs (and long when YouTube is selected) so each pack gets its own duration budget. Mode 1 stays brief rewrite + stills / I2V and does not show Write VO controls.

    Mode 2.5 — Hybrid: same finished-VO Build as Mode 2, but stills hydrate for every non-CTA scene (wiki / Commons / stock still → Agnes ti2vid), not only English monument aliases. Portuguese geography packs (Nile, Nyungwe, Aswan) get a still per beat so Queue can send what the worker uses. The same Wikipedia topic in another language (Wikidata sitelinks / interwiki — e.g. pt.wikipedia.org/wiki/Rio_Nilo and en.wikipedia.org/wiki/Nile) may reuse one still pool. Stock/wiki hits whose title or tags lock a different place (Amazonas / Amazônia on a Nile article) are dropped; a wrong on-screen chip does not keep those photos. Weak discourse chips (ENQUANTO / MAIORIA / …) never drive Commons alone — queries blend the article title, Wikipedia page gallery stills outrank pretty off-topic hits, and click-replace sorts by topic/beat match then quality. Unlike Mode 3, Mode 2.5 still needs a Wikipedia (or allowlisted) page for VO/script — the Sources picker is article disambiguation, not Commons stills. Open + Build reuses the saved article URL and does not re-search name collisions. CTA end cards stay empty T2V slots unless that beat has a locked still, which Queue sends as image→video. Queue locks to Agnes hybrid and first opens a stills confirm (same look as the thumbnail picker): every I2V still that would be sent, grouped by queued platform (Shorts >60, Meta ≤60, YouTube long, and any other) — one card per I2V beat per platform, not one still for the whole job. Checkboxes include or skip (skipped beats stay T2V), and click a still (or Change) to pick an alternate — options are sorted by context match and image quality (Change stills refetches a larger unique pool; From disk adds a local file). Confirm writes the selection on the Job; Cancel creates no Job. Mode 2 (text-only) stays still-free; Phase 1 adds gated monument recognizability constraints on photoreal T2V prompts.

    Mode 2.6 — Hybrid + refined VO: sibling of Mode 2.5 (same stills confirm + agnes_hybrid path; not folded into Mode 2.5). Uses a refined VO craft prompt, a post-script packaging pass (titles / captions / on-screen hook), a PT-aware chip quality gate (reject verb/pronoun/filler chips, including PT discourse like ENQUANTO/MAIORIA), topic-blended Commons queries with still auto-reject/rank (article-subject preference + off-topic demotion) before confirm, Confirm UI warnings + “why matched” query, and full Agnes prompt files under the platform work dir while Jobs logs the I2V line (Mode 2.6 hybrid image→video sends the camera-only documentary line: subtle motion, do not wake the face, do not make the statue come alive — the still-bake sentence and the Pandora name-lock are not appended. Each clip adds one short beat action from that scene's voiceover. Person and weapon locks follow that beat's still: do not add a person who is not pictured, and do not add a bow, sword, or spear that the still does not already show (a knife already in the still may be named). A fight still asks for a real struggle; a hydra-only still stays a hydra shot. Ancient Mediterranean period dress, no modern clothes, and no second monster stay. A beat longer than 5s requests 10s, or 15s/18s when the slot already needs it, and the fitter trims to the voice. Mode 5.01 stays Ken Burns. The previous “comes alive” prompt is in docs/mode-2.6-i2v-prompt-BACKUP-20260925.md). Still rehost prefers the public tunnel and litterbox before catbox. When I2V fails on a still beat, Mode 2.6 falls back to text→video (Ken Burns only if that also fails); Mode 2.5 keeps I2V-fail → Ken Burns still.

    Mode 5.01 — Publish pack (on 2.6): own Mode dropdown value. Production bake is existing Mode 2.6. Adds a 5-check checkpoint (Preview voice / Edge TTS before Voice quality or Pass), 3+1 question bank (opinion / A-B / would-you — not facts the VO already answered), required END CTA on a separate MODE5_01_DEFAULT_VO_INSTRUCTIONS set (Mode 2.6 defaults stay as-is), chosen-question inject into the last 1–2 spoken sentences + PIN_COMMENT (one END ask only — paraphrased second questions are trimmed pre-TTS), Agnes / Flux / Pollination stills. Automatic Flux is off (mode5_auto_flux / MODE5_AUTO_FLUX, default off). Regen buttons still call Flux 2 (schnell fallback on NSFW/quota) or Flux 1, Agnes, or Pollination. From disk adds one or more local jpg/png/webp into the pool and can replace a beat. Stills are 1080×1920. Change shows pools. Still prompts lead with the beat subject, not one shared Cinematic B-roll opener. The question bank does not paste the YouTube title into the ask. A scene missing a Flux, Agnes, or From-disk still warns and does not block Queue. Ken Burns still runs (varied push/pull/pan; each move runs for the whole beat); a gap holds the last valid still. Agnes image→video is not required; no silent text→video fallback; a still whose text mismatches a named still-target gender/role is blocked. A Meta script over 150 spoken words warns on the scene board, not inside the still picker, and does not drop stills already assigned. Upgrade pack to Agnes is hidden on Mode 5.01. Optional Open on thumbnail (default off, in the thumbs & stills pick window) holds that pack’s already selected thumbnail for a configured number of seconds (default 2) before the Ken Burns stills. Off keeps the channel-logo opening. If it is on and no thumbnail is selected, the bake keeps the logo opening and says so. `short_master` keeps 8–12 finals (default 10); Meta 5–7 (default 6); aligned beats share one still set. a missing-question lint when a bank item is selected and the ending is subscribe-only (unless Write already injected the ask), cross-post defaults, and gates Queue until Pass and Schedule/Publish until Pass + thumb pick. After packaging, product code appends locked Fonte/Source (YT description + FB caption; one wiki/Grokipedia URL) and the channel-language AI reconstruction disclaimer (YT / IG / FB) — Mode 2.6 captions unchanged. Other modes unchanged when 5.01 is not selected.

  3. Platform scripts (Python templates)

    prompts.py fills a Shorts 9:16 TikTok master plus a Meta Short ≤60s cut (per-destination captions/hashtags) and/or Long form YouTube 16:9: voiceover, scenes, InVideo text, Veo shots. Legacy TikTok / Reels / youtube_shorts packs still load. Short-form beats prefer one clear hook plus varied what/why/wow facts and skip repeating the same establishment year across captions. Listicle topics (Seven Wonders, named catalogs) pack item names into 1–2 beats, avoid repeating the survivor claim, align on-screen chips to the beat when clear, and allow one strong year punch once. Tone Animated is comics / anime 2D motion (Agnes, then a still if a clip misses — Agnes never loads LTX); Explainer is motion-graphics / here's-why; Mythbust is claim then record. Other tones stay faceless documentary. In VO script mode, voiceovers come from the finished script (templates still fill visuals / chips). YouTube long-form builds ~8 minutes of spoken script from section bodies (~150 wpm) with the same date-lead dedupe (unless VO mode supplied the long script). Channel Video language (Admin) drives VO / refine language and Edge TTS locale. Build also assigns still URLs to each scene.

  4. Save + queue

    One SQLite file in the project folder for all prompts and jobs. Scene-board stills stay in TEMP_DIR until the first job, then the prompt folder moves to output with a scratch folder per platform (preview /media/ links follow that move). After Build, Replace a still from a local jpg/png/webp (copied into that folder). Queue defaults to CPU preview (Pexels stock video when a beat matches, else Ken Burns — no Agnes, no Local GPU). When that pack looks right, Upgrade pack to Agnes from Jobs reuses the same script, voice, and stills (hidden on Mode 5.01). Two jobs run at once. Only one Agnes job at a time; queued Agnes jobs wait. When Shorts and Long form are queued together, the short job always starts first (long waits for that batch’s short). GPU and stills can still run in parallel with each other. A second Local GPU job waits until the 3060 is free.

  5. Render (not prompt AI)

    Edge TTS (default), optional ElevenLabs, or optional Fish Audio speaks the script and supplies WordBoundary timings for burned-in / SRT captions (not equal-time slots). Queue mixes a quiet Openverse instrumental (CC0 / public domain / CC BY, no API key) under the voice. Stills prefer on-article Wikipedia/Wikimedia images, including fair-use title cards (skip icons, tiny frames, cosplay, graffiti, and merch). Documentary tones rank ruin / ash / crater / excavation stills over scenic harbor shots when the topic or voiceover is about death, eruption, or archaeology, and assign each beat by matching the scene line to the filename — not only by pool index. Then AniList posters (no key) and optional TMDB if TMDB_API_KEY is set — catalog key art first for Animated / fiction at Build; Educational and Mythbust stay Wikipedia + documentary stock (no catalog art) — then Wikimedia Commons search if the page is thin. Openverse fill uses beat-aware queries and the same ranking; a hit must mention a distinctive title word or it is dropped (so “TV series” does not pull Netflix posters). Optional Pexels stills only for non-fiction pages if PEXELS_API_KEY is set. Animated and fiction titles skip Pexels. Rebuild re-fetches unlocked remote stills; Lock and local files stay. You can Skip still to cycle a beat to another candidate, Lock a pick, Replace from a local jpg/png/webp (copied into the pack folder), or Add still from disk for the pack. Queue / CPU preview use those chosen stills in scene order. For documentary tones, CPU preview also searches Pexels video per beat (same subject ranking: ruin/ash over harbor), trims the clip to the voiceover slot, and Ken Burns the still only when no clip matches or the clip is shorter than the slot — no looping. Agnes stays still → image-to-video (stock video is preview-only). Animated / fiction / explainer skip stock video. Agnes swaps Wikimedia scene stills per clip to AniList/TMDB/Pexels (fetchable hosts) so create does not hang on rehost-only sets. Locked local stills are kept. Wikimedia is rehosted only when no fetchable substitute exists. Mixing fetched and local is fine. Explainer prefers diagrams / infographics. Mythbust keeps documentary stills but labels beats THE CLAIM / THE RECORD. YouTube long-form uses ~12 stills. Agnes or local GPU animate ~5–15s clips (play once; long I2V that nearly fills the slot is time-stretched so joins do not park on a near-static Ken Burns hold; larger leftovers Ken Burns from the last motion frame — not a hard cut back to the source still; short pads stay in Ken Burns so joins do not park on a dead freeze). Short-form uses ~10 stills by default (up to 12 on longer voiceovers) so slots stay near 5s and Ken Burns tails stay short. Queue offers Agnes image→video (still + ti2vid) or Agnes text→video (prompt only, no still sent; filename -agnes-t2v). Pick T2V on the Queue engine dropdown after Build — not as Admin default; Upgrade pack to Agnes always queues image→video, except Mode 5.01, which hides the button. T2V briefs lock onto a primary subject from the voiceover (listicle beats film one named item, not a collage). Motion prompts pick a per-beat camera (push-in, orbit, parallax, or energy) from each scene’s visual line. Documentary I2V asks the exact still to come alive (likeness locked — living portrait, not a photoreal face rewrite). Fiction / Animated packs prefer AniList/TMDB key art on the scene board at Build, and skip weak commons (cosplay, graffiti, merch). Listicle shorts speak one named item per beat (not a full catalog dump) so captions and motion stay on the same subject. Scene stills are matched to that name (Commons fill when the page gallery is thin); Agnes keeps those stills and rehosts Wikimedia instead of swapping in unrelated stock. Downloaded stills are normalized to real JPEG/PNG before Ken Burns so GIF bytes mislabeled as .jpg do not break ffmpeg -loop. Agnes defaults to agnes-video-v2.0 (Admin can keep that or show Video 2.5 as not I2V-ready yet). Not the 2.5 text models. Free AGNES_API_KEY for Mode 1 by default. Mode 2 uses paid pools: shorts PAYED_AGNES_KEY / PAYED_AGNES_KEY_3 / PAYED_AGNES_KEY_4 (A+C+D rotate by estimated UTC daily seconds); long form PAYED_AGNES_KEY_2 (B) primary — one long/UTC day; if B cannot fit another clip, borrow ≤10% of each shorts key to finish; later longs stay queued until reset. Soft prefer the other key in the same pool near ~450 of 500; 402 marks a key exhausted for the day. Admin shows present/missing + estimates — never the secrets, not live Agnes numbers. Create waits 300s for a task id (one float for all HTTP phases). A timeout on one clip uses a still and the next clip still tries Agnes (Mode 1). The job fails at the end only if no clip got motion. HTTP 502 / 503 / 520 (including video_queue_full) wait ~20s and retry the same key up to twice more (3 tries total), then that clip is a still (or Mode 2 hard-fail). Agnes jobs prefer Pexels/Openverse CDNs and rehost Wikimedia before create. The header Agnes chip is green when their API is reachable, red when it is full or timing out. While nothing is queued or running, the app re-checks about once an hour with GET /v1/models (not a fake video create). ffmpeg stitches the MP4. Portrait captions sit above TikTok/Reels chrome (~5-word phrases) in a local OFL font (Auto from topic — history for volcanoes / ruins — or Queue override). YouTube long-form leaves the picture clean and writes an SRT next to the MP4. Duplicate spoken lines and mid-sentence fragments are dropped. Local LTX keeps T5 on CPU, the 2B transformer on the 3060, and the VAE in float32 (3D conv has no CUDA bfloat16 kernel). Queue GPU quality: Draft, Balanced (default, 41 frames at 512×768), or High. Ken Burns fills the rest of the slot; ffmpeg uses CRF 18 on Balanced. VRAM is capped so the display GPU does not freeze.

Diagram

New prompt
  ├─ Topic search ──► Wikipedia / Grokipedia / allowlisted sites ──► Fetch best source
  ├─ Wikipedia URL ───────────────────────────────────────────────► Fetch Wikipedia
  ├─ Pasted external prompt ──► Parse text in Python ─────────────► Topic brief
  └─ Mode 2 (Text → video) ──► Script LLM auto-writes spoken VO ──► script_mode scenes
Fetch Wikipedia ──► Extractive brief (Python) ──► Enrich? ──► Topic brief
Topic brief ──► Mode 2?
                 ├─ yes ──► Script LLM finished VO ──► prompts.py script_mode
                 └─ no ───► Script provider ready? (this Build, else Admin)
                              ├─ OpenAI / Gemini / Groq / NVIDIA / Claude / Ollama ──► brief rewrite only
                              └─ no ──► prompts.py templates
prompts.py ──► Save pack as a row in project SQLite (stills in TEMP_DIR)
Save ──► Mode 2.5 stills confirm (checkboxes; Wikidata sitelinks share stills; drop off-topic geography) ──► Queue job (engine / tone / voice / captions) ──► move prompt folder to CHANNELS_DIR ──► Edge TTS + ranked stills + Openverse music
                    ├─ Agnes image→video / GPU ──► ~5s from still, then Ken Burns (last frame) ──► ffmpeg
                    ├─ Agnes text→video ──► ~5s from text brief, then Ken Burns (last frame) ──► ffmpeg
                    ├─ Mode 5.01 ──► optional selected-thumbnail hold, then Flux or disk stills + varied Ken Burns for the whole beat (not Agnes I2V) ──► ffmpeg
                    └─ CPU preview ──► Pexels stock video (else Ken Burns) ──► ffmpeg ──► prompt-folder/filename.mp4
Jobs ──► Upgrade pack to Agnes image→video (same script / voice / stills; one Agnes job at a time; not on Mode 5.01)
YouTube long-form also writes filename.srt (no burned-in captions).
Two jobs run at once. A second Local GPU job waits for the 3060.

Who writes what

Piece Who produces it Model / tool
Wikipedia / search / paste This repo (Python fetch or your paste) None
Extractive brief summarize.py sentence scoring None
Rewritten hooks / topics Only if this Build's Script provider is ready (OpenAI, Gemini, Groq, Grok, Hugging Face, OpenRouter, Mistral, NVIDIA, or Claude key, or Ollama up with a pulled model). New prompt is pre-filled from Admin. Skipped on Mode 2 (finished VO path). This Build's OpenAI / Gemini / Groq / NVIDIA / Claude / Ollama model (stamped on the pack and jobs)
Finished spoken VO (Mode 2) Mode 2 Build auto-writes with write_vo + VO instructions. Same Script / LLM; needs key / Ollama. Mode 1 does not offer this. This Build's Script provider model
Spoken script, scenes, InVideo prompt prompts.py templates by default. VO script mode splits the finished VO into beats; templates still fill visuals / chips / InVideo. Short-form skips repeating the same establishment year, packs listicle item names into 1–2 beats, dedupes survivor claims, aligns chips when clear, and allows one strong year punch. Prefers varied what/why/wow beats. YouTube long-form fills ~1100–1300 spoken words (~8 min at 150 wpm) from section bodies with date-lead dedupe; timestamps follow word count. Short articles stay short. No silence padding. None (unless VO mode wrote the voiceover)
Voiceover audio Edge TTS (default), ElevenLabs, or Fish Audio Edge: Andrew, Jenny, Aria, Guy, Christopher, Emma, Sonia, Ryan, Antonio, Francisca, Thalita. Optional ElevenLabs premade only on free keys (Adam, Antoni, Brian, Daniel, Will, George, Callum, Sarah, Matilda, Lily, Jessica, Alice — ELEVENLAB_API_KEY1; library voices need paid). Fish Audio · … (FISHAUDIO_API_KEY1; s2.1-pro-free).
Background music Openverse audio search (instrumental, CC0 / pdm / CC BY). Duck under speech. Optional: skip if the download fails. None
Stills On-article Wikimedia (incl. fair-use; skip cosplay/graffiti/merch); beat-matched to voiceover; AniList/TMDB for Animated/fiction only (Educational stays documentary); Openverse fill must match the title; Pexels only for non-fiction. Local replace for episode frames. None
Motion clips After you queue a job. CPU preview uses Pexels stock video when available, else Ken Burns; Upgrade pack to Agnes from Jobs is image→video (not shown on Mode 5.01). Queue engine also offers Agnes text→video. Agnes Admin generation (default v2.0; opt-in 2.5 Flash) or local LTX
Final MP4 ffmpeg mux + OFL captions (SRT on YouTube long-form) None

Start the server

Run this in a GNOME terminal, not inside Cursor (closing Cursor kills that process). Prefer the start script so uvicorn and the Cloudflare tunnel come up together (needed for TikTok / Meta OAuth). Skip --reload so a long Agnes or Local GPU job is not killed by a code save.

cd ~/wiki_to_video
./scripts/start_server.sh

Same as ./scripts/restart_with_tunnel.sh. Logs: /tmp/wiki_to_video_uvicorn.log, /tmp/wiki_to_video_cloudflared.log. Local-only (no tunnel): source .venv/bin/activate && uvicorn app:app --host 0.0.0.0 --port 8765.

Open http://127.0.0.1:8765

Mode 2 how-to

On New prompt, pick Mode 2 — Text → video (Agnes T2V), a Channel (when more than one exists), and a Topic search. Then:

  1. Platforms — check Shorts Meta (≤60s) and/or Shorts >60 (TikTok / YT Shorts / FB Reels) and/or Long form (16:9 YouTube). Both Shorts boxes default on (dual export). Uncheck one to build only that cut.
  2. Optional — Wikipedia URL or Search sources, edit VO instructions, set Tone and Voice, leave Enrich with Wikidata… on if you want extras on the brief, and pick Script / LLM Provider + Model for this Build only (pre-filled from Admin).
  3. Click Build video prompts. Mode 2 always auto-writes a finished spoken VO with that Script / LLM — there is no separate Write VO step. Templates then split the VO into scenes. After a successful Build (Modes 1, 2, 2.5), three short Agnes T2I stills (this pack’s topic + one-line fact from its title/brief; A Relic = one concrete topic relic (macro relic prompt first; never the word “icon”; cube ban via API negative); silhouette — shard / amphora / key / map / fossil, never a cube; B Face; C Reveal, with faces matching the topic’s people and place — Sparta → Greek / Mediterranean) are generated as YouTube-thumbnail candidates — pick one in the modal, From disk, Redo, or dismiss. The selected still is uploaded as a custom thumbnail on YouTube publish and as a Facebook Reels cover when Graph allows it (Stories have no cover API).
  4. Optional: edit the Scene board — Voiceover, On-screen text, and Visual (T2V prompt) per beat — then Save script. Mode 2 has no stills (no Skip / Lock / Replace).
  5. Queue — engine is locked to Agnes text→video. Click Queue selected platforms, then watch progress on Jobs.

Long form vs Shorts: Long builds a longer spoken VO (~1600–1900 words / ~700s when YouTube-only; Shorts ~225–275 / ~90–110s, never under 65s), renders 16:9, and writes an .srt next to the MP4 instead of burning captions into the frame. Shorts stay 9:16 with burned-in captions.

Mode 3.5 how-to

On New prompt, pick Mode 3.5 — Themed music long-form. First test: Sands of Amun + both channels. Then:

  1. Prompt — type topic keywords or click a chip (chips also set the palette).
  2. Music — pick a top-level WAV/MP3 from /mnt/nas_share/Videos/Channels/Musics (MUSIC_DIR, default CHANNELS_DIR/Musics; not Extended/).
  3. Type — Original (short WAV + one unique picture) or Extended (repeats + crossfade audio; longer unique picture, never N copies of the short MP4).
  4. Search vectors — keep Existing (Mix) plates (checkboxes; default = current / all if All vectors), then Vecteezy search (topic/prompt is editable; check hits and Add to selection to append). Selection done reviews Mix + every Vecteezy add (remove any; no search). Use selected vectors PUTs Mix motif ids + Vecteezy resource ids onto the pack. Cancel/X discards the draft and does not PUT. Vecteezy is search/preview thumbs only (no PAYG download). Mix stays the default. DreamShaper hides this picker.
  5. Then pick Palette and Style (Vector is the Mix default and looks selected; or DreamShaper / real — Comfy DreamShaper 8 + AnimateDiff, prompt + audio only). Vector Mix shows that family’s plates with All vectors on unless you drop some. DreamShaper hides Mix vector chips. Egypt gold-amber is not a recolor of Olympus marble twilight. Empty / unknown songs stay Dusk, never Egypt.
  6. Preview 10–15s — look-proof only (render_themed_music(..., preview_s=15) to TEMP/themed-preview/…/lookproof-15s.mp4). Not a Job. Does not overwrite full-short.mp4, v14, v16-dreamshaper, or library shorts.
  7. Check HistBuffer (EN) and/or Revisitando (PT). Fade in/out default 0.5s; Extended also shows crossfade / repeats (0.5 / 10).
  8. Bake themed music pack (existing Mode 3.5 generate — stamps palette, motifs, Vecteezy ids, and effect flags; PUT /api/prompts/{id}/themed-music updates a saved pack). Then Queue themed music when you want Jobs. Publish MP4s land as {music-title}_{channel}_original.mp4 / …_extended.mp4 (EN cut tags; display titles still use Extended / Estendido). After a server restart (hard-refresh is not enough for new Python), watch Jobs.
  9. YouTube long auto-publish uses that channel’s Admin Auto-publish → YouTube toggle (same as other modes); Publish / Schedule still work from Jobs. Shorts / Meta / TikTok auto-publish does not pick these up. Do not auto-cross-post the same MP4.

Extended audio is written as a new file under Musics/Extended/ next to the originals. Originals stay put. Mix and Vectors never fetch photos or stock video. Style vector / look=vector is Mix Pillow. Style dreamshaper / look=real is Comfy DreamShaper 8 + AnimateDiff (not base SD1.5). The Pexels radio still uses empty-landscape stock when a key is present. Vecteezy search is optional on Search vectors (preview/search only); Mix / Style vector stays the default. Policy notes: docs/themed-music-longform.md.

Operator flow

  1. Create a prompt — pick Mode 1 (wiki/stills), Mode 2 (text→video), Mode 2.5 (hybrid), Mode 3 (freeform prompt → HeartMuLa music, no wiki), or Mode 3.5 (themed music long-form: prompt keywords → music file → Original/Extended → Search vectors (keep Mix, append Vecteezy previews, review, PUT) → palette + Style (vector / Mix or dreamshaper / real) + effects → Preview 10–15s look-proof → Bake). Search a topic (Build uses the first source unless you pick another; exact-title / myth-history pages rank above lists, albums, and games), paste a URL, or (Mode 1) paste an external script. Opening a saved pack keeps that article — Build does not re-search. Mode 2 shows editable VO instructions and auto-writes on Build. Mode 3 asks for a music prompt + gen mode + duration (wiki fields are hidden). Script / LLM is pre-filled from Admin; change it for this Build only. The New icon (top of the form) wipes the page back to first-visit defaults (Admin Default Mode, leftover Mode 1 stills cleared) and focuses the Wikipedia URL field so you can paste. Step-by-step Mode 2: see Mode 2 how-to above.
  2. Build — Mode 1 / 3 always rewrites the brief with the Script / LLM selected on New prompt (this Build only), even if a pack with that title already exists. Mode 2 writes a finished VO and splits scenes from it. Wikipedia can be fetched again; local stills are kept when the scene list lines up. Stills stay in temp until you queue a job. Same title + tone + platforms overwrites the pack, not old Jobs rows — except after you Open a saved prompt and change anything; then Build/Save copies to a new id so the opened pack stays intact.
  3. Edit script — change voiceover, on-screen text, visuals, or caption. Mode 1: each beat shows the still Queue will use; Skip still cycles to another candidate, or lock before Queue. Mode 2: no stills — edit Voiceover / On-screen text / Visual (T2V prompt) only. Mode 2.5: each non-CTA scene can keep a wiki/stock still for I2V (Queue confirm grouped by platform). Mode 3 / 3.5: music pack only (no scene board). Agnes waits until Queue.
  4. Queue — moves the prompt folder to output, then the Admin default engine (shipped as CPU preview), Agnes image→video, Agnes text→video, or local GPU, plus a quiet Openverse bed under the voice for Mode 1 / 2 / 2.5. Mode 3 queues HeartMuLa music only (MP3 from the pack’s prompt — no wiki video). Mode 3.5 queues 16:9 YouTube longs (short + extended × selected channels; ffmpeg extend WAV → Musics/Extended/; Mix/Vectors/Pexels/ComfyUI unique picture per cut (empty-landscape stock only; ComfyUI is txt2vid vectors from the keyword prompt) + intro/Cinzel title lockup (word spaces kept)/logo — extended picture is not copies of the short MP4). Shorts auto-publish does not pick these up. Mode 2 locks the engine to Agnes text→video. Mode 2.5 Queue first shows every I2V still that would be sent, grouped by queued platform (Shorts >60, Meta ≤60, YouTube long, and any other) — one card per I2V beat per platform, not one still for the whole job (checkboxes; click a still or Change to pick an alternate sorted by context + quality; Change stills refetches; From disk); Confirm stores hybrid_stills on the Job. Mode 1 can still override the engine per job. CPU preview uses Pexels stock video clips when a beat matches (else Ken Burns). Tone and Voice are the same dropdowns as New prompt. Queue tone changes look, music, still preference, and filename; script shape stays from Build. Captions picks an OFL font for TikTok / Reels / Shorts (Auto from topic); YouTube long-form writes an SRT instead of burning text. Two jobs run at once (separate SQLite connections so parallel queue writes cannot crash a job). Agnes uses the free AGNES_API_KEY unless Admin fallback is free→paid and PAYED_AGNES_KEY is set. Mode 2 defaults to paid keys. The model defaults to agnes-video-v2.0 (change on Admin; Video 2.5 is listed but disabled). Create waits 300s for a task id. 503 retries stay on the current key. A Mode 1 miss stays a still; Mode 2 hard-fails after retries. Only one Agnes job at a time (queued Agnes jobs wait). GPU and stills can still run in parallel with each other. A second Local GPU job waits for the 3060. Local GPU has Draft / Balanced / High. Each platform gets a scratch folder; the MP4 lands at the prompt root.
  5. Jobs — duration, Mode (1 / 2 / 2.5 / 3), and publish status on the table; started/ended, file path, and download live in the expanded details. Play MP4, copy caption/hashtags, logs (newest first), output filename (not the host path). Mode comes from the stamped job field, else the pack’s video_mode, else a -mode2 prompt id suffix (older rows without those clues show —). CPU preview rows show a preview badge. Expanded rows (and a small badge on the row) show which script model wrote the brief, stamped at Build — e.g. Groq · openai/gpt-oss-20b, or extractive (no LLM) when the rewrite did not run. Stop on running marks cancelled and unwinds the worker. Separate row buttons: Retry and Delete on failed/cancelled; Delete on queued (cancel before start) or done asks to confirm, then removes the row from the list (MP4s stay). On failed/cancelled Mode 2 / 2.5 Shorts >60 rows (and any long-shorts row whose error asks to rewrite a longer VO), Rewrite VO lengthens the TikTok/YT/FB Reels voiceover on the existing pack, clears that platform scratch folder, and retries that job — no new Build; Meta ≤60s sibling stays. Hidden for Mode 3 / 3.5 music. Not gated on output file, backend (t2v vs hybrid), or used_llm. Emphasized when the error mentions Shorts voiceover after TTS / silence padding. On failed/cancelled meta_shorts rows, Rewrite Meta VO shortens only the Meta ≤60s voiceover on the existing pack (LLM when Mode 2 / provider available, else clip to ~113–137 words), clears that platform scratch folder, and retries that job — no new Build; Shorts >60 sibling stays. Emphasized when the error mentions Meta voiceover / ≤60s after TTS. Upgrade pack to Agnes (image→video) reuses the same script, assets, and brief LLM stamp (separate Jobs rows, not a retry). For text→video, queue Agnes text→video directly. Retry queues a new job; the table shows one row per chain with attempt history. For Agnes, Retry keeps complete clips on disk and continues from the first gap (use Retry, not a fresh Queue, after quota or restart). After Rewrite VO or Rewrite Meta VO, clips/voice for that cut are wiped so TTS uses the new script.
  6. Admin — settings page. Pick the Script provider (Groq default, OpenAI, Ollama, Gemini, Hugging Face, OpenRouter, Mistral, or NVIDIA; Claude and Grok not selectable) and model (Groq default qwen/qwen3.8-27b; also openai/gpt-oss-20b, openai/gpt-oss-120b; OpenAI paid gpt-4o-mini / gpt-4o / gpt-4.1-mini / gpt-4.1; Ollama list comes from this machine; Gemini: gemini-3.5-flash-lite default free-tier AI Studio, gemini-3.6-flash, gemini-3.5-flash, gemini-3.1-flash-lite; Hugging Face: meta-llama/Llama-3.1-8B-Instruct:fastest default plus other credit-limited :fastest router ids; OpenRouter: openrouter/free default plus :free models; Mistral: mistral-small-latest default plus Experiment Nemo/Ministral; NVIDIA: free preview chat NIMs from the public catalog, default openai/gpt-oss-20b). Gemini, Groq, OpenRouter free, Mistral Experiment, and NVIDIA preview are free-tier cloud; Hugging Face is credit-limited (~$0.10/mo then paid); Claude is disabled in the picker (paid); Grok (xAI) is paid backlog; Ollama is free-local but can freeze the machine (default auto start/stop: app-owned ollama serve only while a local LLM call runs); OpenAI is paid. Also the Agnes video model (default agnes-video-v2.0), free-only vs free→paid fallback, default Create-prompt Mode (1 / 2 / 2.5 / 3 / 3.5; shipped as Mode 2), default Queue engine (CPU preview / Agnes / Local GPU), and Light / Dark theme. Shows OpenAI / Claude / Gemini / Groq / Grok / Hugging Face / OpenRouter / NVIDIA key present/missing, Ollama reachable/stopped (auto), paid-key present/missing, and last Agnes GET /v1/models probe (video models + queue note). Saved in SQLite. Theme applies to every page immediately. Keys are not shown.

Admin and Agnes Video 2.5

Admin stores these settings in SQLite: Script provider (groq default, openai, ollama, gemini, huggingface, or nvidia; claude and grok not selectable) and model (Groq: qwen/qwen3.8-27b default, plus openai/gpt-oss-20b, openai/gpt-oss-120b; OpenAI paid: gpt-4o-mini, plus gpt-4o, gpt-4.1-mini, gpt-4.1; Ollama: tags from GET /api/tags on OLLAMA_HOST; Gemini: gemini-3.5-flash-lite default, plus gemini-3.6-flash, gemini-3.5-flash, gemini-3.1-flash-lite; Hugging Face: openai/gpt-oss-20b:fastest default plus other :fastest router ids; NVIDIA: free preview chat NIMs, default openai/gpt-oss-20b), Agnes model, fallback (free or free_then_paid), default Create-prompt Mode (mode1 / mode2 / mode2_5 / mode2_6 / mode5_01 / mode3 / mode3_5; shipped mode2), default Queue engine (stills / agnes / gpu), channel branding (name, description, logo, Video language, and per-network binders for YouTube / Meta / TikTok / X / Bilibili — handle, Short/Long modes, secrets, Connect, auto-publish), and page theme (light is the current default; dark is a full page theme). Renders burn the logo as a watermark on every clip and show the channel name plus the platform @ on the last few seconds (end card). Spoken follow/subscribe CTA and the on-screen CTA chip appear on the final beat only (short and long); mid-video chapter titles stay narration nouns, not “FOLLOW FOR MORE”. Default logo: static/brand/history-buffer-icon.png. New Queue jobs use the saved engine when you do not pick one. New Agnes jobs stamp the selected model at queue time. Fallback default is free (Mode 1 proven mode). free_then_paid adds shorts-pool paid slots when PAYED_AGNES_KEY and/or PAYED_AGNES_KEY_3 / PAYED_AGNES_KEY_4 are present (long key B is reserved for YouTube long); if all shorts keys are missing, jobs keep using free and Admin shows a warning. Mode 2 plan defaults to paid with pool-scoped rotation by estimated UTC daily video seconds (A+C+D shorts · B long; soft threshold ~450 of 500; 402 exhausts a key for the day). Keys themselves are never shown — Admin shows present/missing and local estimates. Agnes status is a GET /v1/models probe (refresh on the page) — video models and last queue/health note, no billed create.

Publishing: connect YouTube / Meta / TikTok on Admin; Jobs Publish uploads when connected. Admin Auto-publish toggles (YouTube long / Shorts default on; others off). Google (YouTube) + Meta OAuth click-by-click (two channels, same tunnel) — docs/oauth-google-meta.md. X and Bilibili are extra destinations for the same finished MP4 (not new Queue platforms) — see docs/x-bilibili-publish.md. Both are manual only for now (Mark published after upload on x.com / bilibili.com; OAuth API is optional/future). Checking Shorts produces two Jobs rows: long Shorts (≥65s) for TikTok / YT Shorts / FB Reels, and Meta Short (≤60s) for Instagram (Reels / Stories) + Facebook Stories. Meta Jobs publish supports Instagram Reels and Stories (≤60s; default on) via Instagram format checkboxes on the Meta Short row (any non-empty subset; Publish posts each selected format in turn). There is no Instagram Feed Post checkbox on meta_shorts. Facebook from that row is Stories only — no Facebook Reels on meta_shorts. Facebook Stories use the Meta Short master; Facebook Page Reels use the long Shorts master (Reels only — no Post/Stories on Shorts >60). Admin auto-publish stays Reels-only (IG from Meta cut, FB from long Shorts). YouTube PT: English channels upload soft Portuguese captions (captions.insert, filename.pt.srt from timed EN SRT) alongside English; Brazilian channels keep a single PT track. Dubbed audio (PT-BR voiceover file for Studio Languages — API does not upload dubs yet) is still backlog. Channels: Admin can add named profiles. Each social network is a collapsible binder (handle, Short/Long, optional SQLite secrets, Connect / Mark, auto-publish). YouTube supports Shorts and long-form together. New prompt picks a channel when more than one exists; Jobs shows a Channel column and a Mode column (1 / 2). Jobs filters (status, tone, platform, channel, mode, backend) are dropdowns with checkboxes — pick several values; Any clears the filter.

Video 2.5 / 2.5 Flash (updated 14 Sep 2026): Official ids are agnes-video-2.5 and agnes-video-2.5-flash (Flash docs). Create uses a different Videos contract (mode text / keyframe / reference, seconds / size / aspect_ratio; I2V via first_frame or images[], not ti2vid). Poll prefers GET /agnesapi?video_id=…&model_name=…. Admin Agnes generation offers 2.0 (default) or 2.5 Flash — one control for Modes 1 / 2 / 2.5 / 2.6 video and paired non-thumb image models (agnes-image-2.0-flash vs agnes-image-2.5-flash). YouTube prompt thumbnails always use agnes-image-2.0-flash (2.5 Flash invents Rubik/cube Icon stills). Paid bare agnes-video-2.5 stays not selectable. Share-link camera prompts: docs/agnes-25-flash-share-prompts.md.

Full operator notes: README on GitHub and README.md in the repo.