"""置信度评分系统 — 财务Bot分析结论管理""" from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from sqlalchemy import func from app.database import get_db from app.auth_middleware import require_auth from app.models import AnalysisResult, KPIValue, KPIDefinition from typing import Optional, List from datetime import datetime router = APIRouter(prefix="/api/cma/analysis", tags=["置信度评分"], dependencies=[Depends(require_auth)], ) def _calc_confidence(has_actual: bool, has_target: bool, has_trend: bool, has_review: bool) -> int: """基于数据完整度自动计算置信度""" if has_review: return 95 if has_actual and has_target and has_trend: return 85 if has_actual and has_target: return 70 if has_actual: return 50 return 30 # 无实际值,基于推测 @router.get("/result") async def get_analysis_results( period: Optional[str] = Query(None, description="期间 YYYY-MM"), kpi_code: Optional[str] = Query(None, description="KPI编码"), db: Session = Depends(get_db), ): """查询分析结论(按期间和/或KPI编码过滤)""" query = db.query(AnalysisResult).order_by(AnalysisResult.created_at.desc()) if period: query = query.filter(AnalysisResult.period == period) if kpi_code: query = query.filter(AnalysisResult.kpi_code == kpi_code) results = query.all() return { "total": len(results), "period": period, "results": [ { "id": r.id, "period": r.period, "结论": r.conclusion, "置信度": f"{r.confidence}%", "数据来源": r.data_source, "计算逻辑": r.calculation_logic, "可比基准": r.comparable_benchmark, "局限": r.limitations, "kpi_code": r.kpi_code, "kpi_name": r.kpi_name, "has_actual": bool(r.has_actual), "has_target": bool(r.has_target), "has_trend": bool(r.has_trend), "has_review": bool(r.has_review), "created_at": r.created_at.strftime("%Y-%m-%d %H:%M:%S") if r.created_at else None, } for r in results ], } @router.post("/result") def create_analysis_result(data: dict = None, db: Session = Depends(get_db)): """提交分析结果(自动计算置信度)""" if not data: data = {} period = data.get("period", "") conclusion = data.get("conclusion", "") data_source = data.get("data_source", "") calculation_logic = data.get("calculation", "") comparable_benchmark = data.get("comparable_benchmark") limitations = data.get("limitations") kpi_code = data.get("kpi_code") kpi_name = data.get("kpi_name") has_actual = data.get("has_actual", False) has_target = data.get("has_target", False) has_trend = data.get("has_trend", False) has_review = data.get("has_review", False) confidence = _calc_confidence(has_actual, has_target, has_trend, has_review) result = AnalysisResult( period=period, conclusion=conclusion, confidence=confidence, data_source=data_source, calculation_logic=calculation_logic, comparable_benchmark=comparable_benchmark, limitations=limitations, kpi_code=kpi_code, kpi_name=kpi_name, has_actual=1 if has_actual else 0, has_target=1 if has_target else 0, has_trend=1 if has_trend else 0, has_review=1 if has_review else 0, ) db.add(result) db.commit() db.refresh(result) return { "id": result.id, "period": result.period, "结论": result.conclusion, "置信度": f"{result.confidence}%", "数据来源": result.data_source, "计算逻辑": result.calculation_logic, "可比基准": result.comparable_benchmark, "局限": result.limitations, "confidence_score": result.confidence, "message": "分析结论已保存", } @router.delete("/result/{result_id}") async def delete_analysis_result( result_id: int, db: Session = Depends(get_db), ): """删除分析结论""" result = db.query(AnalysisResult).filter(AnalysisResult.id == result_id).first() if not result: raise HTTPException(404, "分析结论不存在") db.delete(result) db.commit() return {"message": "已删除"} @router.post("/auto-calculate") async def auto_calculate_confidence( period: str = Query(..., description="期间 YYYY-MM"), kpi_code: str = Query(..., description="KPI编码"), db: Session = Depends(get_db), ): """根据KPI数据完整性自动生成置信度评分""" # 查找KPI定义 kpi = db.query(KPIDefinition).filter(KPIDefinition.kpi_code == kpi_code).first() if not kpi: raise HTTPException(404, f"KPI编码 {kpi_code} 不存在") # 查找该期间的实际值 value = db.query(KPIValue).filter( KPIValue.kpi_id == kpi.id, KPIValue.period == period, ).first() # 查找历史数据(趋势) trend_values = db.query(KPIValue).filter( KPIValue.kpi_id == kpi.id, ).order_by(KPIValue.period.desc()).limit(6).all() has_actual = value is not None and value.actual_value is not None has_target = kpi.target_value is not None has_trend = len(trend_values) >= 2 has_review = False confidence = _calc_confidence(has_actual, has_target, has_trend, has_review) return { "kpi_code": kpi_code, "kpi_name": kpi.kpi_name, "period": period, "has_actual": has_actual, "has_target": has_target, "has_trend": has_trend, "has_review": has_review, "confidence": confidence, "confidence_label": f"{confidence}%", "数据完备度": { "10%": "无数据", "50%": "有实际值", "70%": "有实际值+目标值", "85%": "有实际值+目标值+历史趋势", "95%": "有全部数据+人工复核", }.get(str(confidence), "基于推测"), }