版本 v0.3.0 | 服务地址:
http://localhost:${PORT}(默认端口 48002)
NoteSystem Agent 提供笔记自动整理能力,通过 HTTP API 接收原始 Markdown 内容,经由 AI 流水线处理后将笔记保存到本地文件系统。
交互模式(异步 + SSE):
- 调用
POST /api/organize提交任务 → 立即获得task_id - 连接
GET /api/organize/{task_id}/stream→ 通过 SSE 实时接收进度和结果
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/api/organize |
提交笔记整理任务 |
GET |
/api/organize/{task_id}/stream |
SSE 订阅任务进度与结果 |
GET |
/health |
服务健康检查 |
GET |
/ |
服务基本信息 |
GET |
/docs |
交互式 API 文档(Swagger UI) |
提交一条笔记给 AI 流水线处理。
POST /api/organize
Content-Type: application/json| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
markdown_content |
string |
✅ | — | 原始 Markdown 笔记内容 |
notes_root_path |
`string | null` | ❌ | 服务端 .env 中 NOTES_ROOT_PATH |
images_dir |
`string | null` | ❌ | notes_root_path |
enable_image_semantic |
`bool | null` | ❌ | 读取配置文件 |
enable_note_format |
`bool | null` | ❌ | 读取配置文件 |
enable_classify_and_save |
`bool | null` | ❌ | 读取配置文件 |
add_date_stamp |
bool |
❌ | true |
是否在保存前插入日期行(格式 YYYY-MM-DD) |
分类来源说明: 服务会扫描
notes_root_path下的一级和二级目录作为可选分类。目录不存在时 LLM 自由命名,并在写文件时自动创建目录。
**enable_* 优先级:** API 参数 >config/models.yaml中的organize配置。
# 最简调用(使用服务端默认目录和配置)
curl -X POST http://localhost:48002/api/organize \
-H "Content-Type: application/json" \
-d '{"markdown_content": "# Docker 快速入门\n\nDocker 是一个容器化平台。"}'
# 指定目录(另一个项目的笔记库)
curl -X POST http://localhost:48002/api/organize \
-H "Content-Type: application/json" \
-d '{
"markdown_content": "# Docker 快速入门\n\nDocker 是一个容器化平台。",
"notes_root_path": "/home/user/my-project/notes",
"enable_image_semantic": false,
"enable_note_format": true,
"enable_classify_and_save": true,
"add_date_stamp": true
}'{
"task_id": "a1b2c3d4-...",
"message": "任务已创建,请订阅 SSE 获取进度"
}| 字段 | 类型 | 说明 |
|---|---|---|
task_id |
string |
用于订阅 SSE 流的唯一任务 ID(UUID) |
message |
string |
固定提示文本 |
订阅指定任务的进度和结果,使用 Server-Sent Events(SSE) 协议。
GET /api/organize/{task_id}/stream
Accept: text/event-stream连接成功后持续接收事件,直到流关闭(任务完成或出错)。
每条 SSE 事件的格式:
event: <event_type>
data: <JSON 字符串>
在流水线各步骤开始和完成时发送。
{
"step": "note_classify",
"progress": 0.75,
"message": "分类: 编程/Python",
"timestamp": "2026-04-15T10:49:31.740656"
}| 字段 | 类型 | 说明 |
|---|---|---|
step |
string |
当前步骤标识,见下表 |
progress |
float |
整体进度 0.0 ~ 1.0 |
message |
string |
步骤状态描述文本 |
timestamp |
string |
ISO 8601 时间戳 |
步骤标识说明:
step 值 |
说明 |
|---|---|
image_semantic |
图像语义提取(qwen3-vl-flash) |
note_format |
笔记内容整理(qwen3.5-plus) |
note_classify |
AI 笔记分类(qwen3.5-flash) |
file_save |
保存到本地文件系统 |
任务完成后发送,是流的最后一条事件。
{
"success": true,
"note_path": "编程/Python/Python asyncio 入门.md",
"category": "编程",
"subcategory": "Python",
"title": "Python asyncio 入门",
"token_summary": {
"total_tokens": 1280,
"total_cost": 0.0023,
"breakdown": [
{ "step": "note_classify", "tokens": 320, "cost": 0.0008 }
]
},
"processed_content": null,
"timestamp": "2026-04-15T10:49:45.123456"
}| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool |
任务是否成功 |
note_path |
string |
相对于 notes_root_path 的存储路径,如 编程/Python/Python asyncio 入门.md(enable_classify_and_save=false 时为空) |
category |
string |
笔记一级分类 |
subcategory |
string |
笔记二级分类 |
title |
string |
AI 生成的笔记标题 |
token_summary |
object |
Token 用量和费用统计 |
processed_content |
`string | null` |
timestamp |
string |
ISO 8601 时间戳 |
任务失败时发送(代替 result)。
{
"error": "DashScope API call failed: rate limit exceeded",
"retry": false,
"step": "note_format",
"timestamp": "2026-04-15T10:49:35.000000"
}curl:
curl -N "http://localhost:48002/api/organize/a1b2c3d4-.../stream"Python:
import httpx, json
task_id = "a1b2c3-..."
with httpx.stream("GET", f"http://localhost:48002/api/organize/{task_id}/stream") as r:
for line in r.iter_lines():
if line.startswith("data:"):
event = json.loads(line[5:].strip())
print(event)JavaScript (Browser / Node):
const source = new EventSource(
`http://localhost:48002/api/organize/${taskId}/stream`
);
source.addEventListener("progress", (e) => {
const data = JSON.parse(e.data);
console.log(`[${data.step}] ${data.message}`);
});
source.addEventListener("result", (e) => {
const data = JSON.parse(e.data);
if (data.success) {
console.log("✅ 保存路径:", data.note_path);
}
source.close();
});
source.addEventListener("error", () => source.close());健康检查,用于监控服务是否存活。
curl http://localhost:48002/health{
"status": "ok",
"service": "notesys",
"version": "0.3.0"
}╔══════════════════════╗ ①POST /api/organize ╔══════════════╗
║ 调用方(客户端) ║ ─────────────────────────────► ║ notesys ║
║ ║ ◄───────────────────────────── ║ ║
║ 获得 task_id ║ { task_id: "abc..." } ║ ║
║ ║ ║ ║
║ ②GET /stream ║ ─────────────────────────────► ║ 异步处理中 ║
║ ║ ◄── event:progress (多条) ──── ║ ║
║ ║ ◄── event:result (最后一条) ── ║ ║
╚══════════════════════╝ ╚══════════════╝
注意事项:
task_id仅在服务运行期间有效(内存存储),服务重启后失效stream连接断开后任务仍在后台继续执行(断开不等于取消)note_path是相对于notes_root_path的相对路径- 分类由
notes_root_path下的实际目录结构决定,无需维护静态配置文件 - 若 ragData 服务在运行,文件保存后会在下次同步周期内被自动向量化
| HTTP 状态码 | 含义 |
|---|---|
200 |
请求成功(任务提交成功或 SSE 流正常) |
404 |
task_id 不存在(已过期或服务曾重启) |
422 |
请求体格式错误(缺少必填字段等) |
500 |
服务内部错误 |