schemas.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. from __future__ import annotations
  2. from typing import Any, Literal
  3. from pydantic import BaseModel, Field, field_validator
  4. ConfirmStatus = Literal["PENDING", "TRUSTED", "SUSPICIOUS", "IGNORED", "NEED_MORE_INFO"]
  5. ItemType = Literal["service", "process"]
  6. AiProviderType = Literal["OPENAI", "OPENAI_COMPATIBLE", "GOOGLE_GEMINI"]
  7. MouseAutomationAction = Literal["move_to", "move_rel", "click", "double_click", "right_click", "drag_to", "scroll"]
  8. KeyboardAutomationAction = Literal["press", "hotkey", "write", "key_down", "key_up"]
  9. AutomationNodeType = Literal["mouse", "keyboard", "text_input", "start_program", "close_programs"]
  10. class StatusUpdate(BaseModel):
  11. confirm_status: ConfirmStatus
  12. user_note: str | None = None
  13. class BatchStatusUpdate(BaseModel):
  14. ids: list[int] = Field(default_factory=list)
  15. confirm_status: ConfirmStatus
  16. user_note: str | None = None
  17. class AiImportItem(BaseModel):
  18. type: ItemType
  19. name: str
  20. description: str | None = None
  21. judgement: Literal["TRUSTED", "SUSPICIOUS", "NEED_MORE_INFO"]
  22. risk_level: Literal["LOW", "MEDIUM", "HIGH"]
  23. reason: str | None = None
  24. suggestion: str | None = None
  25. tags: list[str] | None = None
  26. @field_validator("tags", mode="before")
  27. @classmethod
  28. def normalize_tags(cls, value: Any) -> list[str] | None:
  29. if value is None:
  30. return None
  31. if isinstance(value, str):
  32. return [value]
  33. if isinstance(value, list):
  34. names: list[str] = []
  35. for item in value:
  36. if isinstance(item, str):
  37. names.append(item)
  38. elif isinstance(item, dict) and item.get("name"):
  39. names.append(str(item["name"]))
  40. return names
  41. raise ValueError("tags must be a string, list of strings, or list of objects with name")
  42. class AiImportRequest(BaseModel):
  43. items: list[AiImportItem]
  44. class PromptRequest(BaseModel):
  45. ids: list[int] | None = None
  46. scope: Literal["selected", "pending"] = "pending"
  47. class TagCreate(BaseModel):
  48. name: str = Field(min_length=1, max_length=80)
  49. description: str | None = None
  50. is_controllable: bool = True
  51. class TagUpdate(BaseModel):
  52. name: str = Field(min_length=1, max_length=80)
  53. description: str | None = None
  54. is_controllable: bool = True
  55. class TagAssignRequest(BaseModel):
  56. tag_ids: list[int] = Field(default_factory=list)
  57. class ProcessStartRequest(BaseModel):
  58. command: str = Field(min_length=1)
  59. cwd: str | None = None
  60. class AutomationPowerRequest(BaseModel):
  61. delay_seconds: int = Field(default=0, ge=0, le=86400)
  62. force: bool = False
  63. reason: str | None = Field(default=None, max_length=512)
  64. class AutomationProgramStartRequest(BaseModel):
  65. command: str = Field(min_length=1)
  66. cwd: str | None = None
  67. shell: bool = True
  68. class AutomationProgramStopRequest(BaseModel):
  69. pid: int | None = Field(default=None, ge=0)
  70. name: str | None = Field(default=None, min_length=1)
  71. timeout_seconds: float = Field(default=8, ge=0, le=60)
  72. kill_after_timeout: bool = True
  73. class AutomationScreenshotRequest(BaseModel):
  74. save_path: str | None = None
  75. include_base64: bool = True
  76. class AutomationMouseRequest(BaseModel):
  77. action: MouseAutomationAction
  78. x: int | None = None
  79. y: int | None = None
  80. duration: float = Field(default=0, ge=0, le=60)
  81. button: Literal["left", "middle", "right"] = "left"
  82. clicks: int = Field(default=1, ge=1, le=20)
  83. amount: int = 0
  84. class AutomationKeyboardRequest(BaseModel):
  85. action: KeyboardAutomationAction
  86. key: str | None = None
  87. keys: list[str] | None = None
  88. text: str | None = None
  89. interval: float = Field(default=0, ge=0, le=10)
  90. class AutomationVisionAnalyzeRequest(BaseModel):
  91. provider_id: int
  92. model_id: int
  93. temperature: float = Field(default=0.1, ge=0, le=2)
  94. class AutomationActionBase(BaseModel):
  95. screen_id: int | None = None
  96. provider_id: int | None = None
  97. model_id: int | None = None
  98. temperature: float = Field(default=0.1, ge=0, le=2)
  99. workflow_id: int | None = None
  100. node_id: int | None = None
  101. class AutomationMouseActionRequest(AutomationActionBase):
  102. x: int
  103. y: int
  104. mouse_action: Literal["click", "double_click", "right_click"]
  105. class AutomationKeyboardActionRequest(AutomationActionBase):
  106. keys: list[str] = Field(min_length=1)
  107. class AutomationTextInputRequest(AutomationActionBase):
  108. text: str
  109. class AutomationStartProgramRequest(AutomationActionBase):
  110. command: str = Field(min_length=1)
  111. cwd: str | None = None
  112. shell: bool = True
  113. class AutomationCloseProgramsRequest(BaseModel):
  114. pids: list[int] | None = None
  115. class AutomationWorkflowNode(BaseModel):
  116. node_type: AutomationNodeType
  117. screen_id: int | None = None
  118. title: str | None = None
  119. config: dict[str, Any] = Field(default_factory=dict)
  120. class AutomationWorkflowSaveRequest(BaseModel):
  121. name: str = Field(min_length=1, max_length=160)
  122. description: str | None = None
  123. nodes: list[AutomationWorkflowNode] = Field(default_factory=list)
  124. class AiProviderCreate(BaseModel):
  125. name: str = Field(min_length=1, max_length=120)
  126. provider_type: AiProviderType
  127. base_url: str | None = None
  128. api_key: str | None = None
  129. enabled: bool = True
  130. class AiProviderUpdate(BaseModel):
  131. name: str = Field(min_length=1, max_length=120)
  132. provider_type: AiProviderType
  133. base_url: str | None = None
  134. api_key: str | None = None
  135. clear_api_key: bool = False
  136. enabled: bool = True
  137. class AiModelCreate(BaseModel):
  138. provider_id: int
  139. name: str = Field(min_length=1, max_length=160)
  140. display_name: str | None = None
  141. is_default: bool = False
  142. class AiModelUpdate(BaseModel):
  143. provider_id: int
  144. name: str = Field(min_length=1, max_length=160)
  145. display_name: str | None = None
  146. is_default: bool = False
  147. class AiChatRequest(BaseModel):
  148. provider_id: int
  149. model_id: int
  150. prompt: str = Field(min_length=1)
  151. temperature: float = Field(default=0.2, ge=0, le=2)
  152. class AiAnalyzeRequest(BaseModel):
  153. provider_id: int
  154. model_id: int
  155. temperature: float = Field(default=0.2, ge=0, le=2)
  156. ids: list[int] | None = None
  157. scope: Literal["selected", "pending"] = "pending"