Files
matrix-show/backend/app/models/schemas.py
T
2026-06-04 17:59:53 +08:00

238 lines
5.0 KiB
Python

from datetime import datetime
from enum import Enum
from typing import Optional
from pydantic import BaseModel, Field
class GamePhase(str, Enum):
INTRO = "intro"
ROUND1_SPEAK = "round1_speak"
ROUND1_SEARCH = "round1_search"
ROUND2_SPEAK = "round2_speak"
ROUND2_SEARCH = "round2_search"
FINAL_DISCUSS = "final_discuss"
VOTING = "voting"
REVEAL = "reveal"
@classmethod
def ordered_phases(cls) -> list[str]:
return [
"intro", "round1_speak", "round1_search",
"round2_speak", "round2_search",
"final_discuss", "voting", "reveal"
]
@classmethod
def phase_count(cls) -> int:
return len(cls.ordered_phases())
class CharacterRole(str, Enum):
DETECTIVE = "detective"
SUSPECT = "suspect"
WITNESS = "witness"
VICTIM = "victim"
KILLER = "killer"
class CharacterStatus(str, Enum):
ALIVE = "alive"
DEAD = "dead"
INACTIVE = "inactive"
class MessageType(str, Enum):
SYSTEM = "system"
DM = "dm"
CHARACTER = "character"
VOTE = "vote"
CLUE = "clue"
class ClueType(str, Enum):
PHYSICAL = "physical"
TESTIMONY = "testimony"
MOTIVE = "motive"
ALIBI = "alibi"
FORENSIC = "forensic"
class ClueVisibility(str, Enum):
ALL = "all"
SPECIFIC = "specific"
HIDDEN = "hidden"
class ScriptUploadRequest(BaseModel):
title: str
content: str
file_type: str = "natural_language"
class ScriptParsePreview(BaseModel):
title: str
background: str
characters: list[dict]
clues: list[dict]
phases: list[dict]
class ScriptImportRequest(BaseModel):
title: str
background: str = ""
characters: list[dict] = Field(default_factory=list)
clues: list[dict] = Field(default_factory=list)
phases: list[dict] = Field(default_factory=list)
class ScriptResponse(BaseModel):
id: str
title: str
background: str
character_count: int
created_at: datetime
model_config = {"from_attributes": True}
class CharacterCreate(BaseModel):
name: str
role: CharacterRole = CharacterRole.SUSPECT
personality: str = ""
speaking_style: str = ""
background: str = ""
secret: str = ""
motive: str = ""
avatar_url: str = ""
class CharacterResponse(BaseModel):
id: str
script_id: str
name: str
role: CharacterRole
status: CharacterStatus
personality: str
speaking_style: str
background: str
secret: str
motive: str
avatar_url: str
hermes_profile: str
soul_md: str
is_revealed_killer: bool
created_at: datetime
model_config = {"from_attributes": True}
class SoulUpdateRequest(BaseModel):
soul_md: str
knowledge_base: str = ""
class CharacterSpeakRequest(BaseModel):
prompt: str = ""
target_character_id: Optional[str] = None
class CharacterGenerateRequest(BaseModel):
script_id: str
character_names: list[str]
class MessageCreate(BaseModel):
session_id: str = ""
character_id: Optional[str] = None
game_phase: str = ""
msg_type: str = "character"
content: str
target_character_id: Optional[str] = None
class MessageResponse(BaseModel):
id: str
session_id: str
character_id: Optional[str] = None
game_phase: str
msg_type: str
content: str
target_character_id: Optional[str] = None
clue_id: Optional[str] = None
metadata: dict
created_at: datetime
character_name: Optional[str] = None
character_role: Optional[CharacterRole] = None
model_config = {"from_attributes": True}
class ClueCreate(BaseModel):
script_id: str
name: str
content: str
clue_type: ClueType = ClueType.PHYSICAL
owner_id: Optional[str] = None
phase: str = "round1_search"
visibility: ClueVisibility = ClueVisibility.ALL
visible_to: list[str] = Field(default_factory=list)
class ClueUnlockRequest(BaseModel):
character_id: str
class ClueResponse(BaseModel):
id: str
script_id: str
name: str
content: str
clue_type: ClueType
owner_id: Optional[str] = None
phase: str
visibility: ClueVisibility
visible_to: list
is_unlocked: bool
unlocked_by: Optional[str] = None
unlocked_at: Optional[datetime] = None
created_at: datetime
model_config = {"from_attributes": True}
class DmSpeakRequest(BaseModel):
content: str
phase: str = ""
class GameStateResponse(BaseModel):
id: str
current_phase: GamePhase
current_speaker_id: Optional[str] = None
speaker_order: list
active_script_id: Optional[str] = None
is_running: bool
is_paused: bool
phase_started_at: Optional[datetime] = None
config: dict
progress_percent: float = 0.0
model_config = {"from_attributes": True}
class VoteCreate(BaseModel):
voter_id: str
target_id: str
reason: str = ""
class VoteResponse(BaseModel):
id: str
voter_id: str
target_id: str
round_number: int
reason: str
created_at: datetime
model_config = {"from_attributes": True}