# continuation.md

## 当前项目状态

djapi — Django 5.2 金融数据 API 项目，2026-06-17 已部署。

## Checkpoint 记录

| 日期 | 内容 |
|------|------|
| 2026-08-03 | 新增日报查询 API ×2（news/reports/ + news/events/），基于 news_report/news_event 表，已部署 doorcome ✅ |

服务器：`simon@doorcome.cn`，路径 `/home/simon/myquant/djapi/`，虚拟环境 `/opt/miniconda/envs/django/`。

## 已完成

### 1. 安全：密钥统一管理
- 所有密钥 → 环境变量，`.env` 统一管理
- `djapi/env_loader.py`（Django 端）+ `api/video/env.py`（video 端）双加载器
- 共享 `MySQLDB` → `api/utils/mysql_handler.py`
- `.env.example`、`.gitignore`

### 2. 代码质量
- `api/views.py`：227 → ~130 行，消除重复
- `api/stock/stock_utils.py`：`viewFunc_singleParam()` 包装器
- `api/stock/config.py`：拆分为 config / strategy_config / scan_config

### 3. drf-spectacular 集成
- 14 端点 `@api_view` + `@extend_schema`，8 tag 分组
- 13 Serializer，Swagger `/api/docs/`

### 4. 股息率 API 优化
- **删除** `api/stock/getDivData_AK.py`（akshare 版），`/api/getdivak/` 路由移除
- **优化** `api/stock/getStockDiv2.py`：
  - TTM 计算：`calculate_ttm_div` 行级循环 O(n²) → `rolling('360D').sum()` O(n)
  - 删除向前填充逻辑（~30 行），避免与毛刺平滑冲突
- **修复** `api/stock/smoothBrush.py`：if/elif 分支中 prev_valid/next_valid 赋值反了

### 5. video 模块重构与 Bug 修复
- 新增 `api/video/env.py` — .env 加载
- `newsRedo.py` 重写 — 三分支智能重处理
- **P0 修复**：`getVideo5.py` 日期校验 bug（`start_date > start_date` → `start_date > end_date`）
- **P1 清理**：删除 `ai.py`（两个函数均为死代码），清理 `newsProcess.py` 冗余 import
- **P2 修复**：`audioRead.py` — `transcribe_audio` 异常时返回 `['', '']` 统一类型；`analyze_and_correct_text` 防御 None
- **P3 修复**：`newsProcess.py` — `news_to_db()` JSON 解析自适应 dict/list（DeepSeek json_object 模式返回 dict 包装）

### 6. 文档与测试
- `CLAUDE.md`、`README.md`、`continuation.md`
- 18 个单元测试

## video 目录文件现状（10 个 .py）

| 文件 | 职责 |
|------|------|
| `env.py` | .env 加载 |
| `getVideo5.py` | 主流程：抓取→下载→ASR→入库 |
| `audioRead.py` | 音频转换、分割、ASR 识别、文本纠错 |
| `deepseek.py` | DeepSeek API 封装（类 + `deepseek_text` 函数，支持 `response_format`） |
| `newsProcess.py` | AI 新闻分割+标题提取，JSON 自适应解析 |
| `newsRedo.py` | 手动重处理（三分支） |
| `main.py` | 定时任务入口（当天） |
| `main_videos.py` | 批量补缺（扫描缺失日期） |
| `mysqlHandle.py` | MySQLDB 重新导出 |

## 所有 API 端点（16 个）

| 端点 | 数据源 | 说明 |
|------|--------|------|
| `stockbasic/` | Tushare | 日线行情 |
| `stockinfo/` | Tushare | 个股基本信息 |
| `industrys/` | Tushare | 行业股票列表 |
| `stockparam/` | Tushare | 个股参数 |
| `stockep/` | Tushare | TTM EPS |
| `quarterlyEps/` | Tushare | 季度 EPS |
| `indexByName/` | Tushare | 指数查询 |
| `indexDatas/` | Tushare | 指数行情 |
| `dailymargin/` | Tushare | 每日融资融券汇总 |
| `stockmargin/` | Tushare | 个股融资融券 |
| `finance/` | Tushare | 财务报表分析 |
| `getdiv/` | Tushare | 股息率（TTM rolling + 毛刺平滑） |
| `xwlbNews/` | MySQL | 新闻联播原始文本 |
| `xwlbFine/` | MySQL | 新闻联播 AI 精编 |
| `news/reports/` | MySQL (news_) | 日报查询：默认最近 24h；传 id 返回详情含事件 |
| `news/events/` | MySQL (news_) | 重要事件聚合：最近 N 天 importance≥阈值 |

---

## 日报查询 API（2026-08-03 新增）

### 模块

- 新增 `api/report/` 包（独立于 stock）：`query.py`（连库+查询 SQL）/ `views.py`（2 视图）/ `serializers.py`（OpenAPI）/ `tests.py`（17 个单测，mock 查询层）
- `api/urls.py` 注册 `news/reports/`、`news/events/`；`settings.py` SPECTACULAR TAGS 加「日报」
- 数据库：doorcome 本机 MariaDB `myquant` 库 `news_report`（180 行）+ `news_event`（4372 条），与现有 `MYSQL_*` 同库同用户
- 连接配置：服务器 `djapi/.env` 新增 `NEWS_DB_*`（复用 MYSQL_* 值，密码必填否则 500）
- 文档：`docs/news_report_api.md`（使用手册，含线上地址/curl/真实样例）；README API 概览表已加两行

### 部署（2026-08-03 完成）

- rsync 增量同步（**未用文档中的 --delete**，见下）→ 重启 uWSGI → 冒烟通过（列表/详情/聚合/400/404）
- 线上：`https://api.doorcome.cn/api/news/reports/`、`/api/news/events/`，Swagger `/api/docs/`「日报」tag

### 已知事项

1. **服务器顶层历史平铺文件未清理**：`/home/simon/myquant/djapi/` 顶层有 views.py/urls.py/smoothBrush.py/getStockDiv2.py/env_loader.py/akshare_data.py（历史 rsync 陷阱产物），`--delete` 会删除它们，但 `divSearch.py`（离线脚本）仍绝对导入顶层 getStockDiv2/smoothBrush → 本次增量同步保留；清理前需先修 divSearch.py 的导入
2. **既有失败测试**：`api.tests.DateFormatCorrectionTest.test_empty_string`（date_format_correction('') 期望 None 实得 ''），与本次无关
3. 冒烟曾发现 fetch_reports 列表 SQL 缺 `r.` 别名前缀（1052 ambiguous），已修复
4. 本地验证需绕过 macOS TCC：`HOME=/tmp/djtest_home PYTHONPATH=/tmp/djtest_pkgs`（tushare 写 ~/tk.csv 被拦 + quant 环境缺 mysql-connector-python）

## 部署

```bash
# 全量同步
rsync -avz --delete \
  --exclude='.env' --exclude='db.sqlite3' \
  --exclude='*.log' --exclude='uwsgi.pid' \
  --exclude='__pycache__/' --exclude='*.pyc' \
  --exclude='xwlb_video/' --exclude='audio_processing/' \
  /Users/summer/Downloads/cc-cursor/djapi/ \
  simon@doorcome.cn:/home/simon/myquant/djapi/

# 单文件同步必须写完整路径
# 正确：rsync api/views.py simon@...:/.../djapi/api/views.py

# 重启
ssh simon@doorcome.cn "kill \$(lsof -ti:5004); sleep 2; /opt/miniconda/envs/django/bin/uwsgi --ini /home/simon/myquant/djapi/uwsgi.ini"
```

## 关键设计决策

- video 模块保护、向后兼容优先、不使用 python-dotenv
- rsync 陷阱：多文件源会展平路径
- `.env` 双加载：Django 端 `djapi/env_loader.py` + video 端 `api/video/env.py`
- 股息率 TTM 用 `rolling('360D').sum()` 向量化，不手动循环
- DeepSeek json_object 模式返回 dict，newsProcess 自适应提取 list
