185 lines
6.4 KiB
Python
185 lines
6.4 KiB
Python
"""置信度评分系统 — 财务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")
|
|
async def create_analysis_result(
|
|
period: str = Query(..., description="期间 YYYY-MM"),
|
|
conclusion: str = Query(..., description="分析结论"),
|
|
data_source: Optional[str] = Query(None, description="数据来源"),
|
|
calculation_logic: Optional[str] = Query(None, description="计算逻辑"),
|
|
comparable_benchmark: Optional[str] = Query(None, description="可比基准"),
|
|
limitations: Optional[str] = Query(None, description="局限说明"),
|
|
kpi_code: Optional[str] = Query(None, description="关联KPI编码"),
|
|
kpi_name: Optional[str] = Query(None, description="关联KPI名称"),
|
|
has_actual: bool = Query(False, description="有实际值"),
|
|
has_target: bool = Query(False, description="有目标值"),
|
|
has_trend: bool = Query(False, description="有历史趋势"),
|
|
has_review: bool = Query(False, description="有人工复核"),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
"""提交分析结果(自动计算置信度)"""
|
|
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), "基于推测"),
|
|
}
|