from __future__ import annotations from typing import Literal from pydantic import BaseModel, Field, field_validator, model_validator FeedbackTargetType = Literal["demand", "video", "hit_content"] FeedbackAction = Literal["support", "oppose", "correct", "supplement"] REASON_CODES_BY_TARGET: dict[str, set[str]] = { "demand": { "not_a_demand", "wrong_grade", "wrong_category", "unclear_wording", "wrong_reason", "missing_demand", "other", }, "video": { "irrelevant", "weak_relevance", "unavailable", "duplicate", "wrong_info", "missing_video", "other", }, "hit_content": { "not_hit", "wrong_point_type", "inaccurate_wording", "wrong_reason", "duplicate", "missing_content", "other", }, } class CreateDemandFeedbackBody(BaseModel): client_request_id: str = Field(min_length=8, max_length=64) target_type: FeedbackTargetType demand_grade_id: int = Field(gt=0) video_id: str | None = Field(default=None, max_length=64) demand_video_expansion_id: int | None = Field(default=None, gt=0) feedback_action: FeedbackAction reason_code: str | None = Field(default=None, max_length=64) content: str | None = Field(default=None, max_length=1000) @field_validator("client_request_id", "video_id", "reason_code", "content") @classmethod def strip_text(cls, value: str | None) -> str | None: if value is None: return None stripped = value.strip() return stripped or None @model_validator(mode="after") def validate_target_and_content(self) -> "CreateDemandFeedbackBody": if self.target_type == "demand": if self.video_id is not None or self.demand_video_expansion_id is not None: raise ValueError("需求反馈不能包含视频或命中内容 ID") elif self.target_type == "video": if not self.video_id or self.demand_video_expansion_id is not None: raise ValueError("视频反馈必须且只能包含视频 ID") elif not self.video_id or self.demand_video_expansion_id is None: raise ValueError("命中内容反馈必须包含视频 ID 和命中内容 ID") if self.feedback_action == "oppose" and not self.reason_code: raise ValueError("不认可反馈必须选择问题原因") if self.feedback_action in {"correct", "supplement"} and not self.content: raise ValueError("纠错或补充反馈必须填写说明") if ( self.reason_code is not None and self.reason_code not in REASON_CODES_BY_TARGET[self.target_type] ): raise ValueError("问题原因不适用于当前反馈对象") return self