Files

1 line
38 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "aizhen1412/smartnas", "files": {"scripts/start_smartnas.sh": {"1a2801a5679cd2216c377dc18978fedd78c386cf": {"t": 1785745958.2752016, "n": 2179, "h": "1c4d425d4c7e0f50", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_CONFIG=\"${SMARTNAS_CONFIG:-$ROOT_DIR/config/config.json}\"\nmapfile -t CONFIG_VALUES < <(\n python3 -c 'import json,os; c=json.load(open(os.environ[\"SMARTNAS_CONFIG\"])); [print(c[k]) for k in (\"core_port\",\"agent_port\",\"deepseek_api_base\",\"deepseek_model\",\"data_dir\",\"database_path\",\"deepseek_api_key\")]'\n)\nCORE_PORT=\"${CONFIG_VALUES[0]}\"\nAGENT_PORT=\"${CONFIG_VALUES[1]}\"\nDEEPSEEK_API=\"${CONFIG_VALUES[2]}\"\nDEEPSEEK_MODEL=\"${CONFIG_VALUES[3]}\"\nDATA_DIR=\"${CONFIG_VALUES[4]}\"\nDATABASE_PATH=\"${CONFIG_VALUES[5]}\"\nCONFIG_DEEPSEEK_KEY=\"${CONFIG_VALUES[6]}\"\n[[ \"$DATA_DIR\" = /* ]] || DATA_DIR=\"$ROOT_DIR/$DATA_DIR\"\n[[ \"$DATABASE_PATH\" = /* ]] || DATABASE_PATH=\"$ROOT_DIR/$DATABASE_PATH\"\n\nmkdir -p \"$DATA_DIR\" \"$(dirname \"$DATABASE_PATH\")\"\nif [[ ! -w \"$DATA_DIR\" || ! -w \"$(dirname \"$DATABASE_PATH\")\" ]]; then\n echo \"SmartNAS data directories are not writable: $DATA_DIR or $(dirname \"$DATABASE_PATH\")\" >&2\n exit 1\nfi\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\ncmake --build \"$ROOT_DIR/build\"\n\n\"$ROOT_DIR/build/bin/SmartNAS\" \"$SMARTNAS_CONFIG\" &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:$CORE_PORT\"\necho \"SmartNAS Agent: http://127.0.0.1:$AGENT_PORT\"\necho \"LLM provider: DeepSeek\"\necho \"DeepSeek API: $DEEPSEEK_API\"\necho \"DeepSeek model: $DEEPSEEK_MODEL\"\nif [[ -n \"${SMARTNAS_DEEPSEEK_API_KEY:-${DEEPSEEK_API_KEY:-$CONFIG_DEEPSEEK_KEY}}\" ]]; then\n echo \"DeepSeek key: configured\"\nelse\n echo \"DeepSeek key: missing (set SMARTNAS_DEEPSEEK_API_KEY or DEEPSEEK_API_KEY)\"\nfi\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "6137c4f53c41ac9a4651ab2f87252ad1befd0e40": {"t": 1785758264.9656355, "n": 2179, "h": "1c4d425d4c7e0f50", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_CONFIG=\"${SMARTNAS_CONFIG:-$ROOT_DIR/config/config.json}\"\nmapfile -t CONFIG_VALUES < <(\n python3 -c 'import json,os; c=json.load(open(os.environ[\"SMARTNAS_CONFIG\"])); [print(c[k]) for k in (\"core_port\",\"agent_port\",\"deepseek_api_base\",\"deepseek_model\",\"data_dir\",\"database_path\",\"deepseek_api_key\")]'\n)\nCORE_PORT=\"${CONFIG_VALUES[0]}\"\nAGENT_PORT=\"${CONFIG_VALUES[1]}\"\nDEEPSEEK_API=\"${CONFIG_VALUES[2]}\"\nDEEPSEEK_MODEL=\"${CONFIG_VALUES[3]}\"\nDATA_DIR=\"${CONFIG_VALUES[4]}\"\nDATABASE_PATH=\"${CONFIG_VALUES[5]}\"\nCONFIG_DEEPSEEK_KEY=\"${CONFIG_VALUES[6]}\"\n[[ \"$DATA_DIR\" = /* ]] || DATA_DIR=\"$ROOT_DIR/$DATA_DIR\"\n[[ \"$DATABASE_PATH\" = /* ]] || DATABASE_PATH=\"$ROOT_DIR/$DATABASE_PATH\"\n\nmkdir -p \"$DATA_DIR\" \"$(dirname \"$DATABASE_PATH\")\"\nif [[ ! -w \"$DATA_DIR\" || ! -w \"$(dirname \"$DATABASE_PATH\")\" ]]; then\n echo \"SmartNAS data directories are not writable: $DATA_DIR or $(dirname \"$DATABASE_PATH\")\" >&2\n exit 1\nfi\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\ncmake --build \"$ROOT_DIR/build\"\n\n\"$ROOT_DIR/build/bin/SmartNAS\" \"$SMARTNAS_CONFIG\" &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:$CORE_PORT\"\necho \"SmartNAS Agent: http://127.0.0.1:$AGENT_PORT\"\necho \"LLM provider: DeepSeek\"\necho \"DeepSeek API: $DEEPSEEK_API\"\necho \"DeepSeek model: $DEEPSEEK_MODEL\"\nif [[ -n \"${SMARTNAS_DEEPSEEK_API_KEY:-${DEEPSEEK_API_KEY:-$CONFIG_DEEPSEEK_KEY}}\" ]]; then\n echo \"DeepSeek key: configured\"\nelse\n echo \"DeepSeek key: missing (set SMARTNAS_DEEPSEEK_API_KEY or DEEPSEEK_API_KEY)\"\nfi\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "ae28c5c82f7abb2ba87647dd6726f75bc0da05bd": {"t": 1785758266.344678, "n": 1702, "h": "b4ec58c548df02ac", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_DEEPSEEK_API_BASE=\"${SMARTNAS_DEEPSEEK_API_BASE:-https://api.deepseek.com}\"\nexport SMARTNAS_DEEPSEEK_MODEL=\"${SMARTNAS_DEEPSEEK_MODEL:-deepseek-chat}\"\nexport SMARTNAS_CORE_API=\"${SMARTNAS_CORE_API:-http://127.0.0.1:8080}\"\n\nmkdir -p \"$ROOT_DIR/var/data\" \"$ROOT_DIR/var/db\"\nif [[ ! -w \"$ROOT_DIR/var/data\" || ! -w \"$ROOT_DIR/var/db\" ]]; then\n echo \"SmartNAS data directories are not writable: $ROOT_DIR/var/data or $ROOT_DIR/var/db\" >&2\n exit 1\nfi\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\ncmake --build \"$ROOT_DIR/build\"\n\n(\n cd \"$ROOT_DIR/build/bin\"\n ./SmartNAS\n) &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:8080\"\necho \"SmartNAS Agent: http://127.0.0.1:8081\"\necho \"LLM provider: DeepSeek\"\necho \"DeepSeek API: $SMARTNAS_DEEPSEEK_API_BASE\"\necho \"DeepSeek model: $SMARTNAS_DEEPSEEK_MODEL\"\nif [[ -n \"${SMARTNAS_DEEPSEEK_API_KEY:-${DEEPSEEK_API_KEY:-}}\" ]]; then\n echo \"DeepSeek key: configured\"\nelse\n echo \"DeepSeek key: missing (set SMARTNAS_DEEPSEEK_API_KEY or DEEPSEEK_API_KEY)\"\nfi\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "3d357b3ee317c922fa1ecfbe50b7fcde4a082564": {"t": 1785758267.6211507, "n": 1767, "h": "f0c292f738ce434f", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_DEEPSEEK_API_BASE=\"${SMARTNAS_DEEPSEEK_API_BASE:-https://api.deepseek.com}\"\nexport SMARTNAS_DEEPSEEK_MODEL=\"${SMARTNAS_DEEPSEEK_MODEL:-deepseek-chat}\"\nexport SMARTNAS_MAX_NEW_TOKENS=\"${SMARTNAS_MAX_NEW_TOKENS:-256}\"\nexport SMARTNAS_CORE_API=\"${SMARTNAS_CORE_API:-http://127.0.0.1:8080}\"\n\nmkdir -p \"$ROOT_DIR/var/data\" \"$ROOT_DIR/var/db\"\nif [[ ! -w \"$ROOT_DIR/var/data\" || ! -w \"$ROOT_DIR/var/db\" ]]; then\n echo \"SmartNAS data directories are not writable: $ROOT_DIR/var/data or $ROOT_DIR/var/db\" >&2\n exit 1\nfi\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\ncmake --build \"$ROOT_DIR/build\"\n\n(\n cd \"$ROOT_DIR/build/bin\"\n ./SmartNAS\n) &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:8080\"\necho \"SmartNAS Agent: http://127.0.0.1:8081\"\necho \"LLM provider: DeepSeek\"\necho \"DeepSeek API: $SMARTNAS_DEEPSEEK_API_BASE\"\necho \"DeepSeek model: $SMARTNAS_DEEPSEEK_MODEL\"\nif [[ -n \"${SMARTNAS_DEEPSEEK_API_KEY:-${DEEPSEEK_API_KEY:-}}\" ]]; then\n echo \"DeepSeek key: configured\"\nelse\n echo \"DeepSeek key: missing (set SMARTNAS_DEEPSEEK_API_KEY or DEEPSEEK_API_KEY)\"\nfi\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "055c8f825b6e2bdf333b99196669cd8d46979587": {"t": 1785758268.8931334, "n": 1595, "h": "2d5289a228b6f72f", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_DEEPSEEK_API_BASE=\"${SMARTNAS_DEEPSEEK_API_BASE:-https://api.deepseek.com}\"\nexport SMARTNAS_DEEPSEEK_MODEL=\"${SMARTNAS_DEEPSEEK_MODEL:-deepseek-chat}\"\nexport SMARTNAS_MAX_NEW_TOKENS=\"${SMARTNAS_MAX_NEW_TOKENS:-256}\"\nexport SMARTNAS_CORE_API=\"${SMARTNAS_CORE_API:-http://127.0.0.1:8080}\"\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\nif [[ ! -x \"$ROOT_DIR/build/bin/SmartNAS\" ]]; then\n cmake --build \"$ROOT_DIR/build\"\nfi\n\n(\n cd \"$ROOT_DIR/build/bin\"\n ./SmartNAS\n) &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:8080\"\necho \"SmartNAS Agent: http://127.0.0.1:8081\"\necho \"LLM provider: DeepSeek\"\necho \"DeepSeek API: $SMARTNAS_DEEPSEEK_API_BASE\"\necho \"DeepSeek model: $SMARTNAS_DEEPSEEK_MODEL\"\nif [[ -n \"${SMARTNAS_DEEPSEEK_API_KEY:-${DEEPSEEK_API_KEY:-}}\" ]]; then\n echo \"DeepSeek key: configured\"\nelse\n echo \"DeepSeek key: missing (set SMARTNAS_DEEPSEEK_API_KEY or DEEPSEEK_API_KEY)\"\nfi\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "0a493bbb7af80e238c96a500c988d086051f9ce5": {"t": 1785758270.470636, "n": 1213, "h": "12fec464dad8da75", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_MODEL_PATH=\"${SMARTNAS_MODEL_PATH:-$ROOT_DIR/models/llm/qwen2.5-7b-instruct-q4_k_m.gguf}\"\nexport SMARTNAS_CORE_API=\"${SMARTNAS_CORE_API:-http://127.0.0.1:8080}\"\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\nif [[ ! -x \"$ROOT_DIR/build/bin/SmartNAS\" ]]; then\n cmake --build \"$ROOT_DIR/build\"\nfi\n\n(\n cd \"$ROOT_DIR/build/bin\"\n ./SmartNAS\n) &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:8080\"\necho \"SmartNAS Agent: http://127.0.0.1:8081\"\necho \"LLM backend: transformers\"\necho \"Model path: $SMARTNAS_MODEL_PATH\"\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}, "6861d18eeecc3089153d65d9a6994c1ea4df1d4f": {"t": 1785758272.2902687, "n": 1201, "h": "6d7e066094688b70", "c": "#!/usr/bin/env bash\nset -euo pipefail\n\nROOT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")/..\" && pwd)\"\ncd \"$ROOT_DIR\"\n\nexport SMARTNAS_MODEL_PATH=\"${SMARTNAS_MODEL_PATH:-$ROOT_DIR/models/llm/qwen2.5-7b-instruct}\"\nexport SMARTNAS_CORE_API=\"${SMARTNAS_CORE_API:-http://127.0.0.1:8080}\"\n\nif [[ ! -f \"$ROOT_DIR/build/Makefile\" ]]; then\n cmake -S \"$ROOT_DIR\" -B \"$ROOT_DIR/build\"\nfi\n\nif [[ ! -x \"$ROOT_DIR/build/bin/SmartNAS\" ]]; then\n cmake --build \"$ROOT_DIR/build\"\nfi\n\n(\n cd \"$ROOT_DIR/build/bin\"\n ./SmartNAS\n) &\nCORE_PID=$!\n\npython3 \"$ROOT_DIR/scripts/agent_service.py\" &\nAGENT_PID=$!\n\ncleanup() {\n kill \"$CORE_PID\" \"$AGENT_PID\" 2>/dev/null || true\n}\ntrap cleanup EXIT INT TERM\n\nsleep 1\nif ! kill -0 \"$CORE_PID\" 2>/dev/null; then\n echo \"SmartNAS Core failed to start.\"\n kill \"$AGENT_PID\" 2>/dev/null || true\n exit 1\nfi\n\nif ! kill -0 \"$AGENT_PID\" 2>/dev/null; then\n echo \"SmartNAS Agent failed to start.\"\n kill \"$CORE_PID\" 2>/dev/null || true\n exit 1\nfi\n\necho \"SmartNAS Core: http://127.0.0.1:8080\"\necho \"SmartNAS Agent: http://127.0.0.1:8081\"\necho \"LLM backend: transformers\"\necho \"Model path: $SMARTNAS_MODEL_PATH\"\necho \"Press Ctrl+C to stop both services.\"\n\nwait\n"}}, "docs/agent-service.md": {"1a2801a5679cd2216c377dc18978fedd78c386cf": {"t": 1785746410.983145, "n": 5579, "h": "41f891d2800e9f90", "c": "# SmartNAS Agent 功能说明\n\n## 1. 服务定位\n\nSmartNAS Agent 是独立运行的 Python/FastAPI 服务,默认监听 `8081`。它负责:\n\n- 调用 DeepSeek OpenAI-compatible API;\n- 普通对话与 SSE 流式对话;\n- 文件转 Markdown、摘要和标签生成;\n- 单文件全文问答和文件内 RAG 问答;\n- Markdown 分块、向量生成、FAISS 检索和索引持久化;\n- 摘要后台任务、取消、重试、去重与状态持久化;\n- Agent 操作审计。\n\nNAS Core 仍负责 JWT 鉴权、文件存储、下载、元数据和目录操作。Agent 不直接读取 Core 的 SQLite,而是携带用户 JWT 调用 Core HTTP API。\n\n## 2. 启动与依赖\n\n安装依赖:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r scripts/requirements-agent.txt\n```\n\n单独启动 Agent:\n\n```bash\nexport SMARTNAS_DEEPSEEK_API_KEY=sk-...\npython3 scripts/agent_service.py\n```\n\n也可以同时启动 Core 和 Agent:\n\n```bash\n./scripts/start_smartnas.sh\n```\n\nAgent 默认通过 `http://127.0.0.1:8080` 访问 Core。\n\n## 3. 配置项\n\n默认参数统一存放在 `config/config.json`。下列环境变量用于部署时覆盖对应 JSON 值,优先级为:环境变量 > JSON 配置 > 代码默认值。\n\n| 环境变量 | 默认值 | 用途 |\n| --- | --- | --- |\n| `SMARTNAS_CORE_API` | `http://127.0.0.1:8080` | Core API 地址 |\n| `SMARTNAS_DEEPSEEK_API_KEY` | 空 | DeepSeek API Key,也兼容 `DEEPSEEK_API_KEY` |\n| `SMARTNAS_DEEPSEEK_API_BASE` | `https://api.deepseek.com` | 模型 API 地址 |\n| `SMARTNAS_DEEPSEEK_MODEL` | `deepseek-chat` | 模型名称 |\n| `SMARTNAS_DEEPSEEK_TIMEOUT` | `60` | 模型请求超时秒数 |\n| `SMARTNAS_GENERATION_TEMPERATURE` | `0.7` | 生成温度 |\n| `SMARTNAS_GENERATION_TOP_P` | `0.8` | Top-P |\n| `SMARTNAS_MAX_MARKDOWN_CHARS` | `12000` | 单次摘要输入长度 |\n| `SMARTNAS_SUMMARY_CHUNK_CHARS` | `7000` | 长文摘要分块长度 |\n| `SMARTNAS_FILE_QA_DIRECT_CHARS` | `30000` | 全文问答与 RAG 问答切换阈值 |\n| `SMARTNAS_CACHE_DIR` | `var/cache/markdown` | Markdown 缓存目录 |\n| `SMARTNAS_VECTOR_DIR` | `var/cache/vector` | 向量数据和 FAISS 索引目录 |\n| `SMARTNAS_EMBEDDING_MODEL` | `BAAI/bge-small-zh-v1.5` | Embedding 模型 |\n| `SMARTNAS_RAG_CHUNK_CHARS` | `900` | RAG 文本块长度 |\n| `SMARTNAS_RAG_CHUNK_OVERLAP` | `120` | RAG 分块重叠长度 |\n| `SMARTNAS_RAG_TOP_K` | `6` | 默认召回数量 |\n| `SMARTNAS_RAG_MIN_SCORE` | `0.28` | 最低相似度 |\n| `SMARTNAS_TASK_DB` | `var/cache/agent_tasks.db` | 摘要任务数据库 |\n| `SMARTNAS_AUDIT_LOG` | `var/log/agent_audit.jsonl` | 审计日志路径 |\n| `SMARTNAS_AUDIT_LOG_MAX_BYTES` | `20971520` | 单个审计日志最大字节数 |\n| `SMARTNAS_AUDIT_LOG_BACKUPS` | `10` | 审计日志保留数量 |\n| `SMARTNAS_AUDIT_LOG_FULL_CONTENT` | `0` | 是否记录完整内容 |\n| `SMARTNAS_AGENT_HOST` | `127.0.0.1` | Agent 监听地址 |\n| `SMARTNAS_AGENT_PORT` | `8081` | Agent 监听端口 |\n| `SMARTNAS_SUMMARY_WORKER_COUNT` | `1` | 摘要后台 worker 数 |\n\n## 4. 鉴权与用户隔离\n\n除健康检查外,接口都使用 Core 签发的 JWT:\n\n```http\nAuthorization: Bearer <token>\n```\n\n- Agent 通过 `/api/v1/me` 向 Core 验证身份;\n- 普通聊天上下文按用户隔离;\n- 单文件问答上下文按“用户 + 文件 hash”隔离,并保留最近三轮问答;\n- 向量缓存按用户命名空间隔离;\n- 摘要任务只能由任务所属用户查看、取消或重试。\n\n聊天和单文件问答上下文目前保存在 Agent 内存中,服务重启后会清空。摘要任务与向量索引会持久化。\n\n## 5. HTTP API\n\n### 健康检查\n\n`GET /api/agent/health`\n\n返回模型配置、依赖状态、缓存路径、RAG 参数和支持格式。\n\n### 普通聊天\n\n- `POST /api/agent/chat`:非流式聊天,请求体为 `{\"prompt\":\"...\"}`。\n- `POST /api/agent/chat/stream`:SSE 流式聊天,请求体相同。\n- `POST /api/agent/clear_history`:清空当前用户普通聊天上下文。\n\n流式接口使用以下事件:\n\n```text\ndata: {\"type\":\"delta\",\"content\":\"增量文本\"}\n\ndata: {\"type\":\"done\"}\n\ndata: {\"type\":\"error\",\"message\":\"错误信息\"}\n```\n\n上游 SSE 使用小块读取,并关闭代理转换和缓冲。模型输出中的 Markdown 星号会在 Agent 输出层统一移除。\n\n### 文件摘要与标签\n\n- `POST /api/agent/summarize`:同步摘要,请求体为 `{\"hash\":\"...\",\"force\":false}`。\n- `POST /api/agent/summarize/start`:创建后台摘要任务。\n- `GET /api/agent/summarize/status/{task_id}`:查询任务。\n- `GET /api/agent/summarize/tasks`:列出当前用户任务。\n- `POST /api/agent/summarize/cancel/{task_id}`:取消任务。\n- `POST /api/agent/summarize/retry/{task_id}`:重试失败或取消的任务。\n- `POST /api/agent/summarize/missing`:为缺少摘要的支持文件批量排队;页面登录后会自动调用一次。\n\nWeb UI 在登录后会自动扫描并补齐缺失摘要;文件上传、恢复、重命名和移动成功后,也会静默调用 `summarize/start`。任务在后台完成 Markdown 转换、摘要、标签和向量索引,不阻塞文件操作。\n\n### Markdown 与单文件问答\n\n- `GET /api/agent/markdown/{file_hash}`:返回转换后的 Markdown。\n- `POST /api/agent/file_qa`:非流式单文件问答,请求体为 `{\"hash\":\"...\",\"question\":\"...\"}`。\n- `POST /api/agent/file_qa/stream`:SSE 流式单文件问答,请求体相同。\n\n文件长度不超过 `SMARTNAS_FILE_QA_DIRECT_CHARS` 时,模型接收全文;超过阈值时只召回该文件相关片段。后续问题会携带该文件最近三轮问答,大文件检索还会结合上一个问题处理“它、这个结论”等指代。\n\n`file_qa/stream` 的事件格式与普通流式聊天一致,`done` 事件额外带有 `mode`,值为 `full` 或 `rag`。\n\n### RAG 查询\n\n`POST /api/agent/rag/query`\n\n请求体:\n\n```json\n{\"query\":\"检索问题\",\"top_k\":6,\"file_hash\":\"可选文件 hash\",\"directory\":\"可选目录\"}\n```\n\n返回召回片段、文件名、hash、块序号、综合分数、召回来源和基于片段生成的回答。检索层会融合向量语义召回与本地 SQLite 关键词召回;关键词召回优先使用 FTS5,运行环境不支持 FTS5 时自动退回 `LIKE` 匹配。关键词索引用 `dirty` 状态驱动刷新:摘要索引和显式重建会刷新关键词库,临时补索引会标脏,查询只在索引缺失或标脏时补建。\n\n`GET /api/agent/index/status` 返回当前用户索引 manifest 汇总,包括已记录文件数、状态计数、每个文件的 chunk 数、模型名、更新时间,以及关键词索引的 `dirty`、`indexed_chunks` 和 FTS 可用状态。\n\n索引维护接口:\n\n- `GET /api/agent/index/missing`:扫描当前用户文件,返回支持索引但缺少有效 chunk 的文件。\n- `POST /api/agent/index/rebuild/start`:后台重建索引,请求体为 `{\"hash\":\"可选文件 hash\",\"force\":false,\"include_keyword\":true}`;不传 `hash` 时扫描全部支持文件。\n- `GET /api/agent/index/rebuild/status/{task_id}`:查询索引重建任务。\n- `GET /api/agent/index/rebuild/tasks`:列出当前用户最近索引任务。\n\n## 6. 文档处理与缓存\n\n- MarkItDown 用于 PDF、Office、文本、网页、EPUB、ZIP、Notebook 等格式转换;\n- 图片使用尺寸、EXIF、嵌入元数据和 SVG 文本生成 fallback Markdown;\n- 音视频在无法提取转录时使用媒体元数据;\n- Markdown 按文件 hash 缓存在 `var/cache/markdown`;\n- RAG 块、embedding、FAISS 索引、关键词 SQLite 索引和索引 manifest 缓存在 `var/cache/vector`;\n- 摘要成功后会同时写回 Core 摘要与标签,并更新该用户向量索引;\n- 查询前会对照 Core 当前文件列表,移除已删除文件的块并同步重命名后的文件名。\n\n## 7. 后台任务与审计\n\n摘要任务使用单工作线程执行,避免多个文档转换和本地 embedding 同时挤占内存。相同用户、相同文件的待处理任务会去重。任务状态包括:\n\n- `pending`\n- `running`\n- `cancel_requested`\n- `cancelled`\n- `success`\n- `failed`\n\n任务记录保存在 `var/cache/agent_tasks.db`。Agent 重启时,未完成任务会标记为失败,可通过重试接口重新排队。\n\n审计日志采用轮转 JSONL,记录用户、操作、状态、耗时、线程及结果或错误。默认路径为 `var/log/agent_audit.jsonl`,文件权限会尝试设置为 `0600`。\n\n## 8. 主要代码位置\n\n- Agent 服务与全部 API:`agent/service.py`\n- Agent 配置、请求模型、模型客户端和 SSE:`agent/`\n- 兼容启动入口:`scripts/agent_service.py`\n- Python 依赖:`scripts/requirements-agent.txt`\n- Web 调用与流式渲染:`web/index.html`\n- Core/Agent 边界:`docs/architecture.md`\n"}, "1e4f1b429b0bd6a1eb7914a29d1f5624e8219918": {"t": 1785758265.9726815, "n": 4908, "h": "5a74ae11dd426dc5", "c": "# SmartNAS Agent 功能说明\n\n## 1. 服务定位\n\nSmartNAS Agent 是独立运行的 Python/FastAPI 服务,默认监听 `8081`。它负责:\n\n- 调用 DeepSeek OpenAI-compatible API;\n- 普通对话与 SSE 流式对话;\n- 文件转 Markdown、摘要和标签生成;\n- 单文件全文问答和文件内 RAG 问答;\n- Markdown 分块、向量生成、FAISS 检索和索引持久化;\n- 摘要后台任务、取消、重试、去重与状态持久化;\n- Agent 操作审计。\n\nNAS Core 仍负责 JWT 鉴权、文件存储、下载、元数据和目录操作。Agent 不直接读取 Core 的 SQLite,而是携带用户 JWT 调用 Core HTTP API。\n\n## 2. 启动与依赖\n\n安装依赖:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r scripts/requirements-agent.txt\n```\n\n单独启动 Agent:\n\n```bash\nexport SMARTNAS_DEEPSEEK_API_KEY=sk-...\npython3 scripts/agent_service.py\n```\n\n也可以同时启动 Core 和 Agent:\n\n```bash\n./scripts/start_smartnas.sh\n```\n\nAgent 默认通过 `http://127.0.0.1:8080` 访问 Core。\n\n## 3. 配置项\n\n默认参数统一存放在 `config/config.json`。下列环境变量用于部署时覆盖对应 JSON 值,优先级为:环境变量 > JSON 配置 > 代码默认值。\n\n| 环境变量 | 默认值 | 用途 |\n| --- | --- | --- |\n| `SMARTNAS_CORE_API` | `http://127.0.0.1:8080` | Core API 地址 |\n| `SMARTNAS_DEEPSEEK_API_KEY` | 空 | DeepSeek API Key,也兼容 `DEEPSEEK_API_KEY` |\n| `SMARTNAS_DEEPSEEK_API_BASE` | `https://api.deepseek.com` | 模型 API 地址 |\n| `SMARTNAS_DEEPSEEK_MODEL` | `deepseek-chat` | 模型名称 |\n| `SMARTNAS_DEEPSEEK_TIMEOUT` | `60` | 模型请求超时秒数 |\n| `SMARTNAS_GENERATION_TEMPERATURE` | `0.7` | 生成温度 |\n| `SMARTNAS_GENERATION_TOP_P` | `0.8` | Top-P |\n| `SMARTNAS_MAX_MARKDOWN_CHARS` | `12000` | 单次摘要输入长度 |\n| `SMARTNAS_SUMMARY_CHUNK_CHARS` | `7000` | 长文摘要分块长度 |\n| `SMARTNAS_FILE_QA_DIRECT_CHARS` | `30000` | 全文问答与 RAG 问答切换阈值 |\n| `SMARTNAS_CACHE_DIR` | `var/cache/markdown` | Markdown 缓存目录 |\n| `SMARTNAS_VECTOR_DIR` | `var/cache/vector` | 向量数据和 FAISS 索引目录 |\n| `SMARTNAS_EMBEDDING_MODEL` | `BAAI/bge-small-zh-v1.5` | Embedding 模型 |\n| `SMARTNAS_RAG_CHUNK_CHARS` | `900` | RAG 文本块长度 |\n| `SMARTNAS_RAG_CHUNK_OVERLAP` | `120` | RAG 分块重叠长度 |\n| `SMARTNAS_RAG_TOP_K` | `6` | 默认召回数量 |\n| `SMARTNAS_RAG_MIN_SCORE` | `0.28` | 最低相似度 |\n| `SMARTNAS_TASK_DB` | `var/cache/agent_tasks.db` | 摘要任务数据库 |\n| `SMARTNAS_AUDIT_LOG` | `var/log/agent_audit.jsonl` | 审计日志路径 |\n| `SMARTNAS_AUDIT_LOG_MAX_BYTES` | `20971520` | 单个审计日志最大字节数 |\n| `SMARTNAS_AUDIT_LOG_BACKUPS` | `10` | 审计日志保留数量 |\n| `SMARTNAS_AUDIT_LOG_FULL_CONTENT` | `0` | 是否记录完整内容 |\n| `SMARTNAS_AGENT_HOST` | `127.0.0.1` | Agent 监听地址 |\n| `SMARTNAS_AGENT_PORT` | `8081` | Agent 监听端口 |\n| `SMARTNAS_SUMMARY_WORKER_COUNT` | `1` | 摘要后台 worker 数 |\n\n## 4. 鉴权与用户隔离\n\n除健康检查外,接口都使用 Core 签发的 JWT:\n\n```http\nAuthorization: Bearer <token>\n```\n\n- Agent 通过 `/api/v1/me` 向 Core 验证身份;\n- 普通聊天上下文按用户隔离;\n- 单文件问答上下文按“用户 + 文件 hash”隔离,并保留最近三轮问答;\n- 向量缓存按用户命名空间隔离;\n- 摘要任务只能由任务所属用户查看、取消或重试。\n\n聊天和单文件问答上下文目前保存在 Agent 内存中,服务重启后会清空。摘要任务与向量索引会持久化。\n\n## 5. HTTP API\n\n### 健康检查\n\n`GET /api/agent/health`\n\n返回模型配置、依赖状态、缓存路径、RAG 参数和支持格式。\n\n### 普通聊天\n\n- `POST /api/agent/chat`:非流式聊天,请求体为 `{\"prompt\":\"...\"}`。\n- `POST /api/agent/chat/stream`:SSE 流式聊天,请求体相同。\n- `POST /api/agent/clear_history`:清空当前用户普通聊天上下文。\n\n流式接口使用以下事件:\n\n```text\ndata: {\"type\":\"delta\",\"content\":\"增量文本\"}\n\ndata: {\"type\":\"done\"}\n\ndata: {\"type\":\"error\",\"message\":\"错误信息\"}\n```\n\n上游 SSE 使用小块读取,并关闭代理转换和缓冲。模型输出中的 Markdown 星号会在 Agent 输出层统一移除。\n\n### 文件摘要与标签\n\n- `POST /api/agent/summarize`:同步摘要,请求体为 `{\"hash\":\"...\",\"force\":false}`。\n- `POST /api/agent/summarize/start`:创建后台摘要任务。\n- `GET /api/agent/summarize/status/{task_id}`:查询任务。\n- `GET /api/agent/summarize/tasks`:列出当前用户任务。\n- `POST /api/agent/summarize/cancel/{task_id}`:取消任务。\n- `POST /api/agent/summarize/retry/{task_id}`:重试失败或取消的任务。\n- `POST /api/agent/summarize/missing`:为缺少摘要的支持文件批量排队,保留作管理 API,页面不再提供手动入口。\n\nWeb UI 在文件上传、恢复、重命名和移动成功后,会静默调用 `summarize/start`。任务在后台完成 Markdown 转换、摘要、标签和向量索引,不阻塞文件操作。\n\n### Markdown 与单文件问答\n\n- `GET /api/agent/markdown/{file_hash}`:返回转换后的 Markdown。\n- `POST /api/agent/file_qa`:非流式单文件问答,请求体为 `{\"hash\":\"...\",\"question\":\"...\"}`。\n- `POST /api/agent/file_qa/stream`:SSE 流式单文件问答,请求体相同。\n\n文件长度不超过 `SMARTNAS_FILE_QA_DIRECT_CHARS` 时,模型接收全文;超过阈值时只召回该文件相关片段。后续问题会携带该文件最近三轮问答,大文件检索还会结合上一个问题处理“它、这个结论”等指代。\n\n`file_qa/stream` 的事件格式与普通流式聊天一致,`done` 事件额外带有 `mode`,值为 `full` 或 `rag`。\n\n### RAG 查询\n\n`POST /api/agent/rag/query`\n\n请求体:\n\n```json\n{\"query\":\"检索问题\",\"top_k\":6}\n```\n\n返回相似片段、文件名、hash、块序号、相似度和基于片段生成的回答。\n\n## 6. 文档处理与缓存\n\n- MarkItDown 用于 PDF、Office、文本、网页、EPUB、ZIP、Notebook 等格式转换;\n- 图片使用尺寸、EXIF、嵌入元数据和 SVG 文本生成 fallback Markdown;\n- 音视频在无法提取转录时使用媒体元数据;\n- Markdown 按文件 hash 缓存在 `var/cache/markdown`;\n- RAG 块、embedding 和 FAISS 索引缓存在 `var/cache/vector`;\n- 摘要成功后会同时写回 Core 摘要与标签,并更新该用户向量索引;\n- 查询前会对照 Core 当前文件列表,移除已删除文件的块并同步重命名后的文件名。\n\n## 7. 后台任务与审计\n\n摘要任务使用单工作线程执行,避免多个文档转换和本地 embedding 同时挤占内存。相同用户、相同文件的待处理任务会去重。任务状态包括:\n\n- `pending`\n- `running`\n- `cancel_requested`\n- `cancelled`\n- `success`\n- `failed`\n\n任务记录保存在 `var/cache/agent_tasks.db`。Agent 重启时,未完成任务会标记为失败,可通过重试接口重新排队。\n\n审计日志采用轮转 JSONL,记录用户、操作、状态、耗时、线程及结果或错误。默认路径为 `var/log/agent_audit.jsonl`,文件权限会尝试设置为 `0600`。\n\n## 8. 主要代码位置\n\n- Agent 服务与全部 API:`agent/service.py`\n- Agent 配置、请求模型、模型客户端和 SSE:`agent/`\n- 兼容启动入口:`scripts/agent_service.py`\n- Python 依赖:`scripts/requirements-agent.txt`\n- Web 调用与流式渲染:`web/index.html`\n- Core/Agent 边界:`docs/agent-decoupling.md`\n"}, "6137c4f53c41ac9a4651ab2f87252ad1befd0e40": {"t": 1785758267.4050243, "n": 4906, "h": "57ee777c0a86d2aa", "c": "# SmartNAS Agent 功能说明\n\n## 1. 服务定位\n\nSmartNAS Agent 是独立运行的 Python/FastAPI 服务,默认监听 `8081`。它负责:\n\n- 调用 DeepSeek OpenAI-compatible API;\n- 普通对话与 SSE 流式对话;\n- 文件转 Markdown、摘要和标签生成;\n- 单文件全文问答和文件内 RAG 问答;\n- Markdown 分块、向量生成、FAISS 检索和索引持久化;\n- 摘要后台任务、取消、重试、去重与状态持久化;\n- Agent 操作审计。\n\nNAS Core 仍负责 JWT 鉴权、文件存储、下载、元数据和目录操作。Agent 不直接读取 Core 的 SQLite,而是携带用户 JWT 调用 Core HTTP API。\n\n## 2. 启动与依赖\n\n安装依赖:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r scripts/requirements-agent.txt\n```\n\n单独启动 Agent:\n\n```bash\nexport SMARTNAS_DEEPSEEK_API_KEY=sk-...\npython3 scripts/agent_service.py\n```\n\n也可以同时启动 Core 和 Agent:\n\n```bash\n./scripts/start_smartnas.sh\n```\n\nAgent 默认通过 `http://127.0.0.1:8080` 访问 Core。\n\n## 3. 配置项\n\n默认参数统一存放在 `config/config.json`。下列环境变量用于部署时覆盖对应 JSON 值,优先级为:环境变量 > JSON 配置 > 代码默认值。\n\n| 环境变量 | 默认值 | 用途 |\n| --- | --- | --- |\n| `SMARTNAS_CORE_API` | `http://127.0.0.1:8080` | Core API 地址 |\n| `SMARTNAS_DEEPSEEK_API_KEY` | 空 | DeepSeek API Key,也兼容 `DEEPSEEK_API_KEY` |\n| `SMARTNAS_DEEPSEEK_API_BASE` | `https://api.deepseek.com` | 模型 API 地址 |\n| `SMARTNAS_DEEPSEEK_MODEL` | `deepseek-chat` | 模型名称 |\n| `SMARTNAS_DEEPSEEK_TIMEOUT` | `60` | 模型请求超时秒数 |\n| `SMARTNAS_GENERATION_TEMPERATURE` | `0.7` | 生成温度 |\n| `SMARTNAS_GENERATION_TOP_P` | `0.8` | Top-P |\n| `SMARTNAS_MAX_MARKDOWN_CHARS` | `12000` | 单次摘要输入长度 |\n| `SMARTNAS_SUMMARY_CHUNK_CHARS` | `7000` | 长文摘要分块长度 |\n| `SMARTNAS_FILE_QA_DIRECT_CHARS` | `30000` | 全文问答与 RAG 问答切换阈值 |\n| `SMARTNAS_CACHE_DIR` | `var/cache/markdown` | Markdown 缓存目录 |\n| `SMARTNAS_VECTOR_DIR` | `var/cache/vector` | 向量数据和 FAISS 索引目录 |\n| `SMARTNAS_EMBEDDING_MODEL` | `BAAI/bge-small-zh-v1.5` | Embedding 模型 |\n| `SMARTNAS_RAG_CHUNK_CHARS` | `900` | RAG 文本块长度 |\n| `SMARTNAS_RAG_CHUNK_OVERLAP` | `120` | RAG 分块重叠长度 |\n| `SMARTNAS_RAG_TOP_K` | `6` | 默认召回数量 |\n| `SMARTNAS_RAG_MIN_SCORE` | `0.28` | 最低相似度 |\n| `SMARTNAS_TASK_DB` | `var/cache/agent_tasks.db` | 摘要任务数据库 |\n| `SMARTNAS_AUDIT_LOG` | `var/log/agent_audit.jsonl` | 审计日志路径 |\n| `SMARTNAS_AUDIT_LOG_MAX_BYTES` | `20971520` | 单个审计日志最大字节数 |\n| `SMARTNAS_AUDIT_LOG_BACKUPS` | `10` | 审计日志保留数量 |\n| `SMARTNAS_AUDIT_LOG_FULL_CONTENT` | `1` | 是否记录完整内容 |\n| `SMARTNAS_AGENT_HOST` | `0.0.0.0` | Agent 监听地址 |\n| `SMARTNAS_AGENT_PORT` | `8081` | Agent 监听端口 |\n| `SMARTNAS_SUMMARY_WORKER_COUNT` | `1` | 摘要后台 worker 数 |\n\n## 4. 鉴权与用户隔离\n\n除健康检查外,接口都使用 Core 签发的 JWT:\n\n```http\nAuthorization: Bearer <token>\n```\n\n- Agent 通过 `/api/v1/me` 向 Core 验证身份;\n- 普通聊天上下文按用户隔离;\n- 单文件问答上下文按“用户 + 文件 hash”隔离,并保留最近三轮问答;\n- 向量缓存按用户命名空间隔离;\n- 摘要任务只能由任务所属用户查看、取消或重试。\n\n聊天和单文件问答上下文目前保存在 Agent 内存中,服务重启后会清空。摘要任务与向量索引会持久化。\n\n## 5. HTTP API\n\n### 健康检查\n\n`GET /api/agent/health`\n\n返回模型配置、依赖状态、缓存路径、RAG 参数和支持格式。\n\n### 普通聊天\n\n- `POST /api/agent/chat`:非流式聊天,请求体为 `{\"prompt\":\"...\"}`。\n- `POST /api/agent/chat/stream`:SSE 流式聊天,请求体相同。\n- `POST /api/agent/clear_history`:清空当前用户普通聊天上下文。\n\n流式接口使用以下事件:\n\n```text\ndata: {\"type\":\"delta\",\"content\":\"增量文本\"}\n\ndata: {\"type\":\"done\"}\n\ndata: {\"type\":\"error\",\"message\":\"错误信息\"}\n```\n\n上游 SSE 使用小块读取,并关闭代理转换和缓冲。模型输出中的 Markdown 星号会在 Agent 输出层统一移除。\n\n### 文件摘要与标签\n\n- `POST /api/agent/summarize`:同步摘要,请求体为 `{\"hash\":\"...\",\"force\":false}`。\n- `POST /api/agent/summarize/start`:创建后台摘要任务。\n- `GET /api/agent/summarize/status/{task_id}`:查询任务。\n- `GET /api/agent/summarize/tasks`:列出当前用户任务。\n- `POST /api/agent/summarize/cancel/{task_id}`:取消任务。\n- `POST /api/agent/summarize/retry/{task_id}`:重试失败或取消的任务。\n- `POST /api/agent/summarize/missing`:为缺少摘要的支持文件批量排队,保留作管理 API,页面不再提供手动入口。\n\nWeb UI 在文件上传、恢复、重命名和移动成功后,会静默调用 `summarize/start`。任务在后台完成 Markdown 转换、摘要、标签和向量索引,不阻塞文件操作。\n\n### Markdown 与单文件问答\n\n- `GET /api/agent/markdown/{file_hash}`:返回转换后的 Markdown。\n- `POST /api/agent/file_qa`:非流式单文件问答,请求体为 `{\"hash\":\"...\",\"question\":\"...\"}`。\n- `POST /api/agent/file_qa/stream`:SSE 流式单文件问答,请求体相同。\n\n文件长度不超过 `SMARTNAS_FILE_QA_DIRECT_CHARS` 时,模型接收全文;超过阈值时只召回该文件相关片段。后续问题会携带该文件最近三轮问答,大文件检索还会结合上一个问题处理“它、这个结论”等指代。\n\n`file_qa/stream` 的事件格式与普通流式聊天一致,`done` 事件额外带有 `mode`,值为 `full` 或 `rag`。\n\n### RAG 查询\n\n`POST /api/agent/rag/query`\n\n请求体:\n\n```json\n{\"query\":\"检索问题\",\"top_k\":6}\n```\n\n返回相似片段、文件名、hash、块序号、相似度和基于片段生成的回答。\n\n## 6. 文档处理与缓存\n\n- MarkItDown 用于 PDF、Office、文本、网页、EPUB、ZIP、Notebook 等格式转换;\n- 图片使用尺寸、EXIF、嵌入元数据和 SVG 文本生成 fallback Markdown;\n- 音视频在无法提取转录时使用媒体元数据;\n- Markdown 按文件 hash 缓存在 `var/cache/markdown`;\n- RAG 块、embedding 和 FAISS 索引缓存在 `var/cache/vector`;\n- 摘要成功后会同时写回 Core 摘要与标签,并更新该用户向量索引;\n- 查询前会对照 Core 当前文件列表,移除已删除文件的块并同步重命名后的文件名。\n\n## 7. 后台任务与审计\n\n摘要任务使用单工作线程执行,避免多个文档转换和本地 embedding 同时挤占内存。相同用户、相同文件的待处理任务会去重。任务状态包括:\n\n- `pending`\n- `running`\n- `cancel_requested`\n- `cancelled`\n- `success`\n- `failed`\n\n任务记录保存在 `var/cache/agent_tasks.db`。Agent 重启时,未完成任务会标记为失败,可通过重试接口重新排队。\n\n审计日志采用轮转 JSONL,记录用户、操作、状态、耗时、线程及结果或错误。默认路径为 `var/log/agent_audit.jsonl`,文件权限会尝试设置为 `0600`。\n\n## 8. 主要代码位置\n\n- Agent 服务与全部 API:`agent/service.py`\n- Agent 配置、请求模型、模型客户端和 SSE:`agent/`\n- 兼容启动入口:`scripts/agent_service.py`\n- Python 依赖:`scripts/requirements-agent.txt`\n- Web 调用与流式渲染:`web/index.html`\n- Core/Agent 边界:`docs/agent-decoupling.md`\n"}}}}