DouBao2Api/README.md

261 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DouBao2Api
将网页版豆包doubao.com转换为 OpenAI 兼容 API 的 Docker 化方案。通过 VNC + Playwright 模拟真人浏览器操作,间接发送消息并捕获回复,对外暴露标准 `/v1/chat/completions` 接口。
<div align="center">
<br>
[**中文**](README.md) [English](README_EN.md)
<br>
</div>
## 工作原理
```
┌──────────────────────────────────────────────────────────┐
│ Docker 容器 (RockyLinux 9) │
│ │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ Xvfb │──│ openbox │──│ Chromium │──│Playwright│ │
│ │ 虚拟显示 │ │ 窗口管理器 │ │ 浏览器 │ │ 自动化 │ │
│ └─────────┘ └──────────┘ └──────────┘ └────────┘ │
│ │ │ │
│ │ ┌──────────┐ │ │
│ └──────────│ x11vnc │◄───────────────────┘ │
│ │ VNC 服务 │ │
│ └────┬─────┘ │
│ │ │
│ ┌────┴─────┐ ┌──────────┐ │
│ │websockify│──│ noVNC │ │
│ │ 代理 │ │ Web 客户端 │ │
│ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ FastAPI (端口 8000) │ │
│ │ OpenAI 兼容 API │ │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
API :8000 VNC :5900 noVNC :6080
```
**核心流程**API 收到请求 → Playwright 在 Chromium 中操作豆包页面输入消息、Enter 发送) → DOM 轮询捕获流式回复 → 以 SSE 或 JSON 返回。
## 功能特性
- **OpenAI 兼容**:标准 `/v1/chat/completions` 接口支持流式SSE和非流式响应
- **VNC 可视化**:通过 noVNC Web 客户端实时查看浏览器画面,支持只读/交互切换
- **反检测**Playwright stealth 脚本隐藏 webdriver 标志,模拟人类打字延迟
- **会话持久化**:登录状态通过 `storage_state` 保存到 Docker volume重启免登录
- **聊天复用**:默认复用当前聊天会话,降低风控风险;支持按需新建对话
- **调试端点**`/inspect` 返回页面 DOM 结构,方便选择器适配
## 快速开始
### 1. 构建与启动
```bash
docker compose build
docker compose up -d
```
### 2. 登录豆包
容器启动后,浏览器打开 noVNC
```
http://localhost:6080/vnc.html
```
VNC 密码:`doubao123`(可在 `docker-compose.yml` 中修改 `VNC_PASSWORD`
noVNC 默认为**只读模式**(防止误触)。在左侧设置面板取消勾选 "View Only" 即可切换到交互模式。
在 VNC 中的 Chromium 浏览器里登录豆包账号,确认能看到聊天输入框。
### 3. 保存登录状态
```bash
curl -X POST http://localhost:8000/login/save
```
### 4. 调用 API
```bash
# 非流式
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":"你好"}]}'
# 流式
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":"你好"}],"stream":true}'
```
## 配置项
所有配置通过环境变量设置,在 `docker-compose.yml``.env` 中修改:
| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `API_KEY` | `sk-your-api-key-here` | API 鉴权密钥,客户端需在 Header 中携带 `Authorization: Bearer <key>` |
| `API_PORT` | `8000` | API 服务端口 |
| `VNC_PASSWORD` | `doubao123` | VNC 连接密码 |
| `VNC_VIEW_ONLY` | `false` | x11vnc 服务端是否强制只读(`true` 时即使 noVNC 取消勾选也无法操作) |
| `VNC_PORT` | `5900` | VNC 直连端口 |
| `NOVNC_PORT` | `6080` | noVNC Web 客户端端口 |
| `DOUBAO_URL` | `https://www.doubao.com/chat/` | 豆包聊天页面 URL |
| `BROWSER_HEADLESS` | `false` | 浏览器是否无头模式VNC 方案需设为 `false` |
| `RESPONSE_TIMEOUT` | `120` | 响应超时时间(秒) |
| `TYPING_DELAY_MIN` | `30` | 打字延迟下限(毫秒/字符) |
| `TYPING_DELAY_MAX` | `80` | 打字延迟上限(毫秒/字符) |
| `INTER_MESSAGE_DELAY` | `0.5` | 消息发送前等待时间(秒) |
| `SCREEN_WIDTH` | `1280` | 虚拟屏幕宽度 |
| `SCREEN_HEIGHT` | `720` | 虚拟屏幕高度 |
| `SCREEN_DEPTH` | `24` | 虚拟屏幕色深 |
| `LOG_LEVEL` | `INFO` | 日志级别 |
## API 接口
### `POST /v1/chat/completions`
OpenAI 兼容的对话接口。
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `model` | string | `doubao-pro` | 模型名称 |
| `messages` | array | 必填 | 消息数组,同 OpenAI 格式 |
| `stream` | bool | `false` | 是否流式返回 |
| `new_chat` | bool | `false` | 是否新建聊天会话(自定义扩展字段) |
### `GET /v1/models`
返回支持的模型列表。
### `GET /login/status`
检查当前豆包登录状态。
### `POST /login/save`
保存当前浏览器状态cookies、storage到磁盘。
### `POST /chat/new`
显式开启新的豆包聊天会话。
### `GET /inspect`
返回当前页面的 DOM 结构信息,用于调试选择器。
### `GET /vnc/mode`
查看当前 VNC 模式(`viewonly``interactive`)。
### `POST /vnc/mode`
切换 VNC 模式(服务端强制):
```bash
# 切换到交互模式
curl -X POST http://localhost:8000/vnc/mode \
-H "Authorization: Bearer sk-your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"mode":"interactive"}'
# 切换到只读模式
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`
重启浏览器会话。
### `GET /health`
健康检查端点。
## VNC 模式说明
提供两层只读控制:
| 层级 | 控制方式 | 默认 | 说明 |
|------|---------|------|------|
| 客户端 | noVNC 侧边栏 "View Only" 勾选框 | 勾选(只读) | 取消勾选即时切换到交互模式,刷新后恢复只读 |
| 服务端 | API `POST /vnc/mode` | `interactive` | `viewonly` 模式下 x11vnc 拒绝所有输入,即使客户端取消勾选也无效 |
日常使用:客户端层即可满足需求。如需更强控制(防止任何 VNC 客户端操作),使用 API 切换服务端模式。
## 项目结构
```
DouBao2Api/
├── Dockerfile # Docker 镜像构建文件
├── docker-compose.yml # 容器编排配置
├── requirements.txt # Python 依赖
├── .env.example # 环境变量模板
├── app/
│ ├── __init__.py
│ ├── config.py # 配置管理pydantic-settings
│ ├── models.py # OpenAI 兼容数据模型
│ ├── browser_manager.py # Playwright 浏览器管理
│ ├── doubao.py # 豆包页面交互逻辑
│ └── main.py # FastAPI 服务入口
└── scripts/
├── entrypoint.sh # 容器入口脚本
├── supervisord.conf # 进程管理配置
├── start_wm.sh # 窗口管理器启动脚本
└── start_x11vnc.sh # x11vnc 启动脚本(支持只读/交互切换)
```
## 进程架构
容器内通过 supervisord 管理五个进程,按优先级启动:
| 优先级 | 进程 | 说明 |
|--------|------|------|
| 10 | Xvfb | 虚拟帧缓冲 X 服务器 |
| 20 | openbox | 轻量级窗口管理器 |
| 30 | x11vnc | VNC 服务器,映射 Xvfb 显示 |
| 40 | websockify | WebSocket 代理,提供 noVNC Web 访问 |
| 50 | uvicorn | FastAPI 应用服务器 |
## 常见问题
### 构建失败:找不到包
本项目基于 RockyLinux 9。RHEL 10 / RockyLinux 10 移除了 X11 server 包不支持本方案。Docker 容器独立于宿主系统,在 RL10 宿主上运行 RL9 容器完全兼容。
### API 返回空响应
豆包前端更新可能导致 CSS 选择器失效。调用 `GET /inspect` 查看当前 DOM 结构,然后修改 `app/doubao.py` 中的选择器常量。
### 提示 "Not logged in"
需先通过 VNC 浏览器登录豆包,再调用 `POST /login/save` 保存状态。调用 `GET /login/status` 检查登录状态。
### VNC 无法操作
确认 noVNC 侧边栏 "View Only" 已取消勾选。若仍无法操作,检查服务端模式:`GET /vnc/mode`,如为 `viewonly` 则调用 API 切换为 `interactive`
## 技术栈
- **RockyLinux 9** — 容器基础系统
- **Xvfb + x11vnc + noVNC** — 虚拟显示与远程查看
- **Playwright** — 浏览器自动化
- **FastAPI + Uvicorn** — API 服务
- **Supervisor** — 进程管理
- **websockify** — VNC over WebSocket 代理
## 免责声明
本项目仅供学习和研究用途。使用前请确保遵守豆包的服务条款。作者不对因使用本项目而产生的任何直接或间接后果承担责任。