174 lines
5.5 KiB
Python

"""Risk prediction request and response contracts."""
from typing import Literal
from pydantic import Field
from app.domain.risk_engine import RiskLevel
from app.schemas.common import ApiSchema
class RiskIndicator(ApiSchema):
name: str = Field(min_length=1, max_length=64)
value: float = Field(ge=0, le=100)
weight: float = Field(default=1, gt=0, le=100)
class RiskAssessmentRequest(ApiSchema):
subject_id: str = Field(min_length=1, max_length=128)
indicators: list[RiskIndicator] = Field(default_factory=list, max_length=50)
product_category: str | None = Field(default=None, max_length=100)
material_type: str | None = Field(default=None, max_length=200)
supplier: str | None = Field(default=None, max_length=300)
factory: str | None = Field(default=None, max_length=300)
stage_new: str | None = Field(default=None, max_length=100)
defect_level: str | None = Field(default=None, max_length=10)
class RiskFactorResult(ApiSchema):
name: str
value: float
weight: float
contribution: float
class CategoryWarning(ApiSchema):
category: str
anomaly_count: int
risk_level: str
similar_category: str | None = None
similar_count: int | None = None
suggestion: str | None = None
class SupplierFrequency(ApiSchema):
supplier_name: str | None = None
cooperation_count: int | None = None
anomaly_count: int | None = None
alpha: float | None = None
tier: str | None = None
suggestion: str | None = None
frequency_basis: str = "暂无匹配采购订单"
note: str | None = None
data_available: bool = False
class StandardJudgment(ApiSchema):
category: str
risk_point: str
rule: str
source: str | None = None
status: str = "待检测"
class RiskDimensionScore(ApiSchema):
dimension: str
score: float
weight: float
status: str = "database"
reason: str | None = None
sample_size: int | None = None
raw_value: float | int | None = None
class SimilarCase(ApiSchema):
case_id: int | None = None
date: str | None = None
product: str | None = None
category: str | None = None
material: str | None = None
anomaly_type: str | None = None
description: str | None = None
root_cause: str | None = None
defect_level: str | None = None
result: str | None = None
problem: str | None = None
solution: str | None = None
similarity: float | None = None
class AiSolutionRisk(ApiSchema):
level: str
title: str
detail: str
class AiSolutionReport(ApiSchema):
title: str = "AI 案例推理生成"
confidence: str | None = None
analysis_base: str | None = None
standard_fallback_enabled: bool = False
standards: list[StandardJudgment] = Field(default_factory=list)
similar_cases: list[SimilarCase] = Field(default_factory=list)
risks: list[AiSolutionRisk] = Field(default_factory=list)
suggestions: list[str] = Field(default_factory=list)
warning: str | None = None
class ReportCard(ApiSchema):
"""A response card explicitly appended to the risk report.
The card is intentionally a superset of the five assistant card types so
that the report page and both export formats can consume the exact same
payload without type-specific ad-hoc transformations.
"""
type: Literal["supplier", "material", "standard", "compliance", "solution"]
title: str = "风险分析卡片"
name: str | None = None
party_type: str | None = None
material: str | None = None
category: str | None = None
question: str | None = None
anomaly_count: int | None = None
cooperation_count: int | None = None
frequency_coefficient: float | None = None
supplier_base_score: float | None = None
supplier_score: float | None = None
tier: str | None = None
matched_count: int | None = None
detected_values: list[dict[str, str]] = Field(default_factory=list)
top_problems: list[dict[str, int | str]] = Field(default_factory=list)
frequent_problems: list[dict[str, int | str]] = Field(default_factory=list)
standards: list[StandardJudgment] = Field(default_factory=list)
similar_cases: list[SimilarCase] = Field(default_factory=list)
confidence: str | None = None
analysis_base: str | None = None
standard_fallback_enabled: bool = False
risks: list[AiSolutionRisk] = Field(default_factory=list)
suggestions: list[str] = Field(default_factory=list)
note: str | None = None
warning: str | None = None
frequency_basis: str | None = None
data_available: bool | None = None
class RiskAssessmentResult(ApiSchema):
subject_id: str
score: float
level: RiskLevel
model_version: str
factors: list[RiskFactorResult]
risk_badge: str | None = None
alert_text: str | None = None
category_warning: CategoryWarning | None = None
supplier_freq: SupplierFrequency | None = None
standard_judgment: list[StandardJudgment] = Field(default_factory=list)
dimension_scores: list[RiskDimensionScore] = Field(default_factory=list)
similar_cases: list[SimilarCase] = Field(default_factory=list)
ai_suggestions: list[str] = Field(default_factory=list)
ai_solution_cards: list[AiSolutionReport] = Field(default_factory=list)
report_cards: list[ReportCard] = Field(default_factory=list)
class ModelInfo(ApiSchema):
model_version: str
score_range: str = "0-100"
levels: tuple[RiskLevel, ...] = (
RiskLevel.LOW,
RiskLevel.MODERATELY_LOW,
RiskLevel.MEDIUM,
RiskLevel.HIGH,
RiskLevel.VERY_HIGH,
)