Files
PoemClassify/README.md
2026-03-23 22:31:48 +08:00

385 lines
12 KiB
Markdown
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.
# 古诗词阅读网站
基于大模型分类的中国古诗词阅读管理系统
## 系统架构
```
┌─────────────────────────────────────────────────────────┐
│ 古诗词阅读网站 │
├─────────────────────────────────────────────────────────┤
│ Frontend (原生 JS + CSS) │ Backend (FastAPI + SQLite)│
│ - 多类别组合筛选 │ - RESTful API │
│ - 阅读标记管理 │ - SQLite 数据库 │
│ - 标签云浏览 │ - 分类查询 │
│ - 进度统计 │ - 批量导入 │
├─────────────────────────────────────────────────────────┤
│ classify_pois.py (LLM 分类脚本) │
│ - 20 维分类标签体系 │
│ - 繁体转简体支持 │
│ - 实时去重 + 持久化 │
└─────────────────────────────────────────────────────────┘
```
## 核心功能
### 1. 20 维分类标签体系
| 维度分类 | 标签数量 | 示例 |
|---------|---------|------|
| **季节时序** | 39 | 春、夏、秋、冬、24 节气、时辰 |
| **题材类型** | 17 | 山水田园、边塞征战、咏史怀古等 |
| **情感心境** | 31 | 情感基调 11 种 + 具体情感 20 种 |
| **景物意象** | 77 | 自然、植物、动物、建筑、色彩、声音 |
| **哲理思想** | 7 | 儒家、道家、佛家、人生感悟等 |
| **艺术手法** | 18 | 写作手法、修辞手法 |
| **人物社会** | 33 | 人生阶段、社会身份、地理方位、节日 |
### 2. 繁体转简体支持
- ✅ 自动识别繁体中文诗词
- ✅ LLM 自动转换为简体中文
- ✅ 保留原始繁体版本(可选)
- ✅ 基于简体内容去重(繁简同一首诗不会重复)
- ✅ 所有分类标签统一使用简体
**输入示例(繁体):**
```json
{
"title": "山居秋暝",
"author": "王維",
"paragraphs": ["空山新雨後,天氣晚來秋。", "明月鬆間照,清泉石上流。"]
}
```
**输出示例(简体):**
```json
{
"title": "山居秋暝",
"author": "王维",
"paragraphs": ["空山新雨后,天气晚来秋。", "明月松间照,清泉石上流。"],
"original_paragraphs": ["空山新雨後,天氣晚來秋。", "明月鬆間照,清泉石上流。"],
"llm_classification": {
"season": ["秋"],
"genre": ["山水田园", "隐逸闲适"],
...
}
}
```
### 3. 多类别组合筛选
支持同时选择多个分类标签进行组合筛选:
- 题材=山水田园 AND 情感=宁静淡泊
- 季节=春 AND 地点=江南 AND 情感=喜悦
- 使用 SQL 查询优化,支持复杂筛选条件
### 4. 阅读管理
- 标记诗词为已读/未读
- 阅读进度统计(百分比 + 数量)
- 阅读时间记录
- 快速切换阅读状态
### 5. 批量导入
- 支持 JSON/JSONL 格式
- 自动去重(基于内容签名 MD5
- 实时写入数据库
- 导入结果反馈
## 快速开始
### 1. 安装依赖
```bash
pip install -r requirements.txt
```
### 2. 使用 LLM 脚本分类诗词
```bash
# 本地模型 (Ollama 等)
python classify_pois.py ./poems ./output.jsonl --llm \
--base-url http://localhost:11434/v1 \
--model qwen:7b
# 远程模型 (OpenAI 等)
python classify_pois.py ./poems ./output.jsonl --llm \
--base-url https://api.openai.com/v1 \
--model gpt-4 \
--api-key sk-xxx
# 繁体诗词测试
python classify_pois.py ./ ./output.jsonl --llm \
--base-url http://localhost:11434/v1 \
--model qwen:7b
```
### 3. 启动后端服务
```bash
cd backend
python main.py
```
服务启动后访问http://localhost:8000
### 4. 前端页面
浏览器打开http://localhost:8000
### 5. 上传诗词
通过前端界面的上传功能,上传分类后的 JSONL 文件到数据库。
## API 端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/` | 前端页面 |
| GET | `/api/categories` | 获取分类体系 |
| GET | `/api/stats` | 获取统计数据 |
| POST | `/api/poems/import` | 批量导入诗词 |
| GET | `/api/poems` | 获取诗词列表(支持分页、筛选) |
| GET | `/api/poems/{id}` | 获取诗词详情 |
| PUT | `/api/poems/{id}/read` | 切换阅读状态 |
| GET | `/api/poems/random` | 随机一首 |
| GET | `/api/tags/cloud` | 标签云数据 |
### API 使用示例
```bash
# 获取诗词列表(带多类别筛选)
GET /api/poems?page=1&page_size=20&categories=genre:山水田园,emotion_tone:宁静淡泊
# 搜索诗词
GET /api/poems?search=李白
# 获取已读诗词
GET /api/poems?is_read=true
# 获取未读诗词
GET /api/poems?is_read=false
# 标记为已读
PUT /api/poems/{id}/read?is_read=true
# 标记为未读
PUT /api/poems/{id}/read?is_read=false
```
## 数据格式
### 输入格式JSON/JSONL
```json
{
"id": "poem_001",
"title": "山居秋暝",
"author": "王维",
"paragraphs": [
"空山新雨后,天气晚来秋。",
"明月松间照,清泉石上流。",
"竹喧归浣女,莲动下渔舟。",
"随意春芳歇,王孙自可留。"
],
"llm_classification": {
"season": ["秋"],
"solar_terms": ["白露"],
"time_of_day": "黄昏",
"genre": ["山水田园", "隐逸闲适"],
"emotion_tone": "宁静淡泊",
"emotions": ["静", "喜", "乐"],
"nature_scenery": ["山", "水", "月"],
"plants": ["松", "竹"],
"animals": ["鸟"],
"buildings": [],
"imagery": ["空山", "新雨", "明月"],
"philosophy": ["道家思想", "自然之道"],
"life_stage": "中年",
"social_role": "隐士",
"technique": ["借景抒情", "动静结合"],
"rhetoric": ["拟人"],
"colors": ["青", "白"],
"sounds": [],
"location": "终南山",
"festival": "无",
"analysis": "这首诗描绘了秋日山居的幽静景色..."
}
}
```
### 输出格式API 响应)
```json
{
"id": "poem_001",
"title": "山居秋暝",
"author": "王维",
"paragraphs": ["空山新雨后,天气晚来秋。", ...],
"original_paragraphs": null,
"classifications": {
"season": ["秋"],
"genre": ["山水田园", "隐逸闲适"],
...
},
"is_read": false,
"read_at": null,
"created_at": "2024-01-01T00:00:00"
}
```
## 数据库结构
### poems 表
```sql
CREATE TABLE poems (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
author TEXT NOT NULL,
paragraphs TEXT,
signature TEXT UNIQUE,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
```
### classifications 表
```sql
CREATE TABLE classifications (
id INTEGER PRIMARY KEY,
poem_id TEXT,
category TEXT,
tags TEXT,
FOREIGN KEY (poem_id) REFERENCES poems(id)
);
```
### reading_records 表
```sql
CREATE TABLE reading_records (
id INTEGER PRIMARY KEY,
poem_id TEXT UNIQUE,
is_read BOOLEAN,
read_at TIMESTAMP,
FOREIGN KEY (poem_id) REFERENCES poems(id)
);
```
## 完整分类标签体系
| 维度 | 键名 | 标签数量 | 标签示例 |
|------|------|---------|---------|
| 季节 | season | 6 | 春、夏、秋、冬、四季 |
| 节气 | solar_terms | 24 | 立春、雨水、清明、谷雨 |
| 时辰 | time_of_day | 9 | 清晨、黄昏、夜晚、黎明 |
| 题材 | genre | 17 | 山水田园、边塞征战、咏史怀古 |
| 情感基调 | emotion_tone | 11 | 宁静淡泊、喜悦欢快、悲伤哀愁 |
| 具体情感 | emotions | 20 | 喜、怒、哀、乐、忧、思 |
| 自然景物 | nature_scenery | 14 | 山、水、云、雨、日、月 |
| 植物 | plants | 15 | 松、竹、梅、兰、菊、荷 |
| 动物 | animals | 14 | 鸟、雁、燕、蝉、蛙、鱼 |
| 建筑 | buildings | 15 | 楼、阁、亭、台、桥、寺 |
| 哲理 | philosophy | 7 | 儒家思想、道家思想、佛家禅理 |
| 人生阶段 | life_stage | 5 | 少年、青年、中年、老年 |
| 社会身份 | social_role | 10 | 士人、官员、隐士、游子 |
| 写作手法 | technique | 9 | 比兴、借景抒情、托物言志 |
| 修辞手法 | rhetoric | 9 | 比喻、拟人、夸张、对偶 |
| 色彩 | colors | 10 | 青、绿、红、白、黄、紫 |
| 声音 | sounds | 9 | 钟声、琴声、鸟鸣、雨声 |
| 地理 | location | 9 | 江南、塞北、巴蜀、关中 |
| 节日 | festival | 9 | 春节、中秋、重阳、端午 |
## 技术栈
- **后端**: FastAPI + SQLite + Uvicorn
- **前端**: 原生 JavaScript + CSS (无框架依赖)
- **分类**: 基于 LLM API (支持本地/远程模型)
- **简繁转换**: LLM 自动识别和转换
## 扩展开发
### 添加新的分类维度
1.`backend/main.py``CATEGORY_SYSTEM` 中添加新维度
2.`classify_pois.py``CLASSIFICATION_PROMPT` 中添加对应提示
3. 在前端 CSS 中添加对应标签样式
### 部署建议
```bash
# 生产环境使用
uvicorn backend.main:app --host 0.0.0.0 --port 8000 --workers 4
# 或使用 gunicorn
gunicorn backend.main:app -w 4 -k uvicorn.workers.UvicornWorker
```
### 简繁切换显示(可选)
在前端添加简繁切换功能:
```javascript
let showTraditional = false;
function toggleTraditional() {
showTraditional = !showTraditional;
const poem = state.currentPoem;
const content = showTraditional && poem.original_paragraphs
? poem.original_paragraphs
: poem.paragraphs;
// 重新渲染内容
}
```
## 常见问题
**Q: 导入时提示重复?**
A: 系统基于诗词内容签名MD5去重相同内容的诗词只会保留一份。繁体和简体版本会被识别为同一首诗。
**Q: 如何重置阅读进度?**
A: 直接修改数据库中 `reading_records` 表的 `is_read` 字段,或在前端重新标记。
**Q: 支持哪些 LLM 模型?**
A: 任何支持 OpenAI 兼容 API 的模型,包括 Ollama、vLLM、OpenAI GPT、Anthropic Claude 等。
**Q: 繁体诗词如何处理?**
A: 分类脚本会自动识别繁体中文LLM 会返回简体版本。原始繁体会保存在 `original_paragraphs` 字段中。
**Q: JSONL 文件和 SQLite 数据库的关系?**
A: JSONL 是分类脚本的输出格式中间产物SQLite 是网站运行的数据库(最终存储)。通过 API 导入功能将 JSONL 导入数据库。
## 项目结构
```
PoemClassify/
├── classify_pois.py # LLM 分类脚本
├── requirements.txt # Python 依赖
├── backend/
│ ├── main.py # FastAPI 后端
│ └── poems.db # SQLite 数据库(运行时生成)
├── frontend/
│ ├── index.html # 前端页面
│ ├── script.js # 前端逻辑
│ └── style.css # 样式文件
├── test_traditional.json # 繁体测试文件
└── README.md # 本文档
```
## 数据备份
```bash
# 备份 SQLite 数据库
cp backend/poems.db backup_$(date +%Y%m%d).db
# 导出数据库为 JSONL
sqlite3 backend/poems.db "SELECT json_object('id',id,'title',title,'author',author,'paragraphs',paragraphs) FROM poems;" > export.jsonl
# 从 JSONL 恢复
curl -X POST http://localhost:8000/api/poems/import -F "file=@export.jsonl"
```
## License
MIT License