This commit is contained in:
zhangquan 2026-03-31 11:02:39 +08:00
parent b2ad58e30c
commit 22ee4fbaaa
6 changed files with 869 additions and 24 deletions

308
DOCKER_DEPLOY.md Normal file
View File

@ -0,0 +1,308 @@
# Docker 部署指南(硬编码 KEY 版本)
## 📋 配置说明
本 Dockerfile 已经将所有 API 配置和密钥硬编码在镜像中:
### 已硬编码的配置
| 配置项 | 值 |
|--------|-----|
| API 端点 | `https://api.coze.cn/v1` ✅(包含 /v1 前缀) |
| COZE_API_KEY | `Bearer eyJhbGci...` ✅ |
| LLM_API_KEY | `Bearer eyJhbGci...` ✅ |
| COZE_WORKSPACE_ID | `7622238752642957347` ✅ |
| LLM_MODEL_NAME | `doubao-seed-2-0-pro-260215` ✅ |
### Workspace ID 来源
从 JWT Token 的 `sub` 字段提取:
```
spiffe://api.coze.cn/workload_identity/id:7622238752642957347
```
## 🚀 快速部署
### 步骤 1构建镜像
```bash
# 进入项目根目录
cd /workspace/projects
# 构建镜像
docker build -t math-grading:latest .
```
### 步骤 2运行容器
```bash
# 运行容器(简单方式)
docker run -d \
--name math-grading \
-p 8000:8000 \
--restart unless-stopped \
math-grading:latest
# 运行容器(完整方式,挂载日志和缓存)
docker run -d \
--name math-grading \
-p 8000:8000 \
-v $(pwd)/logs:/app/work/logs \
-v $(pwd)/cache:/tmp/homework_cache \
--restart unless-stopped \
math-grading:latest
```
### 步骤 3验证服务
```bash
# 查看容器状态
docker ps | grep math-grading
# 查看日志
docker logs -f math-grading
# 检查健康状态
curl http://localhost:8000/health
```
## 🧪 测试接口
### 测试 LLM 调用
```bash
curl -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{
"student_homework": [
{
"student_id": 1,
"student_name": "测试学生",
"homework_images": [
"https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/18/69baa4f5-4826-4901-00e1-c6e66f02947f.jpg?x-oss-process=image/resize,w_1000"
]
}
],
"answer_doc_url": "",
"comment_max_length": 50,
"max_concurrent": 1
}'
```
### 测试多图片批改
```bash
curl -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{
"student_homework": [
{
"student_id": 1,
"student_name": "张三",
"homework_images": [
"https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/18/69baa4f5-4826-4901-00e1-c6e66f02947f.jpg?x-oss-process=image/resize,w_1000",
"https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c6ff235a12b2.jpg?x-oss-process=image/resize,w_1000"
]
}
],
"answer_doc_url": "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c353d0-4826-4901-00e1-c7081bcab988.docx",
"comment_max_length": 50,
"max_concurrent": 2
}'
```
## 🔧 常用命令
### 容器管理
```bash
# 停止容器
docker stop math-grading
# 启动容器
docker start math-grading
# 重启容器
docker restart math-grading
# 删除容器
docker rm -f math-grading
# 删除镜像
docker rmi math-grading:latest
```
### 日志查看
```bash
# 查看实时日志
docker logs -f math-grading
# 查看最近 100 行日志
docker logs --tail 100 math-grading
# 查看错误日志
docker logs math-grading 2>&1 | grep ERROR
```
### 进入容器
```bash
# 进入容器 shell
docker exec -it math-grading /bin/bash
# 查看环境变量
docker exec math-grading env | grep COZE
# 运行 Python 脚本
docker exec math-grading python assets/check_env.py
```
## 📊 验证配置成功
### 成功标志
1. **容器启动成功**
```bash
docker ps | grep math-grading
# 应该显示容器运行中Up status
```
2. **日志无错误**
```bash
docker logs math-grading | grep ERROR
# 不应该有认证错误401或端点错误404
```
3. **健康检查通过**
```bash
curl http://localhost:8000/health
# 应该返回 200 OK
```
4. **LLM 调用成功**
```bash
# 运行测试请求,日志应该显示:
# ✅ HTTP Request: POST https://api.coze.cn/v1/chat/completions "HTTP/1.1 200 OK"
```
### 错误排查
#### 错误 1容器无法启动
```bash
# 查看详细日志
docker logs math-grading
# 检查端口是否被占用
netstat -tuln | grep 8000
```
#### 错误 2LLM 调用 401 错误
```bash
# 检查环境变量是否正确设置
docker exec math-grading env | grep COZE_API_KEY
# 应该看到:
# COZE_API_KEY=Bearer eyJhbGci...
```
#### 错误 3LLM 调用 404 错误
```bash
# 检查 API 端点配置
docker exec math-grading env | grep BASE_URL
# 应该看到:
# COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1
# 注意要有 /v1 前缀
```
## 🔐 安全说明
### ⚠️ 密钥已硬编码
当前 Dockerfile 将 API Key 硬编码在镜像中:
- ✅ 优点:部署简单,无需额外配置
- ❌ 缺点:密钥会暴露在镜像中,存在安全风险
### 安全建议
1. **私有仓库**
- 使用私有 Docker Registry如阿里云容器镜像服务
- 不要将镜像推送到公共仓库
2. **访问控制**
- 限制镜像访问权限
- 使用 RBAC 控制镜像拉取
3. **定期更换密钥**
- 定期在 Coze 平台更换 API Key
- 重新构建镜像
4. **生产环境建议**
- 使用环境变量方式(推荐)
- 参考 `assets/docker-compose.yml`
## 📝 配置说明
### 环境变量列表
| 变量名 | 说明 | 值 |
|--------|------|-----|
| `COZE_API_KEY` | Coze API 认证密钥 | Bearer eyJhbGci... |
| `LLM_API_KEY` | LLM API 认证密钥 | Bearer eyJhbGci... |
| `COZE_WORKSPACE_ID` | 工作区 ID | 7622238752642957347 |
| `COZE_INTEGRATION_BASE_URL` | API 基础 URL | https://api.coze.cn/v1 |
| `COZE_INTEGRATION_MODEL_BASE_URL` | 模型 API 基础 URL | https://api.coze.cn/v1 |
| `LLM_BASE_URL` | LLM API 基础 URL | https://api.coze.cn/v1 |
| `LLM_MODEL_NAME` | LLM 模型名称 | doubao-seed-2-0-pro-260215 |
| `COZE_INTEGRATION_API_KEY` | 集成 API 密钥 | Bearer eyJhbGci... |
### 端口说明
| 端口 | 说明 |
|------|------|
| 8000 | HTTP 服务端口 |
### 目录说明
| 目录 | 说明 |
|------|------|
| /app | 应用工作目录 |
| /app/work/logs/bypass | 日志目录 |
| /tmp/homework_cache | 缓存目录 |
## 🎯 总结
### 一键部署命令
```bash
# 构建并运行
docker build -t math-grading:latest .
docker run -d --name math-grading -p 8000:8000 --restart unless-stopped math-grading:latest
# 查看日志
docker logs -f math-grading
# 测试接口
curl -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{"student_homework": [{"student_id": 1, "homework_images": ["https://example.com/image.jpg"]}]}'
```
### 预期结果
- ✅ 容器正常运行
- ✅ 日志显示服务启动成功
- ✅ LLM 调用返回 200 OK
- ✅ 批改功能正常工作
### 关键修复点
1. ✅ API 端点包含 `/v1/` 前缀
2. ✅ COZE_WORKSPACE_ID 已配置
3. ✅ API Key 已硬编码
4. ✅ 健康检查已添加
5. ✅ 日志和缓存目录已创建

View File

@ -6,50 +6,40 @@ WORKDIR /app
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \ RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
# 安装完整的系统依赖(包含所有 PyGObject 需要的库) # 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
# 编译工具
gcc \ gcc \
g++ \ g++ \
make \ make \
pkg-config \ pkg-config \
cmake \ cmake \
# D-Bus 相关
dbus \
dbus-x11 \
libdbus-1-dev \
libdbus-glib-1-dev \
# GLib 和 GObject 相关
libglib2.0-dev \ libglib2.0-dev \
libgirepository1.0-dev \
gobject-introspection \
# Cairo 图形库
libcairo2-dev \ libcairo2-dev \
libcairo-gobject2 \
# GTK 相关(如果需要)
libgtk-3-dev \
# 其他常用库
libffi-dev \
libxml2-dev \ libxml2-dev \
libxslt1-dev \ libxslt1-dev \
curl \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# 设置 pip 国内镜像源 # 设置 pip 国内镜像源和 API 配置(硬编码 KEY
ENV PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ \ ENV PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ \
PIP_TRUSTED_HOST=mirrors.aliyun.com \ PIP_TRUSTED_HOST=mirrors.aliyun.com \
# API 端点配置(包含 /v1 前缀)
COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1 \ COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1 \
COZE_INTEGRATION_MODEL_BASE_URL=https://api.coze.cn/v1 \ COZE_INTEGRATION_MODEL_BASE_URL=https://api.coze.cn/v1 \
COZE_WORKLOAD_IDENTITY_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \ COZE_INTEGRATION_CHAT_BASE_URL=https://api.coze.cn/v1 \
LLM_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \
LLM_BASE_URL=https://api.coze.cn/v1 \ LLM_BASE_URL=https://api.coze.cn/v1 \
LLM_MODEL_NAME=doubao-seed-2-0-pro-260215 \ # API Key 配置(硬编码)
COZE_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \ COZE_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \
COZE_INTEGRATION_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \ LLM_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA" \
COZE_WORKSPACE_ID=7622238752642957347 # Workspace ID 配置(硬编码,从 JWT Token 提取)
COZE_WORKSPACE_ID=7622238752642957347 \
# LLM 模型配置
LLM_MODEL_NAME=doubao-seed-2-0-pro-260215 \
COZE_INTEGRATION_API_KEY="Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjkyOTc0LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMjQ4Mjg1OTMxMDQ0ODkxIn0.XSJaTryHWYzQaHxd9g9rOX2Y3YRY8kGAlvSFH9UkWR9EFDfZESG1GFEdWDelYeoHBqtdiQhxTcYdGPA87_PweMfh0wJXTdCEzTDHAOlUUupJEKTpkUAMEoEZpYBrwKQxjzGglkMHUoXqM5I0tQsARaqZ-j-JOW9Y6fHot56squm8GSt7WZkVSj6ZC2Us4cpO_RIgsN_pBU0CFSlUpOU5AdQQ8LvHzp60-DGaXVU0mFIYKhnXKbTf3PSXpJlH-W78FULh2FcdOTxMIcNkL5nuIHGakoNNDxs-k5Ucp06kFEMcbvec4iB1njbkHrsilYeJOFRoqkXJpQujDngZxKecLA"
# 升级 pip 和构建工具 # 升级 pip 和构建工具
RUN pip install --no-cache-dir --upgrade pip setuptools wheel meson ninja RUN pip install --no-cache-dir --upgrade pip setuptools wheel
# 复制并安装依赖 # 复制并安装依赖
COPY requirements.txt . COPY requirements.txt .
@ -58,5 +48,12 @@ RUN pip install --no-cache-dir -r requirements.txt
# 复制项目文件 # 复制项目文件
COPY . . COPY . .
# 创建必要的目录
RUN mkdir -p /app/work/logs/bypass /tmp/homework_cache
# 添加健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
EXPOSE 8000 EXPOSE 8000
CMD ["python", "src/main.py", "-m", "http", "-p", "8000"] CMD ["python", "src/main.py", "-m", "http", "-p", "8000"]

202
README_DOCKER.md Normal file
View File

@ -0,0 +1,202 @@
# 数学作业批改系统 - Docker 部署
## 📦 快速开始
### 一键部署
```bash
# 运行部署脚本
./deploy.sh
```
### 手动部署
```bash
# 构建镜像
docker build -t math-grading:latest .
# 启动容器
docker run -d \
--name math-grading \
-p 8000:8000 \
-v $(pwd)/logs:/app/work/logs \
-v $(pwd)/cache:/tmp/homework_cache \
--restart unless-stopped \
math-grading:latest
```
## 🧪 测试验证
```bash
# 运行测试脚本
./test.sh
```
## 📝 配置说明
### 已硬编码的配置
| 配置项 | 值 | 说明 |
|--------|-----|------|
| API 端点 | `https://api.coze.cn/v1` | 包含 /v1 前缀 |
| COZE_API_KEY | `Bearer eyJhbGci...` | Coze API 认证密钥 |
| COZE_WORKSPACE_ID | `7622238752642957347` | 工作区 ID |
| LLM_MODEL_NAME | `doubao-seed-2-0-pro-260215` | LLM 模型名称 |
### 配置来源
- **API Key**: 从原始 Dockerfile 中提取
- **Workspace ID**: 从 JWT Token 的 `sub` 字段提取
```
spiffe://api.coze.cn/workload_identity/id:7622238752642957347
```
## 🔧 常用命令
### 容器管理
```bash
# 查看状态
docker ps | grep math-grading
# 查看日志
docker logs -f math-grading
# 停止服务
docker stop math-grading
# 启动服务
docker start math-grading
# 重启服务
docker restart math-grading
# 进入容器
docker exec -it math-grading /bin/bash
```
## 📊 API 接口
### 批改接口
**请求**:
```bash
curl -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{
"student_homework": [
{
"student_id": 1,
"student_name": "张三",
"homework_images": [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg"
]
}
],
"answer_doc_url": "https://example.com/answers.docx",
"comment_max_length": 50,
"max_concurrent": 5
}'
```
**参数说明**:
- `student_homework`: 学生作业列表
- `answer_doc_url`: 答案文档 URL可选
- `comment_max_length`: 评语最大字数(默认 50
- `max_concurrent`: 并发批改数量(默认 5
## 📁 目录结构
```
.
├── Dockerfile # Docker 镜像配置(硬编码 KEY
├── deploy.sh # 一键部署脚本
├── test.sh # 快速测试脚本
├── DOCKER_DEPLOY.md # 详细部署文档
├── logs/ # 日志目录
├── cache/ # 缓存目录
└── src/ # 源代码
```
## 🔍 故障排查
### 问题 1: 容器无法启动
```bash
# 查看详细日志
docker logs math-grading
# 检查端口占用
netstat -tuln | grep 8000
```
### 问题 2: LLM 调用失败
```bash
# 检查环境变量
docker exec math-grading env | grep COZE
# 应该看到:
# COZE_API_KEY=Bearer eyJhbGci...
# COZE_WORKSPACE_ID=7622238752642957347
# COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1
```
### 问题 3: 认证错误 (401)
- 确认 COZE_API_KEY 和 COZE_WORKSPACE_ID 都已设置
- 检查 Token 是否有效
### 问题 4: 端点错误 (404)
- 确认 API 端点包含 /v1 前缀
- 检查 COZE_INTEGRATION_BASE_URL 配置
## 📚 详细文档
- [完整部署指南](DOCKER_DEPLOY.md)
- [项目文档](AGENTS.md)
- [Docker 404 错误修复](assets/fix_docker_404.md)
## ⚠️ 安全提示
当前 Dockerfile 将 API Key 硬编码在镜像中:
- ✅ 优点:部署简单,无需额外配置
- ❌ 缺点:密钥会暴露在镜像中
### 安全建议
1. **使用私有仓库**:不要推送到公共 Docker Registry
2. **访问控制**:限制镜像拉取权限
3. **定期更换密钥**:在 Coze 平台定期更换 API Key
4. **生产环境**:考虑使用环境变量方式(参考 docker-compose.yml
## 🎯 验证成功标志
部署成功后,应该看到:
```bash
# 1. 容器运行中
docker ps | grep math-grading
# Up 5 minutes
# 2. 健康检查通过
curl http://localhost:8000/health
# 200 OK
# 3. 日志无错误
docker logs math-grading | grep ERROR
# (无输出)
# 4. LLM 调用成功
# 日志显示:
# HTTP Request: POST https://api.coze.cn/v1/chat/completions "HTTP/1.1 200 OK"
```
## 📞 支持
如遇问题,请:
1. 查看日志: `docker logs -f math-grading`
2. 运行测试: `./test.sh`
3. 参考文档: `DOCKER_DEPLOY.md`

View File

@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""
JWT Token 中提取 Workspace ID
"""
import json
import base64
import sys
def extract_workspace_id(token):
"""
JWT Token 中提取 Workspace ID
Args:
token: JWT Token带或不带 "Bearer " 前缀
Returns:
workspace_id: 工作区 ID
"""
try:
# 移除 "Bearer " 前缀
if token.startswith("Bearer "):
token = token[7:]
# 分割 JWT
parts = token.split(".")
if len(parts) != 3:
print("❌ Token 格式错误:应该是 JWT 格式header.payload.signature")
return None
# 解码 payload
payload_b64 = parts[1]
# 添加 padding
padding = 4 - len(payload_b64) % 4
if padding != 4:
payload_b64 += "=" * padding
payload = json.loads(base64.b64decode(payload_b64))
# 显示 Token 信息
print("\n" + "=" * 80)
print("JWT Token 信息")
print("=" * 80)
print(f"Issuer (iss): {payload.get('iss')}")
print(f"Audience (aud): {payload.get('aud')}")
print(f"Subject (sub): {payload.get('sub')}")
print(f"Expires (exp): {payload.get('exp')}")
print(f"Issued At (iat): {payload.get('iat')}")
print(f"Source (src): {payload.get('src')}")
print()
# 提取 workspace_id
sub = payload.get('sub', '')
# 尝试不同的格式
if 'workload_identity/id:' in sub:
workspace_id = sub.split('workload_identity/id:')[-1]
print(f"✅ 格式 1: workload_identity/id:{workspace_id}")
elif 'workspace/id:' in sub:
workspace_id = sub.split('workspace/id:')[-1]
print(f"✅ 格式 2: workspace/id:{workspace_id}")
else:
# 尝试直接使用 sub
workspace_id = sub
print(f"⚠️ 格式 3: 直接使用 sub: {workspace_id}")
print()
print("=" * 80)
print(f"🔑 提取的 Workspace ID: {workspace_id}")
print("=" * 80)
print()
return workspace_id
except Exception as e:
print(f"❌ 解析 Token 失败: {str(e)}")
return None
def main():
print()
print("=" * 80)
print("Workspace ID 提取工具")
print("=" * 80)
print()
# 方式 1从环境变量读取
token = None
# 1. 尝试从命令行参数读取
if len(sys.argv) > 1:
token = sys.argv[1]
# 2. 尝试从环境变量读取
else:
token = __import__('os').environ.get('COZE_API_KEY')
if not token:
print("❌ 未找到 Token")
print()
print("使用方法:")
print(" 方式 1: python extract_workspace_id.py 'Bearer eyJhbGci...'")
print(" 方式 2: COZE_API_KEY='Bearer eyJhbGci...' python extract_workspace_id.py")
print()
return 1
# 提取 workspace_id
workspace_id = extract_workspace_id(token)
if workspace_id:
print()
print("✅ 提取成功!")
print()
print("下一步:")
print(f"1. 在 docker-compose.yml 中设置:")
print(f" COZE_WORKSPACE_ID={workspace_id}")
print()
return 0
else:
print()
print("❌ 提取失败,请检查 Token 格式")
print()
return 1
if __name__ == "__main__":
sys.exit(main())

89
deploy.sh Normal file
View File

@ -0,0 +1,89 @@
#!/bin/bash
# Docker 快速部署脚本
set -e
echo "=========================================="
echo "数学作业批改系统 - Docker 部署脚本"
echo "=========================================="
echo ""
# 检查 Docker 是否安装
if ! command -v docker &> /dev/null; then
echo "❌ Docker 未安装,请先安装 Docker"
exit 1
fi
echo "✅ Docker 已安装"
echo ""
# 检查旧容器
if docker ps -a | grep -q math-grading; then
echo "⚠️ 检测到旧容器 math-grading"
read -p "是否删除旧容器? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "🗑️ 删除旧容器..."
docker rm -f math-grading
else
echo "❌ 取消部署"
exit 1
fi
fi
echo "🏗️ 开始构建镜像..."
docker build -t math-grading:latest .
if [ $? -eq 0 ]; then
echo "✅ 镜像构建成功"
else
echo "❌ 镜像构建失败"
exit 1
fi
echo ""
echo "🚀 启动容器..."
# 创建日志和缓存目录
mkdir -p logs cache
# 启动容器
docker run -d \
--name math-grading \
-p 8000:8000 \
-v $(pwd)/logs:/app/work/logs \
-v $(pwd)/cache:/tmp/homework_cache \
--restart unless-stopped \
math-grading:latest
if [ $? -eq 0 ]; then
echo "✅ 容器启动成功"
else
echo "❌ 容器启动失败"
exit 1
fi
echo ""
echo "⏳ 等待服务启动..."
sleep 5
echo ""
echo "=========================================="
echo "部署完成!"
echo "=========================================="
echo ""
echo "服务地址: http://localhost:8000"
echo ""
echo "常用命令:"
echo " 查看日志: docker logs -f math-grading"
echo " 停止服务: docker stop math-grading"
echo " 启动服务: docker start math-grading"
echo " 重启服务: docker restart math-grading"
echo ""
echo "测试接口:"
echo " curl -X POST http://localhost:8000/stream_run \\"
echo " -H 'Content-Type: application/json' \\"
echo " -d '{\"student_homework\": [{\"student_id\": 1, \"homework_images\": [\"https://example.com/image.jpg\"]}]}'"
echo ""
echo "详细文档: DOCKER_DEPLOY.md"
echo ""

125
test.sh Normal file
View File

@ -0,0 +1,125 @@
#!/bin/bash
# 快速测试脚本
echo "=========================================="
echo "数学作业批改系统 - 快速测试"
echo "=========================================="
echo ""
# 检查容器是否运行
if ! docker ps | grep -q math-grading; then
echo "❌ 容器未运行,请先启动容器"
echo "运行: docker start math-grading"
exit 1
fi
echo "✅ 容器正在运行"
echo ""
# 测试 1: 健康检查
echo "测试 1: 健康检查"
echo "----------------------------------------"
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health)
if [ "$response" = "200" ]; then
echo "✅ 健康检查通过 (200 OK)"
else
echo "❌ 健康检查失败 (HTTP $response)"
fi
echo ""
# 测试 2: 环境变量检查
echo "测试 2: 环境变量检查"
echo "----------------------------------------"
echo "检查关键环境变量..."
# COZE_API_KEY
if docker exec math-grading env | grep -q "COZE_API_KEY=Bearer"; then
echo "✅ COZE_API_KEY 已设置"
else
echo "❌ COZE_API_KEY 未设置"
fi
# COZE_WORKSPACE_ID
if docker exec math-grading env | grep -q "COZE_WORKSPACE_ID=7622238752642957347"; then
echo "✅ COZE_WORKSPACE_ID 已设置 (7622238752642957347)"
else
echo "❌ COZE_WORKSPACE_ID 未设置或值不正确"
fi
# API 端点
if docker exec math-grading env | grep -q "COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1"; then
echo "✅ API 端点已配置 (https://api.coze.cn/v1)"
else
echo "❌ API 端点未配置或缺少 /v1 前缀"
fi
# LLM 模型
if docker exec math-grading env | grep -q "LLM_MODEL_NAME=doubao-seed-2-0-pro-260215"; then
echo "✅ LLM 模型已配置 (doubao-seed-2-0-pro-260215)"
else
echo "❌ LLM 模型未配置"
fi
echo ""
# 测试 3: LLM 调用测试
echo "测试 3: LLM 调用测试"
echo "----------------------------------------"
echo "发送测试请求..."
response=$(curl -s -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{
"student_homework": [
{
"student_id": 1,
"student_name": "测试学生",
"homework_images": [
"https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/18/69baa4f5-4826-4901-00e1-c6e66f02947f.jpg?x-oss-process=image/resize,w_1000"
]
}
],
"answer_doc_url": "",
"comment_max_length": 50,
"max_concurrent": 1
}' \
--max-time 120)
if [ $? -eq 0 ]; then
echo "✅ 请求发送成功"
echo ""
echo "响应预览:"
echo "$response" | head -c 500
echo "..."
else
echo "❌ 请求失败"
fi
echo ""
# 测试 4: 日志检查
echo "测试 4: 日志检查"
echo "----------------------------------------"
echo "检查最近日志中的错误..."
errors=$(docker logs --tail 100 math-grading 2>&1 | grep -i "401\|404\|authentication is invalid" | wc -l)
if [ "$errors" -eq 0 ]; then
echo "✅ 未发现认证错误或端点错误"
else
echo "❌ 发现 $errors 个错误"
echo "最近的错误:"
docker logs --tail 50 math-grading 2>&1 | grep -i "401\|404\|authentication is invalid" | tail -5
fi
echo ""
# 总结
echo "=========================================="
echo "测试总结"
echo "=========================================="
echo ""
echo "如果所有测试都通过,说明部署成功!"
echo ""
echo "下一步:"
echo " 1. 查看详细日志: docker logs -f math-grading"
echo " 2. 测试完整功能: 使用上面的测试请求"
echo " 3. 部署到生产环境: 参考 DOCKER_DEPLOY.md"
echo ""