chiyiandDevin 4d31219368 feat(ui): 全站统一首页墨黑中性风格,固定亮色并移除光暗切换
- 全站紫/青/粉写死色值与 CSS 变量改为墨黑中性色板
- 移除 aurora 光斑/星点装饰,登录弹窗改纯白卡片
- theme.js 固定亮色并清除历史 dark 选择,删除前台/后台/画布切换按钮
- 模型页空状态文案对齐「保存渠道即自动同步」

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-27 16:17:55 +08:00
2026-07-01 23:22:26 +08:00

image2api

image2api

vivid-protocol AI image / video generation gateway — channel-based upstream routing, a ready-to-run operations system

Live instance (brand): Vivid AI · vividai.run

简体中文 | English

Online Demo

Go Vue 3 Docker Self-hosted License

Live Demo · Features · Deploy · API


✨ Introduction

image2api is a homogeneous gateway. Upstream, it connects any number of vivid-protocol (vividai) instances as "channels" and routes jobs across them. Downstream, it exposes the same vivid-protocol API to callers: POST /v1/generate (NDJSON stream) · POST /v1/uploads (presigned upload) · GET /v1/models · GET /v1/balance. No built-in provider code, no account pools — an upstream is just another vividai instance, so gateways can be layered arbitrarily.

It is more than a gateway: built-in credit billing, CDK top-ups, online payment (epay), invite rewards, reseller pricing, user accounts, an admin console and a modern generation UI — one command turns it into a production AI generation site. The author's live instance Vivid AI · vividai.run runs on this project.

💡 Frontend + backend fully open source (MIT). Go + Vue 3.

One-liner 🔁 vivid-protocol channel mesh · 📦 save-a-channel syncs all models · 💳 credits + payment + reseller pricing · 🧩 concurrency groups · 🎨 generation UI + admin console · 🐳 one-command deploy

🚀 Features

🎨 Generation

  • Image + video in one place, with multi-modal references (images / first-last frames / video / audio) per model capability
  • Multiple resolutions (1K/2K/4K images · 720p/1080p/768p video), aspect ratios, discrete or per-second video durations — all per-model configurable and priced
  • Priced = listed: no enable switch — a model goes public once every tier is priced and an enabled channel serves it
  • Model aliases: one upstream model can map to several public ids
  • Optional de-AI post-processing on generated images (per-tier surcharge)

🔁 Channel routing

  • Save = full sync: storing a channel pulls the upstream /v1/models, binds everything, unbinds what disappeared and deletes orphans
  • Weight + concurrency-aware dispatch with failover; upstream 4xx rejections pass through in Chinese, transient errors move to the next channel
  • Channel keys stored AES-GCM encrypted (CHANNEL_SECRET); upstream balance probed live

🔌 vivid-protocol API

  • POST /v1/generate — NDJSON stream: first frame returns jobId, ~25s blank-line heartbeats, terminal succeeded/failed
  • POST /v1/uploads — presigned PUT direct-to-storage for reference files
  • GET /v1/models — bare array with capability specs · GET /v1/balance — balance
  • jobId reconnect: resubmit with only jobId to resume a dropped stream — no duplicate job or charge; pending jobs resume after a server restart too
  • Unified errors {"error":{"code","message"}} (4001 rejected / 4002 insufficient / 4011 unauthorized / 4293 concurrency / 5001 server); API keys are vk_ + 48 hex

💳 Billing & operations

  • Credits (pre-charge + auto-refund), per model/tier/duration pricing; de-AI surcharge per tier
  • Reseller pricing: reseller role + per-model reseller prices (API calls included)
  • Online payment (epay): WeChat/Alipay QR, fixed + custom amounts, unpaid orders auto-cancel after 30 min, MD5-verified idempotent callbacks
  • CDK codes · invite rewards · email register / verification / password reset
  • Concurrency groups: per-group in-flight caps across UI + API (0 = unlimited)
  • Roles: user / reseller / admin

🛠️ Admin console

  • Dashboard (trends / DAU / top failures / top spenders)
  • Channels (save-to-sync, upstream balance, enable, concurrency, weight) · models (standard + reseller pricing, aliases, read-only listable state) · concurrency groups · orders · global logs · users · CDK · media manager · showcase · announcements · site config
  • Banned words: prompt hits rejected, per-word / per-user trigger stats

🧰 Engineering: S3/RustFS media behind an authenticated proxy + retention cleanup · presigned reference uploads · self-healing maintenance (stale-job resume/refund, expired file pruning) · one-command Docker deploy (TLS is your reverse proxy's job).

🔌 Channel architecture

caller ──vivid protocol──▶ image2api ──vivid protocol──▶ upstream vividai A (weight w, conc c)
                          (this host)                  ├─ upstream vividai B
                                                       └─ …any number
  • A channel = a homogeneous upstream: base_url + vk_ key + enable switch + concurrency cap + routing weight
  • Models come from the upstream /v1/models sync; locally they only get aliases and pricing; one model can fail over across channels
  • This service speaks the same protocol externally — it can itself be mounted as someone's channel, infinitely nestable
  • No OpenAI-protocol upstreams: a channel must be a vivid-protocol instance

📡 vivid-protocol API

# generate — NDJSON stream; first frame returns jobId
curl -N https://your-domain/v1/generate \
  -H "Authorization: Bearer vk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"model": "seedance-2.0", "prompt": "a cute cat on a desk", "ratio": "16:9", "quality": "720p"}'
# → {"jobId":"…","status":"running"}  …heartbeats…  {"status":"succeeded","outputs":[{"url":"…"}]}

# reconnect — resubmit with only jobId, no duplicate job
curl -N https://your-domain/v1/generate -H "Authorization: Bearer vk_xxxx" -d '{"jobId":"<jobId>"}'

# reference files — presigned upload session, then PUT the bytes
curl https://your-domain/v1/uploads -H "Authorization: Bearer vk_xxxx" -d '{"kind":"image","mime":"image/png"}'

curl https://your-domain/v1/models  -H "Authorization: Bearer vk_xxxx"
curl https://your-domain/v1/balance -H "Authorization: Bearer vk_xxxx"

Full parameters, the error-code table and Python examples live on the in-app /docs page.

🚀 Deployment

Docker (recommended): docker compose up -d --build brings up PostgreSQL + Redis + RustFS + backend + frontend (nginx listens on container HTTP :2000); point your reverse proxy at http://<host>:2000.

⚠️ Change the secrets in docker-compose.yml before deploying — especially CHANNEL_SECRET (encrypts stored channel keys; rotating it makes saved keys undecryptable).

Manual build needs PostgreSQL · Redis · RustFS (or any S3) · a reverse proxy — see backend/.env.example for all env vars.

After deploy: admin → Channels → add channel (upstream URL + vk_ key) → models auto-sync → price them in 模型管理 → done.

🧱 Stack

Layer Tech
Backend Go · gin · gorm (PostgreSQL) · go-redis
Frontend Vue 3 · Vue Router · Vite · Tailwind CSS v4
Infra PostgreSQL · Redis · RustFS (S3-compatible) · Nginx

💬 Contact

🌐 Site vividai.run
👥 QQ group 1106849765 · join
🐧 QQ 1114639355 · add
✉️ Email vividairun@gmail.com

📄 License

MIT — see LICENSE.

S
Description
No description provided
Readme MIT
8.1 MiB
Languages
Vue 52.2%
Go 42.4%
JavaScript 2.8%
CSS 2.5%
Dockerfile 0.1%