SKILL.md
SKILL.mdBrowse 9 files
9,304 bytes
Token encoding: o200k_base
Snapshot 24fd22b
AI Presenter Video
Turn a topic (or finished script) plus ONE authorized adult presenter image into a complete, publish-ready presenter-led video: locked narration, avatar generation with lip-sync QA, captions, deterministic editing, loudness-normalized master/share encodes, and machine + visual acceptance reports.
Use this skill for new presenter videos AND for continuing, revising,
captioning, lip-sync-repairing, or re-exporting an existing presenter-video
job. The workflow is provider-neutral: pick generation capabilities from what
is actually available in the session (FAL video/image models via
image_generate and the video-gen plugin, TTS via text_to_speech, ASR via
the whisper/STT tooling, ffmpeg for everything deterministic).
Ported from cclank/lanshu-create-ai-presenter-video (MIT). Upstream body kept substantively verbatim in
references/; Hermes adaptations live in this hub file. Scripts are deterministic (no network, no credentials).
Hermes adaptations (read first)
-
Skill dir resolution — upstream hardcoded its own agent's skills path. In Hermes the loader expands
${HERMES_SKILL_DIR}to this skill's installed directory, so every command below uses that token directly:SKILL_DIR="${HERMES_SKILL_DIR}"Shell variables do not persist between tool calls — re-paste the assignment (or the expanded path) in each terminal call that uses it.
-
Capability mapping — where the references say "a voice generation capability", use
text_to_speech(OpenAI/Edge/ElevenLabs per user config); "presenter/avatar generation" → FAL image-to-video families (Kling, Wan, MiniMax H3 etc.) through the configured video tooling, or an avatar/lipsync endpoint the user has access to; "word-timestamp ASR" → whisper via the STT tooling orfaster-whisperin a venv; "deterministic compositor" → ffmpeg filtergraphs, or thehyperframesskill when installed (the editing reference has a HyperFrames section that maps directly onto it). -
Visual QA — do the "normal-speed visual review" steps with
vision_analyzeon the generated contact sheet plus sampled frames (identity, mouth timing, hands, blinking, continuity). Numeric checks come from the scripts' ffprobe output. -
Paid-generation consent — remote avatar/TTS generation is billable. Follow the upstream operating rules: before the first paid call state the uploaded assets, requested seconds, known cost, pilot size, and retry ceiling, and get the user's explicit go-ahead. Never upload the presenter image to a remote provider before
remote_upload_approvedis true injob.json. -
Consent flags live under
input—rights_confirmed,adult_presenter_confirmed,remote_upload_approved, andvoice_clone_approvedsit inside theinputobject ofjob.json(init flags set them; hand-editing must targetinput.*, not the job root).manual_input_review.*sits at the root.preflight.pydistinguisheserrors(block everything) fromremote_blockers(block only remote generation) — local script/audio work may proceed while remote is blocked.
Workflow
-
Start or resume a job. New job:
python3 "$SKILL_DIR/scripts/init_job.py" \ --job-dir ~/Videos/my-presenter-video \ --presenter-image /path/to/presenter.png \ --topic "explain context engineering in one minute" \ --duration 60 --aspect 9:16 \ --rights-confirmed --adult-presenter-confirmedUse
--scriptfor an existing script file; other flags:--voice-sample,--supporting-media,--width,--height,--fps,--watermark,--cta. For an existing job, readjob.json+ QA reports and resume from the earliest unfinished state — never regenerate accepted work. -
Manual input review. Actually look at the presenter image (
vision_analyze) and listen to any voice sample; record findings by setting themanual_input_reviewbooleans injob.json, e.g.:python3 - <<'PY' import json p = "~/Videos/my-presenter-video/job.json" # expand ~ or use an absolute path import os; p = os.path.expanduser(p) j = json.load(open(p)) j["manual_input_review"].update(image_viewed=True, single_clear_face=True, image_has_no_unwanted_text=True) json.dump(j, open(p, "w"), indent=2) PYThen gate:
python3 "$SKILL_DIR/scripts/preflight.py" ~/Videos/my-presenter-video/job.jsonProceed only when
ok: true; do remote generation only whenremote_ready: true. Note: preflight also updatesjob.jsonin place (records the report path) — re-read it after running rather than editing a stale copy. -
Lock content and audio — read
references/generation.md. Script → full narration viatext_to_speech→ ASR-verify the narration against the script → record real durations. The locked audio is the master clock for everything downstream. -
Plan and generate the presenter — read
references/generation.md. Short low-cost pilot first; full run only after the pilot passes identity and mouth-timing review. -
Edit — read
references/editing.md. Deterministic timeline driven by the locked audio; captions and keyword callouts only after audio and media are final. -
Verify and deliver — read
references/qa-recovery.md, render, then:bash "$SKILL_DIR/scripts/finalize_delivery.sh" \ ~/Videos/my-presenter-video/renders/rendered.mp4 \ ~/Videos/my-presenter-video/outputs my-videoThe finalizer preserves aspect ratio, runs two-pass loudness normalization (program ≈ −16 LUFS), produces master + share encodes, decode-verifies both, writes a delivery report JSON, and emits a nine-frame contact sheet. Inspect the contact sheet with
vision_analyzebefore claiming completion.
Operating rules (non-negotiable)
- Confirm image rights, adult status, remote-upload approval, and voice-cloning authorization before the relevant remote action.
- Never infer or clone a real person's voice from an image; use an authorized sample or a stock TTS voice.
- Lock the complete narration before presenter generation, caption timing, or final scene boundaries.
- Mute video sources in the final composition; only the approved narration and intentional mix tracks carry audio.
- Preserve provider request bodies and task IDs (minus credentials/expiring URLs). Poll interrupted work before resubmitting — avoid double billing.
- Stop after three rejected paid candidates and summarize the failure mode.
- Do not claim completion until the final files fully decode and the contact sheet or full playback has been reviewed.
Defaults for minimal input
9:16, 1080×1920, 30fps; topic-derived videos target 45–75s; stock voice when no authorized sample; presenter-led layout with hook → 2–4 beats → close; no music/CTA unless requested; language inferred from the request.
Reference routing
references/generation.md— intake, content, voice, capability selection, presenter prompts, paid generation, provider changes.references/editing.md— timeline contract, openings/closes, captions, keyword-callout presets, HyperFrames composition, exports.references/qa-recovery.md— technical acceptance, visual acceptance, and recovery for lip-sync/identity/hands/exposure/freeze/caption/audio faults.
Pitfalls
preflight.pyrequires ffprobe; on a bare box install ffmpeg first.- The consent booleans set by init flags land under
input.*; editing them at the job-json root silently does nothing (preflight keeps blocking). finalize_delivery.shneeds bash + jq + awk and a fully decodable input — a truncated render fails the decode check by design, not by accident.- Long avatar clips drift: prefer one continuous presenter source sliced on the audio timeline over many regenerated chapter clips (identity drift across regenerations is the #1 visual-QA failure).
- FAL i2v endpoints cap duration (typically 5–15s); plan chapter-level presenter segments accordingly and reuse the pilot's seed/params for consistency where the endpoint supports it.
Verification
Validated hands-on (Aug 2026): init_job.py → job.json with correct state
machine; preflight.py correctly blocked on unreviewed inputs, flipped to
ok: true after review booleans, and kept remote_ready: false until
input.remote_upload_approved; finalize_delivery.sh on a synthetic 5s
1080×1920 render produced decode-verified master (631kbit/s) + share encodes,
delivery-report JSON, and a 9-frame contact sheet, exit 0.
Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root AGENTS.md.