文档版本: v1.0
创建日期: 2025-01-29
设计者: Backend Team
状态: 设计阶段
拍照解题功能基于阿里云百炼 EduTutor 服务,提供两大核心能力:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ Backend │ │ 百炼 EduTutor │
│ │ │ │ │ │
│ 图片上传 │───▶│ 图片处理 │───▶│ Cut API │
│ 题目展示 │ │ 请求转发 │ │ Answer API │
│ 答案渲染 │◀───│ 结果解析 │◀───│ (SSE 流式) │
│ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
│ ▼
│ ┌─────────────────┐
│ │ PostgreSQL │
└─────────────▶│ │
(可选) │ 题目记录 │
│ 解答历史 │
└─────────────────┘
试卷切题流程:
解题辅导流程:
端点: POST /api/edu/cut-questions
请求参数:
{
"image_url": "https://oss.example.com/paper.png",
"options": {
"struct": true, // 是否返回结构化信息
"extract_images": true // 是否返回子题图片链接
}
}
响应结构:
{
"success": true,
"data": {
"questions": [
{
"index": 0,
"type": "填空题",
"stem": {
"text": "若 a + b = -1, ab = 4, 则...",
"pos_list": [[21, 4, 364, 4, 364, 78, 21, 78]]
},
"options": [],
"answer": [{"text": "-17"}],
"merged_image": "https://oss.../question_0.png",
"sub_images": ["https://oss.../sub_0_0.png"]
}
]
},
"input_tokens": 80,
"output_tokens": 38
}
端点: POST /api/edu/answer (SSE 流式)
请求参数:
{
"image_url": "https://oss.example.com/question.png",
"parameters": {
"grade": 6, // 年级(0-17, 99=其他)
"stage": "小学", // 学段
"subject": "数学" // 学科
}
}
SSE 流式响应:
data: {"type": "start", "content": "### 【考点分析】:\n"}
data: {"type": "chunk", "content": "本题涉及代数表达式..."}
data: {"type": "chunk", "content": "### 【方法点拨】:\n"}
data: {"type": "finish", "finish_reason": "stop", "tokens": {"input": 654, "output": 457}}
| 字段 | 类型 | 说明 |
|---|---|---|
| id | UUID | 主键 |
| user_id | UUID | 用户ID(外键) |
| image_url | TEXT | 原始图片链接 |
| question_type | VARCHAR(20) | 题目类型 |
| stem_text | TEXT | 题干文本 |
| answer_text | TEXT | 答案文本 |
| structured_data | JSONB | 完整结构化数据 |
| created_at | TIMESTAMP | 创建时间 |
| 字段 | 类型 | 说明 |
|---|---|---|
| id | UUID | 主键 |
| question_id | UUID | 题目ID(外键) |
| user_id | UUID | 用户ID(外键) |
| answer_content | TEXT | 解答内容(Markdown) |
| grade | INTEGER | 年级 |
| subject | VARCHAR(50) | 学科 |
| input_tokens | INTEGER | 输入Token数 |
| output_tokens | INTEGER | 输出Token数 |
| created_at | TIMESTAMP | 创建时间 |
上传策略:
图片要求:
后端实现:
async def answer_stream(image_url: str, params: dict):
client = create_edututor_client()
request = build_answer_request(image_url, params)
async for chunk in client.answer_sse_async(request):
yield format_sse_event(chunk)
前端实现:
const eventSource = new EventSource('/api/edu/answer');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
appendAnswer(data.content);
};
常见错误场景:
| 指标 | 目标值 |
|---|---|
| 切题响应时间 | < 5s(单页试卷) |
| 解题首字响应 | < 2s |
| 解题完整响应 | < 15s |
| 并发支持 | 100 QPS |
优化策略:
试卷切题:
解题辅导:
后端:
alibabacloud-edututor20250707: 百炼 SDKalibabacloud-credentials: 凭证管理oss2: 阿里云 OSS SDK(图片上传)前端:
react-markdown: Markdown 渲染katex: 数学公式渲染react-dropzone: 文件上传组件| 风险 | 影响 | 应对措施 |
|---|---|---|
| API 调用超限 | 服务不可用 | 实现本地缓存 + 用户限流 |
| 识别准确率低 | 用户体验差 | 提供手动编辑入口 + 反馈机制 |
| 图片加载慢 | 响应时间长 | CDN 加速 + 图片压缩 |
| 成本超预算 | 运营压力 | 实施分级收费策略 |
# 阿里云凭证
ALIBABA_CLOUD_ACCESS_KEY_ID=your_access_key_id
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your_access_key_secret
# 百炼 Workspace ID
BAILIAN_WORKSPACE_ID=llm-uflun9q7q59osmbb
# OSS 配置(图片上传)
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_BUCKET=your-bucket-name
OSS_ACCESS_KEY_ID=your_oss_ak
OSS_ACCESS_KEY_SECRET=your_oss_sk
切题示例:
curl -X POST "http://localhost:8000/api/edu/cut-questions" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/paper.png",
"options": {"struct": true, "extract_images": true}
}'
解题示例:
curl -N "http://localhost:8000/api/edu/answer" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/question.png",
"parameters": {"grade": 6, "subject": "数学"}
}'
文档结束