Files
auv/backend/routes/ai_analysis.py
T

114 lines
3.8 KiB
Python
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.
"""AI 分析报告路由(/api/ai-analysis)
提供:
- 报告列表
- 报告详情
- 手动触发分析(12小时频率限制)
- 重新生成报告
- 检查某日是否有报告
"""
import json
from datetime import datetime, timezone, timedelta
from fastapi import APIRouter, HTTPException
from fastapi.responses import JSONResponse
from database import get_connection, dict_from_row
_CST = timezone(timedelta(hours=8))
_NO_CACHE_HEADERS = {"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0"}
router = APIRouter()
def _has_ai_report(trade_date: str) -> bool:
conn = get_connection()
try:
row = conn.execute(
"SELECT 1 FROM ai_reports WHERE trade_date = ? AND report_type = 'daily' LIMIT 1",
(trade_date,)
).fetchone()
return row is not None
finally:
conn.close()
def _can_trigger(trade_date: str) -> tuple[bool, str]:
"""检查是否可以触发分析(同一交易日内可随时重新生成)"""
return True, ""
@router.get("/ai-analysis/latest", summary="最新 AI 分析报告")
async def get_latest_report():
conn = get_connection()
try:
# issue_number:按报告日期序数作为总期号
row = conn.execute(
"""SELECT r.*,
(SELECT COUNT(*) FROM ai_reports WHERE trade_date <= r.trade_date) AS issue_number
FROM ai_reports r ORDER BY r.trade_date DESC, r.id DESC LIMIT 1"""
).fetchone()
if not row:
raise HTTPException(status_code=404, detail="暂无分析报告")
item = dict_from_row(row)
item["toolsUsed"] = json.loads(item.pop("tools_used") or "[]")
return JSONResponse({"data": item}, headers=_NO_CACHE_HEADERS)
finally:
conn.close()
@router.get("/ai-analysis", summary="AI 分析报告列表")
async def list_reports():
conn = get_connection()
try:
rows = conn.execute(
"SELECT id, trade_date, report_type, title, summary, tools_used, model, tokens_used, "
"generation_count, llm_calls, created_at, updated_at "
"FROM ai_reports ORDER BY trade_date DESC, id DESC LIMIT 50"
).fetchall()
items = []
for r in rows:
item = dict_from_row(r)
item["toolsUsed"] = json.loads(item.pop("tools_used") or "[]")
items.append(item)
return JSONResponse({"data": items}, headers=_NO_CACHE_HEADERS)
finally:
conn.close()
@router.get("/ai-analysis/{report_id}", summary="AI 分析报告详情")
async def get_report(report_id: int):
conn = get_connection()
try:
row = conn.execute("SELECT * FROM ai_reports WHERE id = ?", (report_id,)).fetchone()
if not row:
raise HTTPException(status_code=404, detail="报告不存在")
item = dict_from_row(row)
item["toolsUsed"] = json.loads(item.pop("tools_used") or "[]")
return JSONResponse({"data": item}, headers=_NO_CACHE_HEADERS)
finally:
conn.close()
@router.get("/ai-analysis/check/{trade_date}", summary="检查某日是否有 AI 分析报告")
async def check_report(trade_date: str):
has = _has_ai_report(trade_date)
return JSONResponse({"data": {"hasReport": has, "tradeDate": trade_date}})
@router.post("/ai-analysis/{report_id}/regenerate", summary="重新生成 AI 分析报告")
async def regenerate_report(report_id: int):
conn = get_connection()
try:
row = conn.execute("SELECT trade_date FROM ai_reports WHERE id = ?", (report_id,)).fetchone()
if not row:
raise HTTPException(status_code=404, detail="报告不存在")
trade_date = row["trade_date"]
finally:
conn.close()
from services.ai_service import collect_ai_analysis
result = await collect_ai_analysis(trade_date)
return JSONResponse({"data": result})