This repository contains a backend service that takes a code/script input, generates an AI narration (TTS), converts the script into a tutorial-style scrolling video using FFmpeg and Canvas, and exposes the resulting media for a frontend to display.
This README explains the project structure, how the parts connect, how to run the server, and suggested improvements for production use.
Repository layout
-
src/- Main server code and helpersserver.ts- Express server. Servessrc/outputstatically and mounts the API routes under/api.cli.ts- Command-line interface for local usage (analyze a file and optionally generate voice/video).codeAnalyzer.ts- Uses OpenAI to convert code into segmented narration or tutorial text.textToSpeech.ts- Uses OpenAI TTS to generate.mp3voiceover files.videoGenerator.ts- Creates slides or a scrolling image of the script and usesffmpegto produce a final.mp4synchronized to the audio.output/- Output directory for generated.mp3and.mp4files (served at/outputby the server).slides/- Temporary slide assets used during video generation.types.ts,config.ts, etc. - small helpers and types.
-
weaveit-generator/- Canonical API route implementationsgenerateRoute.ts- POST/api/generate— accepts{ script, title?, transactionSignature? }, enhances the script withcodeAnalyzer, produces audio and video intosrc/output, and returns{ contentId, videoUrl }when finished.videosStatusRoute.ts- GET/api/videos/status/:id— checks whether/src/output/:id.mp4or/src/output/:id.mp3exists and returns a JSON status.
Notes: small re-export stubs exist in src/ so existing imports remain compatible while the canonical implementations live under weaveit-generator/.
How the pieces connect
-
Frontend POSTs to
/api/generatewith a JSON body containing the script text. -
weaveit-generator/generateRoute.tsreceives the request, optionally generates acontentId, and:- Calls
enhanceScriptfromsrc/codeAnalyzer.tsto produce a narrated explanation (segmented or continuous text). - Calls
generateSpeech(fromsrc/textToSpeech.ts) to produce an.mp3voiceover saved tosrc/output/<id>.mp3. - Calls
generateScrollingScriptVideo(fromsrc/videoGenerator.ts) which makes a tall image or slide images, produces a scrolling/cropped video withffmpeg, merges audio, and savessrc/output/<id>.mp4. - Returns
{ contentId, videoUrl }when the generation completes successfully.
- Calls
-
The server (
src/server.ts) serves the generated files athttp://<host>:<port>/output/<id>.mp4(static) and provides a status endpoint at/api/videos/status/:idto allow polling.
API endpoints
- POST
/api/generate- Request body:
{"script": string, "title"?: string, "transactionSignature"?: string} - Synchronous behavior: current implementation waits for TTS + FFmpeg to finish and responds with JSON containing
contentIdandvideoUrl. - Example using
curl:
- Request body:
curl -X POST 'http://localhost:3001/api/generate' \
-H 'Content-Type: application/json' \
-d '{"script":"console.log(\"hello\")","title":"Hello demo"}'- GET
/api/videos/status/:id- Returns JSON with
ready,status, andcontentUrlpointing to/output/<id>.mp4or/output/<id>.mp3. - Example:
- Returns JSON with
curl 'http://localhost:3001/api/videos/status/<contentId>'- Static media:
GET /output/<id>.mp4serves the generated video file directly.
Local development / prerequisites
- Node.js (compatible with the
package.jsondev dependencies). Recommended: Node 18+. - A package manager:
pnpm,npm, oryarn. ffmpegmust be installed and available onPATH(the video generator usesfluent-ffmpeg).- An OpenAI API key must be present as
OPENAI_API_KEYin a.envfile at the project root.
Install and run locally:
# install
pnpm install
# start dev server (uses ts-node / ESM)
pnpm run dev
# or
npx ts-node-esm src/server.tsCLI
There is a small CLI for local testing:
# Analyze a file and optionally create voice/video
npx ts-node src/cli.ts analyze -f path/to/script.ts --voice --videoBehavioral notes & production recommendations
- Synchronous vs asynchronous: The current
POST /api/generateimplementation runs TTS and FFmpeg inside the request handler and only responds when finished. This is simple but not ideal for production because:- Requests may take a long time (tens of seconds to minutes) which can lead to client or proxy timeouts.
- It blocks server resources.
Recommended production improvements:
- Convert generation into an asynchronous job: return
202 Acceptedwith acontentId, enqueue a job (Redis/Bull, RabbitMQ, or a simple worker process), and let the frontend poll/api/videos/status/:id. - Provide progress updates via Server-Sent Events (SSE) or WebSockets if you want real-time progress in the frontend.
- Add authentication and rate-limiting to protect the TTS / OpenAI usage.
- Add strict request size limits (body parser limits) and input validation.
- Persist metadata about jobs (timestamps, user, size) to a lightweight DB if auditing is needed.
Security & Cost
- TTS uses the OpenAI API: protect your API key and avoid exposing it to clients.
- Generating videos and calling the TTS API has costs — add usage limits, quotas or billing controls.
Troubleshooting
- If ffmpeg fails or you see errors while generating videos, confirm
ffmpegis installed and the PATH is correct. - If TTS fails, ensure
OPENAI_API_KEYis valid and environment variables are loaded (server reads.envby default). - Check server logs (console output) —
videoGenerator.tsandtextToSpeech.tslog progress and errors.
Where to go next
- I can convert the synchronous generator into a job queue and make
/api/generatereturn immediately with202plus a polling-friendly status endpoint. - I can add SSE/WebSocket-based progress events to show generation progress to the frontend.
If you'd like either of those, tell me which approach you prefer and I will implement it.
Generated by repository automation — keep this README updated as code moves between src/ and weaveit-generator/.
Quick Frontend Example
This minimal example demonstrates how a frontend can POST the script, poll for readiness, and then display the video.
// POST the script
const resp = await fetch('http://localhost:3001/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ script: "console.log('hello')", title: 'Demo' })
});
const { contentId } = await resp.json();
// Poll status
let ready = false;
while (!ready) {
await new Promise(r => setTimeout(r, 2000));
const s = await fetch(`http://localhost:3001/api/videos/status/${contentId}`);
const data = await s.json();
if (data.ready) ready = true;
}
// Show video
const videoUrl = `http://localhost:3001/output/${contentId}.mp4`;
document.querySelector('#player').src = videoUrl;Environment variables
.envat project root should include:OPENAI_API_KEY— required for TTS and code analysis.
Important runtime details
- Default server port:
3001(seesrc/server.ts). - Generated media is written to
src/output/and served statically at/output. - Video generation is CPU- and IO-heavy. Ensure adequate disk and CPU resources on the host.
npm / Scripts
pnpm run dev— runts-node-esm src/server.ts(development)pnpm run build— compile TypeScript (tsc)pnpm run start— run compiled server (node dist/server.js)
Extra notes
- File retention: generated media remains in
src/outputuntil you remove it. Add a retention policy or cleanup job for production. - Concurrency: if many users submit jobs simultaneously, convert generation to background jobs to avoid exhausting resources.
If you'd like I can also:
- Convert
/api/generateto enqueue background jobs and return202 Acceptedimmediately. - Add SSE or WebSocket progress events so the frontend receives real-time logs/progress.
- Create a sample HTML/JS frontend that uploads scripts and displays status/video.
Tell me which of those you prefer and I will implement it.