550 lines
10 KiB
Markdown
550 lines
10 KiB
Markdown
# 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. 当前未实现文件音频上传,只实现了“转写文本写回后端”的数据链路
|