English · العربية · Español · Français · 日本語 · 한국어 · Tiếng Việt · 中文 (简体) · 中文(繁體) · Deutsch · Русский
AI-assisted video workflow for generation, subtitle processing, metadata, and optional publishing.
Upload or generate -> transcribe -> translate/polish -> burn subtitles -> caption/keyframes -> metadata -> publish
Studio publish workflow with platform selection, live preview, process status, and queue tracking.
LazyEdit is an end-to-end AI-assisted video workflow for creation, processing, and optional publishing. It combines prompt-based generation (Stage A/B/C), media processing APIs, subtitle rendering, keyframe captioning, metadata generation, and AutoPublish handoff.
| Quick fact | Value |
|---|---|
| 📘 Canonical README | README.md (this file) |
| 🌐 Language variants | i18n/README.*.md (single language bar is intentionally kept at top) |
| 🧠 Backend entrypoint | app.py (Tornado) |
| 🖥️ Frontend app | app/ (Expo web/mobile) |
| 🧩 Runtime styles | python app.py (manual), ./start_lazyedit.sh (tmux), optional lazyedit.service |
| 🎯 Primary references | README.md, references/QUICKSTART.md, references/API_GUIDE.md, references/APP_GUIDE.md |
| 🛠️ Ops references | references/DEPLOYMENT_SYSTEMS.md, references/TMUX_SESSIONS.md, references/LAZYEDIT_DATABASE_SPLIT_FROM_ECHOMIND.md, references/LOCAL_DNS_HOST_CACHE.md, references/XIAOHONGSHU_AUTOPUBLISH_LAYOUT_CHANGE_2026_03.md |
- Overview
- Quick Facts
- At a Glance
- Architecture Snapshot
- Demos
- Features
- Documentation & i18n
- Project Structure
- Prerequisites
- Installation
- Quick Start
- Command Cheat Sheet
- Usage
- Configuration
- Configuration Files
- API Examples
- Examples
- Development Notes
- Testing
- Assumptions & Known Limits
- Deployment & Sync Notes
- Troubleshooting
- Roadmap
- Contributing
- Support
- License
- Acknowledgements
LazyEdit is built around a Tornado backend (app.py) and an Expo frontend (app/).
Note: If repo/runtime details differ by machine, preserve existing defaults and override via environment variables instead of deleting machine-specific fallbacks.
| Why teams use it | Practical result |
|---|---|
| Unified operator flow | Upload/generate/remix/publish from one workflow |
| API-first design | Easy to script and integrate with other tools |
| Local-first runtime | Works with tmux + service-based deployment patterns |
| Step | What happens |
|---|---|
| 1 | Upload or generate video |
| 2 | Transcribe and optionally translate subtitles |
| 3 | Burn multilingual subtitles with layout controls |
| 4 | Generate keyframes, captions, and metadata |
| 5 | Package and optionally publish via AutoPublish |
- Upload, generation, remix, and library management from a single operator UI.
- API-first processing flow for transcription, subtitle polish/translation, burn-in, and metadata.
- Optional generation-provider integrations (Veo / Venice / A2E / Sora helpers in
agi/). - Optional publish handoff through
AutoPublish.
| Area | Included in LazyEdit | Status |
|---|---|---|
| Core app | Tornado API backend + Expo web/mobile frontend | ✅ |
| Media pipeline | ASR, subtitle translation/polish, burn-in, keyframes, captions, metadata | ✅ |
| Generation | Stage A/B/C and provider helper routes (agi/) |
✅ |
| Distribution | Optional AutoPublish handoff | 🟡 Optional |
| Runtime model | Local-first scripts, tmux workflows, optional systemd service | ✅ |
The repository is organized as an API-first media pipeline with a UI layer:
app.pyis the Tornado entrypoint and route orchestrator for upload, processing, generation, publish handoff, and media serving.lazyedit/contains modular pipeline building blocks (DB persistence, translation, subtitle burn-in, captions, metadata, provider adapters).app/is an Expo Router app (web/mobile) that drives upload, processing, preview, and publishing flows.config.pycentralizes environment loading and default/fallback runtime paths.start_lazyedit.shandlazyedit_config.shprovide reproducible tmux-based local/deployed run modes.
| Layer | Main paths | Responsibility |
|---|---|---|
| API & orchestration | app.py, config.py |
Endpoints, routing, env resolution |
| Processing core | lazyedit/, agi/ |
Subtitle/caption/metadata pipeline + providers |
| UI | app/ |
Operator experience (web/mobile via Expo) |
| Runtime scripts | start_lazyedit.sh, lazyedit_config.sh, install_lazyedit.sh |
Local/service startup and ops |
High-level flow:
Upload/Generate -> Transcribe -> Translate/Polish -> Burn Subtitles -> Keyframes/Captions -> Metadata -> Optional AutoPublish
Screens below show the main operator path from ingestion to metadata generation.
Home · Upload |
Home · Generate |
Home · Remix |
Library |
Video overview |
Translation preview |
Burn slots |
Burn layout |
Keyframes + captions |
Metadata generator |
- ✨ Prompt-based generation workflow (Stage A/B/C) with Sora and Veo integration paths.
- 🧵 Full processing pipeline: transcription -> subtitle polish/translation -> burn-in -> keyframes -> captions -> metadata.
- 🌏 Multilingual subtitle composition with furigana/IPA/romaji-related support paths.
- 🔌 API-first backend with upload, processing, media serving, and publish queue endpoints.
- 🚚 Optional AutoPublish integration for social-platform handoff.
- 🖥️ Combined backend + Expo workflow supported via tmux launch scripts.
- Canonical source:
README.md - Language variants:
i18n/README.*.md - Language navigation: keep a single language-options line at the top of each README (no duplicate language bars)
- Current languages in this repo: Arabic, German, English, Spanish, French, Japanese, Korean, Russian, Vietnamese, Simplified Chinese, Traditional Chinese
If there is ever a mismatch between translations and English docs, treat this English README as source of truth, then update each language file one-by-one.
| i18n policy | Rule |
|---|---|
| Canonical source | Keep README.md as source of truth |
| Language bar | Exactly one language-options line at top |
LazyEdit/
├── app.py # Tornado backend entrypoint and API orchestration
├── app/ # Expo frontend (web/mobile)
├── lazyedit/ # Core pipeline modules (translation, metadata, burner, DB, templates)
├── agi/ # Generation provider abstraction (Sora/Veo/A2E/Venice routes)
├── DATA/ # Runtime media input/output (symlink in this workspace)
├── translation_logs/ # Translation logs
├── temp/ # Temporary runtime files
├── install_lazyedit.sh # systemd installer (expects config/start/stop scripts)
├── start_lazyedit.sh # tmux launcher for backend + Expo
├── stop_lazyedit.sh # tmux stop helper
├── lazyedit_config.sh # Deployment/runtime shell config
├── config.py # Environment/config resolution (ports, paths, autopublish URL)
├── .env.example # Environment override template
├── references/ # Additional docs (API guide, quickstart, deployment notes)
├── AutoPublish/ # Submodule (optional publishing pipeline)
├── AutoPubMonitor/ # Submodule (monitor/sync automation)
├── whisper_with_lang_detect/ # Submodule (ASR/VAD)
├── vit-gpt2-image-captioning/ # Submodule (primary captioner)
├── clip-gpt-captioning/ # Submodule (fallback captioner)
└── furigana/ # External dependency in workflow (tracked submodule in this checkout)
Submodule/external dependency note:
- Git submodules in this repository include
AutoPublish,AutoPubMonitor,whisper_with_lang_detect,vit-gpt2-image-captioning,clip-gpt-captioning, andfurigana. - Operational guidance treats
furiganaandechomindas external/read-only in this repo workflow. If uncertain, preserve upstream and avoid editing in place.
| Dependency | Notes |
|---|---|
| Linux environment | systemd/tmux scripts are Linux-oriented |
| Python 3.10+ | Use Conda env lazyedit |
| Node.js 20+ + npm | Required for Expo app in app/ |
| FFmpeg | Must be available on PATH |
| PostgreSQL | Local peer auth or DSN-based connection |
| Git submodules | Required for key pipelines |
- Clone and initialize submodules:
git clone [email protected]:lachlanchen/LazyEdit.git
cd LazyEdit
git submodule update --init --recursive- Activate Conda environment:
source ~/miniconda3/etc/profile.d/conda.sh
conda activate lazyedit- Optional system-level install (service mode):
chmod +x install_lazyedit.sh
sudo ./install_lazyedit.sh --start /path/to/lazyeditService install notes:
install_lazyedit.shinstallsffmpegandtmux, validates thelazyeditconda env plus Node/npm/npx, then creates or updateslazyedit.service.- Use
--startto restart the service immediately after install/update. - Re-running the installer is safe; already-installed packages are skipped and the service file is refreshed in place.
- It does not generate
lazyedit_config.sh,start_lazyedit.sh, orstop_lazyedit.sh; these must already exist and be correct.
Backend + frontend local run (minimal path):
source ~/miniconda3/etc/profile.d/conda.sh
conda activate lazyedit
python app.pyIn a second shell:
cd app
npm install
EXPO_PUBLIC_API_URL="http://localhost:8787" npx expo start --web --port 8091Optional local database bootstrap:
createdb lazyedit_db || true
psql -d lazyedit_db -tAc "SELECT 'ok'"Or use the repeat-safe helper:
sudo ./scripts/prepare_lazyedit_db.sh| Profile | Start command | Default backend | Default frontend |
|---|---|---|---|
| Local dev (manual) | python app.py + Expo command |
8787 |
8091 (example command) |
| Tmux orchestrated | ./start_lazyedit.sh |
18787 |
18791 |
| systemd service | sudo systemctl start lazyedit.service |
Config/env-driven | N/A |
| Task | Command |
|---|---|
| Initialize submodules | git submodule update --init --recursive |
| Start backend only | python app.py |
| Start backend + Expo (tmux) | ./start_lazyedit.sh |
| Stop tmux run | ./stop_lazyedit.sh |
| Open tmux session | tmux attach -t lazyedit |
| Service status | sudo systemctl status lazyedit.service |
| Service logs | sudo journalctl -u lazyedit.service |
| DB smoke test | python db_smoke_test.py |
| Pytest smoke test | pytest tests/test_db_smoke.py |
source ~/miniconda3/etc/profile.d/conda.sh
conda activate lazyedit
python app.pyAlternate entry used in current deployment scripts:
python app.py -m lazyeditBackend default URL: http://localhost:8787 (from config.py, override with PORT or LAZYEDIT_PORT).
./start_lazyedit.shDefault start_lazyedit.sh ports:
- Backend:
18787 - Expo web:
18791 EXPO_PUBLIC_API_URL=http://localhost:18787
Attach to session:
tmux attach -t lazyeditStop session:
./stop_lazyedit.shsudo systemctl start lazyedit.service
sudo systemctl stop lazyedit.service
sudo systemctl status lazyedit.service
sudo journalctl -u lazyedit.serviceCopy .env.example to .env and update paths/secrets:
cp .env.example .envConfiguration precedence note:
config.pyloads.envvalues if present and only sets keys not already exported in the shell.- Runtime values can therefore come from: shell-exported env vars ->
.env-> code defaults. - For tmux/service runs,
lazyedit_config.shcontrols startup/session parameters (LAZYEDIT_DIR,CONDA_ENV,APP_ARGS, ports via startup script env).
| Variable | Purpose | Default/Fallback |
|---|---|---|
PORT, LAZYEDIT_PORT |
Backend port | 8787 |
LAZYEDIT_UPLOAD_DIR |
Media root directory | DATA/ |
LAZYEDIT_DATABASE_URL, DATABASE_URL |
PostgreSQL DSN | Local DB fallback lazyedit_db |
LAZYEDIT_AUTOPUBLISH_URL |
AutoPublish endpoint | http://localhost:8081/publish |
LAZYEDIT_AUTOPUBLISH_TIMEOUT |
AutoPublish request timeout (seconds) | 60 |
LAZYEDIT_WHISPER_SCRIPT |
Whisper/VAD script path | Environment-dependent |
LAZYEDIT_WHISPER_MODEL, LAZYEDIT_WHISPER_FALLBACK_MODEL |
ASR model names | large-v3 / large-v2 (example) |
LAZYEDIT_CAPTION_PYTHON |
Python runtime for caption pipeline | Environment-dependent |
LAZYEDIT_CAPTION_PRIMARY_ROOT, LAZYEDIT_CAPTION_PRIMARY_SCRIPT |
Primary captioning path/script | Environment-dependent |
LAZYEDIT_CAPTION_FALLBACK_SCRIPT, LAZYEDIT_CAPTION_FALLBACK_CWD |
Fallback captioning path/script/cwd | Environment-dependent |
GRSAI_API_* |
Veo/GRSAI integration settings | Environment-dependent |
VENICE_*, A2E_* |
Venice/A2E integration settings | Environment-dependent |
OPENAI_API_KEY |
Required for OpenAI-backed features | None |
Machine-specific notes:
app.pymay set CUDA behavior (CUDA_VISIBLE_DEVICESusage in codebase context).- Some paths in defaults are workstation-specific; use
.envoverrides for portable setups. lazyedit_config.shcontrols tmux/session startup variables for deployment scripts.
| File | Purpose |
|---|---|
.env.example |
Template for environment variables used by backend/services |
.env |
Machine-local overrides; loaded by config.py/app.py if present |
config.py |
Backend defaults and environment resolution |
lazyedit_config.sh |
tmux/service runtime profile (deploy path, conda env, app args, session name) |
start_lazyedit.sh |
Launches backend + Expo in tmux with selected ports |
install_lazyedit.sh |
Creates lazyedit.service and validates existing scripts/config |
Recommended update order for machine portability:
- Copy
.env.exampleto.env. - Set path- and API-related
LAZYEDIT_*values in.env. - Adjust
lazyedit_config.shonly for tmux/service deployment behavior.
Base URL examples assume http://localhost:8787.
| API group | Representative endpoints |
|---|---|
| Upload and media | /upload, /upload-stream, /media/* |
| Video records | /api/videos, /api/videos/{id} |
| Processing | /api/videos/{id}/transcribe, /translate, /burn-subtitles, /caption, /metadata, /process |
| Publish | /api/videos/{id}/publish, /api/autopublish/queue |
| Generation | /api/videos/generate (+ provider routes in app.py) |
Upload:
curl -F "video=@/path/to/video.mp4" \
-F "title=my_video" \
-F "filename=video.mp4" \
-F "source=api" \
http://localhost:8787/uploadEnd-to-end process:
curl -X POST \
-d "file_path=/abs/path/to/DATA/my_video/video.mp4" \
-d "use_translation_cache=true" \
-d "use_metadata_cache=true" \
http://localhost:8787/video-processingList videos:
curl http://localhost:8787/api/videosPublish package:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"platforms":{"xiaohongshu":true,"douyin":true}}' \
http://localhost:8787/api/videos/123/publishMore endpoints and payload details: references/API_GUIDE.md.
Related endpoint groups you will likely use:
- Video lifecycle:
/upload,/upload-stream,/api/videos,/api/videos/{id},/media/* - Processing actions:
/api/videos/{id}/transcribe,/api/videos/{id}/translate,/api/videos/{id}/burn-subtitles,/api/videos/{id}/metadata,/api/videos/{id}/caption,/api/videos/{id}/process - Generation/provider paths:
/api/videos/generateplus Venice/A2E routes exposed inapp.py - Distribution:
/api/videos/{id}/publish,/api/autopublish/queue
cd app
npm install
EXPO_PUBLIC_API_URL="http://localhost:8787" npx expo start --web --port 8091If backend is on 8887:
EXPO_PUBLIC_API_URL="http://localhost:8887" npx expo start --web --port 8091EXPO_PUBLIC_API_URL="http://10.0.2.2:8787" npx expo start --androidEXPO_PUBLIC_API_URL="http://127.0.0.1:8787" npx expo start --iospython -m agi.demo_fantasy_woman --seconds 8 --size 1280x720 --output DATA/sora_oracle_valley.mp4Supported seconds: 4, 8, 12.
Supported sizes: 720x1280, 1280x720, 1024x1792, 1792x1024.
- Use
pythonfrom Conda envlazyedit(do not assume systempython3). - Keep large media out of Git; store runtime media in
DATA/or external storage. - Initialize/update submodules whenever pipeline components fail to resolve.
- Keep edits scoped; avoid unrelated large-formatting changes.
- For frontend work, backend API URL is controlled by
EXPO_PUBLIC_API_URL. - CORS is open on the backend for app development.
Submodule and external dependency policy:
- Treat external dependencies as upstream-owned. In this repository workflow, avoid editing submodule internals unless intentionally working in those projects.
- Operational guidance in this repo treats
furigana(and sometimesechomindin local setups) as external dependency paths; if uncertain, preserve upstream and avoid in-place edits.
Helpful references:
references/QUICKSTART.mdreferences/API_GUIDE.mdreferences/APP_GUIDE.mdreferences/DEPLOYMENT_SYSTEMS.mdreferences/TMUX_SESSIONS.mdreferences/LAZYEDIT_DATABASE_SPLIT_FROM_ECHOMIND.mdreferences/LOCAL_DNS_HOST_CACHE.md
Security/config hygiene:
- Keep API keys and secrets in environment variables; do not commit credentials.
- Prefer
.envfor machine-local overrides and keep.env.exampleas the public template. - If CUDA/GPU behavior differs by host, override via environment instead of hardcoding machine-specific values.
Current formal test surface is minimal and DB-oriented.
| Validation layer | Command or method |
|---|---|
| DB smoke | python db_smoke_test.py |
| Pytest DB check | pytest tests/test_db_smoke.py |
| Functional flow | Web UI + API run using short sample in DATA/ |
python db_smoke_test.py
pytest tests/test_db_smoke.pyFor functional validation, use the web UI and API flow with a short sample clip in DATA/.
Assumptions and portability notes:
- Some default paths in code are workstation-specific fallbacks; this is expected in current repo state.
- If a default path does not exist on your machine, set the corresponding
LAZYEDIT_*variable in.env. - If uncertain about a machine-specific value, preserve existing settings and add explicit overrides rather than deleting defaults.
- The backend dependency set is not pinned by a root lockfile; environment reproducibility currently depends on local setup discipline.
app.pyis intentionally monolithic in current repo state and contains a large route surface.- Most pipeline validation is integration/manual (UI + API + sample media), with limited formal automated tests.
- Runtime directories (
DATA/,temp/,translation_logs/) are operational outputs and can grow significantly. - Submodules are required for full functionality; partial checkout often leads to missing-script errors.
Current known paths and sync flow (from repository operations docs):
- Development workspace:
/home/lachlan/ProjectsLFS/LazyEdit - Deployed LazyEdit backend + app:
/home/lachlan/DiskMech/Projects/lazyedit - Deployed AutoPubMonitor:
/home/lachlan/DiskMech/Projects/autopub-monitor - Publishing system host:
/home/lachlan/Projects/auto-publishonlazyingart
| Environment | Path | Notes |
|---|---|---|
| Dev workspace | /home/lachlan/ProjectsLFS/LazyEdit |
Main source + submodules |
| Deployed LazyEdit | /home/lachlan/DiskMech/Projects/lazyedit |
tmux la-lazyedit in ops docs |
| Deployed AutoPubMonitor | /home/lachlan/DiskMech/Projects/autopub-monitor |
Monitor/sync/process sessions |
| Publishing host | /home/lachlan/Projects/auto-publish (lazyingart) |
Pull after submodule updates |
After pushing AutoPublish/ updates from this repo, pull on publishing host:
ssh lachlan@lazyingart
cd ~/Projects/auto-publish
git pull github main| Problem | Check / Fix |
|---|---|
| Missing pipeline modules or scripts | Run git submodule update --init --recursive |
| FFmpeg not found | Install FFmpeg and confirm ffmpeg -version works |
| Port conflicts | Backend defaults to 8787; start_lazyedit.sh defaults to 18787; set LAZYEDIT_PORT or PORT explicitly |
| Expo cannot reach backend | Ensure EXPO_PUBLIC_API_URL points to active backend host/port |
| Database connection issues | Verify PostgreSQL + DSN/env vars; optional smoke check: python db_smoke_test.py |
| GPU/CUDA issues | Confirm driver/CUDA compatibility with installed Torch stack |
| Service script fails at install | Ensure lazyedit_config.sh, start_lazyedit.sh, and stop_lazyedit.sh exist before running installer |
- In-app subtitle/segment editing with A/B preview and per-line controls.
- Stronger end-to-end test coverage for core API flows.
- Documentation convergence across i18n README variants and deployment modes.
- Additional workflow hardening for generation-provider retries and status visibility.
Contributions are welcome.
- Fork and create a feature branch.
- Keep commits focused and scoped.
- Validate changes locally (
python app.py, key API flow, and app integration if relevant). - Open a PR with purpose, reproduction steps, and before/after notes (screenshots for UI changes).
Practical guidelines:
- Follow Python style (PEP 8, 4 spaces, snake_case naming).
- Avoid committing credentials or large binaries.
- Update docs/config scripts when behavior changes.
- Preferred commit style: short, imperative, scoped (for example:
fix ffmpeg 7 compatibility).
| Donate | PayPal | Stripe |
|---|---|---|
LazyEdit builds on open-source libraries and services, including:
- FFmpeg for media processing
- Tornado for backend APIs
- MoviePy for editing workflows
- OpenAI models for AI-assisted pipeline tasks
- CJKWrap and multilingual text tooling in subtitle workflows










