schemas.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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 = str
  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 | None = None
  92. model_id: int | None = None
  93. temperature: float = Field(default=0.1, ge=0, le=2)
  94. class AutomationScreenshotCaptureRequest(BaseModel):
  95. save: bool = True
  96. class AutomationElementLocateRequest(BaseModel):
  97. provider_id: int | None = None
  98. model_id: int | None = None
  99. temperature: float = Field(default=0.1, ge=0, le=2)
  100. class AutomationActionBase(BaseModel):
  101. screen_id: int | None = None
  102. provider_id: int | None = None
  103. model_id: int | None = None
  104. temperature: float = Field(default=0.1, ge=0, le=2)
  105. workflow_id: int | None = None
  106. node_id: int | None = None
  107. class AutomationMouseActionRequest(AutomationActionBase):
  108. x: int
  109. y: int
  110. mouse_action: Literal["click", "double_click", "right_click"]
  111. class AutomationKeyboardActionRequest(AutomationActionBase):
  112. keys: list[str] = Field(min_length=1)
  113. class AutomationTextInputRequest(AutomationActionBase):
  114. text: str
  115. class AutomationStartProgramRequest(AutomationActionBase):
  116. command: str = Field(min_length=1)
  117. cwd: str | None = None
  118. shell: bool = True
  119. class AutomationCloseProgramsRequest(BaseModel):
  120. pids: list[int] | None = None
  121. class AutomationWorkflowPosition(BaseModel):
  122. x: float = 80
  123. y: float = 80
  124. class AutomationWorkflowValueRef(BaseModel):
  125. source: Literal["literal", "variable", "node_output", "runtime"]
  126. value: Any = None
  127. name: str | None = None
  128. node_id: str | None = None
  129. output: str | None = None
  130. class AutomationWorkflowNode(BaseModel):
  131. id: str = Field(min_length=1, max_length=120)
  132. type: AutomationNodeType = Field(min_length=1, max_length=120)
  133. title: str | None = Field(default=None, max_length=160)
  134. position: AutomationWorkflowPosition = Field(default_factory=AutomationWorkflowPosition)
  135. params: dict[str, Any] = Field(default_factory=dict)
  136. inputs: dict[str, AutomationWorkflowValueRef | Any] = Field(default_factory=dict)
  137. class AutomationWorkflowSaveRequest(BaseModel):
  138. schema_version: Literal["workflow/v1"] = "workflow/v1"
  139. workflow_key: str | None = Field(default=None, min_length=1, max_length=80, pattern=r"^[a-zA-Z0-9][a-zA-Z0-9_-]*$")
  140. name: str = Field(min_length=1, max_length=160)
  141. description: str | None = None
  142. variables: dict[str, Any] = Field(default_factory=dict)
  143. settings: dict[str, Any] = Field(default_factory=dict)
  144. nodes: list[AutomationWorkflowNode] = Field(default_factory=list)
  145. edges: list[dict[str, Any]] = Field(default_factory=list)
  146. class AutomationWorkflowRunRequest(BaseModel):
  147. provider_id: int | None = None
  148. model_id: int | None = None
  149. temperature: float | None = Field(default=None, ge=0, le=2)
  150. variables: dict[str, Any] = Field(default_factory=dict)
  151. class AutomationWorkflowImportRequest(BaseModel):
  152. workflow: AutomationWorkflowSaveRequest
  153. conflict_strategy: Literal["error", "replace"] = "error"
  154. class AutomationWorkflowPlanRequest(BaseModel):
  155. requirement: str = Field(min_length=1, max_length=4000)
  156. provider_id: int | None = None
  157. model_id: int | None = None
  158. temperature: float | None = Field(default=None, ge=0, le=2)
  159. class AutomationWorkflowPlanContinueRequest(BaseModel):
  160. session_id: str = Field(min_length=1)
  161. user_message: str = Field(min_length=1, max_length=4000)
  162. provider_id: int | None = None
  163. model_id: int | None = None
  164. temperature: float | None = Field(default=None, ge=0, le=2)
  165. class SystemSettingsUpdate(BaseModel):
  166. default_ai_provider_id: int | None = None
  167. default_ai_model_id: int | None = None
  168. default_ai_temperature: float | None = Field(default=None, ge=0, le=2)
  169. automation_file_root: str | None = None
  170. automation_screen_path: str | None = None
  171. automation_error_path: str | None = None
  172. automation_runtime_path: str | None = None
  173. automation_auto_screenshot_enabled: bool | None = None
  174. automation_auto_screenshot_interval: int | None = Field(default=None, ge=1, le=3600)
  175. automation_remote_token: str | None = Field(default=None, max_length=256)
  176. class AiProviderCreate(BaseModel):
  177. name: str = Field(min_length=1, max_length=120)
  178. provider_type: AiProviderType
  179. base_url: str | None = None
  180. api_key: str | None = None
  181. enabled: bool = True
  182. class AiProviderUpdate(BaseModel):
  183. name: str = Field(min_length=1, max_length=120)
  184. provider_type: AiProviderType
  185. base_url: str | None = None
  186. api_key: str | None = None
  187. clear_api_key: bool = False
  188. enabled: bool = True
  189. class AiModelCreate(BaseModel):
  190. provider_id: int
  191. name: str = Field(min_length=1, max_length=160)
  192. display_name: str | None = None
  193. is_default: bool = False
  194. class AiModelUpdate(BaseModel):
  195. provider_id: int
  196. name: str = Field(min_length=1, max_length=160)
  197. display_name: str | None = None
  198. is_default: bool = False
  199. class AiChatRequest(BaseModel):
  200. provider_id: int
  201. model_id: int
  202. prompt: str = Field(min_length=1)
  203. temperature: float = Field(default=0.2, ge=0, le=2)
  204. class AiAnalyzeRequest(BaseModel):
  205. provider_id: int
  206. model_id: int
  207. temperature: float = Field(default=0.2, ge=0, le=2)
  208. ids: list[int] | None = None
  209. scope: Literal["selected", "pending"] = "pending"