From cfeb1b2b1a227feddc5c4384b454c65e99e3d66e Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Wed, 22 Apr 2026 17:22:59 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=AE=8C=E5=96=84=20README=20=E6=96=87?= =?UTF-8?q?=E6=A1=A3=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=8E=A5=E5=8F=A3=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E3=80=81=E5=B8=B8=E8=A7=81=E9=97=AE=E9=A2=98=E3=80=81?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 265 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 217 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index b0de696..e150a82 100644 --- a/README.md +++ b/README.md @@ -1,91 +1,260 @@ # 数字人对接中转服务 -基于 Docker Compose 部署的数字人对接中转服务,连接客户端与 Dify LLM 平台。 +基于 Docker Compose 部署的数字人对接中转服务,连接客户端与 Dify LLM 平台,支持流式与非流式对话、多轮会话上下文(Redis 缓存)。 + +## 目录 + +- [架构](#架构) +- [快速部署](#快速部署) +- [接口说明](#接口说明) +- [环境变量](#环境变量) +- [端口说明](#端口说明) +- [本地测试](#本地测试) +- [常见问题](#常见问题) +- [生产部署](#生产部署) +- [目录结构](#目录结构) + +--- ## 架构 ``` -Client --> digital-human (8000) --> Dify LLM Platform - | - +--> Redis (6379) +Client --> Nginx/Traefik(反向代理) --> digital-human(:8000) --> Dify LLM Platform + | | + | +--> Redis(:6379, 容器内网) ``` +- **digital-human**:FastAPI 中转服务,转发请求至 Dify 并统一响应格式 +- **Redis**:存储 session_id 与 dify conversation_id 的映射关系,支持多轮对话 +- 两者通过 Docker Compose 内部 DNS (`redis`) 通信,不占用宿主机端口 + +--- + ## 快速部署 -### 1. 配置环境变量 +### 1. 克隆项目 + +```bash +git clone https://github.com/ClawCopilot/digital-human-dify-relay.git +cd digital-human-dify-relay +``` + +### 2. 配置环境变量 ```bash cp .env.example .env -# 编辑 .env,填入 DIFY_URL 和 DIFY_API_KEY +# 编辑 .env,填入以下两个必填变量 ``` -### 2. 启动服务 +`.env` 必填项: + +```env +# Dify 服务地址(末尾不要加 /chat-messages,代码会自动拼接) +DIFY_URL=https://your-dify-domain.com/v1 + +# Dify API 密钥(纯密钥,不要加 Bearer 前缀) +DIFY_API_KEY=app-PDkSHiHZsZIluoZF7N2OlNZM +``` + +### 3. 启动服务 ```bash docker compose up -d ``` -### 3. 验证服务 +### 4. 验证服务 ```bash # 健康检查 -curl http://localhost:8000/health +curl http://localhost:8000/ -# 转发测试(chat/completions) -curl -X POST http://localhost:8000/v1/chat/completions \ - -H "Content-Type: application/json" \ - -d '{ - "model": "dify", - "messages": [{"role": "user", "content": "你好"}] - }' +# 重启后确认容器状态(healthy 表示正常) +docker ps | grep digital-human ``` +--- + +## 接口说明 + +### `POST /digital-human` + +数字人中转核心接口。 + +**请求体:** + +```json +{ + "messages": [ + { "content": "你好,请用一句话介绍自己。" } + ], + "app_id": "app-xxxxxxxx", + "user": "user-001", + "session_id": "550e8400-e29b-41d4-a716-446655440000", + "is_stream": true +} +``` + +| 字段 | 类型 | 必填 | 说明 | +|:---|:---|:---:|:---| +| `messages` | `Array` | ✅ | 消息列表,目前只取第一条 `content` 作为 Dify query | +| `app_id` | `string` | ✅ | Dify 应用 ID | +| `user` | `string` | ✅ | 用户标识,用于 Dify 会话上下文 | +| `session_id` | `string` | ✅ | 会话 ID,用于关联多轮对话上下文,留空自动生成 | +| `is_stream` | `boolean` | ✅ | `true` = SSE 流式响应,`false` = 非流式阻塞返回 | + +**响应(非流式 is_stream=false):** + +```json +{ + "id": "131424542124", + "created": 20230512084843, + "choices": [ + { + "index": 0, + "message": { + "content": "你好!我是..." + } + } + ] +} +``` + +**响应(流式 is_stream=true):** + +SSE 格式,每个 chunk: + +``` +data: {"id":"1231414141541252525","created":20230512084843,"choices":[{"message":{"content":"你"}}]} + +data: {"id":"1231414141541252525","created":20230512084843,"choices":[{"message":{"content":"好"}}]} + +... + +data: [DONE] +``` + +--- + +### `GET /` + +健康检查端点,用于 Docker healthcheck 和外部监控。 + +```json +{ "status": "ok" } +``` + +--- + +## 环境变量 + +| 变量 | 必填 | 默认值 | 说明 | +|:---|:---:|:---|:---| +| `DIFY_URL` | ✅ | — | Dify 服务地址,如 `https://atwdify.antiwearvalve.com/v1` | +| `DIFY_API_KEY` | ✅ | — | Dify API 密钥(纯密钥,不要加 `Bearer ` 前缀) | +| `REDIS_HOST` | 否 | `redis` | Redis 主机,Docker Compose 内部 DNS,始终填 `redis` | +| `REDIS_PORT` | 否 | `6379` | Redis 端口 | +| `DH_PORT` | 否 | `8000` | 宿主机映射端口 | + +> **注意**:`DIFY_URL` 末尾不要包含 `/chat-messages`,代码会自动拼接。 + +--- + ## 端口说明 | 端口 | 服务 | 说明 | |:---|:---|:---| -| `${DH_PORT:-8000}` | digital-human | 中转服务,对外暴露(可通过 `DH_PORT` 自定义) | -| — | Redis | **默认不暴露**,仅在 Docker Compose 内部网络互通 | +| `${DH_PORT:-8000}` | digital-human | 中转服务,通过反向代理或直连访问 | +| — | Redis | **默认不暴露**,仅在 Docker 容器网络内部互通 | -## 环境变量 - -| 变量 | 必填 | 默认值 | 说明 | -|:---|:---|:---|:---| -| `DIFY_URL` | 是 | - | Dify 服务地址,如 `https://xxx.com/v1` | -| `DIFY_API_KEY` | 是 | - | Dify API 密钥 | -| `DH_PORT` | 否 | `8000` | 宿主机映射端口(如设为 `9000` 则访问 `http://IP:9000`) | -| `REDIS_HOST` | 否 | `redis` | Redis 主机(Docker Compose 内部 DNS,始终有效) | -| `REDIS_PORT` | 否 | `6379` | Redis 端口 | -| `REDIS_EXPOSE_PORT` | 否 | 不暴露 | 需要暴露时在 `.env` 中设置(如 `6379`),配合 `docker-compose.redis-expose.yml` 使用 | - -## Redis 端口暴露(可选) - -默认情况下 Redis **不占用宿主机任何端口**,digital-human 通过 Docker Compose 内部 DNS 直连。如需从宿主机直连 Redis(如本地调试),执行以下命令: +如需从宿主机直连 Redis,合并 `docker-compose.redis-expose.yml`: ```bash -# 启动时合并 Redis 暴露配置 docker compose -f docker-compose.yml -f docker-compose.redis-expose.yml up -d - -# 宿主机即可访问 -redis-cli -h localhost -p 6379 ``` -## 生产部署注意事项 +--- -1. **防火墙**:确保服务器 TCP 8000 端口对外部开放 -2. **HTTPS**:生产环境建议在 `digital-human` 前加一层 Nginx/Caddy 反向代理, termination TLS -3. **环境变量**:不要将密钥提交到代码仓库,`.env` 已加入 `.gitignore` -4. **Redis**:生产环境可移除内建 Redis,连接外部 Redis 集群 +## 本地测试 + +项目内置两个测试页面: + +| 文件 | 用途 | 访问方式 | +|:---|:---|:---| +| `test.html` | 测试中转服务 `/digital-human` 接口 | 浏览器直接打开或部署后访问 | +| `test-dify.html` | 直连 Dify API,跳过中转 | 浏览器直接打开 | + +### test.html 使用方法 + +1. 打开 `test.html` +2. 填写**中转服务地址**,如 `https://chat-agent-demo.aigc-quickapp.com` +3. 填写 Session ID(留空自动生成) +4. 填写 App ID(对应 Dify 应用) +5. 填写 User +6. 填写测试消息 +7. 点击**发送请求** + +--- + +## 常见问题 + +### Q:容器状态为 unhealthy? + +执行以下命令查看具体报错: + +```bash +docker compose logs digital-human +``` + +常见原因: +- `.env` 中 `DIFY_URL` 或 `DIFY_API_KEY` 未填写或格式错误 +- Redis 连接失败(确保 `REDIS_HOST=redis` 且两个容器在同一网络) + +### Q:POST /digital-human 返回 500? + +通常是 Dify 请求失败。检查: +- `.env` 中 `DIFY_URL` 是否正确(末尾是否为 `/v1`) +- `DIFY_API_KEY` 是否有效 +- 服务器能否访问 Dify 地址:`curl -I $DIFY_URL` + +### Q:Redis Connection refused? + +确认 `docker-compose.yml` 中 `REDIS_HOST: "redis"` 生效,且 Redis 容器正常运行: + +```bash +docker ps | grep redis +docker compose logs redis +``` + +### Q:外网无法访问服务? + +1. 检查容器是否正常:`docker ps` 状态应为 `healthy` +2. 检查防火墙:`sudo ufw allow 8000/tcp`(或对应端口) +3. 通过域名访问时检查反向代理配置是否正确转发到容器端口 + +--- + +## 生产部署 + +1. **反向代理**:在 digital-human 前配置 Nginx/Caddy 进行 TLS termination +2. **HTTPS**:生产环境务必使用 HTTPS +3. **环境变量**:`.env` 不要提交到代码仓库,已在 `.gitignore` 中排除 +4. **Redis 高可用**:可替换为外部 Redis 集群,修改 `REDIS_HOST` +5. **域名配置**:将域名 DNS 解析到服务器,通过反向代理转发到容器端口 + +--- ## 目录结构 ``` . -├── docker-compose.yml # 主容器编排(Redis 默认内部模式) -├── docker-compose.redis-expose.yml # Redis 端口暴露扩展(按需合并) -├── Dockerfile # 应用镜像构建 -├── digital-human.py # FastAPI 中转服务源码 -├── requirements.txt # Python 依赖 -├── .env.example # 环境变量模板 -└── README.md # 本文件 +├── docker-compose.yml # 主容器编排(Redis 默认内部模式) +├── docker-compose.redis-expose.yml # Redis 端口暴露扩展(按需合并) +├── Dockerfile # 应用镜像构建 +├── digital-human.py # FastAPI 中转服务源码 +├── requirements.txt # Python 依赖 +├── .env.example # 环境变量模板 +├── test.html # 中转服务测试页面 +├── test-dify.html # Dify 直连测试页面 +├── downloads/ # 独立部署包(Systemd + Shell) +└── README.md # 本文件 ```