11 KiB
DouBao2Api
A Dockerized solution that converts the web version of Doubao (doubao.com) into an OpenAI-compatible API. It uses VNC + Playwright to simulate real human browser interaction — sending messages indirectly and capturing replies — while exposing a standard /v1/chat/completions endpoint.
How It Works
┌──────────────────────────────────────────────────────────┐
│ Docker Container (RockyLinux 9) │
│ │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ Xvfb │──│ openbox │──│ Chromium │──│Playwright│ │
│ │ Virtual │ │ Window Mgr │ │ Browser │ │ Automation│ │
│ │ Display │ └──────────┘ └──────────┘ └────────┘ │
│ └─────────┘ │ │
│ │ ┌──────────┐ │ │
│ └──────────│ x11vnc │◄───────────────────────┘ │
│ │ VNC Server│ │
│ └────┬─────┘ │
│ │ │
│ ┌────┴─────┐ ┌──────────┐ │
│ │websockify│──│ noVNC │ │
│ │ Proxy │ │ Web Client│ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ FastAPI (port 8000) │ │
│ │ OpenAI-compatible API │ │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
API :8000 VNC :5900 noVNC :6080
Core flow: API receives request → Playwright operates the Doubao page in Chromium (type message, press Enter) → DOM polling captures streaming reply → returned as SSE or JSON.
Features
- OpenAI-compatible: Standard
/v1/chat/completionsendpoint with both streaming (SSE) and non-streaming responses - VNC visualization: Real-time browser view via noVNC web client, with view-only/interactive toggle
- Anti-detection: Playwright stealth script hides webdriver flags, simulates human typing delays
- Session persistence: Login state saved via
storage_stateto a Docker volume — no re-login after restart - Chat reuse: Reuses the current chat session by default to reduce risk control triggers; supports on-demand new chat creation
- Debug endpoint:
/inspectreturns page DOM structure for easy selector adaptation
Quick Start
1. Build & Start
docker compose build
docker compose up -d
2. Login to Doubao
After the container starts, open noVNC in your browser:
http://localhost:6080/vnc.html
VNC password: doubao123 (configurable via VNC_PASSWORD in docker-compose.yml)
noVNC defaults to view-only mode (to prevent accidental interaction). Uncheck "View Only" in the left sidebar settings to switch to interactive mode.
Log in to your Doubao account in the Chromium browser within VNC. Make sure you can see the chat input box.
3. Save Login State
curl -X POST http://localhost:8000/login/save
4. Call the API
# Non-streaming
curl http://localhost:8000/v1/chat/completions \
-H "Authorization: Bearer sk-your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"model":"doubao-pro","messages":[{"role":"user","content":"Hello"}]}'
# Streaming
curl http://localhost:8000/v1/chat/completions \
-H "Authorization: Bearer sk-your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"model":"doubao-pro","messages":[{"role":"user","content":"Hello"}],"stream":true}'
Configuration
All settings are configured via environment variables in docker-compose.yml or .env:
| Variable | Default | Description |
|---|---|---|
API_KEY |
sk-your-api-key-here |
API authentication key; clients must send Authorization: Bearer <key> header |
API_PORT |
8000 |
API service port |
VNC_PASSWORD |
doubao123 |
VNC connection password |
VNC_VIEW_ONLY |
false |
Force x11vnc server-side view-only (true blocks all input even if noVNC unchecks View Only) |
VNC_PORT |
5900 |
Direct VNC port |
NOVNC_PORT |
6080 |
noVNC web client port |
DOUBAO_URL |
https://www.doubao.com/chat/ |
Doubao chat page URL |
BROWSER_HEADLESS |
false |
Run browser in headless mode (must be false for VNC) |
RESPONSE_TIMEOUT |
120 |
Response timeout in seconds |
TYPING_DELAY_MIN |
30 |
Minimum typing delay (ms per character) |
TYPING_DELAY_MAX |
80 |
Maximum typing delay (ms per character) |
INTER_MESSAGE_DELAY |
0.5 |
Delay before sending message (seconds) |
SCREEN_WIDTH |
1280 |
Virtual screen width |
SCREEN_HEIGHT |
720 |
Virtual screen height |
SCREEN_DEPTH |
24 |
Virtual screen color depth |
LOG_LEVEL |
INFO |
Log level |
API Reference
POST /v1/chat/completions
OpenAI-compatible chat endpoint.
| Parameter | Type | Default | Description |
|---|---|---|---|
model |
string | doubao-pro |
Model name |
messages |
array | required | Message array, same format as OpenAI |
stream |
bool | false |
Enable SSE streaming response |
new_chat |
bool | false |
Start a new chat session (custom extension field) |
GET /v1/models
Returns the list of supported models.
GET /login/status
Check current Doubao login status.
POST /login/save
Persist current browser state (cookies, storage) to disk.
POST /chat/new
Explicitly start a new Doubao chat session.
GET /inspect
Return current page DOM structure for debugging selectors.
GET /vnc/mode
Get current VNC mode (viewonly or interactive).
POST /vnc/mode
Switch VNC mode (server-side enforcement):
# Switch to interactive mode
curl -X POST http://localhost:8000/vnc/mode \
-H "Authorization: Bearer sk-your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"mode":"interactive"}'
# Switch to view-only mode
curl -X POST http://localhost:8000/vnc/mode \
-H "Authorization: Bearer sk-your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"mode":"viewonly"}'
POST /browser/restart
Restart the browser session.
GET /health
Health check endpoint.
VNC Modes
Two layers of view-only control:
| Layer | Control | Default | Description |
|---|---|---|---|
| Client | noVNC sidebar "View Only" checkbox | Checked (read-only) | Uncheck to switch to interactive instantly; refresh restores read-only |
| Server | API POST /vnc/mode |
interactive |
viewonly mode makes x11vnc reject all input, even if the client unchecks View Only |
For daily use, the client layer is sufficient. For stronger enforcement (prevent any VNC client from interacting), use the API to switch the server-side mode.
Project Structure
DouBao2Api/
├── Dockerfile # Docker image build file
├── docker-compose.yml # Container orchestration
├── requirements.txt # Python dependencies
├── .env.example # Environment variable template
├── app/
│ ├── __init__.py
│ ├── config.py # Configuration management (pydantic-settings)
│ ├── models.py # OpenAI-compatible data models
│ ├── browser_manager.py # Playwright browser management
│ ├── doubao.py # Doubao page interaction logic
│ └── main.py # FastAPI service entry point
└── scripts/
├── entrypoint.sh # Container entrypoint script
├── supervisord.conf # Process management config
├── start_wm.sh # Window manager startup script
└── start_x11vnc.sh # x11vnc startup script (view-only/interactive toggle)
Process Architecture
Five processes managed by supervisord inside the container, started by priority:
| Priority | Process | Description |
|---|---|---|
| 10 | Xvfb | Virtual framebuffer X server |
| 20 | openbox | Lightweight window manager |
| 30 | x11vnc | VNC server, maps Xvfb display |
| 40 | websockify | WebSocket proxy, provides noVNC web access |
| 50 | uvicorn | FastAPI application server |
Troubleshooting
Build failure: package not found
This project is based on RockyLinux 9. RHEL 10 / RockyLinux 10 removed X11 server packages and does not support this approach. Docker containers are independent of the host OS — running an RL9 container on an RL10 host is fully compatible.
API returns empty response
Doubao frontend updates may break CSS selectors. Call GET /inspect to view the current DOM structure, then update the selector constants in app/doubao.py.
"Not logged in" error
You must first log in to Doubao through the VNC browser, then call POST /login/save to persist the state. Use GET /login/status to check login status.
VNC cannot interact
Make sure "View Only" is unchecked in the noVNC sidebar. If still unable to interact, check server-side mode: GET /vnc/mode. If it returns viewonly, use the API to switch to interactive.
Tech Stack
- RockyLinux 9 — Container base OS
- Xvfb + x11vnc + noVNC — Virtual display and remote viewing
- Playwright — Browser automation
- FastAPI + Uvicorn — API service
- Supervisor — Process management
- websockify — VNC over WebSocket proxy
Disclaimer
This project is for educational and research purposes only. Please ensure compliance with Doubao's terms of service before use. The author is not responsible for any direct or indirect consequences arising from the use of this project.