operator manual / legacy edition
Documentation
A self-hostable AI faceless-video auto-poster. You bring API keys; it generates a daily AI video per account and posts it on schedule.
Overview
Each scheduled post runs one resumable pipeline:
AI character → AI video (Kling) → AI music (Stable Audio) → viral text overlay → + your app demo → caption → publish (Zernio).
You describe your app once; a minute-by-minute cron fires due slots; a detached worker runs each job and is crash-resumable. Cost ≈ $0.70/video (fal) + cents (OpenAI), capped by a daily budget.
Requirements
- PHP 8.3+ with
pdo_sqlite,curl,mbstring - ffmpeg + ffprobe built with
libfreetype(the overlay usesdrawtext) +fonts-dejavu - A web server with PHP-FPM (Caddy / nginx / Apache), docroot
public/ - Accounts: fal.ai, OpenAI, Cloudflare R2, Google OAuth, Zernio
Quick start
php bin/setup.php # checks deps, creates .env, inits the SQLite DB
$EDITOR .env # fill in FAL_KEY, OPENAI_API_KEY, R2_*, GOOGLE_CLIENT_ID, secrets
php -S 127.0.0.1:8090 public/index.php
# open http://127.0.0.1:8090 → sign inThen in the app: connect your Zernio key → create a workspace → add accounts → set up an AI character per account → upload your app-demo clips → set a schedule.
Environment
Everything is in .env (gitignored, chmod 600). See .env.example for every key with notes. Generate secrets with php -r "echo bin2hex(random_bytes(32)).PHP_EOL;".
| Key | What |
|---|---|
FAL_KEY | fal.ai — AI image / video / music |
FAL_DAILY_BUDGET_USD | kill-switch: stop generating past this daily spend |
OPENAI_API_KEY / OPENAI_MODEL | caption + on-video hook text |
R2_* | Cloudflare R2 (S3-compatible) storage |
GOOGLE_CLIENT_ID | sign-in (Authorized JS origin = APP_URL) |
APP_NAME | your brand (navbar + titles) |
DRY_RUN | 1 = generate but don't post |
Operator access
Single-operator by design. ENTITLEMENT_ALLOWLIST empty = open (anyone who signs in); set it to your email to lock the instance to yourself. ADMIN_EMAILS controls admin-only features.
The pipeline
Per post: a fresh variation of the account's locked character image → a 5s Kling reaction clip → a Stable Audio bed (vibe per character) → the OpenAI hook is burned on TikTok-style (white + black stroke, centered) → your app-demo clip is appended → muxed with the music → an OpenAI caption → published via Zernio. State persists per stage so a crashed worker resumes.
First real post
- Set up an AI character on an account (Schedule tab → describe → save).
- Upload at least one app-demo clip (Library tab).
- Enable a schedule hour, or watch the cron fire the due slot.
- Watch the Overview dashboard light up
IMAGE → VIDEO → MUSIC → OVERLAY → PUBLISH.
Deploy
Serve public/ with PHP-FPM behind Caddy/nginx. Add the cron (every minute):
* * * * * php /path/to/app/bin/cron.php >> /path/to/app/logs/cron.log 2>&1Set APP_ENV=production, DEV_LOGIN=0, and a real SESSION_COOKIE_DOMAIN.
Customize
- Brand:
APP_NAMEin.env; logo SVG inpublic/views/_brand.php. - Theme: CSS variables at the top of
public/assets/style.css(light/dark/blue). - Prompts & models: character/video/music prompts in
src/gen_pipeline.php; caption/hook insrc/openai_caption.php; model IDs + costs insrc/fal_client.php. - Overlay style: font/size/stroke in
Mux::hookFilters()(src/ffmpeg_mux.php).
Code layout
public/ index.php (front controller) + views + assets
src/ gen_pipeline, fal_client, openai_caption, ffmpeg_mux,
zernio_client, r2_client, media_select, auth, gate, db, crypto
bin/ cron.php (scheduler), gen_worker.php (one job), setup.php
db/schema.sql SQLite schema (IF NOT EXISTS; safe to re-apply)Support
Questions? Email support@goviraldev.com. License terms are in LICENSE.