# 教学反馈助手 API ## 交互文档 服务启动后提供以下文档入口: - Scalar:`GET /scalar` - OpenAPI JSON:`GET /openapi.json` - 完整调用流程:[API_GUIDE.md](./API_GUIDE.md) Scalar 中的业务接口需要填写微信登录换取的 Bearer 令牌,请求体接口提供了示例。按 ID 操作时,应使用创建或列表接口返回的真实 ID。 ## 启动和数据库策略 本服务不会创建或启动本地 PostgreSQL。 - 未设置 `DATABASE_URL` 时,`cargo run` 只启动 HTTP 服务;`GET /health` 返回成功,数据接口返回 `503`。 - 获得远程 PostgreSQL 地址后,将其写入本地未提交的 `server/.env`,执行 `cargo run --bin migrate`,再执行 `cargo run`。 - 迁移不会使用 PostgreSQL 扩展,UUID 由 Rust 服务生成。 ```bash cd server cp .env.example .env # 在 .env 中填写 DATABASE_URL # 同时填写 WECHAT_APP_ID 和 WECHAT_APP_SECRET cargo run --bin migrate cargo run ``` ## 语音转录和反馈汇总 长短录音统一通过小程序原生录音器上传到本服务。服务先将音频保存在 `AUDIO_STORAGE_DIR` 并立即响应,再由持久化后台队列调用本地 FunASR;模型暂时不可用或 API 重启都不会丢失已上传音频。 ```text AUDIO_STORAGE_DIR=./data/audio ASR_PROVIDER=local LOCAL_ASR_URL=http://127.0.0.1:10095 ASR_REQUEST_TIMEOUT_SECONDS=1800 ASR_WORKER_CONCURRENCY=1 ASR_JOB_LEASE_SECONDS=3600 ``` 在项目根目录执行 `docker compose -f compose.asr.yml up --build -d` 启动中文模型。`GET /health` 中 `speech_available=true` 表示模型已下载并可以接收任务;`wechat_auth_configured=true` 且 `development_auth_enabled=false` 表示生产微信鉴权已就绪。 腾讯云仅作为可选提供方保留。需要切换时配置: ```text ASR_PROVIDER=tencent TENCENT_CLOUD_ASR_APP_ID=1234567890 TENCENT_CLOUD_ASR_SECRET_ID=your-secret-id TENCENT_CLOUD_ASR_SECRET_KEY=your-secret-key TENCENT_CLOUD_ASR_ENGINE_TYPE=16k_zh ``` 反馈汇总支持可选的 OpenAI 兼容 Chat Completions 接口。未配置时使用本地抽取式汇总,录音转录和保存流程仍可工作: ```text FEEDBACK_SUMMARY_API_URL=https://api.example.com/v1/chat/completions FEEDBACK_SUMMARY_API_KEY=your-api-key FEEDBACK_SUMMARY_MODEL=your-model ``` ## 微信登录和会话 小程序调用 `wx.login()`,再把一次性 code 发送到: ```text POST /api/v1/auth/wechat/login ``` Rust API 使用服务端 `WECHAT_APP_ID` 和 `WECHAT_APP_SECRET` 调用微信 `code2Session`,把 `openid` 映射为内部教师 UUID,并返回 30 天有效的随机会话令牌。业务接口统一使用: ```text Authorization: Bearer ``` 数据库仅保存令牌的 SHA-256 哈希,AppSecret 和微信 session_key 不会返回客户端。本地兼容头只有设置 `ALLOW_DEVELOPMENT_USER_HEADER=true` 时才启用,生产 Compose 强制为 `false`。 ## 接口 | 方法 | 路径 | 说明 | | --- | --- | --- | | `GET` | `/health` | 服务、数据库、语音提供方及模型可用状态。 | | `POST` | `/api/v1/auth/wechat/login` | 用 `wx.login` code 换取后端会话。 | | `GET` | `/api/v1/auth/me` | 读取当前教师身份和会话状态。 | | `POST` | `/api/v1/auth/logout` | 撤销当前会话。 | | `GET` | `/api/v1/profiles` | 列出学生档案;可选 `query`、`grade`、`subject` 参数。 | | `POST` | `/api/v1/profiles` | 创建学生档案。 | | `GET` | `/api/v1/profiles/{profile_id}` | 读取单个学生档案。 | | `PUT` | `/api/v1/profiles/{profile_id}` | 更新学生档案。 | | `DELETE` | `/api/v1/profiles/{profile_id}` | 删除学生档案。 | | `GET` | `/api/v1/profile-defaults` | 读取学生档案预设;未配置时返回美术课默认值。 | | `PUT` | `/api/v1/profile-defaults` | 写入年级、学科和上课时长预设。 | | `GET` | `/api/v1/feedback-records` | 列出反馈记录;可选 `profile_id` 参数。 | | `POST` | `/api/v1/feedback-records` | 创建反馈记录。 | | `DELETE` | `/api/v1/feedback-records/{record_id}` | 删除反馈记录。 | | `GET` | `/api/v1/feedback-sessions/active` | 读取指定学生进行中的语音反馈批次。 | | `POST` | `/api/v1/feedback-sessions` | 创建或恢复语音反馈批次。 | | `PUT` | `/api/v1/feedback-sessions/{session_id}` | 自动保存反馈正文和日期。 | | `POST` | `/api/v1/feedback-sessions/{session_id}/lessons` | 开始下一节课堂录音。 | | `POST` | `/api/v1/feedback-lessons/{lesson_id}/segments` | 上传一个自动切分的片段并加入后台转录队列。 | | `POST` | `/api/v1/feedback-lessons/{lesson_id}/finish` | 结束课节并汇总片段状态。 | | `POST` | `/api/v1/feedback-lessons/{lesson_id}/mark-applied` | 标记短录音文字已直接加入反馈。 | | `POST` | `/api/v1/audio-segments/{segment_id}/retry` | 重试失败片段的转录。 | | `POST` | `/api/v1/feedback-sessions/{session_id}/generate` | 汇总多节转录并生成反馈正文。 | ### 创建学生档案 ```json { "name": "小谢", "grade": "艺术类", "subject": "美术", "academic_year": 2026, "term": "暑", "guardian_title": "小谢妈妈", "start_time": "18:00", "end_time": "19:00" } ``` ### 保存默认预设 ```json { "grade": "艺术类", "subject": "美术", "lesson_duration_minutes": 60 } ``` ### 创建反馈记录 ```json { "profile_id": "5fa5af2c-cfc9-4bb8-b0b3-8715f080b167", "feedback_date": "2026-07-14", "content": "今天完成了色彩搭配练习,构图有明显进步。", "feedback_session_id": null } ```