|
@@ -0,0 +1,185 @@
|
|
|
|
|
+# 题库PLUS 服务端
|
|
|
|
|
+
|
|
|
|
|
+C/S 架构数学题库管理系统 — 服务端。Python + FastAPI + SQLite,以 docx 原生格式存储题目。
|
|
|
|
|
+
|
|
|
|
|
+## 快速部署
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+git clone ssh://git@xn--48s96u.top:10022/nonvioce/tiku.git /opt/tiku-server
|
|
|
|
|
+cd /opt/tiku-server/tiku-server
|
|
|
|
|
+bash install.sh # 安装依赖、构建知识点
|
|
|
|
|
+nohup bash run.sh > tiku.log 2>&1 & # 后台启动(崩溃/更新自动重启)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+部署后打开 `http://<服务器IP>:8765`,使用 `./tiku-server token` 查看 API Token。
|
|
|
|
|
+
|
|
|
|
|
+## 目录结构
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+tiku-server/
|
|
|
|
|
+├── app/
|
|
|
|
|
+│ ├── config.py # YAML 配置加载(路径、端口、Token)
|
|
|
|
|
+│ ├── database.py # SQLite 连接、建表、CRUD、FTS5
|
|
|
|
|
+│ ├── models.py # Pydantic 请求/响应模型
|
|
|
|
|
+│ ├── main.py # FastAPI 入口 + CLI 入口
|
|
|
|
|
+│ ├── routers/ # API 路由层(仅参数校验和 HTTP 返回)
|
|
|
|
|
+│ │ ├── auth.py # Token + HMAC 签名认证
|
|
|
|
|
+│ │ ├── problems.py # 题目 CRUD、搜索、渲染、标注
|
|
|
|
|
+│ │ ├── import_.py # 整卷 docx 上传拆分导入
|
|
|
|
|
+│ │ ├── export_.py # 按章节/试题篮导出 docx
|
|
|
|
|
+│ │ ├── knowledge.py # 知识点树浏览和搜索
|
|
|
|
|
+│ │ ├── carts.py # 试题篮 CRUD
|
|
|
|
|
+│ │ └── admin.py # 备份、索引重建、知识点构建、Git 更新
|
|
|
|
|
+│ └── services/ # 业务逻辑层
|
|
|
|
|
+│ ├── knowledge.py # 5层知识点树解析(Markdown → 编码映射)
|
|
|
|
|
+│ ├── docx_parser.py # 整卷 docx 拆分 + 单题 docx 生成
|
|
|
|
|
+│ ├── docx_builder.py # 多题 docx 合并导出
|
|
|
|
|
+│ ├── indexer.py # 增量索引(mtime+checksum 检测变更)
|
|
|
|
|
+│ ├── renderer.py # pandoc docx→HTML+MathJax 渲染管线
|
|
|
|
|
+│ ├── backup.py # 本地备份 + WebDAV 远程推送
|
|
|
|
|
+│ └── search.py # FTS5 全文搜索封装
|
|
|
|
|
+├── data/ # 运行时数据(不提交 Git)
|
|
|
|
|
+│ ├── problems/ # 单题 docx(<sha256-8>.docx)
|
|
|
|
|
+│ ├── bank.db # SQLite 数据库
|
|
|
|
|
+│ ├── papers/ # 导出试卷
|
|
|
|
|
+│ ├── backups/ # 自动备份(保留 30 个)
|
|
|
|
|
+│ └── uploads/ # 上传临时文件
|
|
|
|
|
+├── src/
|
|
|
|
|
+│ ├── 知识点树.md # 5层 Markdown 知识树(1811 叶)
|
|
|
|
|
+│ └── knowledge_map.json # 编码→路径映射(knowledge build 生成)
|
|
|
|
|
+├── web/ # Flutter Web 构建产物(可选)
|
|
|
|
|
+├── config.yaml # 配置文件
|
|
|
|
|
+├── install.sh # 安装脚本
|
|
|
|
|
+├── run.sh # 启动+自动重启脚本
|
|
|
|
|
+├── tiku-server # CLI 入口
|
|
|
|
|
+└── requirements.txt # Python 依赖
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## CLI 命令
|
|
|
|
|
+
|
|
|
|
|
+| 命令 | 说明 |
|
|
|
|
|
+|------|------|
|
|
|
|
|
+| `./tiku-server serve` | 启动 FastAPI 服务 |
|
|
|
|
|
+| `./tiku-server knowledge build` | 解析 `src/知识点树.md` 生成编码映射 |
|
|
|
|
|
+| `./tiku-server rebuild-index` | 手动增量扫描 problems/ 目录 |
|
|
|
|
|
+| `./tiku-server stats` | 终端显示题库统计 |
|
|
|
|
|
+| `./tiku-server backup` | 创建本地备份快照 |
|
|
|
|
|
+| `./tiku-server backup --remote` | 备份并推送到 WebDAV |
|
|
|
|
|
+| `./tiku-server token` | 显示 API Token |
|
|
|
|
|
+| `./tiku-server token regenerate` | 重新生成 Token |
|
|
|
|
|
+
|
|
|
|
|
+## API 参考
|
|
|
|
|
+
|
|
|
|
|
+### 认证
|
|
|
|
|
+
|
|
|
|
|
+所有需要认证的端点必须携带:
|
|
|
|
|
+- `Authorization: Bearer <token>`
|
|
|
|
|
+- `X-Timestamp: <unix_timestamp>`(5 分钟内有效)
|
|
|
|
|
+- `X-Signature: HMAC-SHA256(token, METHOD+PATH+timestamp)`(hex 编码)
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 认证 | 说明 |
|
|
|
|
|
+|------|------|------|------|
|
|
|
|
|
+| GET | `/api/health` | 否 | 健康检查 |
|
|
|
|
|
+| POST | `/api/auth/verify` | 否 | 验证 Token |
|
|
|
|
|
+
|
|
|
|
|
+### 题库查询
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 参数 | 说明 |
|
|
|
|
|
+|------|------|------|------|
|
|
|
|
|
+| GET | `/api/stats` | — | 仪表盘统计(总数、按题型/类型/章节分布) |
|
|
|
|
|
+| GET | `/api/problems` | `page`, `page_size`, `chapter`, `question_type`, `import_type`, `annotated` | 题目列表(分页+筛选) |
|
|
|
|
|
+| GET | `/api/problems/{id}` | — | 题目详情(含渲染 HTML) |
|
|
|
|
|
+| GET | `/api/problems/{id}/render` | `include_answer` | 题目 HTML 渲染片段(JSON) |
|
|
|
|
|
+| GET | `/api/problems/{id}/view` | `token`, `include_answer` | 题目完整 HTML 页面(IFrame 用,Token 在 URL 中) |
|
|
|
|
|
+| GET | `/api/problems/next-unannotated` | `current_id`, `direction` | 连续标注导航 |
|
|
|
|
|
+| GET | `/api/search` | `q`, `page`, `page_size` | 全文搜索(FTS5 trigram) |
|
|
|
|
|
+
|
|
|
|
|
+### 元数据编辑
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| PUT | `/api/problems/{id}/metadata` | 更新元数据(难度、题型、类型、评语) |
|
|
|
|
|
+| PUT | `/api/problems/{id}/knowledge` | 更新知识点编码 |
|
|
|
|
|
+
|
|
|
|
|
+### 导入导出
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| POST | `/api/import` | 上传整卷 docx(multipart: `file` + `import_type`) |
|
|
|
|
|
+| GET | `/api/import/{task_id}/status` | 轮询导入进度 |
|
|
|
|
|
+| POST | `/api/export/chapter` | 按章节+类型导出(JSON body: `chapter`, `import_type`, `title`) |
|
|
|
|
|
+| POST | `/api/export/cart/{id}` | 按试题篮导出 |
|
|
|
|
|
+| GET | `/api/exports/{filename}` | 下载导出 docx 文件 |
|
|
|
|
|
+
|
|
|
|
|
+### 知识点
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| GET | `/api/knowledge/tree` | 完整知识树(5层嵌套 JSON) |
|
|
|
|
|
+| GET | `/api/knowledge/search` | 搜索知识点(`q` 参数) |
|
|
|
|
|
+
|
|
|
|
|
+### 试题篮
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| GET | `/api/carts` | 篮子列表(含题目数量) |
|
|
|
|
|
+| POST | `/api/carts` | 创建篮子(JSON: `name`) |
|
|
|
|
|
+| DELETE | `/api/carts/{id}` | 删除篮子 |
|
|
|
|
|
+| GET | `/api/carts/{id}` | 篮子详情(含题目列表) |
|
|
|
|
|
+| POST | `/api/carts/{id}/items` | 添加题目(JSON: `problem_id`) |
|
|
|
|
|
+| DELETE | `/api/carts/{id}/items/{pid}` | 移除题目 |
|
|
|
|
|
+
|
|
|
|
|
+### 管理
|
|
|
|
|
+
|
|
|
|
|
+| 方法 | 路径 | 说明 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| GET | `/api/admin/backup-config` | 查看 WebDAV 配置 |
|
|
|
|
|
+| PUT | `/api/admin/backup-config` | 设置 WebDAV(JSON: `url`, `username`, `password`) |
|
|
|
|
|
+| POST | `/api/admin/backup/trigger` | 手动触发备份 |
|
|
|
|
|
+| GET | `/api/admin/backup/history` | 备份历史 |
|
|
|
|
|
+| POST | `/api/admin/rebuild-index` | 增量重建索引 |
|
|
|
|
|
+| POST | `/api/admin/knowledge-build` | 重建知识点编码 |
|
|
|
|
|
+| POST | `/api/admin/git-update` | `git pull` + 自动重启 |
|
|
|
|
|
+
|
|
|
|
|
+## 单题 docx 格式
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+[题目正文段落(含 OMML 公式、图片、选项)]
|
|
|
|
|
+【答案】X ← 分割线
|
|
|
|
|
+【分析】解题思路... (可选)
|
|
|
|
|
+【详解】详细步骤... (可选)
|
|
|
|
|
+【点睛】... (可选)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+自定义属性(`custom.xml`,Word 不可见):
|
|
|
|
|
+- `question_type`:单选题 / 多选题 / 填空题 / 解答题
|
|
|
|
|
+- `difficulty`:0~1 浮点数,越大越容易
|
|
|
|
|
+- `knowledge_codes`:JSON 数组,如 `["01.01.03.02.01"]`
|
|
|
|
|
+- `import_type`:精选题 / 经典题 / 高考题
|
|
|
|
|
+- `comment`:评语
|
|
|
|
|
+- `source`:来源文件名
|
|
|
|
|
+
|
|
|
|
|
+## 数据库结构
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+problems (id, file_path, mtime, checksum, chapters, difficulty,
|
|
|
|
|
+ question_type, import_type, knowledge_codes, comment, source, ...)
|
|
|
|
|
+
|
|
|
|
|
+problems_fts (problem_id, body) — FTS5 trigram 全文索引
|
|
|
|
|
+
|
|
|
|
|
+knowledge_points (code, path, leaf_name, chapter_code, chapter_name)
|
|
|
|
|
+
|
|
|
|
|
+carts (id, name, created_at)
|
|
|
|
|
+
|
|
|
|
|
+cart_items (cart_id, problem_id, added_at) — 联合主键
|
|
|
|
|
+
|
|
|
|
|
+import_tasks (id, status, total, completed, message, result)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 域名转换
|
|
|
|
|
+
|
|
|
|
|
+中文域名 `数学.top` 的 punycode 编码为 `xn--48s96u.top`,在 Git remote 等处使用:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+ssh://git@xn--48s96u.top:10022/nonvioce/tiku.git
|
|
|
|
|
+```
|