# 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. 录音文件上传与播放 5. AI 总结生成与查询 6. 笔记分享与分享只读访问 路由注册位置: - [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` 模块使用以下 6 张表: 1. `note_user` 用于小程序用户登录和用户资料 2. `note_item` 笔记主表,包含正文、转写累计文本、状态、录音时长等 3. `note_transcript` 实时转写分片记录表 4. `note_ai_summary` AI 总结结果表 5. `note_audio` 录音附件表,保存上传后的音频文件地址与时长 6. `note_share` 分享记录表,保存分享 token 与查看次数 --- ## 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 上传录音文件 - 方法:`POST` - 路径:`/note/v1/item/audio/:id` - 是否鉴权:是 - Content-Type:`multipart/form-data` 表单参数: | 字段 | 类型 | 必填 | 说明 | | :--- | :--- | :--- | :--- | | `audio` | file | 是 | 录音文件 | | `audio_duration_ms` | int | 否 | 录音时长 | 说明: - 上传成功后会返回可直接播放的 `audio_url` - 后端会同步写入 `note_audio`,并更新笔记的录音时长 成功响应示例: ```json { "code": 200, "msg": "上传成功", "data": { "audio_id": 2, "disk": "public", "file_path": "note/audio/20260417/test.m4a", "audio_url": "http://127.0.0.1:8000/storage/note/audio/20260417/test.m4a", "file_size": 20480, "mime_type": "audio/mp4", "duration_ms": 18500, "updated_at": 1710000400 }, "time": 1710000400 } ``` --- ### 5.11 生成 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.12 查看 AI 总结 - 方法:`GET` - 路径:`/note/v1/ai/summary/:id` - 是否鉴权:是 说明: - 返回指定笔记最新的一条总结记录 --- ### 5.13 创建分享 - 方法:`POST` - 路径:`/note/v1/share/create/:id` - 是否鉴权:是 成功响应示例: ```json { "code": 200, "msg": "分享已生成", "data": { "note_id": 10, "share_token": "7a4d2f2d4a5f1b20f6f9670bb1f4d123", "share_path": "/pages/note/edit?share_token=7a4d2f2d4a5f1b20f6f9670bb1f4d123", "title": "会议纪要" }, "time": 1710000600 } ``` 说明: - 返回 `share_token` 和小程序页面路径 - 小程序可用该路径做转发 --- ### 5.14 读取分享内容 - 方法:`GET` - 路径:`/note/v1/share/read/:token` - 是否鉴权:否 成功响应示例: ```json { "code": 200, "msg": "success", "data": { "id": 10, "note_user_id": 1, "title": "会议纪要", "content": "今天确认了下周需求排期", "transcript_text": "今天确认了下周需求排期", "source_type": "mix", "status": "draft", "audio_duration_ms": 18500, "summary_status": "success", "last_transcript_time": 1710000300, "created_at": 1710000000, "updated_at": 1710000600, "audio": { "audio_id": 2, "disk": "public", "file_path": "note/audio/20260417/test.m4a", "audio_url": "http://127.0.0.1:8000/storage/note/audio/20260417/test.m4a", "file_size": 20480, "mime_type": "audio/mp4", "duration_ms": 18500, "updated_at": 1710000400 }, "summary": { "summary_text": "今天确认了下周需求排期,需要继续跟进接口联调。", "status": "success" }, "share": { "share_token": "7a4d2f2d4a5f1b20f6f9670bb1f4d123", "title": "会议纪要", "view_count": 3 } }, "time": 1710000601 } ``` 说明: - 用于收件人直接查看分享的笔记内容、录音和 AI 摘要 --- ## 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/item/audio/:id` 7. 需要生成总结时调用 `POST /note/v1/ai/summary/:id` 8. 分享前调用 `POST /note/v1/share/create/:id` 9. 打开详情页时调用 `GET /note/v1/item/:id` --- ## 8. 当前限制 1. AI 总结目前是规则版,不是大模型版 2. 微信登录依赖服务端已正确配置 `WECHAT_MINI_APPID` 和 `WECHAT_MINI_SECRET` 3. 分享读取接口为公开接口,建议前端仅用于只读展示