Hafiza-Laiba-Faisal/video-gen-tenbit

0

stars

1

commits

TypeScript

primary language

Sep 5, 2026

updated

README

AI Video Generation SaaS

Text / image / voice → AI video, with a multi-model catalogue, AI assistance, credit billing, and GPU generation on RunPod serverless.

Everything runs on this machine except the GPU work.

just-right-main/   frontend   TanStack Start + React 19 + Tailwind v4    :8080
api/               backend    Fastify + Prisma + BullMQ + PostgreSQL     :4100
worker/            GPU        Python + diffusers, runs on RunPod serverless
infra/             ops        docker-compose, pm2, provisioning, deployment
storage/           data       generated videos, thumbnails, uploads
PLAN.md            the build plan and architecture decisions

Quick start

docker compose -f infra/docker-compose.yml up -d
cd api && npm install && npx prisma migrate deploy && npm run db:seed

Then in two terminals:

cd api && npm run dev
cd api && npm run worker

And the frontend:

cd just-right-main && npm install && npm run dev

Open http://localhost:8080, register, and generate. New accounts get 500 free credits.

Verify the whole stack end to end at any time:

cd api && npm run smoke

Current state

PieceStatus
Auth, sessions, API keysworking
Credit ledger (hold → capture → release/refund)working, 48/48 tests
Model registry — 22 video models + 6 support modelsworking
Capability resolver / grey-out engineworking
Job pipeline, progress, storage, downloadworking
Frontend, fully wired to the APIworking
GPU generationmock provider — renders a real mp4 with ffmpeg
RunPod endpointnot deployed (account balance is $0)
Model weightsnot downloaded (~956 GB)
Card paymentsnot built (needs a public webhook URL)
Voice transcriptionnot available (Whisper lives on the GPU volume)

The mock provider produces a genuine, playable, correctly-sized h264 mp4 with the prompt burned in and marked "PREVIEW RENDER — no GPU used". Every other part of the system — credits, queueing, timing, storage, history, download — behaves exactly as it will in production. Switching to real generation is one env var.


Going live on RunPod

1. Fund the account. Nothing below works at $0. runpod.io/console/billing

2. Build and push the worker image.

cd api && npm run export:registry
cd worker && docker build -t <your-registry>/videogen-worker:latest . && docker push <your-registry>/videogen-worker:latest

3. Create the RunPod infrastructure. Creates the network volume, template, B200 endpoint and B300 fallback, then writes the ids into api/.env.

node infra/runpod-deploy.mjs --image <your-registry>/videogen-worker:latest --volume-gb 2000

4. Download the model weights. Start a cheap RunPod pod with the volume mounted, then:

python infra/provision-models.py --volume /workspace --api https://<tunnel>/api/v1 --token <RUNPOD_WEBHOOK_SECRET>

Priority order, resumable, and it reports progress back so models light up in the UI as they land. The first four (~150 GB) make the platform genuinely usable; the full catalogue is ~956 GB and takes many hours.

5. Restart the API. It picks up GPU_PROVIDER=runpod and starts dispatching to real B200s.

Optional: a public URL, free, no domain

Needed for RunPod webhooks and for videos over the 10 MB inline return limit.

cloudflared tunnel --url http://localhost:4100

Put the printed https://….trycloudflare.com into PUBLIC_BASE_URL in api/.env and restart. Webhooks and direct worker upload switch on automatically.


How pricing works

credits = ceil(billed_gpu_seconds × $/sec × MARGIN × 100)     1 credit = $0.01

MARGIN is 2.0 — the user pays twice what RunPod charges us. Queue time and cold starts are excluded; we absorb those.

Every generation runs estimate → hold → capture → release:

  • the price is quoted live before you press Generate;
  • hold × 1.25 is reserved so the balance can't be overdrawn;
  • on completion we charge the actual executionTime and return the rest;
  • on failure, timeout or cancellation the hold is returned in full.

The ledger is append-only and reconciled nightly, so the balance is always reconstructible from it.

The per-GPU rates in api/src/billing/rates.ts are derived from RunPod's pod prices read on 2026-08-07 and are marked NEEDS_CALIBRATION. Compare them against real executionTime values and the RunPod billing page after the first ~20 live generations, then correct that one file.


Adding a model

  1. Add an entry to api/src/models/registry.ts — capabilities, constraints, cost model, hfRepo.
  2. cd api && npm run export:registry
  3. If it's a new architecture, add an adapter class in worker/adapters.py. Existing families (Wan, LTX, Hunyuan, CogVideoX, Mochi, AnimateDiff, SVD, Allegro) need nothing.
  4. Download the weights with provision-models.py --only <model-id>.

The frontend needs no changes — it renders the entire settings UI, including which options grey out and why, from GET /api/v1/models and POST /api/v1/models/resolve.


Operations

pm2 start infra/pm2.config.cjs
pm2 logs vg-api --lines 100
CheckURL
Livenesshttp://localhost:4100/healthz
Readiness (DB, Redis, GPU)http://localhost:4100/readyz
Admin statsGET /api/v1/admin/stats

Seeded admin: admin@videogen.local / changeme-admin-2026change this before the machine is reachable from anywhere but localhost.

Ports

ServicePortNote
Frontend8080
API41004000 was already taken by another process on this machine
PostgreSQL5433non-standard, avoids clashing with a local install
Redis6380non-standard, same reason

Security notes before this leaves localhost

  • Change the seeded admin password
  • Set COOKIE_SECURE=true (requires HTTPS)
  • Rotate JWT_SECRET — this invalidates every session
  • Change the Postgres password in docker-compose.yml and DATABASE_URL
  • Put the API behind a reverse proxy with TLS
  • Review WEB_ORIGIN — it's currently permissive for local development

svd-xt-1.1 is in the registry but blocked from dispatch: its licence is non-commercial research only, and this is a paid product. hunyuanvideo carries a community licence that excludes the EU, UK and South Korea — gate it by user region before launching there.

Contributors

Hafiza-Laiba-Faisal/video-gen-tenbit

0

stars

1

commits

TypeScript

primary language

Sep 5, 2026

updated

README

AI Video Generation SaaS

Text / image / voice → AI video, with a multi-model catalogue, AI assistance, credit billing, and GPU generation on RunPod serverless.

Everything runs on this machine except the GPU work.

just-right-main/   frontend   TanStack Start + React 19 + Tailwind v4    :8080
api/               backend    Fastify + Prisma + BullMQ + PostgreSQL     :4100
worker/            GPU        Python + diffusers, runs on RunPod serverless
infra/             ops        docker-compose, pm2, provisioning, deployment
storage/           data       generated videos, thumbnails, uploads
PLAN.md            the build plan and architecture decisions

Quick start

docker compose -f infra/docker-compose.yml up -d
cd api && npm install && npx prisma migrate deploy && npm run db:seed

Then in two terminals:

cd api && npm run dev
cd api && npm run worker

And the frontend:

cd just-right-main && npm install && npm run dev

Open http://localhost:8080, register, and generate. New accounts get 500 free credits.

Verify the whole stack end to end at any time:

cd api && npm run smoke

Current state

PieceStatus
Auth, sessions, API keysworking
Credit ledger (hold → capture → release/refund)working, 48/48 tests
Model registry — 22 video models + 6 support modelsworking
Capability resolver / grey-out engineworking
Job pipeline, progress, storage, downloadworking
Frontend, fully wired to the APIworking
GPU generationmock provider — renders a real mp4 with ffmpeg
RunPod endpointnot deployed (account balance is $0)
Model weightsnot downloaded (~956 GB)
Card paymentsnot built (needs a public webhook URL)
Voice transcriptionnot available (Whisper lives on the GPU volume)

The mock provider produces a genuine, playable, correctly-sized h264 mp4 with the prompt burned in and marked "PREVIEW RENDER — no GPU used". Every other part of the system — credits, queueing, timing, storage, history, download — behaves exactly as it will in production. Switching to real generation is one env var.


Going live on RunPod

1. Fund the account. Nothing below works at $0. runpod.io/console/billing

2. Build and push the worker image.

cd api && npm run export:registry
cd worker && docker build -t <your-registry>/videogen-worker:latest . && docker push <your-registry>/videogen-worker:latest

3. Create the RunPod infrastructure. Creates the network volume, template, B200 endpoint and B300 fallback, then writes the ids into api/.env.

node infra/runpod-deploy.mjs --image <your-registry>/videogen-worker:latest --volume-gb 2000

4. Download the model weights. Start a cheap RunPod pod with the volume mounted, then:

python infra/provision-models.py --volume /workspace --api https://<tunnel>/api/v1 --token <RUNPOD_WEBHOOK_SECRET>

Priority order, resumable, and it reports progress back so models light up in the UI as they land. The first four (~150 GB) make the platform genuinely usable; the full catalogue is ~956 GB and takes many hours.

5. Restart the API. It picks up GPU_PROVIDER=runpod and starts dispatching to real B200s.

Optional: a public URL, free, no domain

Needed for RunPod webhooks and for videos over the 10 MB inline return limit.

cloudflared tunnel --url http://localhost:4100

Put the printed https://….trycloudflare.com into PUBLIC_BASE_URL in api/.env and restart. Webhooks and direct worker upload switch on automatically.


How pricing works

credits = ceil(billed_gpu_seconds × $/sec × MARGIN × 100)     1 credit = $0.01

MARGIN is 2.0 — the user pays twice what RunPod charges us. Queue time and cold starts are excluded; we absorb those.

Every generation runs estimate → hold → capture → release:

  • the price is quoted live before you press Generate;
  • hold × 1.25 is reserved so the balance can't be overdrawn;
  • on completion we charge the actual executionTime and return the rest;
  • on failure, timeout or cancellation the hold is returned in full.

The ledger is append-only and reconciled nightly, so the balance is always reconstructible from it.

The per-GPU rates in api/src/billing/rates.ts are derived from RunPod's pod prices read on 2026-08-07 and are marked NEEDS_CALIBRATION. Compare them against real executionTime values and the RunPod billing page after the first ~20 live generations, then correct that one file.


Adding a model

  1. Add an entry to api/src/models/registry.ts — capabilities, constraints, cost model, hfRepo.
  2. cd api && npm run export:registry
  3. If it's a new architecture, add an adapter class in worker/adapters.py. Existing families (Wan, LTX, Hunyuan, CogVideoX, Mochi, AnimateDiff, SVD, Allegro) need nothing.
  4. Download the weights with provision-models.py --only <model-id>.

The frontend needs no changes — it renders the entire settings UI, including which options grey out and why, from GET /api/v1/models and POST /api/v1/models/resolve.


Operations

pm2 start infra/pm2.config.cjs
pm2 logs vg-api --lines 100
CheckURL
Livenesshttp://localhost:4100/healthz
Readiness (DB, Redis, GPU)http://localhost:4100/readyz
Admin statsGET /api/v1/admin/stats

Seeded admin: admin@videogen.local / changeme-admin-2026change this before the machine is reachable from anywhere but localhost.

Ports

ServicePortNote
Frontend8080
API41004000 was already taken by another process on this machine
PostgreSQL5433non-standard, avoids clashing with a local install
Redis6380non-standard, same reason

Security notes before this leaves localhost

  • Change the seeded admin password
  • Set COOKIE_SECURE=true (requires HTTPS)
  • Rotate JWT_SECRET — this invalidates every session
  • Change the Postgres password in docker-compose.yml and DATABASE_URL
  • Put the API behind a reverse proxy with TLS
  • Review WEB_ORIGIN — it's currently permissive for local development

svd-xt-1.1 is in the registry but blocked from dispatch: its licence is non-commercial research only, and this is a paid product. hunyuanvideo carries a community licence that excludes the EU, UK and South Korea — gate it by user region before launching there.

Contributors

Languages

TypeScript

63.8%

HTML

20.5%

Python

8.2%

JavaScript

3.8%

CSS

1.8%

Shell

1.0%