Files
AIPortPilot/backend/app/services/health_calculator.py
T
selfrelease fad458b2a7 docs(uiux): UIUX 设计方案大改 + 5 份作业指导书对齐 + 开发任务文档
- UIUX 文档:填充 19 个缺口(多主体画像/健康度/AI+看板/增长域/洞察域/创始人端/OODA/助推/商密)
- UIUX 文档:插入 6 个新章节(十四~十九),旧章节重编号为二十~三十一,更新目录和交叉引用
- 作业指导书 x5:导航改为 6 域分组,新增 Context Bar/工作模式/Insight Rail/决策线程/多工作区等 UI 概念
- 新建 docs/2-task-uiux.md:50 个代码落地开发任务,按 P0-P6 分优先级 + 8 Sprint 规划
- 后端/前端:大量新增模型、路由、组件(来自之前 Phase 开发)
2026-07-19 11:53:38 +08:00

434 lines
13 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.
"""健康度评分计算引擎。
基于月报结构化数据,计算多维度评分:
- 基础 4 维度:财务、经营、AI 商业化、AI 成本
- T2.9 扩展 5 维度:组织人才、产品技术、市场竞争、治理合规、融资资本
- T3.11 扩展 5 维度:协同赋能、AI 模型产品、数据合规、团队技术、客户成功
总分 = 加权平均,输出 0-100 分。
"""
import logging
from typing import Any
logger = logging.getLogger(__name__)
# 14 维度权重配置
WEIGHTS = {
"financial": 0.15,
"operational": 0.10,
"ai_commercial": 0.10,
"ai_cost": 0.05,
"org_talent": 0.10,
"product_tech": 0.10,
"market_compete": 0.10,
"governance": 0.05,
"financing": 0.05,
"synergy": 0.05,
"ai_model_product": 0.05,
"data_compliance": 0.05,
"team_tech": 0.03,
"customer_success": 0.07,
}
def _safe_float(value: Any, default: float = 0.0) -> float:
"""安全转换为 float。"""
if value is None or value == "":
return default
try:
return float(value)
except (ValueError, TypeError):
return default
def _calc_financial_score(data: dict[str, Any]) -> float:
"""计算财务健康度。
指标:
- 现金跑道(runway_months):>12 月=90+6-12=60-90<6=<60
- 营收同比增长(yoy_change):正=加分,负=减分
- 烧钱率趋势(burn_rate trend):down=加分,up=减分
"""
score = 50.0 # 基础分
cash = data.get("cash_balance", {})
runway = _safe_float(cash.get("runway_months"))
if runway > 0:
if runway >= 12:
score += 30
elif runway >= 6:
score += 15
elif runway >= 3:
score -= 10
else:
score -= 30
revenue = data.get("revenue", {})
yoy = revenue.get("yoy_change", "")
if yoy:
yoy_val = _safe_float(str(yoy).replace("%", "").replace("+", ""))
if yoy_val > 0:
score += 15
elif yoy_val < 0:
score -= 15
burn = data.get("burn_rate", {})
trend = burn.get("trend", "")
if trend == "down":
score += 10
elif trend == "up":
score -= 10
return max(0, min(100, score))
def _calc_operational_score(data: dict[str, Any]) -> float:
"""计算经营健康度。
指标:
- 团队规模变化(headcount):净增长=加分
- 关键指标达成情况
"""
score = 60.0
headcount = data.get("headcount", {})
new_hires = _safe_float(headcount.get("new_hires"))
departures = _safe_float(headcount.get("departures"))
net_change = new_hires - departures
if net_change > 0:
score += 15
elif net_change < 0:
score -= 10
if departures > 5:
score -= 10 # 高流失率
key_metrics = data.get("key_metrics", [])
if key_metrics:
positive_count = sum(
1 for m in key_metrics
if _safe_float(str(m.get("change", "")).replace("%", "").replace("+", "")) > 0
)
score += (positive_count / len(key_metrics)) * 20
return max(0, min(100, score))
def _calc_ai_commercial_score(data: dict[str, Any]) -> float:
"""计算 AI 商业化度。
基于 key_metrics 中 AI 相关指标的达成情况。
"""
score = 50.0
key_metrics = data.get("key_metrics", [])
ai_metrics = [
m for m in key_metrics
if "ai" in str(m.get("name", "")).lower()
or "模型" in str(m.get("name", ""))
or "推理" in str(m.get("name", ""))
]
if ai_metrics:
for m in ai_metrics:
change = str(m.get("change", ""))
val = _safe_float(change.replace("%", "").replace("+", ""))
if val > 0:
score += 15
elif val < 0:
score -= 10
else:
# 无 AI 相关指标,给中等偏下分数
score = 40.0
return max(0, min(100, score))
def _calc_ai_cost_score(data: dict[str, Any]) -> float:
"""计算 AI 成本效率。
基于 burn_rate 和 AI 相关支出估算。
"""
score = 55.0
burn = data.get("burn_rate", {})
trend = burn.get("trend", "")
if trend == "down":
score += 20
elif trend == "up":
score -= 15
# 如果有 key_metrics 中的成本相关指标
key_metrics = data.get("key_metrics", [])
cost_metrics = [
m for m in key_metrics
if "成本" in str(m.get("name", "")) or "cost" in str(m.get("name", "")).lower()
]
for m in cost_metrics:
change = str(m.get("change", ""))
val = _safe_float(change.replace("%", "").replace("+", ""))
if val < 0: # 成本下降是好事
score += 10
elif val > 0:
score -= 10
return max(0, min(100, score))
def _calc_org_talent_score(data: dict[str, Any]) -> float:
"""计算组织人才健康度。
指标:团队规模变化、流失率、关键岗位填补。
"""
score = 60.0
headcount = data.get("headcount", {})
new_hires = _safe_float(headcount.get("new_hires"))
departures = _safe_float(headcount.get("departures"))
total = _safe_float(headcount.get("total"), 1)
if total > 0:
turnover_rate = departures / total
if turnover_rate < 0.05:
score += 20
elif turnover_rate < 0.10:
score += 10
elif turnover_rate > 0.20:
score -= 20
elif turnover_rate > 0.15:
score -= 10
if new_hires > 0:
score += 10
return max(0, min(100, score))
def _calc_product_tech_score(data: dict[str, Any]) -> float:
"""计算产品技术健康度。
指标:产品迭代频率、技术指标达成。
"""
score = 55.0
key_metrics = data.get("key_metrics", [])
tech_metrics = [
m for m in key_metrics
if any(k in str(m.get("name", "")).lower()
for k in ["产品", "product", "迭代", "release", "技术", "tech"])
]
if tech_metrics:
for m in tech_metrics:
change = str(m.get("change", ""))
val = _safe_float(change.replace("%", "").replace("+", ""))
if val > 0:
score += 12
elif val < 0:
score -= 8
else:
score = 50.0
return max(0, min(100, score))
def _calc_market_compete_score(data: dict[str, Any]) -> float:
"""计算市场竞争健康度。
指标:市场份额变化、竞品动态、客户增长。
"""
score = 55.0
key_metrics = data.get("key_metrics", [])
market_metrics = [
m for m in key_metrics
if any(k in str(m.get("name", ""))
for k in ["市场", "份额", "客户", "竞品", "MAU", "DAU", "GMV"])
]
if market_metrics:
for m in market_metrics:
change = str(m.get("change", ""))
val = _safe_float(change.replace("%", "").replace("+", ""))
if val > 0:
score += 12
elif val < 0:
score -= 8
return max(0, min(100, score))
def _calc_governance_score(data: dict[str, Any]) -> float:
"""计算治理合规健康度。
指标:董事会召开频率、合规事件。
"""
score = 70.0
governance = data.get("governance", {})
if governance.get("board_meeting_held"):
score += 10
if governance.get("compliance_issues"):
score -= 20
return max(0, min(100, score))
def _calc_financing_score(data: dict[str, Any]) -> float:
"""计算融资资本健康度。
指标:现金跑道、融资进度。
"""
score = 55.0
cash = data.get("cash_balance", {})
runway = _safe_float(cash.get("runway_months"))
if runway >= 18:
score += 25
elif runway >= 12:
score += 15
elif runway >= 6:
score += 5
elif runway < 3:
score -= 25
financing = data.get("financing", {})
if financing.get("in_progress"):
score += 10
return max(0, min(100, score))
def _calc_synergy_score(data: dict[str, Any]) -> float:
"""计算协同赋能健康度(T3.11)。"""
score = 55.0
synergy = data.get("synergy", {})
if synergy.get("active_count", 0) > 0:
score += min(20, synergy.get("active_count", 0) * 5)
if synergy.get("completed_count", 0) > 0:
score += 10
return max(0, min(100, score))
def _calc_ai_model_product_score(data: dict[str, Any]) -> float:
"""计算 AI 模型产品健康度(T3.11)。"""
score = 50.0
ai_data = data.get("ai_metrics", {})
if ai_data.get("model_accuracy"):
score += 15
if ai_data.get("inference_cost_trend") == "down":
score += 10
if ai_data.get("data_quality_score"):
score += min(15, _safe_float(ai_data.get("data_quality_score")) * 0.15)
return max(0, min(100, score))
def _calc_data_compliance_score(data: dict[str, Any]) -> float:
"""计算数据合规健康度(T3.11)。"""
score = 70.0
compliance = data.get("data_compliance", {})
if compliance.get("issues_count", 0) > 0:
score -= min(30, compliance.get("issues_count", 0) * 10)
if compliance.get("audit_passed"):
score += 15
return max(0, min(100, score))
def _calc_team_tech_score(data: dict[str, Any]) -> float:
"""计算团队技术健康度(T3.11)。"""
score = 55.0
team = data.get("team_tech", {})
if team.get("tech_lead_count", 0) > 0:
score += 15
if team.get("patent_count", 0) > 0:
score += min(15, team.get("patent_count", 0) * 3)
return max(0, min(100, score))
def _calc_customer_success_score(data: dict[str, Any]) -> float:
"""计算客户成功健康度(T3.11)。"""
score = 55.0
cs = data.get("customer_success", {})
retention = _safe_float(cs.get("retention_rate"), -1)
if retention >= 0:
if retention >= 0.90:
score += 25
elif retention >= 0.80:
score += 15
elif retention < 0.70:
score -= 15
nps = _safe_float(cs.get("nps"))
if nps > 0:
score += min(15, nps * 0.15)
return max(0, min(100, score))
def calculate_health_score(structured_data: dict[str, Any]) -> dict[str, float]:
"""计算 14 维度健康度评分。
Args:
structured_data: 月报 AI 解析后的结构化数据
Returns:
包含 total_score 和 14 个维度分数的字典
"""
if not structured_data:
return {
"total_score": 0.0,
"financial_score": 0.0,
"operational_score": 0.0,
"ai_commercial_score": 0.0,
"ai_cost_score": 0.0,
"org_talent_score": 0.0,
"product_tech_score": 0.0,
"market_compete_score": 0.0,
"governance_score": 0.0,
"financing_score": 0.0,
"synergy_score": 0.0,
"ai_model_product_score": 0.0,
"data_compliance_score": 0.0,
"team_tech_score": 0.0,
"customer_success_score": 0.0,
}
scores = {
"financial_score": _calc_financial_score(structured_data),
"operational_score": _calc_operational_score(structured_data),
"ai_commercial_score": _calc_ai_commercial_score(structured_data),
"ai_cost_score": _calc_ai_cost_score(structured_data),
"org_talent_score": _calc_org_talent_score(structured_data),
"product_tech_score": _calc_product_tech_score(structured_data),
"market_compete_score": _calc_market_compete_score(structured_data),
"governance_score": _calc_governance_score(structured_data),
"financing_score": _calc_financing_score(structured_data),
"synergy_score": _calc_synergy_score(structured_data),
"ai_model_product_score": _calc_ai_model_product_score(structured_data),
"data_compliance_score": _calc_data_compliance_score(structured_data),
"team_tech_score": _calc_team_tech_score(structured_data),
"customer_success_score": _calc_customer_success_score(structured_data),
}
weight_keys = [
"financial", "operational", "ai_commercial", "ai_cost",
"org_talent", "product_tech", "market_compete", "governance", "financing",
"synergy", "ai_model_product", "data_compliance", "team_tech", "customer_success",
]
score_keys = [
"financial_score", "operational_score", "ai_commercial_score", "ai_cost_score",
"org_talent_score", "product_tech_score", "market_compete_score", "governance_score",
"financing_score", "synergy_score", "ai_model_product_score", "data_compliance_score",
"team_tech_score", "customer_success_score",
]
total = sum(scores[sk] * WEIGHTS[wk] for sk, wk in zip(score_keys, weight_keys))
scores["total_score"] = round(total, 1)
result = {k: round(v, 1) for k, v in scores.items()}
logger.info("健康度评分计算完成(14 维度): %s", result)
return result
def determine_trend(current_score: float, previous_score: float | None) -> str:
"""判断评分趋势。
Args:
current_score: 当前评分
previous_score: 上期评分(如有)
Returns:
"up" / "down" / "stable"
"""
if previous_score is None:
return "stable"
diff = current_score - previous_score
if diff > 5:
return "up"
elif diff < -5:
return "down"
return "stable"