Files
joke/CLAUDE.md
T

175 lines
7.9 KiB
Markdown
Raw 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.
# CLAUDE.md
本文件为 Claude Code (claude.ai/code) 在此仓库中工作时提供指导。
## 启动命令
### API 后端 (port 8001)
```bash
cd api && python -m uvicorn main:app --reload --port 8001
```
### Web 前台 (port 3000)
```bash
cd web && npm run dev # 开发模式
cd web && npm run build # 生产构建
```
### Admin 后台管理 (port 3001)
```bash
cd admin && npm run dev # 开发模式
cd admin && npm run build # 生产构建
```
### 数据库初始化
```bash
cd api && python init_db.py
```
### 爬虫 (AI 自动采集)
```bash
cd crawler && python main.py # 持续采集(无头浏览器)
cd crawler && python main.py --no-headless # 显示浏览器窗口(调试用)
```
### 站点发现(独立工具)
```bash
python crawler/site_finder.py # 搜索笑话站点,保存到 joke_sites.json
python crawler/site_crawler.py --site https://... # 采集指定站点
python crawler/site_crawler.py --file joke_sites.json # 批量采集已发现站点
```
### 笑话优化(质量检测 / AI 润色 / 评价分类)
```bash
python optimizer/main.py # 处理所有笑话
python optimizer/main.py --limit 10 # 只处理前 10 条(调试用)
python optimizer/main.py --status rejected # 只处理已拒绝的
python optimizer/main.py --id 1,2,3 # 指定 ID 处理
```
### 启动顺序
1. API 后端 (port 8001) — 自动建表,必须先启动
2. Web 前台 (port 3000) — 依赖 API
3. Admin 后台 (port 3001) — 依赖 API
4. 爬虫 / 优化器 (可选) — 连接 API 的 8001 端口
## 开发备注
- **无测试**:本项目当前没有自动化测试
- **数据库迁移**:新增字段需手动 `ALTER TABLE` 或重建,不支持自动迁移
- **JWT Secret**:开发环境使用默认值,生产环境需设置 `JWT_SECRET_KEY` 环境变量
## 项目架构
### 目录结构
```
joke/
├── api/ # FastAPI 后端 (Python, port 8001)
│ └── app/
│ ├── models/ # SQLAlchemy 模型(自动建表)
│ ├── routers/ # API 路由
│ └── schemas/ # Pydantic 数据模型
├── web/ # Vue3 前台 (port 3000)
│ └── src/
│ ├── components/ # 通用组件(三栏布局)
│ ├── views/ # 页面(首页/分类/详情/搜索)
│ ├── stores/ # Piniajoke/category/theme
│ └── api/ # Axios 封装
├── admin/ # Vue3 管理后台 (port 3001)
│ └── src/
│ ├── layout/ # 后台布局(侧边栏+顶部导航)
│ ├── views/ # 页面(登录/仪表盘/笑话管理/分类管理/设置)
│ ├── stores/ # Piniaauth/joke
│ └── api/ # Axios 封装
├── crawler/ # AI 爬虫(crawl4ai + NVIDIA NIM
│ ├── main.py # 持续采集主入口
│ ├── processor.py # 流程编排(搜索→深度翻页→AI提取→入库)
│ ├── crawler_service.py # 页面抓取(Bing搜索 + crawl4ai
│ ├── ai_service.py # NVIDIA NIM APIOpenAI 兼容)调用
│ ├── prompts.py # AI 提示词模板
│ ├── site_finder.py # 站点发现工具(搜索 Bing 找笑话站)
│ └── site_crawler.py # 单站点批量采集工具
├── optimizer/ # 笑话优化工具(质量检测→润色→评价分类)
│ ├── main.py # CLI 入口
│ ├── optimizer.py # 三阶段处理管道
│ └── prompts.py # AI 提示词模板
└── docs/ # 文档
```
### 关键约定
- **API 代理**web 和 admin 的 Vite 配置都将 `/api` 代理到 `http://localhost:8001`,不重写路径
- **JWT 认证**:登录接口 `/api/auth/login`token 存 localStorage,请求头 `Authorization: Bearer <token>`
- **笑话审核流**`pending`(待审核)→ `approved`(已通过)。公开 API 只返回 `approved` 的笑话
- **双主题系统**:CSS 变量通过 `:root[data-theme="light"]` / `:root[data-theme="dark"]` 控制,使用 `data-theme` 属性切换
- **数据库**SQLite (`api/joke.db`)SQLAlchemy ORMAPI 启动时自动建表(`Base.metadata.create_all`),但**不自动修改已有表结构**——新增字段需手动 `ALTER TABLE` 或重建
- **爬虫**:使用 crawl4ai 的 `AsyncWebCrawler`(统一 headless/visible 模式),crawl4ai 不可用时回退到 requests
- **AI 服务**:使用 NVIDIA NIM API(兼容 OpenAI),配置通过后台设置页面管理,存储在 `AiSetting`
### 数据模型
| 表名 | 说明 | 关键字段 |
|------|------|----------|
| `jokes` | 笑话 | title, content, polished_content, type_id, crowd_id, status, view_count, like_count |
| `joke_types` | 类型 | name, icon, sort_order |
| `joke_crowds` | 人群 | name, icon, sort_order |
| `admin_users` | 管理员 | username, password_hashbcrypt |
| `ai_settings` | AI 配置 | api_base, api_key, model_name, temperature, is_active |
| `links` | 友链 | name, url, status |
| `feedback` | 用户反馈 | content, contact, status |
### API 接口一览
- `GET /api/jokes/` — 公开:获取已审核笑话列表(支持 `type_id`/`crowd_id` 筛选,分页)
- `GET /api/jokes/{id}` — 公开:获取单条笑话(自动增加浏览次数)
- `GET /api/jokes/random` — 公开:随机获取一条
- `POST /api/jokes/{id}/like` — 公开:为笑话点赞(增加 like_count
- `POST /api/generate` — 公开:AI 生成笑话(keywords + scenarios
- `GET /api/categories/types` — 公开:类型列表
- `GET /api/categories/crowds` — 公开:人群列表
- `POST /api/auth/login` — 公开:管理员登录,返回 JWT token
- `GET/POST /api/admin/jokes` — 需认证:列表(支持 `status` 筛选)/ 创建
- `GET/PUT/DELETE /api/admin/jokes/{id}` — 需认证:单条 CRUD
- `PUT /api/admin/jokes/batch-approve` — 需认证:批量审核通过
- `GET /api/admin/stats` — 需认证:统计数据
- `GET/PUT /api/admin/settings/active` — 需认证:AI 配置管理
- `GET/POST /api/admin/links` — 需认证:友链管理
- `GET/POST /api/admin/feedback` — 需认证:反馈管理
**API 文档**:访问 `/docs` 查看交互式 Swagger UIFastAPI 自动生成)
### 前端三栏布局(web
- **AppSidebar**:左侧宽频/点击/搞笑段子排行
- **AppHeader**:顶部导航 + 分类标签 + 搜索框 + 主题切换
- **AppSubNav**:内容区顶部二级导航(最新/最热/随机)
- **主内容区**JokeCard 列表(无限滚动 + 点赞 + 分类/人群标签)
- **AppRightbar**:右侧类型/人群分类导航
- **AppFooter**:底部信息
### 爬虫深度采集流程
1. Bing 搜索关键词 → 发现笑话聚合站
2. 抓取首页 → AI 提取笑话 → 入库
3. 发现翻页链接(`page_N.html``?page=N` 等)→ 逐页抓取 + AI 提取
4. 发现分类链接(`category-N.html`)→ 逐类深度采集(含分类翻页 `category-N_M.html`
5. 站点容错:连续失败 3 次自动跳过
6. 去重:基于 content MD5 哈希
### 优化器三阶段流程
1. **质量检测** (temperature=0.3) — AI 判断是否有笑点,无则标记 `rejected`
2. **AI 润色** (temperature=0.8) — 优化语言表达,保存到 `polished_content` 字段
3. **评价分类** (temperature=0.3) — 分配 type/crowd,评分 1-10,决定 `approved`/`pending`
### 爬虫/优化器通用模式(复用方式)
所有 Python CLI 工具遵循相同模式:
- 通过 API(非直连数据库)读写数据
- 复用 `httpx` 进行 REST 调用 + Bearer token 认证
- AI 调用使用 `openai.OpenAI` 客户端
- 分类映射:通过 `GET /api/categories/types``GET /api/categories/crowds` 获取 name→id 映射
---
如果有任何问题或需要帮助,请随时告知!