English | 简体中文
An open-source AI storyboard & video generation studio. Go from script -> storyboard -> generated video in a single web UI, across major AI providers.
Get updates, ask questions, and share what you are building with Blue Fish.
Direct contact: mantaxyz2025@gmail.com
Rednote / 小红书: Manta

Blue Fish is a self-hostable studio that turns written ideas into complete video sequences. It bundles a React front end and a FastAPI back end together, and adapts multiple LLM, image, and video generation providers, so you can switch models, compare results, and keep the whole workflow inside one app.
Out of the box it runs with zero infrastructure: one JSON file for persistence, the local filesystem for media, and a mock mode that lets you experience the full UI without any paid API keys.
- Features
- Product Preview
- Quick Start
- Configuration
- Video Provider Network Setup
- Architecture
- Project Structure
- Development
- Security
- Troubleshooting
- Contributing
- Acknowledgments
- Star History
- License & Trademark
Creative
- 🎬 Storyboard generation - text-to-image, image-to-image, and frame-to-frame with reference consistency
- 🎥 Multiple video providers - Kling, Seedance, Runway, Vidu, DashScope, Replicate, Google Veo
- 👤 Character and scene management, with visual references reused across scenes
- ✍️ Script and dialogue generation - powered by Gemini and OpenAI
- 🔊 Text-to-speech - powered by ElevenLabs
- 🎞️ Video editing - captions, sound effects, and music generation are wired into the timeline
Developer-friendly
- 💾 Zero-config persistence - JSON file storage with no Postgres, Redis, or similar services to configure
- 🧪 Mock mode - run the full UI without any paid API keys
- 🌏 Bilingual UI - English and Simplified Chinese (
src/i18n/zhToEnMap.js) - 🐳 Docker Compose - bring up the front end and back end together with one command
- 🧩 Provider adapter pattern - add a new video model by implementing one interface
| Style Settings | Character Gallery |
|---|---|
![]() |
|
| Storyboard Management | Video Generation |
⚠️ Security note: the default first-login credentials areadmin/admin123. ChangeAUTH_BOOTSTRAP_ADMIN_PASSWORDbefore exposing the backend publicly. See Security.
git clone <your-fork-url> bluefish
cd bluefish
cp bluefish-server/.env.example bluefish-server/.env
cp bluefish-client/.env.example bluefish-client/.env.local
docker compose upIf you edit an env file later, restart the matching service so the change takes effect:
docker compose up -d --force-recreate backend
docker compose up -d --force-recreate frontendThe copied example env lets you sign in locally with:
username: admin
password: admin123
Before exposing the backend publicly, edit bluefish-server/.env and set at least:
AUTH_BOOTSTRAP_ADMIN_PASSWORD=choose-a-password
# optional: allow users to create their own accounts
# AUTH_ALLOW_REGISTRATION=trueOpen http://localhost:5173 and sign in with admin plus the bootstrap admin password from bluefish-server/.env or the backend startup logs.
By default, Blue Fish runs in a single-admin self-hosted mode. The public register page stays hidden unless you explicitly set AUTH_ALLOW_REGISTRATION=true.
New accounts and password changes require at least 8 characters by default.
For VIDU, Kling, and Seedance, Blue Fish enables a Cloudflare Quick Tunnel by default. The default .env.example keeps autostart off, so the tunnel is created only when one of those providers actually needs a public temp-asset URL.
Prerequisites: Node.js 20+, Python 3.11+, and ffmpeg on PATH.
# Backend (terminal 1)
cd bluefish-server
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --reload --port 8000
# Frontend (terminal 2)
cd bluefish-client
npm install
cp .env.example .env.local
npm run devRun the full UI against fake providers - useful for demos, UI work, and exploration.
# bluefish-server/.env
LLM_MOCK_MODE=true
VIDEO_MOCK_MODE=trueAll configuration is driven by environment files:
| File | Purpose |
|---|---|
| bluefish-server/.env | API keys, storage paths, feature flags |
| bluefish-client/.env.local | Front-end build-time config (API URL, flags) |
These files are loaded on process start. After changing one, restart the matching service.
| Variable | Default | Purpose |
|---|---|---|
AUTH_BOOTSTRAP_ADMIN_PASSWORD |
admin123 |
Initial password for the bootstrap admin user. It only applies when the first admin user is created |
AUTH_ALLOW_REGISTRATION |
false |
Show the public register page and allow self-service sign-up |
AUTH_MIN_PASSWORD_LENGTH |
8 |
Minimum password length for registration and password changes. Values below 8 are ignored |
AUTH_TOKEN_TTL_SECONDS |
604800 |
Bearer token lifetime (seconds) |
| Variable | Provider | Notes |
|---|---|---|
GEMINI_API_KEY |
Google AI Studio | Free tier available |
GPT_API_KEY |
OpenAI |
| Provider | Variables |
|---|---|
| Kling | KLING_ACCESS_KEY, KLING_SECRET_KEY |
| Seedance (Volcengine) | SEEDANCE_API_KEY |
| Runway | RUNWAY_API_KEY |
| Vidu | VIDU_API_KEY |
| DashScope (Alibaba) | ALI_API_KEY |
| Replicate | REPLICATE_API_TOKEN |
| Google Veo | reuses GEMINI_API_KEY |
| Variable | Default | Purpose |
|---|---|---|
ENABLE_EDITED_VIDEOS |
false |
Enable the edited-videos timeline module |
| Variable | Provider |
|---|---|
ELEVENLABS_API_KEY |
ElevenLabs |
| Variable | Default | Purpose |
|---|---|---|
MAX_IMAGE_UPLOAD_MB |
10 |
Max size for image uploads |
MAX_AUDIO_UPLOAD_MB |
50 |
Max size for transcription uploads |
MAX_DOCUMENT_UPLOAD_MB |
20 |
Max size for PDF / DOCX parsing |
MAX_EDITED_VIDEO_UPLOAD_MB |
250 |
Max size for edited video uploads |
MAX_ADMIN_IMPORT_UPLOAD_MB |
1 |
Max size for admin JSON imports |
Blue Fish stores frames and generated media on the local filesystem. Different providers consume those assets in different ways:
- Runway supports inline image data, so it does not need a public URL.
- VIDU, Kling, and Seedance fetch source images by URL. Blue Fish issues short-lived, signed
/api/temp-assets/<token>URLs. If you enable the built-in Cloudflare Quick Tunnel, Blue Fish publishes only/api/temp-assets/*and/healthon the generated public host. The local frontend still loads raw media fromhttp://localhost:8000/uploads/*on your machine; those local-only paths are not exposed through the built-in Quick Tunnel.
If you only use Runway, no extra setup is required. If you use VIDU, Kling, or Seedance, you can either enable the built-in Quick Tunnel or configure your own stable public hostname via PUBLIC_MEDIA_BASE_URL.
LOCAL_STORAGE_URL_BASE=http://localhost:8000/uploads
PUBLIC_MEDIA_BASE_URL= # Optional stable public HTTPS base URL of the backend
TEMP_ASSET_TTL_SECONDS=900
TEMP_ASSET_SIGNING_SECRET=replace-this-with-a-random-secret
PUBLIC_MEDIA_BASE_URLis optional in the default setup. When it is empty andFREE_TUNNEL_ENABLED=true, Blue Fish will start a Quick Tunnel and inject a temporary public base URL at runtime the first time a provider needs it. If you setPUBLIC_MEDIA_BASE_URLmanually, Blue Fish will reuse it and skip creating a Quick Tunnel as long as the URL stays healthy.
For local development and open-source self-hosting, Blue Fish can optionally manage a Cloudflare Quick Tunnel for you:
FREE_TUNNEL_ENABLED=true
FREE_TUNNEL_AUTOSTART=false
FREE_TUNNEL_LOCAL_PORT=8000
FREE_TUNNEL_HEALTHCHECK_PATH=/healthWith the default FREE_TUNNEL_AUTOSTART=false, Blue Fish lazily creates the tunnel only when VIDU, Kling, or Seedance first needs a public temp-asset URL. Before each such task, Blue Fish checks whether the current public URL is reachable. If it is not, Blue Fish automatically rebuilds the tunnel once. Quick Tunnel URLs are temporary and may change every time the app starts. This mode is ideal for local testing and self-hosted evaluation, but not for long-lived production deployments.
- Create a tunnel that maps
https://media.example.com->http://localhost:8000. - Set
PUBLIC_MEDIA_BASE_URL=https://media.example.cominbluefish-server/.env. - Restart the backend. Blue Fish will hand providers short-lived URLs like
https://media.example.com/api/temp-assets/<token>. - In the tunnel or reverse-proxy config, forward only
/api/temp-assets/*, the/api/*endpoints your providers need, and/health- do not forward/uploads/*or/wspublicly unless you have added authentication.
GET https://your-public-host/healthshould return{"status":"ok"}.- Start one video task with VIDU, Kling, or Seedance.
- If
PUBLIC_MEDIA_BASE_URLis missing or unreachable, the backend returns a clear error before the task is sent to the provider.
┌─────────────┐ HTTP / WebSocket ┌─────────────┐
│ React 19 │ ─────────────────────────────>│ FastAPI │
│ Vite │ <───────────────────────────── │ (uvicorn) │
│ Tailwind │ └──────┬──────┘
└─────────────┘ │
┌──────────────────┬──────────┴────────┬────────────────┐
▼ ▼ ▼ ▼
┌────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ LLM │ │ Video │ │ TTS │ │ Storage │
│ Gemini │ │ Kling │ │ Eleven- │ │ JSON │
│ OpenAI │ │ Runway… │ │ Labs │ │ + files │
└────────┘ └─────────┘ └─────────┘ └─────────┘
- Persistence -
bluefish-server/bluefish.db.jsonstores all project data. Replace or clear it to reset. - Media - uploaded and generated assets are stored under
bluefish-server/uploads/. - Real-time - long-running tasks (video generation) stream progress to the frontend over WebSocket.
- Provider adapters - each video or LLM provider is isolated under
app/services/<provider>_service.py.
.
├── bluefish-client/ # React 19 + Vite + Tailwind front end
│ ├── src/
│ │ ├── pages/ # Route pages (Projects, Storyboards, Videos...)
│ │ ├── components/ # Reusable UI (layout, credits, admin...)
│ │ ├── contexts/ # React contexts (WebSocket, auth)
│ │ ├── stores/ # Zustand stores
│ │ ├── api/ # Typed API client
│ │ ├── services/ # Browser-side service wrappers
│ │ ├── hooks/ # Reusable React hooks
│ │ ├── core/ # Cross-cutting domain logic
│ │ ├── lib/ # Third-party helpers and adapters
│ │ ├── utils/ # Frontend utilities (logging, downloads, navigation)
│ │ ├── constants/ # Shared constants
│ │ ├── assets/ # Static assets
│ │ ├── test/ # vitest setup and utilities
│ │ └── i18n/ # Chinese-English translation map
│ └── vite.config.js
├── bluefish-server/ # FastAPI back end
│ ├── app/
│ │ ├── main.py # FastAPI entrypoint
│ │ ├── models.py # Pydantic schemas
│ │ ├── routes/ # HTTP routes (auth, projects, storyboards,
│ │ │ # generation, temp_assets, music_generation...)
│ │ ├── services/ # Provider adapters (Kling, Runway, Vidu,
│ │ │ # google_genai, elevenlabs...)
│ │ ├── auth/ # Auth dependencies and token handling
│ │ ├── middleware/ # Request middleware
│ │ ├── constants/ # Model catalogs and enums
│ │ ├── db/ # JSON repository layer
│ │ └── utils/ # S3, temp-asset, cost-estimator helpers
│ ├── scripts/ # Maintenance scripts
│ ├── tests/ # pytest suite
│ ├── application.py # ASGI application entrypoint
│ ├── check_dependencies.py # Import-check helper
│ └── requirements.txt
├── docs/ # Project documentation and assets
├── .github/ # GitHub Actions workflows and templates
├── docker-compose.yml
├── CHANGELOG.md
├── LICENSE # Apache 2.0
├── TRADEMARK.md # Trademark terms for forks
├── SECURITY.md # Vulnerability reporting process
├── CONTRIBUTING.md
└── CODE_OF_CONDUCT.md
cd bluefish-server
pytest tests -q # Unit tests
pytest tests -q -m "not slow" # Fast subset (matches CI)
python check_dependencies.py # Verify dependencies can be importedcd bluefish-client
npm run dev # Dev server on :5173
npm run lint # eslint
npm run test # vitest (watch)
npm run test:ci # vitest run
npm run build # Production build -> dist/The bundled Dockerfile.dev files are meant for hot-reload development. For production, build an image without --reload and run it as a non-root user.
The backend Dockerfile.dev now installs a pinned cloudflared binary by default so the built-in Quick Tunnel works out of the box in the dev container. The version and SHA-256 remain explicit build args so the image stays reproducible instead of pulling latest.
GitHub Actions run on every PR targeting main, develop, and new-ui - see .github/workflows/pr-ci.yml. A nightly regression workflow runs the full suite, including slow-marked tests.
- Bootstrap admin password. Blue Fish uses
admin/admin123for a friction-free first local login. ChangeAUTH_BOOTSTRAP_ADMIN_PASSWORDbefore any shared or public deployment. This value only applies when the first admin user is created; after a user changes the password, the existingusers.jsonpassword is kept. Auth tokens also expire (AUTH_TOKEN_TTL_SECONDS, default 7 days). - Password policy. Blue Fish enforces a minimum password length of 8 characters even if
AUTH_MIN_PASSWORD_LENGTHis set lower. The frontend reads this policy from/api/auth/config, so the register form and backend stay aligned. - Registration. Self-service registration is disabled by default, and the frontend hides the register page unless
AUTH_ALLOW_REGISTRATION=true. This keeps the default open-source/self-host workflow in a clean single-admin mode. - Media access model.
/uploads/*is mounted as an unauthenticated static directory so the local frontend can load images and videos directly. The built-in Quick Tunnel does not expose/uploads/*,/ws, or the rest of the API — it only allows/api/temp-assets/*and/health. If you expose the backend through your own stable tunnel, reverse proxy, or direct bind, restrict/uploads/*at that layer - forward only/api/temp-assets/*,/api/*, and/health. Signed temp-asset tokens (TEMP_ASSET_SIGNING_SECRET) protect only the URLs handed to providers; they do not protect the raw static mount. - Signing secret. Before exposing the backend to the public internet, set
TEMP_ASSET_SIGNING_SECRETto a long random string. The default value is a process-scoped random value, which is sufficient for local development but becomes invalid across restarts. - API keys. Never commit
.envfiles. The repository already ignores them by default..env.exampleis the single source of truth for the variable list. - Open-source release hygiene. If this project has ever been used with real provider keys in a private repo, rotate those keys before publishing.
.gitignoreprotects future commits, not secrets that may already exist in git history, screenshots, or copied docs.
Port 8000 or 5173 already in use
lsof -ti:8000,5173 | xargs kill -9ffmpeg: command not found
brew install ffmpeg # macOS
sudo apt-get install -y ffmpeg # Ubuntu / DebianVideo provider returns 502 Bad Gateway / resource download failed
The provider could not fetch the temporary source image. Check PUBLIC_MEDIA_BASE_URL, or let the automatic Quick Tunnel rebuild and retry.
Seedance returns 400 Bad Request - "input image may contain real person"
The provider's content policy rejected the request. Regenerate the source frame.
Mock mode not taking effect
Confirm that LLM_MOCK_MODE=true and/or VIDEO_MOCK_MODE=true are set in bluefish-server/.env, then restart the backend.
Pull requests are welcome. Before opening one:
- Read CONTRIBUTING.md to understand the workflow and commit conventions.
- Read CODE_OF_CONDUCT.md.
- Make sure
pytestandnpm run test:cipass locally.
Translations, new provider adapters, and documentation improvements are especially welcome. For direct collaboration or product questions, contact mantaxyz2025@gmail.com.
Blue Fish stands on the shoulders of many open-source projects, including:
- FastAPI and Pydantic
- React, Vite, Tailwind CSS, and Zustand
- MoviePy and Pillow And the model providers that make generation possible: Google Gemini, OpenAI, Kling, Seedance, Runway, Vidu, DashScope, Replicate, and ElevenLabs.
Source code is released under the Apache License 2.0.
The name Blue Fish and its branding are trademarks - see TRADEMARK.md for usage terms on forks and derived works.
