AI story generation with multi-agent drama simulation
Turn a one-sentence idea into a complete, drama-rich Vietnamese web novel — with character-consistent images, cinematic backgrounds, and any OpenAI-compatible LLM. Self-hosted.
Most AI writers produce flat stories. StoryForge turns each character into an autonomous agent that argues, allies, and betrays in a multi-round drama simulation — uncovering conflicts the author never planned, then rewriting around them until quality thresholds clear.
Generated by the pipeline itself — character-consistent portraits that keep the same face across every chapter, plus a cinematic scene background, for a Vietnamese tiên hiệp (cultivation) story. All rendered locally for free.
![]() Triệu Thiên Phong · nam chính |
![]() Tiểu Vũ · nữ chính |
![]() Hắc Phong Lão Tổ · phản diện |

Scene background — the same characters, kept consistent across chapters · how to set this up ↓
git clone https://github.com/HieuNTg/STORYFORGE.git
cd STORYFORGE
pip install -r requirements.txt
cd frontend && npm install && cd ..
# Windows PowerShell: start backend + frontend in two windows
./dev.ps1Manual mode is still available: run python app.py for the API (:7860) and cd frontend && npm run dev -- --port 3001 for the UI (:3001).
Then open http://localhost:3001/forge/ → Settings → API Keys (add provider profiles + choose models) → Forge → Run → Library / Reader / Branching / Simulation → Export (PDF/EPUB/HTML/ZIP).
- 2-layer pipeline — L1 story generation → L2 drama simulation, with checkpoints, SSE streaming, optional L3 sensory polish
- 13 specialized agents — drama critic, editor, pacing, dialogue, reader simulator, …; 6-dim LLM-as-judge auto-revision
- Vietnamese-first — VN names default; Chinese tiên hiệp / wuxia / xianxia and Western/Sci-Fi optional; arc scaling by chapter count
- Continuation tools — multi-path preview, outline editor, collaborative polish, consistency checker, mid-story insertion, retroactive fixes
- Local-library-first flows — Reader, Branching, Simulation, and Characters start from stories already saved in the local library; no fake
demosessions or pasted orphan text. - Branch reader — LLM-generated CYOA, SVG tree + minimap, undo/redo, bookmarks, WebSocket multi-user, EPUB tree export
- Character-consistent images — the same face carries across every chapter (reference-image / IP-Adapter consistency) plus cinematic scene backgrounds. Free local generation via HuggingFace FLUX or the FlowKit provider (Imagen 3, local-only — account-ban risk, use a secondary Google account); paid via DALL·E / Seedream. See Sample output and the setup table below.
- Provider profiles + model dropdowns — Settings has quick-add cards for Gemini, Anthropic, OpenAI, OpenRouter Free, Z.AI, and Kyma. Model choice is a select list (including Gemini/Gemma, OpenRouter free text models, OpenAI/Anthropic, GLM/Qwen/DeepSeek fallbacks), and L1/L2/cheap-model routing chooses from configured provider profiles instead of raw text fields.
- Any OpenAI-compatible LLM — OpenAI, Gemini, Anthropic, OpenRouter, Z.AI, Kyma, Ollama, custom; preemptive rate-limit switching, latency-aware routing, smart cheap/premium routing, SQLite cache
- Security — CSRF double-submit, 10 MB body cap, prompt-injection middleware, encrypted secrets at rest
Settings tab persists to data/config.json. When STORYFORGE_SECRET_KEY is set,
sensitive fields in that file are encrypted. Key env vars:
| Variable | Purpose |
|---|---|
STORYFORGE_API_KEY / STORYFORGE_BASE_URL / STORYFORGE_MODEL |
provider key, OpenAI-compatible base URL, primary model |
STORYFORGE_SECRET_KEY |
encryption/signing key — set in production for encrypted secrets |
STORYFORGE_AUTH_REQUIRED |
1 = enforce JWT/RBAC on sensitive API routes |
REDIS_URL |
required for multi-instance (NUM_WORKERS>1) shared cache/sessions |
STORYFORGE_ALLOWED_ORIGINS |
CORS origins (comma-separated) |
STORYFORGE_HANDOFF_STRICT |
1 = fail-fast on malformed L1→L2 signals (default: warn) |
STORYFORGE_SEMANTIC_STRICT |
1 = fail-fast on missed foreshadowing payoffs (default: warn) |
CHROMA_PERSIST_DIR / CHROMA_COLLECTION_NAME |
RAG persistence |
Per-layer model overrides, drama ceilings, batch size, voice-revert anchoring, etc. live in config/defaults.py (PipelineConfig) and the Settings UI. Agent prompts are editable in data/prompts/agent_prompts.yaml.
Images are off by default (image_provider = none → text-only). Pick a provider in Settings → API Keys → Provider hình ảnh, or set it in data/config.json:
| Provider | Setup | Cost | Notes |
|---|---|---|---|
none |
— | — | Default. No image calls. |
huggingface |
Set hf_token |
Free tier | FLUX.1-schnell via HF Inference API — easiest free path. |
dalle |
Set image_api_key (+ optional image_api_url) |
Paid | OpenAI / Azure-compatible image endpoint. |
seedream |
Set seedream_api_key + seedream_api_url |
Paid | ByteDance Seedream; also the default character-consistency engine. |
flowkit |
Chrome extension + Google Labs login | Free* | Local-only proxy to Imagen 3. *Account-ban risk — use a secondary Google account. Full walkthrough: FlowKit guide. |
Character consistency — set enable_character_consistency = true to reuse a character's first portrait as a reference image, so the same face carries across every chapter (character_consistency_provider: seedream or replicate). Visual style is set by image_prompt_style (default cinematic) and portraits default to 9:16. The sample portraits above were produced this way.
| Route | Purpose | Notes |
|---|---|---|
/library/ |
Local story library | Source of truth for reader, branching, simulation, and character tools |
/forge/ |
One-sentence story creation pipeline | Runs the main generation flow |
/reader/ |
Story/chapter picker | Opens /reader/[storyId]/[chapterId] after a local story is selected |
/branching/ |
Branch-session starter | Selects a local story, then creates a real /branching/[sessionId]/ session |
/simulation/ |
Multi-character stage setup | Selects a local story and characters; transcript simulation can be enabled via config |
/characters/ |
Character list/detail/generation | Story picker is controlled and library-backed |
/settings/ |
General, API Keys, L1/L2 settings | Provider quick-add, model dropdowns, image style select |
/providers/ |
Provider status table | Shows configured provider profiles only; legacy Primary/Mặc định row is hidden |
pytest tests/ -v -m "not calibration and not bench" # fast subset
pytest tests/ -v -m calibration # real-model calibrationflowchart LR
idea([Idea]) --> L1[L1<br/>Story Generation]
L1 --> L2[L2<br/>Drama Enhancement]
L2 --> media[Images · Export]
media --> out([PDF · EPUB · HTML · ZIP])
L1→L2 signals: conflict_web + foreshadowing_plan feed the simulator; arc_waypoints + threads feed the analyzer/enhancer; voice_fingerprints preserve speaker voice through L2 rewrites.
See docs/system-architecture.md for the full flow.
docs/— full index (architecture, code standards, deployment)docs/adr/— architecture decision records- CONTRIBUTING.md — dev setup, code style, PR process
MIT — Copyright 2026 StoryForge Contributors



