"""统一反馈中心 Pydantic 模型。""" from __future__ import annotations from datetime import date, datetime from typing import Any, Literal, Optional from pydantic import BaseModel, ConfigDict, Field class FeedbackReasonCandidate(BaseModel): model_config = ConfigDict(extra="ignore") code: str label: str confidence: float = 0.0 description: Optional[str] = None source_type: Optional[str] = None field_name: Optional[str] = None class FeedbackCenterRecordRevisionRead(BaseModel): model_config = ConfigDict(from_attributes=True, extra="ignore") id: int record_id: int before_snapshot: Any after_snapshot: Any reviewed_by: Optional[int] = None reviewed_at: Optional[datetime] = None created_at: Optional[datetime] = None class FeedbackCenterRecordRead(BaseModel): model_config = ConfigDict(from_attributes=True, extra="ignore") id: int tenant_id: int project_id: Optional[int] = None source_type: str source_id: int object_type: str object_id: int field_name: str source_title: Optional[str] = None object_title: Optional[str] = None before_value: Any = None after_value: Any = None ai_snapshot: Any = None ai_confidence: Optional[float] = None reason_candidates: list[FeedbackReasonCandidate] = Field(default_factory=list) reason_code: Optional[str] = None reason_text: Optional[str] = None review_status: str reviewed_by: Optional[int] = None reviewed_at: Optional[datetime] = None auto_assigned: bool = False created_at: Optional[datetime] = None updated_at: Optional[datetime] = None revisions: list[FeedbackCenterRecordRevisionRead] = Field(default_factory=list) class FeedbackCenterSummaryReasonRead(BaseModel): code: str label: str count: int class FeedbackCenterSummaryMetricsRead(BaseModel): accepted_rate_reviewed: float manual_override_rate: float rework_rate: float auto_assigned_rate: float avg_review_latency_minutes: float total_task_breakdown_count: int total_task_override_count: int total_qa_feedback_count: int total_signal_feedback_count: int total_revision_count: int class FeedbackCenterTrendDailyRead(BaseModel): model_config = ConfigDict(extra="ignore") date: date total_records: int accepted_count: int rejected_count: int reviewed_count: int pending_count: int task_breakdown_count: int task_override_count: int qa_feedback_count: int signal_feedback_count: int auto_assigned_count: int override_count: int rework_count: int accepted_rate_reviewed: float manual_override_rate: float rework_rate: float auto_assigned_rate: float avg_review_latency_minutes: float revision_count: int class FeedbackCenterTrendWindowRead(BaseModel): model_config = ConfigDict(extra="ignore") total_records: int accepted_count: int rejected_count: int reviewed_count: int pending_count: int task_breakdown_count: int task_override_count: int qa_feedback_count: int signal_feedback_count: int auto_assigned_count: int override_count: int rework_count: int accepted_rate_reviewed: float manual_override_rate: float rework_rate: float auto_assigned_rate: float avg_review_latency_minutes: float revision_count: int class FeedbackCenterTrendDeltaRead(BaseModel): model_config = ConfigDict(extra="ignore") total_records_delta: int accepted_rate_reviewed_delta: float manual_override_rate_delta: float rework_rate_delta: float auto_assigned_rate_delta: float avg_review_latency_minutes_delta: float class FeedbackCenterTrendRead(BaseModel): model_config = ConfigDict(extra="ignore") window_days: int current_window_start: date previous_window_start: date daily: list[FeedbackCenterTrendDailyRead] current: FeedbackCenterTrendWindowRead previous: FeedbackCenterTrendWindowRead deltas: FeedbackCenterTrendDeltaRead class FeedbackCenterSummaryRead(BaseModel): model_config = ConfigDict(extra="ignore") tenant_id: int project_id: Optional[int] = None source_group: str = "all" total: int backlog_count: int pending_count: int reviewed_count: int accepted_count: int rejected_count: int accepted_rate: float avg_confidence: float by_status: dict[str, int] by_source_type: dict[str, int] top_reasons: list[FeedbackCenterSummaryReasonRead] metrics: FeedbackCenterSummaryMetricsRead trend: FeedbackCenterTrendRead class FeedbackCenterListRead(BaseModel): model_config = ConfigDict(extra="ignore") items: list[FeedbackCenterRecordRead] total: int limit: int offset: int has_more: bool class FeedbackCenterReviewRequest(BaseModel): model_config = ConfigDict(extra="ignore") review_status: Literal["reviewed", "accepted", "rejected"] = "accepted" reason_code: Optional[str] = None reason_text: Optional[str] = None class FeedbackCenterReasonCatalogRead(BaseModel): items: list[FeedbackReasonCandidate] __all__ = [ "FeedbackReasonCandidate", "FeedbackCenterRecordRevisionRead", "FeedbackCenterRecordRead", "FeedbackCenterSummaryReasonRead", "FeedbackCenterSummaryMetricsRead", "FeedbackCenterTrendDailyRead", "FeedbackCenterTrendWindowRead", "FeedbackCenterTrendDeltaRead", "FeedbackCenterTrendRead", "FeedbackCenterSummaryRead", "FeedbackCenterListRead", "FeedbackCenterReviewRequest", "FeedbackCenterReasonCatalogRead", ]