diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..1f07d6d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,175 @@ +# 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/ # Pinia(joke/category/theme) +│ └── api/ # Axios 封装 +├── admin/ # Vue3 管理后台 (port 3001) +│ └── src/ +│ ├── layout/ # 后台布局(侧边栏+顶部导航) +│ ├── views/ # 页面(登录/仪表盘/笑话管理/分类管理/设置) +│ ├── stores/ # Pinia(auth/joke) +│ └── api/ # Axios 封装 +├── crawler/ # AI 爬虫(crawl4ai + NVIDIA NIM) +│ ├── main.py # 持续采集主入口 +│ ├── processor.py # 流程编排(搜索→深度翻页→AI提取→入库) +│ ├── crawler_service.py # 页面抓取(Bing搜索 + crawl4ai) +│ ├── ai_service.py # NVIDIA NIM API(OpenAI 兼容)调用 +│ ├── 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 ` +- **笑话审核流**:`pending`(待审核)→ `approved`(已通过)。公开 API 只返回 `approved` 的笑话 +- **双主题系统**:CSS 变量通过 `:root[data-theme="light"]` / `:root[data-theme="dark"]` 控制,使用 `data-theme` 属性切换 +- **数据库**:SQLite (`api/joke.db`),SQLAlchemy ORM,API 启动时自动建表(`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_hash(bcrypt) | +| `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 UI(FastAPI 自动生成) + +### 前端三栏布局(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 映射 + +--- + +如果有任何问题或需要帮助,请随时告知! \ No newline at end of file