# Note 模块接口文档 ## 1. 模块说明 `note` 是独立于现有 `app/api` 业务的笔记小程序模块,代码位置如下: - [app/note/controller](/root/work/tp/app/note/controller) - [app/note/service](/root/work/tp/app/note/service) - [app/note/model](/root/work/tp/app/note/model) 当前已实现能力: 1. 微信小程序登录 2. 笔记创建、列表、详情、更新、删除 3. 实时转写文本保存 4. AI 总结生成与查询 路由注册位置: - [route/app.php](/root/work/tp/route/app.php) --- ## 2. 鉴权说明 除登录接口外,其余 `note` 接口都需要携带 JWT: - Header: `Authorization: Bearer {token}` `note` 模块复用现有 JWT 机制,但要求 token 载荷中必须包含: ```json { "userid": 123, "guard": "note" } ``` 说明: - `userid` 对应 `note_user.id` - `guard=note` 用于和旧 `api` 模块登录态隔离 --- ## 3. 环境变量 微信登录依赖以下配置: - `WECHAT_MINI_APPID` - `WECHAT_MINI_SECRET` - `DB_NOTE_HOSTNAME` - `DB_NOTE_DATABASE` - `DB_NOTE_USERNAME` - `DB_NOTE_PASSWORD` - `DB_NOTE_HOSTPORT` 示例位置: - [\.example.env](/root/work/tp/.example.env) --- ## 4. 数据表 表结构定义位置: - [database.sql](/root/work/tp/database.sql#L26) 当前 `note` 模块使用以下 4 张表: 1. `note_user` 用于小程序用户登录和用户资料 2. `note_item` 笔记主表,包含正文、转写累计文本、状态、录音时长等 3. `note_transcript` 实时转写分片记录表 4. `note_ai_summary` AI 总结结果表 --- ## 5. 接口列表 ### 5.1 获取模块概览 - 方法:`GET` - 路径:`/note/v1/meta/interfaces` - 是否鉴权:否 用途: - 返回 note 模块接口规划概览 --- ### 5.2 微信小程序登录 - 方法:`POST` - 路径:`/note/v1/auth/wechat-login` - 是否鉴权:否 请求参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `code` | string | 是 | `wx.login` 获取的临时 code | | `nickname` | string | 否 | 用户昵称 | | `avatar_url` | string | 否 | 用户头像地址 | 请求示例: ```json { "code": "021xxx", "nickname": "张三", "avatar_url": "https://example.com/avatar.png" } ``` 成功响应示例: ```json { "code": 200, "msg": "登录成功", "data": { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxx", "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.xxx", "expires_in": 604800, "user": { "id": 1, "member_id": 0, "openid": "oxxx", "nickname": "张三", "avatar_url": "https://example.com/avatar.png", "mobile": "", "is_new_user": true } }, "time": 1710000000 } ``` 说明: 1. 首次登录时自动创建 `note_user` 2. 后续登录时按 `openid` 更新资料与最后登录时间 3. 若用户被禁用,返回 403 --- ### 5.3 获取当前用户信息 - 方法:`GET` - 路径:`/note/v1/auth/me` - 是否鉴权:是 成功响应示例: ```json { "code": 200, "msg": "success", "data": { "id": 1, "member_id": 0, "openid": "oxxx", "nickname": "张三", "avatar_url": "https://example.com/avatar.png", "mobile": "", "status": 1, "last_login_time": 1710000000, "created_at": 1710000000 }, "time": 1710000001 } ``` --- ### 5.4 创建笔记 - 方法:`POST` - 路径:`/note/v1/item/create` - 是否鉴权:是 请求参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `source_type` | string | 是 | `text` / `audio` / `mix` | | `title` | string | 否 | 标题 | | `content` | string | 否 | 正文 | | `audio_duration_ms` | int | 否 | 录音时长 | | `status` | string | 否 | 默认 `draft` | 请求示例: ```json { "source_type": "text", "title": "会议纪要", "content": "今天确认了下周需求排期", "status": "draft" } ``` 成功响应示例: ```json { "code": 200, "msg": "创建成功", "data": { "id": 10, "note_user_id": 1, "title": "会议纪要", "content": "今天确认了下周需求排期", "transcript_text": "", "source_type": "text", "status": "draft", "audio_duration_ms": 0, "summary_status": "none", "last_transcript_time": 0, "created_at": 1710000000, "updated_at": 1710000000 }, "time": 1710000000 } ``` 说明: - 如果不传 `title`,后端会根据 `content` 自动生成标题 - 如果 `title` 和 `content` 都为空,标题会默认为 `未命名笔记` --- ### 5.5 笔记列表 - 方法:`GET` - 路径:`/note/v1/item/list` - 是否鉴权:是 查询参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `page` | int | 否 | 默认 1 | | `page_size` | int | 否 | 默认 10,最大 100 | | `keyword` | string | 否 | 搜索标题、正文、转写文本 | | `status` | string | 否 | 按状态筛选 | 响应示例: ```json { "code": 200, "msg": "success", "data": { "list": [ { "id": 10, "note_user_id": 1, "title": "会议纪要", "content": "今天确认了下周需求排期", "transcript_text": "", "source_type": "text", "status": "draft", "audio_duration_ms": 0, "summary_status": "none", "last_transcript_time": 0, "created_at": 1710000000, "updated_at": 1710000000 } ], "total": 1, "page": 1, "page_size": 10 }, "time": 1710000001 } ``` --- ### 5.6 笔记详情 - 方法:`GET` - 路径:`/note/v1/item/:id` - 是否鉴权:是 响应示例: ```json { "code": 200, "msg": "success", "data": { "id": 10, "note_user_id": 1, "title": "会议纪要", "content": "今天确认了下周需求排期", "transcript_text": "需要跟进接口联调", "source_type": "mix", "status": "draft", "audio_duration_ms": 120000, "summary_status": "success", "last_transcript_time": 1710000100, "created_at": 1710000000, "updated_at": 1710000200, "summary": { "summary_id": 3, "summary_type": "brief", "summary_text": "今天确认了下周需求排期\n需要跟进接口联调", "todo_list": [ "需要跟进接口联调" ], "keywords": [ "需求", "排期", "接口联调" ], "status": "success" } }, "time": 1710000201 } ``` --- ### 5.7 更新笔记 - 方法:`POST` - 路径:`/note/v1/item/update/:id` - 是否鉴权:是 请求参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `title` | string | 否 | 标题 | | `content` | string | 否 | 正文 | | `status` | string | 否 | 状态 | | `audio_duration_ms` | int | 否 | 录音时长 | 说明: - 只更新传入字段 - 只能更新自己的笔记 --- ### 5.8 删除笔记 - 方法:`POST` - 路径:`/note/v1/item/delete/:id` - 是否鉴权:是 说明: - 当前为软删除,写入 `deleted_at` 成功响应示例: ```json { "code": 200, "msg": "删除成功", "data": { "deleted": true, "id": 10 }, "time": 1710000300 } ``` --- ### 5.9 保存实时转写内容 - 方法:`POST` - 路径:`/note/v1/item/transcript/:id` - 是否鉴权:是 请求参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `full_text` | string | 是 | 当前累计完整转写文本 | | `segment_no` | int | 否 | 分片序号,默认 0 | | `segment_text` | string | 否 | 当前分片文本 | | `is_final` | int/bool | 否 | 是否最终片段 | | `audio_duration_ms` | int | 否 | 当前累计录音时长 | 请求示例: ```json { "segment_no": 3, "segment_text": "需要跟进接口联调", "full_text": "今天确认了下周需求排期,需要跟进接口联调", "is_final": 1, "audio_duration_ms": 120000 } ``` 成功响应示例: ```json { "code": 200, "msg": "转写保存成功", "data": { "note_id": 10, "segment_no": 3, "is_final": 1, "transcript_text": "今天确认了下周需求排期,需要跟进接口联调", "audio_duration_ms": 120000, "updated_at": 1710000400 }, "time": 1710000400 } ``` 说明: - 后端会同步更新 `note_item.transcript_text` - 同一个 `note_id + segment_no` 会覆盖写入 --- ### 5.10 生成 AI 总结 - 方法:`POST` - 路径:`/note/v1/ai/summary/:id` - 是否鉴权:是 请求参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `summary_type` | string | 否 | `brief` / `outline` / `todo` | | `force_refresh` | int/bool | 否 | 是否强制重新生成 | 请求示例: ```json { "summary_type": "brief", "force_refresh": 1 } ``` 成功响应示例: ```json { "code": 200, "msg": "总结生成成功", "data": { "summary_id": 3, "note_id": 10, "summary_type": "brief", "summary_text": "今天确认了下周需求排期\n需要跟进接口联调", "todo_list": [ "需要跟进接口联调" ], "keywords": [ "需求", "排期", "接口联调" ], "status": "success", "error_message": "", "created_at": 1710000500, "updated_at": 1710000500 }, "time": 1710000500 } ``` 说明: - 当前实现为规则版总结,不依赖外部大模型 - 若已存在成功总结且 `force_refresh=0`,会直接返回已有结果 --- ### 5.11 查看 AI 总结 - 方法:`GET` - 路径:`/note/v1/ai/summary/:id` - 是否鉴权:是 说明: - 返回指定笔记最新的一条总结记录 --- ## 6. 错误码约定 当前模块沿用项目统一返回结构: ```json { "code": 400, "msg": "错误信息", "data": [], "time": 1710000000 } ``` 常见情况: - `400`:参数错误 - `401`:未登录或登录态无效 - `403`:用户被禁用 - `404`:资源不存在 - `500`:服务端错误 - `502`:调用微信接口失败 --- ## 7. 调用顺序建议 小程序端推荐按以下顺序接入: 1. 调 `wx.login` 2. 把 `code` 发给 `POST /note/v1/auth/wechat-login` 3. 保存返回的 `token` 4. 创建笔记 `POST /note/v1/item/create` 5. 录音转写过程中持续调用 `POST /note/v1/item/transcript/:id` 6. 需要生成总结时调用 `POST /note/v1/ai/summary/:id` 7. 打开详情页时调用 `GET /note/v1/item/:id` --- ## 8. 当前限制 1. AI 总结目前是规则版,不是大模型版 2. 微信登录依赖服务端已正确配置 `WECHAT_MINI_APPID` 和 `WECHAT_MINI_SECRET` 3. 当前未实现文件音频上传,只实现了“转写文本写回后端”的数据链路