precis-cli 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. app/__init__.py +16 -0
  2. app/api/__init__.py +32 -0
  3. app/api/dependencies.py +185 -0
  4. app/api/main.py +301 -0
  5. app/api/middleware/__init__.py +34 -0
  6. app/api/middleware/exception_handler.py +126 -0
  7. app/api/middleware/request_logging.py +97 -0
  8. app/api/middleware/token_auth.py +215 -0
  9. app/api/models/__init__.py +151 -0
  10. app/api/models/connection_rules.py +98 -0
  11. app/api/models/files.py +99 -0
  12. app/api/models/full_validation.py +554 -0
  13. app/api/models/project.py +117 -0
  14. app/api/models/projects.py +80 -0
  15. app/api/models/schema.py +121 -0
  16. app/api/models/v2_responses.py +46 -0
  17. app/api/models/validation.py +303 -0
  18. app/api/models/workspace.py +118 -0
  19. app/api/routers/__init__.py +56 -0
  20. app/api/routers/ai/__init__.py +36 -0
  21. app/api/routers/ai/chat.py +243 -0
  22. app/api/routers/ai/generate.py +156 -0
  23. app/api/routers/ai/hardware.py +199 -0
  24. app/api/routers/ai/jobs.py +544 -0
  25. app/api/routers/ai/migrate.py +471 -0
  26. app/api/routers/ai/models.py +352 -0
  27. app/api/routers/ai/ollama.py +108 -0
  28. app/api/routers/ai/providers.py +491 -0
  29. app/api/routers/ai/router.py +44 -0
  30. app/api/routers/ai/stream.py +281 -0
  31. app/api/routers/ai/utils.py +182 -0
  32. app/api/routers/core/__init__.py +34 -0
  33. app/api/routers/core/connection_rules.py +188 -0
  34. app/api/routers/core/data_sources.py +374 -0
  35. app/api/routers/core/regex.py +333 -0
  36. app/api/routers/core/reporting.py +263 -0
  37. app/api/routers/files/__init__.py +24 -0
  38. app/api/routers/files/ops.py +179 -0
  39. app/api/routers/files/transfer.py +101 -0
  40. app/api/routers/preview/__init__.py +35 -0
  41. app/api/routers/preview/content_mode.py +264 -0
  42. app/api/routers/preview/header_row.py +154 -0
  43. app/api/routers/preview/models.py +81 -0
  44. app/api/routers/preview/path_mode.py +440 -0
  45. app/api/routers/preview/router.py +30 -0
  46. app/api/routers/project/__init__.py +61 -0
  47. app/api/routers/project/base.py +111 -0
  48. app/api/routers/project/constraint.py +345 -0
  49. app/api/routers/project/full_config.py +411 -0
  50. app/api/routers/project/full_config_writer.py +327 -0
  51. app/api/routers/project/helpers.py +167 -0
  52. app/api/routers/project/inspection_fix.py +330 -0
  53. app/api/routers/project/manifest.py +605 -0
  54. app/api/routers/project/models.py +177 -0
  55. app/api/routers/project/pattern.py +268 -0
  56. app/api/routers/project/regex.py +358 -0
  57. app/api/routers/project/scanner.py +157 -0
  58. app/api/routers/project/schema.py +567 -0
  59. app/api/routers/project/schema_helpers.py +149 -0
  60. app/api/routers/project/settings.py +399 -0
  61. app/api/routers/project/template.py +325 -0
  62. app/api/routers/project/validation.py +227 -0
  63. app/api/routers/project/view.py +177 -0
  64. app/api/routers/project/workspaces.py +167 -0
  65. app/api/routers/projects/__init__.py +25 -0
  66. app/api/routers/projects/create.py +121 -0
  67. app/api/routers/projects/open.py +103 -0
  68. app/api/routers/projects/scan.py +100 -0
  69. app/api/routers/validation/__init__.py +39 -0
  70. app/api/routers/validation/common.py +263 -0
  71. app/api/routers/validation/content_mode.py +401 -0
  72. app/api/routers/validation/history.py +235 -0
  73. app/api/routers/validation/inline_mode.py +196 -0
  74. app/api/routers/validation/path_mode.py +314 -0
  75. app/api/routers/validation/router.py +51 -0
  76. app/api/services/full_validation_response_builder.py +412 -0
  77. app/api/services/io_error_messages.py +41 -0
  78. app/api/services/preview_service.py +248 -0
  79. app/cli/__init__.py +18 -0
  80. app/cli/__main__.py +30 -0
  81. app/cli/shared_services/__init__.py +42 -0
  82. app/cli/shared_services/config_ops.py +581 -0
  83. app/cli/shared_services/generation_ops.py +160 -0
  84. app/cli/shared_services/project_ops.py +288 -0
  85. app/cli/shell/__init__.py +48 -0
  86. app/cli/shell/commands/__init__.py +63 -0
  87. app/cli/shell/commands/ai/__init__.py +260 -0
  88. app/cli/shell/commands/ai/chat.py +331 -0
  89. app/cli/shell/commands/ai/delete.py +165 -0
  90. app/cli/shell/commands/ai/diff.py +70 -0
  91. app/cli/shell/commands/ai/display.py +428 -0
  92. app/cli/shell/commands/ai/executor.py +225 -0
  93. app/cli/shell/commands/ai/executor_utils.py +271 -0
  94. app/cli/shell/commands/ai/generate.py +285 -0
  95. app/cli/shell/commands/ai/interaction.py +262 -0
  96. app/cli/shell/commands/ai/migrate.py +281 -0
  97. app/cli/shell/commands/ai/resolver.py +224 -0
  98. app/cli/shell/commands/ai/status.py +101 -0
  99. app/cli/shell/commands/ai/switch.py +158 -0
  100. app/cli/shell/commands/ai/utils.py +52 -0
  101. app/cli/shell/commands/base.py +343 -0
  102. app/cli/shell/commands/config/__init__.py +131 -0
  103. app/cli/shell/commands/config/base.py +80 -0
  104. app/cli/shell/commands/config/check.py +246 -0
  105. app/cli/shell/commands/config/edit.py +148 -0
  106. app/cli/shell/commands/config/get.py +111 -0
  107. app/cli/shell/commands/config/init.py +123 -0
  108. app/cli/shell/commands/config/inspect.py +164 -0
  109. app/cli/shell/commands/config/list.py +104 -0
  110. app/cli/shell/commands/config/set.py +119 -0
  111. app/cli/shell/commands/config/show.py +150 -0
  112. app/cli/shell/commands/exit.py +67 -0
  113. app/cli/shell/commands/help.py +104 -0
  114. app/cli/shell/commands/infer_schema.py +156 -0
  115. app/cli/shell/commands/open.py +201 -0
  116. app/cli/shell/commands/project.py +215 -0
  117. app/cli/shell/commands/provider.py +619 -0
  118. app/cli/shell/commands/system.py +170 -0
  119. app/cli/shell/commands/validate.py +455 -0
  120. app/cli/shell/completer.py +231 -0
  121. app/cli/shell/config_storage.py +191 -0
  122. app/cli/shell/exceptions.py +90 -0
  123. app/cli/shell/formatter.py +371 -0
  124. app/cli/shell/interactive_menu.py +348 -0
  125. app/cli/shell/main.py +286 -0
  126. app/cli/shell/parser.py +266 -0
  127. app/cli/start.py +180 -0
  128. app/cli_main.py +52 -0
  129. app/mcp_server.py +311 -0
  130. app/shared/core/__init__.py +18 -0
  131. app/shared/core/app_version.py +59 -0
  132. app/shared/core/config/__init__.py +119 -0
  133. app/shared/core/config/server.py +193 -0
  134. app/shared/core/data_source/__init__.py +106 -0
  135. app/shared/core/data_source/loader.py +348 -0
  136. app/shared/core/data_source/loaders/__init__.py +213 -0
  137. app/shared/core/data_source/loaders/base.py +215 -0
  138. app/shared/core/data_source/loaders/converter.py +337 -0
  139. app/shared/core/data_source/loaders/csv_loader.py +252 -0
  140. app/shared/core/data_source/loaders/excel_loader.py +666 -0
  141. app/shared/core/data_source/loaders/extractor.py +268 -0
  142. app/shared/core/data_source/loaders/json_loader.py +354 -0
  143. app/shared/core/data_source/loaders/registry.py +88 -0
  144. app/shared/core/data_source/loaders/sql_loader.py +313 -0
  145. app/shared/core/data_source/loaders/strategies/__init__.py +100 -0
  146. app/shared/core/data_source/loaders/strategies/array_parser.py +277 -0
  147. app/shared/core/data_source/loaders/strategies/lines_parser.py +355 -0
  148. app/shared/core/data_source/loaders/strategies/object_parser.py +278 -0
  149. app/shared/core/data_source/schema_info.py +50 -0
  150. app/shared/core/data_source/specs/__init__.py +128 -0
  151. app/shared/core/data_source/specs/base.py +258 -0
  152. app/shared/core/data_source/specs/csv_source.py +137 -0
  153. app/shared/core/data_source/specs/excel_source.py +141 -0
  154. app/shared/core/data_source/specs/file_base.py +252 -0
  155. app/shared/core/data_source/specs/json_source.py +226 -0
  156. app/shared/core/data_source/specs/sql_source.py +161 -0
  157. app/shared/core/encoding.py +36 -0
  158. app/shared/core/io/__init__.py +24 -0
  159. app/shared/core/io/yaml.py +379 -0
  160. app/shared/core/manifest_schema/__init__.py +52 -0
  161. app/shared/core/manifest_schema/types.py +99 -0
  162. app/shared/core/manifest_schema/version.py +175 -0
  163. app/shared/core/patterns/__init__.py +24 -0
  164. app/shared/core/patterns/loader.py +134 -0
  165. app/shared/core/patterns/writer.py +244 -0
  166. app/shared/core/project/__init__.py +47 -0
  167. app/shared/core/project/constraint/builders/__init__.py +50 -0
  168. app/shared/core/project/constraint/builders/base.py +100 -0
  169. app/shared/core/project/constraint/builders/composite.py +77 -0
  170. app/shared/core/project/constraint/builders/conditional.py +67 -0
  171. app/shared/core/project/constraint/builders/foreign_key.py +53 -0
  172. app/shared/core/project/constraint/builders/registry.py +64 -0
  173. app/shared/core/project/constraint/builders/scripted.py +51 -0
  174. app/shared/core/project/constraint/builders/single_column.py +86 -0
  175. app/shared/core/project/constraint/builders/unique.py +53 -0
  176. app/shared/core/project/constraint/factory.py +170 -0
  177. app/shared/core/project/constraint/reader.py +214 -0
  178. app/shared/core/project/constraint/registry.py +233 -0
  179. app/shared/core/project/constraint/types/__init__.py +63 -0
  180. app/shared/core/project/constraint/types/constraint_file.py +261 -0
  181. app/shared/core/project/constraint/types/refs.py +460 -0
  182. app/shared/core/project/constraint/types.py +28 -0
  183. app/shared/core/project/constraint/writer.py +181 -0
  184. app/shared/core/project/loader/__init__.py +56 -0
  185. app/shared/core/project/loader/loader.py +30 -0
  186. app/shared/core/project/loader/loader_parts/config_inspector.py +137 -0
  187. app/shared/core/project/loader/loader_parts/embedded_constraints.py +224 -0
  188. app/shared/core/project/loader/loader_parts/file_loaders.py +58 -0
  189. app/shared/core/project/loader/loader_parts/inspection_ids.py +85 -0
  190. app/shared/core/project/loader/loader_parts/inspector_helpers.py +312 -0
  191. app/shared/core/project/loader/loader_parts/inspector_id_checks.py +274 -0
  192. app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +690 -0
  193. app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +286 -0
  194. app/shared/core/project/loader/loader_parts/loading_error_messages.py +298 -0
  195. app/shared/core/project/loader/loader_parts/main.py +432 -0
  196. app/shared/core/project/loader/loader_parts/path_validation.py +117 -0
  197. app/shared/core/project/loader/loader_parts/runtime.py +125 -0
  198. app/shared/core/project/loader/types.py +246 -0
  199. app/shared/core/project/manifest/coverage.py +391 -0
  200. app/shared/core/project/manifest/reader.py +260 -0
  201. app/shared/core/project/manifest/types.py +91 -0
  202. app/shared/core/project/manifest/types_parts/__init__.py +60 -0
  203. app/shared/core/project/manifest/types_parts/constants.py +40 -0
  204. app/shared/core/project/manifest/types_parts/data_source.py +68 -0
  205. app/shared/core/project/manifest/types_parts/info.py +59 -0
  206. app/shared/core/project/manifest/types_parts/manifest.py +294 -0
  207. app/shared/core/project/manifest/types_parts/refs.py +153 -0
  208. app/shared/core/project/manifest/types_parts/settings.py +92 -0
  209. app/shared/core/project/manifest/types_parts/settings_file_processing.py +64 -0
  210. app/shared/core/project/manifest/types_parts/settings_script_security.py +78 -0
  211. app/shared/core/project/manifest/types_parts/settings_validation.py +83 -0
  212. app/shared/core/project/manifest/types_parts/template.py +66 -0
  213. app/shared/core/project/manifest/writer.py +262 -0
  214. app/shared/core/project/manual_data/__init__.py +27 -0
  215. app/shared/core/project/manual_data/types.py +75 -0
  216. app/shared/core/project/regex/reader.py +197 -0
  217. app/shared/core/project/regex/types.py +405 -0
  218. app/shared/core/project/regex/writer.py +123 -0
  219. app/shared/core/project/schema/reader.py +170 -0
  220. app/shared/core/project/schema/types.py +47 -0
  221. app/shared/core/project/schema/types_parts/__init__.py +36 -0
  222. app/shared/core/project/schema/types_parts/column.py +174 -0
  223. app/shared/core/project/schema/types_parts/column_utils.py +72 -0
  224. app/shared/core/project/schema/types_parts/constraint.py +165 -0
  225. app/shared/core/project/schema/types_parts/schema_id.py +66 -0
  226. app/shared/core/project/schema/types_parts/source.py +255 -0
  227. app/shared/core/project/schema/types_parts/source_options.py +347 -0
  228. app/shared/core/project/schema/types_parts/table.py +230 -0
  229. app/shared/core/project/schema/writer.py +139 -0
  230. app/shared/core/project/schema_ref_check.py +95 -0
  231. app/shared/core/project/template/__init__.py +27 -0
  232. app/shared/core/project/template/expander.py +263 -0
  233. app/shared/core/project/template/reader.py +120 -0
  234. app/shared/core/project/template/types.py +114 -0
  235. app/shared/core/project/transform/reader.py +76 -0
  236. app/shared/core/project/transform/types.py +116 -0
  237. app/shared/core/project/transform/writer.py +84 -0
  238. app/shared/core/pydantic_messages.py +59 -0
  239. app/shared/core/reporter/__init__.py +46 -0
  240. app/shared/core/reporter/reporter.py +220 -0
  241. app/shared/core/reporter/reporters/__init__.py +65 -0
  242. app/shared/core/reporter/reporters/base.py +188 -0
  243. app/shared/core/reporter/reporters/dingtalk_app_reporter.py +274 -0
  244. app/shared/core/reporter/reporters/email_reporter.py +271 -0
  245. app/shared/core/reporter/reporters/feishu_app_reporter.py +467 -0
  246. app/shared/core/reporter/reporters/local_file_reporter.py +208 -0
  247. app/shared/core/reporter/reporters/wecom_app_reporter.py +268 -0
  248. app/shared/core/utils/__init__.py +18 -0
  249. app/shared/core/utils/path_utils.py +60 -0
  250. app/shared/core/utils/regex_extract.py +113 -0
  251. app/shared/domain/__init__.py +114 -0
  252. app/shared/domain/constraints/__init__.py +76 -0
  253. app/shared/domain/constraints/allowed_values.py +211 -0
  254. app/shared/domain/constraints/base.py +141 -0
  255. app/shared/domain/constraints/charset.py +337 -0
  256. app/shared/domain/constraints/composite.py +174 -0
  257. app/shared/domain/constraints/condition_registry.py +130 -0
  258. app/shared/domain/constraints/conditional.py +629 -0
  259. app/shared/domain/constraints/date_logic.py +731 -0
  260. app/shared/domain/constraints/foreign_key.py +261 -0
  261. app/shared/domain/constraints/key_normalization.py +56 -0
  262. app/shared/domain/constraints/not_null.py +185 -0
  263. app/shared/domain/constraints/range.py +360 -0
  264. app/shared/domain/constraints/regex.py +218 -0
  265. app/shared/domain/constraints/scripted.py +276 -0
  266. app/shared/domain/constraints/unique.py +233 -0
  267. app/shared/domain/data_engine.py +384 -0
  268. app/shared/domain/data_types.py +113 -0
  269. app/shared/domain/data_types_parts/__init__.py +67 -0
  270. app/shared/domain/data_types_parts/base.py +204 -0
  271. app/shared/domain/data_types_parts/composite.py +250 -0
  272. app/shared/domain/data_types_parts/expression.py +202 -0
  273. app/shared/domain/data_types_parts/extracted.py +106 -0
  274. app/shared/domain/data_types_parts/json_types.py +234 -0
  275. app/shared/domain/data_types_parts/scalars.py +719 -0
  276. app/shared/domain/data_types_parts/sequence.py +129 -0
  277. app/shared/domain/dataset_schema.py +48 -0
  278. app/shared/domain/eval_sandbox.py +63 -0
  279. app/shared/domain/expression_system.py +366 -0
  280. app/shared/domain/regex_flags.py +53 -0
  281. app/shared/domain/schema/builder.py +223 -0
  282. app/shared/domain/schema/models.py +339 -0
  283. app/shared/domain/transforms/__init__.py +28 -0
  284. app/shared/domain/transforms/aggregate.py +141 -0
  285. app/shared/domain/transforms/base.py +171 -0
  286. app/shared/domain/transforms/cast_type.py +120 -0
  287. app/shared/domain/transforms/concat.py +103 -0
  288. app/shared/domain/transforms/conditional_assign.py +114 -0
  289. app/shared/domain/transforms/date_format.py +81 -0
  290. app/shared/domain/transforms/digits.py +77 -0
  291. app/shared/domain/transforms/drop_duplicates.py +94 -0
  292. app/shared/domain/transforms/fill_na.py +94 -0
  293. app/shared/domain/transforms/filter_rows.py +97 -0
  294. app/shared/domain/transforms/lookup.py +78 -0
  295. app/shared/domain/transforms/lower_case.py +70 -0
  296. app/shared/domain/transforms/map_value.py +90 -0
  297. app/shared/domain/transforms/math_expr.py +112 -0
  298. app/shared/domain/transforms/modulo.py +82 -0
  299. app/shared/domain/transforms/regex_extract.py +103 -0
  300. app/shared/domain/transforms/registry.py +95 -0
  301. app/shared/domain/transforms/replace.py +88 -0
  302. app/shared/domain/transforms/sort_rows.py +94 -0
  303. app/shared/domain/transforms/string_split.py +84 -0
  304. app/shared/domain/transforms/strip.py +73 -0
  305. app/shared/domain/transforms/substring.py +92 -0
  306. app/shared/domain/transforms/upper_case.py +70 -0
  307. app/shared/domain/transforms/weighted_sum.py +104 -0
  308. app/shared/domain/validation_constraints.py +69 -0
  309. app/shared/services/__init__.py +62 -0
  310. app/shared/services/ai/__init__.py +48 -0
  311. app/shared/services/ai/agent/__init__.py +40 -0
  312. app/shared/services/ai/agent/chat_tools/__init__.py +47 -0
  313. app/shared/services/ai/agent/chat_tools/apply_actions.py +592 -0
  314. app/shared/services/ai/agent/chat_tools/ask_user.py +237 -0
  315. app/shared/services/ai/agent/chat_tools/read_canvas.py +140 -0
  316. app/shared/services/ai/agent/chat_tools/read_project.py +160 -0
  317. app/shared/services/ai/agent/chat_tools/read_table.py +301 -0
  318. app/shared/services/ai/agent/chat_tools/schemas.py +105 -0
  319. app/shared/services/ai/agent/chat_tools/validate_table.py +131 -0
  320. app/shared/services/ai/agent/executor.py +554 -0
  321. app/shared/services/ai/agent/memory.py +256 -0
  322. app/shared/services/ai/agent/planner.py +282 -0
  323. app/shared/services/ai/agent/tool_registry.py +296 -0
  324. app/shared/services/ai/agent/tools/__init__.py +32 -0
  325. app/shared/services/ai/agent/tools/config_generate.py +133 -0
  326. app/shared/services/ai/agent/tools/config_refine.py +109 -0
  327. app/shared/services/ai/agent/tools/config_validate.py +403 -0
  328. app/shared/services/ai/agent/tools/merge_results.py +136 -0
  329. app/shared/services/ai/agent/tools/plan_chunks.py +79 -0
  330. app/shared/services/ai/agent/tools/script_parse.py +359 -0
  331. app/shared/services/ai/agent/types.py +138 -0
  332. app/shared/services/ai/chat_agent_runner.py +596 -0
  333. app/shared/services/ai/chat_orchestrator.py +725 -0
  334. app/shared/services/ai/failure_messages.py +65 -0
  335. app/shared/services/ai/job_storage.py +274 -0
  336. app/shared/services/ai/migrate_service.py +550 -0
  337. app/shared/services/ai/streaming/__init__.py +65 -0
  338. app/shared/services/ai/streaming/event_journal.py +197 -0
  339. app/shared/services/ai/streaming/orchestrator.py +262 -0
  340. app/shared/services/ai/streaming/pending_interaction_store.py +227 -0
  341. app/shared/services/ai/streaming/sse_response.py +148 -0
  342. app/shared/services/ai/streaming/types.py +73 -0
  343. app/shared/services/ai/types.py +213 -0
  344. app/shared/services/ai/utils.py +322 -0
  345. app/shared/services/diff/config_diff.py +320 -0
  346. app/shared/services/hardware.py +237 -0
  347. app/shared/services/llm/__init__.py +62 -0
  348. app/shared/services/llm/actions/__init__.py +42 -0
  349. app/shared/services/llm/actions/_canvas_validator.py +147 -0
  350. app/shared/services/llm/actions/_constraint_validator.py +401 -0
  351. app/shared/services/llm/actions/_regex_validator.py +85 -0
  352. app/shared/services/llm/actions/_schema_validator.py +82 -0
  353. app/shared/services/llm/actions/_settings_validator.py +76 -0
  354. app/shared/services/llm/actions/_transform_validator.py +78 -0
  355. app/shared/services/llm/actions/action_handlers.py +400 -0
  356. app/shared/services/llm/actions/action_parser.py +63 -0
  357. app/shared/services/llm/actions/action_processor.py +468 -0
  358. app/shared/services/llm/actions/action_validator.py +311 -0
  359. app/shared/services/llm/actions/diff_compute.py +195 -0
  360. app/shared/services/llm/actions/regex_handlers.py +284 -0
  361. app/shared/services/llm/actions/registry.py +336 -0
  362. app/shared/services/llm/actions/schema_handlers.py +335 -0
  363. app/shared/services/llm/actions/settings_handlers.py +180 -0
  364. app/shared/services/llm/actions/specs.py +259 -0
  365. app/shared/services/llm/actions/transform_handlers.py +279 -0
  366. app/shared/services/llm/actions/validation_types.py +147 -0
  367. app/shared/services/llm/cache/__init__.py +18 -0
  368. app/shared/services/llm/cache/response_cache.py +80 -0
  369. app/shared/services/llm/chat/__init__.py +35 -0
  370. app/shared/services/llm/chat/chat_system_prompt.py +561 -0
  371. app/shared/services/llm/chat/response_parser.py +296 -0
  372. app/shared/services/llm/config/__init__.py +45 -0
  373. app/shared/services/llm/config/crypto.py +135 -0
  374. app/shared/services/llm/config/loader.py +258 -0
  375. app/shared/services/llm/config/models.py +202 -0
  376. app/shared/services/llm/config/presets.py +128 -0
  377. app/shared/services/llm/config_generator.py +163 -0
  378. app/shared/services/llm/constraints/__init__.py +41 -0
  379. app/shared/services/llm/constraints/constraint_builder.py +177 -0
  380. app/shared/services/llm/constraints/constraint_deletion.py +84 -0
  381. app/shared/services/llm/constraints/constraint_id.py +174 -0
  382. app/shared/services/llm/constraints/frontend_instructions.py +333 -0
  383. app/shared/services/llm/constraints/inline_batch.py +279 -0
  384. app/shared/services/llm/discovery/__init__.py +35 -0
  385. app/shared/services/llm/discovery/scanner.py +181 -0
  386. app/shared/services/llm/generation/__init__.py +42 -0
  387. app/shared/services/llm/generation/agent_wiring.py +156 -0
  388. app/shared/services/llm/generation/config_builder.py +386 -0
  389. app/shared/services/llm/generation/errors.py +36 -0
  390. app/shared/services/llm/generation/existing_config.py +99 -0
  391. app/shared/services/llm/generation/profiler.py +279 -0
  392. app/shared/services/llm/generation/prompt_builder.py +199 -0
  393. app/shared/services/llm/generation/response_parser.py +144 -0
  394. app/shared/services/llm/generation/service.py +622 -0
  395. app/shared/services/llm/models.py +104 -0
  396. app/shared/services/llm/providers/__init__.py +48 -0
  397. app/shared/services/llm/providers/base.py +310 -0
  398. app/shared/services/llm/providers/cached_provider.py +90 -0
  399. app/shared/services/llm/providers/ollama.py +498 -0
  400. app/shared/services/llm/providers/openai.py +334 -0
  401. app/shared/services/llm/providers/registry.py +108 -0
  402. app/shared/services/llm/schema_resolver.py +141 -0
  403. app/shared/services/llm/suggestion_utils.py +219 -0
  404. app/shared/services/llm/validate_executor.py +163 -0
  405. app/shared/services/llm/yaml_io.py +406 -0
  406. app/shared/services/preview/__init__.py +18 -0
  407. app/shared/services/preview/loader.py +145 -0
  408. app/shared/services/preview/path_validation.py +138 -0
  409. app/shared/services/project_loader.py +57 -0
  410. app/shared/services/schema_inference.py +260 -0
  411. app/shared/services/schema_runtime_builder.py +120 -0
  412. app/shared/services/validation/__init__.py +52 -0
  413. app/shared/services/validation/chunked_loader.py +509 -0
  414. app/shared/services/validation/dag/__init__.py +35 -0
  415. app/shared/services/validation/dag/builder.py +141 -0
  416. app/shared/services/validation/dag/executor.py +225 -0
  417. app/shared/services/validation/dag/sorter.py +77 -0
  418. app/shared/services/validation/data_loader.py +231 -0
  419. app/shared/services/validation/engine.py +446 -0
  420. app/shared/services/validation/executor.py +1030 -0
  421. app/shared/services/validation/extractors.py +266 -0
  422. app/shared/services/validation/history.py +209 -0
  423. app/shared/services/validation/json_payload.py +136 -0
  424. app/shared/services/validation/loader.py +152 -0
  425. app/shared/services/validation/memory_monitor.py +179 -0
  426. app/shared/services/validation/postprocess.py +208 -0
  427. app/shared/services/validation/progress.py +64 -0
  428. app/shared/services/validation/report_export.py +222 -0
  429. app/shared/services/validation/resolver.py +180 -0
  430. app/shared/services/validation/service.py +418 -0
  431. app/shared/services/validation/types.py +238 -0
  432. app/shared/services/validation/validators/__init__.py +36 -0
  433. app/shared/services/validation/validators/adapter.py +182 -0
  434. app/shared/services/validation/validators/base.py +332 -0
  435. app/shared/services/validation/validators/composite.py +233 -0
  436. app/shared/services/validation/validators/date_logic.py +276 -0
  437. app/start_server.py +133 -0
  438. precis_cli-0.1.3.dist-info/METADATA +180 -0
  439. precis_cli-0.1.3.dist-info/RECORD +442 -0
  440. precis_cli-0.1.3.dist-info/WHEEL +5 -0
  441. precis_cli-0.1.3.dist-info/entry_points.txt +4 -0
  442. precis_cli-0.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,258 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview AI 配置加载器
18
+
19
+ 功能概述:
20
+ - 从 ~/.precis/ai_providers.yaml 加载 AI Provider 配置
21
+ - 支持环境变量 ${VAR} 递归替换
22
+ - API Key 加密存储(Fernet 对称加密)
23
+ - 配置版本检查(仅兼容 2.x)
24
+ - 首次使用自动创建默认配置模板
25
+ - mtime 缓存避免重复文件读取
26
+
27
+ 设计原则:
28
+ - AI Provider 配置是用户级全局设置,不属于项目仓库
29
+ - 统一固定读取 ~/.precis/ai_providers.yaml
30
+ - save() 始终写入用户级路径
31
+ - api_key 加密存储:YAML 中以 "enc:" 前缀标记加密值
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import os
37
+ import re
38
+ from pathlib import Path
39
+ from typing import Any
40
+
41
+ import yaml
42
+
43
+ from app.shared.core.config import ConfigPaths
44
+ from app.shared.core.io.yaml import write_yaml_atomic
45
+
46
+ from .crypto import decrypt_api_key, encrypt_api_key, is_encrypted
47
+ from .models import AIConfig, AIProvider
48
+
49
+
50
+ class ConfigLoader:
51
+ """
52
+ @classdesc 配置加载器 - 只支持 v2.0
53
+
54
+ AI Provider 配置固定存放在用户级路径 ~/.precis/ai_providers.yaml,
55
+ 不再支持项目级或系统级配置查找。
56
+ """
57
+
58
+ CONFIG_FILENAME = "ai_providers.yaml"
59
+
60
+ _cached_config: AIConfig | None = None
61
+ _cached_mtime: float | None = None
62
+
63
+ def __init__(self, config_path: Path | None = None):
64
+ """
65
+ @methoddesc 初始化配置加载器
66
+
67
+ 参数:
68
+ config_path: 可选,自定义配置文件路径。主要用于测试。
69
+ 未提供时固定使用 ~/.precis/ai_providers.yaml。
70
+ """
71
+ self._config_path = config_path
72
+ # §2.12: env 注入 api_key 的 provider id 集合(save 时剔除不落盘)
73
+ self._env_sourced_providers: set[str] = set()
74
+
75
+ @property
76
+ def config_path(self) -> Path:
77
+ """用户级 AI 配置文件路径(唯一真相源)"""
78
+ if self._config_path is not None:
79
+ return self._config_path
80
+ return ConfigPaths.ai_providers()
81
+
82
+ @config_path.setter
83
+ def config_path(self, value: Path) -> None:
84
+ """允许测试注入自定义路径。"""
85
+ self._config_path = value
86
+
87
+ @property
88
+ def USER_PATH(self) -> Path: # noqa: N802
89
+ """用户级配置路径(save 的写入目标)"""
90
+ return self.config_path
91
+
92
+ def _expand_env(self, value: Any) -> Any:
93
+ """
94
+ @methoddesc 递归替换字符串中的环境变量 ${VAR}
95
+
96
+ 支持字符串、字典、列表的递归处理。
97
+ 如果环境变量不存在,替换为空字符串。
98
+ """
99
+ if isinstance(value, str):
100
+ return re.sub(r"\$\{([^}]+)\}", lambda m: os.getenv(m.group(1), ""), value)
101
+ elif isinstance(value, dict):
102
+ return {k: self._expand_env(v) for k, v in value.items()}
103
+ elif isinstance(value, list):
104
+ return [self._expand_env(v) for v in value]
105
+ return value
106
+
107
+ def _decrypt_api_keys(self, data: Any) -> Any:
108
+ """递归解密 api_key 字段中的加密值。"""
109
+ if isinstance(data, dict):
110
+ result: dict[Any, Any] = {}
111
+ for k, v in data.items():
112
+ if k == "api_key" and isinstance(v, str) and is_encrypted(v):
113
+ result[k] = decrypt_api_key(v)
114
+ else:
115
+ result[k] = self._decrypt_api_keys(v)
116
+ return result
117
+ elif isinstance(data, list):
118
+ return [self._decrypt_api_keys(item) for item in data]
119
+ return data
120
+
121
+ def _encrypt_api_keys(self, data: Any) -> Any:
122
+ """递归加密 api_key 字段中的明文值。"""
123
+ if isinstance(data, dict):
124
+ result: dict[Any, Any] = {}
125
+ for k, v in data.items():
126
+ if k == "api_key" and isinstance(v, str) and v and not is_encrypted(v) and not re.search(r"\$\{", v):
127
+ result[k] = encrypt_api_key(v)
128
+ else:
129
+ result[k] = self._encrypt_api_keys(v)
130
+ return result
131
+ elif isinstance(data, list):
132
+ return [self._encrypt_api_keys(item) for item in data]
133
+ return data
134
+
135
+ def load(self) -> AIConfig:
136
+ """
137
+ @methoddesc 加载 AI Provider 配置文件
138
+
139
+ 固定读取 ~/.precis/ai_providers.yaml。
140
+ 文件不存在时自动创建默认模板并返回。
141
+ """
142
+ config_path = self.config_path
143
+
144
+ if self._cached_config is not None and config_path.exists():
145
+ try:
146
+ current_mtime = config_path.stat().st_mtime
147
+ if current_mtime == self._cached_mtime:
148
+ return self._cached_config
149
+ except OSError:
150
+ pass
151
+
152
+ if not config_path.exists():
153
+ config = self._create_default()
154
+ self.save(config)
155
+ return config
156
+
157
+ with open(config_path, encoding="utf-8") as f:
158
+ data = yaml.safe_load(f) or {}
159
+
160
+ version = data.get("version", "unknown")
161
+ if not isinstance(version, str) or not version.startswith("2."):
162
+ raise ValueError(f"Unsupported config version: {version}, expected 2.x")
163
+
164
+ data = self._expand_env(data)
165
+ data = self._decrypt_api_keys(data)
166
+ config = AIConfig(**data)
167
+ self._load_api_keys_from_env(config)
168
+
169
+ try:
170
+ self._cached_mtime = config_path.stat().st_mtime
171
+ self._cached_config = config
172
+ except OSError:
173
+ pass
174
+
175
+ return config
176
+
177
+ def _load_api_keys_from_env(self, config: AIConfig) -> None:
178
+ """从环境变量读取 API Key(优先级高于配置文件)。
179
+
180
+ §2.12: 注入的同时记录 env 来源的 provider id——save() 据此把 env 来源的
181
+ api_key 从落盘数据剔除,保持"env 覆盖是临时语义";用户显式改 key 的路径
182
+ 调 mark_api_key_manual() 后正常落盘。
183
+ """
184
+ for provider in config.providers:
185
+ env_key = f"{provider.id.upper().replace('-', '_')}_API_KEY"
186
+ api_key = os.getenv(env_key)
187
+
188
+ if not api_key:
189
+ provider_type = provider.type.value if hasattr(provider.type, "value") else str(provider.type)
190
+ env_key = f"{provider_type.upper()}_API_KEY"
191
+ api_key = os.getenv(env_key)
192
+
193
+ if api_key:
194
+ provider.api_key = api_key
195
+ self._env_sourced_providers.add(provider.id)
196
+
197
+ def mark_api_key_manual(self, provider_id: str) -> None:
198
+ """把 provider 的 api_key 标记为手工设置(save 时正常落盘,不再按 env 来源剔除)。"""
199
+ self._env_sourced_providers.discard(provider_id)
200
+
201
+ def save(self, config: AIConfig) -> None:
202
+ """
203
+ @methoddesc 将配置保存到用户级 YAML 文件
204
+
205
+ 始终写入 ~/.precis/ai_providers.yaml。
206
+ 使用原子写入(临时文件 + os.replace):此文件含 API Key 等敏感配置,
207
+ 裸 open("w") 在写入中途崩溃/断电会产生半截文件,导致用户配置丢失。
208
+
209
+ §2.12: env 注入的 api_key 不落盘(否则 env 覆盖被一次性写死进配置文件,
210
+ 用户此后换 env 变量不再生效还以为 env 是活的)。
211
+ """
212
+ user_path = self.config_path
213
+ user_path.parent.mkdir(parents=True, exist_ok=True)
214
+
215
+ data = config.model_dump(exclude_none=True)
216
+ data = self._encrypt_api_keys(data)
217
+
218
+ if self._env_sourced_providers:
219
+ for provider_data in data.get("providers", []):
220
+ if provider_data.get("id") in self._env_sourced_providers:
221
+ provider_data.pop("api_key", None)
222
+
223
+ write_yaml_atomic(user_path, data)
224
+
225
+ self.invalidate_cache()
226
+
227
+ def invalidate_cache(self) -> None:
228
+ """清除缓存,强制下次 load() 重新读取文件"""
229
+ self._cached_config = None
230
+ self._cached_mtime = None
231
+
232
+ def _create_default(self) -> AIConfig:
233
+ """创建默认配置模板(DeepSeek + Ollama Local)。"""
234
+ return AIConfig(
235
+ providers=[
236
+ AIProvider(
237
+ id="deepseek",
238
+ name="DeepSeek",
239
+ type="openai",
240
+ base_url="https://api.deepseek.com",
241
+ api_key="${DEEPSEEK_API_KEY}",
242
+ model="deepseek-v4-pro",
243
+ ),
244
+ AIProvider(
245
+ id="ollama-local",
246
+ name="Ollama Local",
247
+ type="ollama",
248
+ base_url="http://localhost:11434",
249
+ api_key=None,
250
+ model="llama3.2",
251
+ ),
252
+ ],
253
+ defaults={"chat": "deepseek"},
254
+ )
255
+
256
+
257
+ # 全局实例
258
+ loader = ConfigLoader()
@@ -0,0 +1,202 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview AI Provider 配置模型
18
+
19
+ 功能概述:
20
+ - 定义 AI Provider 的配置结构(AIProvider、AIConfig)
21
+ - 定义 Provider 类型枚举(ProviderType、DeploymentType)
22
+ - 定义网络配置模型(NetworkConfig)
23
+ - 支持根据 base_url 自动推断部署类型(本地/远程)
24
+
25
+ 架构设计:
26
+ - 使用 Pydantic BaseModel 进行数据校验和序列化
27
+ - 字段验证器自动推断 deployment 字段
28
+ - 配置版本固定为 2.0,确保向前兼容
29
+
30
+ 输入示例:
31
+ # ~/.precis/ai_providers.yaml
32
+ version: "2.0"
33
+ providers:
34
+ - id: ollama-local
35
+ name: Ollama
36
+ type: ollama
37
+ base_url: http://localhost:11434
38
+ api_key: null
39
+ model: llama3.2
40
+
41
+ 输出示例:
42
+ AIConfig(
43
+ version="2.0",
44
+ providers=[AIProvider(id="ollama-local", ..., deployment=DeploymentType.LOCAL)],
45
+ defaults={"chat": "ollama-local"}
46
+ )
47
+ """
48
+
49
+ from enum import Enum
50
+ from typing import Any
51
+
52
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
53
+
54
+
55
+ class ProviderType(str, Enum):
56
+ """
57
+ @classdesc Provider 类型枚举
58
+
59
+ 定义支持的 AI Provider 类型:
60
+ - OPENAI: OpenAI 兼容 API(云端/本地通用)
61
+ - OLLAMA: Ollama 原生 API
62
+ """
63
+
64
+ OPENAI = "openai" # OpenAI 兼容 API(云端/本地通用)
65
+ OLLAMA = "ollama" # Ollama 原生 API
66
+
67
+
68
+ class DeploymentType(str, Enum):
69
+ """
70
+ @classdesc 部署类型枚举
71
+
72
+ 根据 base_url 自动推断部署位置:
73
+ - LOCAL: 本地(localhost/127.0.0.1)
74
+ - REMOTE: 远程(内网/公网)
75
+ """
76
+
77
+ LOCAL = "local" # 本地(localhost/127.0.0.1)
78
+ REMOTE = "remote" # 远程(内网/公网)
79
+
80
+
81
+ class NetworkConfig(BaseModel):
82
+ """
83
+ @classdesc 网络连接配置
84
+
85
+ 控制与 AI Provider 通信时的超时和 SSL 校验行为。
86
+
87
+ Attributes:
88
+ timeout: 请求超时时间(秒),范围 5~300,默认 60
89
+ verify_ssl: 是否验证 SSL 证书,默认 True
90
+ """
91
+
92
+ model_config = ConfigDict(use_enum_values=True)
93
+
94
+ timeout: int = Field(default=60, ge=5, le=300, description="请求超时时间(秒)")
95
+ verify_ssl: bool = Field(default=True, description="是否验证 SSL 证书")
96
+
97
+
98
+ class AICacheConfig(BaseModel):
99
+ """
100
+ @classdesc LLM 响应缓存配置
101
+
102
+ 控制 CachedProvider 的缓存行为。默认关闭,显式开启才生效。
103
+
104
+ Attributes:
105
+ enabled: 是否启用缓存,默认 False
106
+ ttl_seconds: 缓存条目过期时间(秒),默认 3600
107
+ max_entries: 缓存最大条目数(LRU 驱逐),默认 100
108
+ cache_temperature_above_zero: 是否缓存 temperature > 0 的请求,默认 False
109
+ """
110
+
111
+ model_config = ConfigDict(use_enum_values=True)
112
+
113
+ enabled: bool = Field(default=False, description="是否启用 LLM 响应缓存")
114
+ ttl_seconds: float = Field(default=3600, ge=1, description="缓存条目过期时间(秒)")
115
+ max_entries: int = Field(default=100, ge=1, description="缓存最大条目数")
116
+ cache_temperature_above_zero: bool = Field(default=False, description="是否缓存 temperature > 0 的请求")
117
+
118
+
119
+ class AIProvider(BaseModel):
120
+ """
121
+ @classdesc AI Provider 配置模型
122
+
123
+ 定义一个 LLM 服务提供者的完整配置信息。
124
+ 设计简化:所有核心字段必填,无向后兼容逻辑。
125
+
126
+ Attributes:
127
+ id: Provider 唯一标识符(如 "openai", "ollama-local")
128
+ name: 显示名称(用于界面展示)
129
+ type: Provider 类型枚举(OPENAI 或 OLLAMA)
130
+ base_url: API 基础 URL(如 https://api.openai.com/v1)
131
+ api_key: API 密钥,本地服务可设为 null
132
+ model: 默认使用的模型名称(如 "gpt-4", "llama3.2")
133
+ context_window: 模型最大上下文窗口(tokens),None 则自动推断
134
+ deployment: 部署类型(LOCAL/REMOTE),根据 base_url 自动推断
135
+ network: 网络连接配置(可选)
136
+ meta: 额外元数据字典(可选)
137
+ """
138
+
139
+ model_config = ConfigDict(use_enum_values=True)
140
+
141
+ id: str = Field(..., description="唯一标识")
142
+ name: str = Field(..., description="显示名称")
143
+ type: ProviderType = Field(..., description="Provider 类型")
144
+
145
+ base_url: str = Field(..., description="API 基础 URL")
146
+ api_key: str | None = Field(default=None, description="API 密钥(本地服务可为 null)")
147
+ model: str = Field(..., description="默认模型名称")
148
+ context_window: int | None = Field(
149
+ default=None,
150
+ ge=1024,
151
+ description="模型最大上下文窗口(tokens),None 时由 Provider 根据模型名自动推断",
152
+ )
153
+
154
+ # 运行时推断字段(不序列化到配置文件)
155
+ deployment: DeploymentType | None = Field(default=None, exclude=True, description="部署类型(自动推断)")
156
+
157
+ # 可选扩展配置
158
+ network: NetworkConfig | None = Field(default=None, description="网络配置")
159
+ meta: dict[str, Any] | None = Field(default=None, description="额外元数据")
160
+
161
+ @model_validator(mode="after")
162
+ def _infer_deployment(self) -> "AIProvider":
163
+ """
164
+ @methoddesc 根据 base_url 推断部署类型
165
+
166
+ 如果 URL 中包含 localhost、127.0.0.1 等本地地址,
167
+ 则推断为 LOCAL,否则为 REMOTE。
168
+ 使用 model_validator 确保在所有字段初始化后执行。
169
+ """
170
+ if self.deployment is None:
171
+ local_hosts = ["localhost", "127.0.0.1", "0.0.0.0", "::1"]
172
+ if any(h in self.base_url for h in local_hosts):
173
+ self.deployment = DeploymentType.LOCAL
174
+ else:
175
+ self.deployment = DeploymentType.REMOTE
176
+ return self
177
+
178
+
179
+ class AIConfig(BaseModel):
180
+ """
181
+ @classdesc AI 配置根对象
182
+
183
+ 对应 ~/.precis/ai_providers.yaml 的完整配置结构。
184
+
185
+ Attributes:
186
+ version: 配置格式版本,固定为 "2.0"
187
+ providers: 所有 AI Provider 的列表
188
+ defaults: 各场景默认使用的 Provider ID,如 {"chat": "ollama-local", "generate": "openai"}
189
+ """
190
+
191
+ model_config = ConfigDict(use_enum_values=True)
192
+
193
+ version: str = Field(default="2.0", description="配置版本号")
194
+ providers: list[AIProvider] = Field(default_factory=list, description="Provider 列表")
195
+
196
+ # 系统设置
197
+ defaults: dict[str, str] = Field(
198
+ default_factory=dict, description="各场景默认 Provider,如 {'chat': 'ollama-local'}"
199
+ )
200
+
201
+ # LLM 响应缓存配置(默认关闭)
202
+ cache: AICacheConfig = Field(default_factory=AICacheConfig, description="LLM 响应缓存配置")
@@ -0,0 +1,128 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview AI Provider 预设定义
18
+
19
+ 功能概述:
20
+ - 定义内置的服务商预设配置(base_url、默认模型、可用模型列表)
21
+ - 所有 OpenAI 兼容服务商统一为 type=openai
22
+ - 后端扩展新服务商时只需在此文件添加预设条目
23
+
24
+ 架构设计:
25
+ - PROVIDER_PRESETS 为字典,key 为预设 ID,value 为预设配置
26
+ - 预设配置包含服务商元信息和可用模型列表
27
+ - API 端点 GET /providers/presets 返回预设列表供前端和 CLI 使用
28
+ - 这是 Provider 元数据的唯一来源,前端和 CLI 共用
29
+ - 字典顺序即前端设置页下拉与 CLI 菜单的展示顺序(国内主流在前、本地服务在后)
30
+ - base_url 必须是 OpenAI 兼容端点(openai SDK 会在其后拼接 /chat/completions),
31
+ 含版本路径的厂商必须带全(如 /v1、/compatible-mode/v1、/api/paas/v4、/api/v3)
32
+
33
+ 维护约定:
34
+ - 各厂商 base_url / 模型 ID / 鉴权要点 / 更新 SOP 见同目录 AI_PROVIDER_PRESETS.md
35
+ - 模型列表有时效性(厂商滚动升级),更新时须对照官方模型列表并同步维护文档的核对日期
36
+
37
+ 输入示例:
38
+ preset = PROVIDER_PRESETS["deepseek"]
39
+
40
+ 输出示例:
41
+ ProviderPreset(id="deepseek", name="DeepSeek", type="openai",
42
+ base_url="https://api.deepseek.com",
43
+ default_model="deepseek-v4-flash",
44
+ models=["deepseek-v4-flash", "deepseek-v4-pro"])
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ from typing import Any
50
+
51
+ PROVIDER_PRESETS: dict[str, dict[str, Any]] = {
52
+ "deepseek": {
53
+ "id": "deepseek",
54
+ "name": "DeepSeek",
55
+ "type": "openai",
56
+ "base_url": "https://api.deepseek.com",
57
+ "default_model": "deepseek-v4-pro",
58
+ "models": ["deepseek-v4-pro", "deepseek-v4-flash"],
59
+ },
60
+ "qwen": {
61
+ "id": "qwen",
62
+ "name": "通义千问 Qwen",
63
+ "type": "openai",
64
+ "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
65
+ "default_model": "qwen3.8-max",
66
+ "models": ["qwen3.8-max", "qwen3.7-plus", "qwen3.8-flash"],
67
+ },
68
+ "glm": {
69
+ "id": "glm",
70
+ "name": "智谱 GLM",
71
+ "type": "openai",
72
+ "base_url": "https://open.bigmodel.cn/api/paas/v4",
73
+ "default_model": "glm-5.3",
74
+ "models": ["glm-5.3", "glm-5.3-flash", "glm-5.2"],
75
+ },
76
+ "kimi": {
77
+ "id": "kimi",
78
+ "name": "月之暗面 Kimi",
79
+ "type": "openai",
80
+ "base_url": "https://api.moonshot.cn/v1",
81
+ "default_model": "kimi-k3",
82
+ "models": ["kimi-k3", "kimi-k2.7-code", "kimi-k2.6", "kimi-latest"],
83
+ },
84
+ "minimax": {
85
+ "id": "minimax",
86
+ "name": "MiniMax",
87
+ "type": "openai",
88
+ "base_url": "https://api.minimaxi.com/v1",
89
+ "default_model": "MiniMax-M3",
90
+ "models": ["MiniMax-M3", "MiniMax-M2.5", "MiniMax-M2.7-highspeed"],
91
+ },
92
+ "mimo": {
93
+ "id": "mimo",
94
+ "name": "Xiaomi MiMo",
95
+ "type": "openai",
96
+ "base_url": "https://api.xiaomimimo.com/v1",
97
+ "default_model": "mimo-v2.5",
98
+ "models": ["mimo-v2.5", "mimo-v2.5-pro"],
99
+ },
100
+ "ollama": {
101
+ "id": "ollama-local",
102
+ "name": "Ollama Local",
103
+ "type": "ollama",
104
+ "base_url": "http://localhost:11434",
105
+ "default_model": "llama3.2",
106
+ "models": [],
107
+ },
108
+ }
109
+
110
+
111
+ def get_preset_list() -> list[dict[str, Any]]:
112
+ """返回所有预设的列表(不含内部字段)"""
113
+ return [
114
+ {
115
+ "id": v["id"],
116
+ "name": v["name"],
117
+ "type": v["type"],
118
+ "base_url": v["base_url"],
119
+ "default_model": v["default_model"],
120
+ "models": list(v["models"]),
121
+ }
122
+ for v in PROVIDER_PRESETS.values()
123
+ ]
124
+
125
+
126
+ def get_preset(preset_id: str) -> dict[str, Any] | None:
127
+ """按 ID 获取预设,不存在返回 None"""
128
+ return PROVIDER_PRESETS.get(preset_id)