feat(ai): Copilot 评分引擎 + Handler + 路由 + 权限码
- scoring.rs: 混合评分 (calculate_risk) + RiskScore/MatchedRule 结构 - engine.rs: CopilotEngine 协调规则评估和评分 - risk_service.rs: 风险计算 + UPSERT 快照 + 规则加载 - insight_service.rs: 洞察 CRUD + 过期清理 - 3 个 Handler: insight/risk/rule,7 个 API 端点 - 5 个权限码: copilot.insights.list/manage, copilot.risk.view, copilot.rules.list/manage - AiState 扩展 risk_service + insight_service
This commit is contained in:
14
crates/erp-ai/src/copilot/engine.rs
Normal file
14
crates/erp-ai/src/copilot/engine.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use crate::copilot::rules::{RuleData, evaluate_rules};
|
||||
use crate::copilot::scoring::{RiskScore, calculate_risk};
|
||||
use serde_json::Value;
|
||||
|
||||
/// Copilot 引擎:协调规则评估和评分
|
||||
pub struct CopilotEngine;
|
||||
|
||||
impl CopilotEngine {
|
||||
/// 对患者数据运行所有规则并生成风险评分
|
||||
pub fn assess_patient(rules: &[RuleData], patient_data: &Value) -> RiskScore {
|
||||
let matched = evaluate_rules(rules, patient_data);
|
||||
calculate_risk(matched)
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
pub mod engine;
|
||||
pub mod rules;
|
||||
pub mod scoring;
|
||||
|
||||
45
crates/erp-ai/src/copilot/scoring.rs
Normal file
45
crates/erp-ai/src/copilot/scoring.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use crate::copilot::rules::MatchedRuleData;
|
||||
|
||||
/// 风险评分结果
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
pub struct RiskScore {
|
||||
pub score: i16,
|
||||
pub level: String,
|
||||
pub matched_rules: Vec<MatchedRule>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
pub struct MatchedRule {
|
||||
pub rule_id: uuid::Uuid,
|
||||
pub name: String,
|
||||
pub score: i16,
|
||||
pub severity: String,
|
||||
pub suggestion: Option<String>,
|
||||
}
|
||||
|
||||
/// 根据匹配规则计算风险评分
|
||||
pub fn calculate_risk(matched: Vec<MatchedRuleData>) -> RiskScore {
|
||||
let total: i16 = matched.iter().map(|(_, _, s, _, _)| *s).sum();
|
||||
let clamped = total.clamp(0, 10);
|
||||
let level = match clamped {
|
||||
0..=2 => "low".to_string(),
|
||||
3..=5 => "medium".to_string(),
|
||||
6..=8 => "high".to_string(),
|
||||
_ => "critical".to_string(),
|
||||
};
|
||||
let matched_rules = matched
|
||||
.into_iter()
|
||||
.map(|(id, name, score, severity, suggestion)| MatchedRule {
|
||||
rule_id: id,
|
||||
name,
|
||||
score,
|
||||
severity,
|
||||
suggestion,
|
||||
})
|
||||
.collect();
|
||||
RiskScore {
|
||||
score: clamped,
|
||||
level,
|
||||
matched_rules,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user