Add external resource registration

This commit is contained in:
2026-06-22 13:19:18 +08:00
parent e5cd87789f
commit 12c767cd68
4 changed files with 496 additions and 11 deletions

213
README.md
View File

@ -10,6 +10,8 @@ Memory Gateway 是一个轻量级 FastAPI 服务,用于在上游记忆服务
## 功能范围
- 上传用户资源文件、图片、音频、PDF、HTML、普通文档、纯文本。
- 登记外部资源:文件真实保存在 Beaver user_files/MinIO 等外部存储,
Gateway 只保存元数据和 URI 映射,不保存原始文件副本。
- 保存资源元数据到 SQLite。
- 为每个资源生成独立的上游记忆服务 `session_id`
- 调用上游记忆服务的 `add``flush` 完成资源记忆摄入,并对临时失败做轻量重试。
@ -285,6 +287,83 @@ curl -X POST http://127.0.0.1:8010/resources \
资源上传接口返回的 `uri` 始终是 `resource://{user_id}/{resource_id}`。按文件名
命中的记忆搜索结果会另外通过 `attachments[].internal_uri` 返回真实 URI。
### 3b. 登记外部资源
```http
POST /resources/external
Content-Type: application/json
```
当文件已经保存在 Beaver user_files/MinIO 等外部存储时,调用该接口登记资源。
Gateway 不会保存原始文件副本,也不会下载 `source_uri``ingest_uri`;它只写入
SQLite 元数据、建立附件映射,并把 `ingest_uri` 作为 content item URI 传给上游
记忆服务完成解析和索引。
请求参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `user_id` | string | 是 | 无 | 用户 ID |
| `user_key` | string | 是 | 无 | 用户 key |
| `app_id` | string | 否 | `default` | 上游记忆服务 app scope |
| `project_id` | string | 否 | `default` | 上游记忆服务 project scope |
| `filename` | string | 是 | 无 | 文件名,用于检索附件匹配和上游解析 |
| `mime_type` | string | 否 | `null` | MIME 类型,如 `image/png``application/pdf` |
| `content_type` | string | 否 | 自动推断 | 上游 content type`image``audio``pdf``html``text``doc`。如果传入 MIME 类型Gateway 会按 MIME/扩展名重新推断 |
| `size_bytes` | integer | 否 | `null` | 文件大小 |
| `sha256` | string | 否 | `null` | 文件内容 sha256同用户同 app/project 下相同 sha256 的活跃资源会复用 |
| `source_uri` | string | 是 | 无 | 长期真实映射 URI`minio://bucket/users/u_123/outputs/chart.png` 或本地开发的 `file://...` |
| `ingest_uri` | string | 否 | `source_uri` | 上游记忆服务当次摄入可读取的 URI。MinIO 场景推荐传短期 presigned GET URL |
| `title` | string | 否 | `null` | 资源标题 |
| `description` | string | 否 | `null` | 资源描述 |
处理流程:
1. 生成 `resource_id`
2. 生成 `session_id = resource:{user_id}:{resource_id}`
3. 写入 `user_resources``uri = source_uri`,状态为 `ingesting`
4. 写入 `memory_attachments``internal_uri = source_uri``source = external_resource`
5. 构造上游 content item`{"type": "...", "name": filename, "uri": ingest_uri, "extras": {"resource_id": "...", "source": "external_resource"}}`
6. 调用上游记忆服务 `/api/v1/memory/add`
7. 调用上游记忆服务 `/api/v1/memory/flush`
8. 成功后状态改为 `extracted`,失败后状态改为 `failed` 并记录错误。
请求示例:
```bash
curl -X POST http://127.0.0.1:8010/resources/external \
-H 'Content-Type: application/json' \
-d '{
"user_id": "u_123",
"user_key": "uk_xxx",
"app_id": "default",
"project_id": "default",
"filename": "chart.png",
"mime_type": "image/png",
"size_bytes": 12345,
"sha256": "abc123...",
"source_uri": "minio://beaver-user-files/users/u_123/outputs/chart.png",
"ingest_uri": "https://minio.example/presigned/chart.png",
"title": "chart.png",
"description": "Beaver user file outputs/chart.png"
}'
```
响应示例:
```json
{
"resource_id": "r_xxx",
"session_id": "resource:u_123:r_xxx",
"uri": "resource://u_123/r_xxx",
"status": "extracted"
}
```
`source_uri` 是 Gateway 长期保存和搜索结果附件映射使用的真实 URI
`ingest_uri` 只用于本次上游解析。不要把短期 presigned URL 作为 `source_uri`
长期入库。
### 4. 查询资源列表
```http
@ -426,7 +505,121 @@ curl -X DELETE "http://127.0.0.1:8010/resources/r_xxx?user_id=u_123&user_key=uk_
}
```
### 7. 搜索记忆
### 7. 添加记忆
```http
POST /memories/add
Content-Type: application/json
```
该接口把一批消息追加到指定 `session_id`,并调用上游记忆服务
`/api/v1/memory/add`。如果消息 content item 中包含 `uri``base64` 附件,
Gateway 会额外登记附件映射,供后续 `/memories/search` 返回
`attachments[].internal_uri`
请求参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `user_id` | string | 是 | 无 | 用户 ID |
| `user_key` | string | 是 | 无 | 用户 key |
| `session_id` | string | 是 | 无 | 记忆 session`chat:{conversation_id}``resource:{user_id}:{resource_id}``memory_edit:{user_id}` |
| `messages` | object[] | 是 | 无 | 追加到该 session 的消息数组,至少 1 条 |
| `app_id` | string | 否 | `default` | 上游记忆服务 app scope |
| `project_id` | string | 否 | `default` | 上游记忆服务 project scope |
`messages[]` 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `sender_id` | string | 是 | 发送方 ID通常为当前用户 ID |
| `role` | string | 是 | `user``assistant``tool` |
| `timestamp` | integer | 是 | Unix 毫秒时间戳,必须大于 0 |
| `content` | string 或 object[] | 是 | 纯文本,或上游记忆服务 content item 数组 |
常见 content item
```json
{"type": "text", "text": "用户喜欢简洁的中文回答"}
```
```json
{
"type": "image",
"uri": "file:///home/tom/memory-gateway/tests/simple-multimodal-image.png",
"ext": "png",
"name": "simple-multimodal-image.png"
}
```
```json
{
"type": "audio",
"base64": "BASE64_DATA",
"ext": "wav",
"name": "tone.wav"
}
```
处理流程:
1. 校验 `user_id``user_key`
2. 检查 `messages` 基本结构。
3. 遍历 object[] content item`uri` 时登记该 URI只有 `base64` 时先校验并保存到 `MEMORY_GATEWAY_STORAGE_DIR/{user_id}/memory_attachments/{sha256}/`,再登记生成的 `file://` URI。
4. 将原始 `session_id``app_id``project_id``messages` 原样转发给上游记忆服务 `/api/v1/memory/add`
5. 上游 add 成功后写入附件映射;失败时不会保留本次新生成的 base64 附件文件。
请求示例:
```bash
curl -X POST http://127.0.0.1:8010/memories/add \
-H 'Content-Type: application/json' \
-d '{
"user_id": "u_123",
"user_key": "uk_xxx",
"session_id": "chat:c_456",
"app_id": "default",
"project_id": "default",
"messages": [
{
"sender_id": "u_123",
"role": "user",
"timestamp": 1781172177000,
"content": [
{
"type": "text",
"text": "记住:我偏好 concise 的中文说明"
},
{
"type": "image",
"uri": "file:///home/tom/memory-gateway/tests/simple-multimodal-image.png",
"ext": "png",
"name": "simple-multimodal-image.png"
}
]
}
]
}'
```
响应示例:
```json
{
"session_id": "chat:c_456",
"backend": {
"request_id": "add",
"data": {
"status": "accumulated"
}
}
}
```
`/memories/add` 只负责追加消息。需要让上游记忆服务对该 session 完成抽取和索引时,
继续调用 `/memories/flush`
### 8. 搜索记忆
```http
POST /memories/search
@ -506,17 +699,19 @@ curl -X POST http://127.0.0.1:8010/memories/search \
附件路径映射规则:
1. `/resources` 上传成功后,将资源真实 URI 与资源 session 写入
1. `/resources` 上传成功后,将 Gateway 本地保存的真实 URI 与资源 session 写入
`memory_attachments`。数据库初始化会自动回填已有 `user_resources`
2. `/memories/add` 中含 `uri` 的 content item 会直接登记 URI。
3. `/memories/add` 中只有 `base64` 的 content item 会保存到
2. `/resources/external` 登记成功后,将外部存储的 `source_uri` 与资源 session
写入 `memory_attachments`,但 Gateway 不保存原始文件副本。
3. `/memories/add` 中含 `uri` 的 content item 会直接登记 URI。
4. `/memories/add` 中只有 `base64` 的 content item 会保存到
`MEMORY_GATEWAY_STORAGE_DIR/{user_id}/memory_attachments/{sha256}/`,再登记
生成的 `file://` URI。相同用户、session、文件名和内容的重试会复用路径。
4. 搜索时根据当前用户和结果 `session_id` 查询附件,递归检查 `raw` 中的字符串
5. 搜索时根据当前用户和结果 `session_id` 查询附件,递归检查 `raw` 中的字符串
值。只有完整文件名出现时才返回对应附件;匹配不区分大小写。
5. `raw` 中键名为 `base64` 的内容不会参与匹配。未匹配时返回
6. `raw` 中键名为 `base64` 的内容不会参与匹配。未匹配时返回
`"attachments": []`
6. 历史 `/memories/add` 请求未保存在 Gateway 数据库中,无法自动补录映射;新
7. 历史 `/memories/add` 请求未保存在 Gateway 数据库中,无法自动补录映射;新
版本上线后的请求会建立映射。
`attachments[].internal_uri` 会按配置和调用方输入直接暴露服务器真实 URI调用
@ -553,7 +748,7 @@ curl -X POST http://127.0.0.1:8010/memories/search \
}
```
### 8. 修改记忆
### 9. 修改记忆
```http
PATCH /memories/{memory_id}
@ -594,7 +789,7 @@ curl -X PATCH http://127.0.0.1:8010/memories/mem_abc \
}
```
### 9. 删除记忆
### 10. 删除记忆
```http
DELETE /memories/{memory_id}