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,182 @@
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 约束适配器模块
18
+
19
+ 功能概述:
20
+ - 提供 ConstraintAdapter,将任意 Domain Constraint 包装为 Service Validator
21
+ - 统一委托模式,消除简单 Validator 文件中的重复模板代码
22
+ - 支持预检、参数映射、自定义 datasets 构建、错误格式化
23
+
24
+ 架构设计:
25
+ - 继承 BaseValidator,实现 validate() 接口
26
+ - 内部创建 Domain Constraint 实例并通过 _delegate_validation 委托
27
+ - kwargs 透传机制:从 Validator kwargs 映射到 Constraint 构造参数
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ import time
33
+ from collections.abc import Callable
34
+ from typing import Any
35
+
36
+ import pandas as pd
37
+
38
+ from app.shared.domain.constraints.base import Constraint
39
+
40
+ from ..types import ValidationResult
41
+ from .base import BaseValidator
42
+
43
+ PreCheckFn = Callable[[pd.DataFrame, str, dict], str | None]
44
+ KwargsBuilderFn = Callable[[str, dict], dict[str, Any]]
45
+ DatasetsBuilderFn = Callable[[pd.DataFrame, str, dict], dict[str, pd.DataFrame]]
46
+
47
+
48
+ class ConstraintAdapter(BaseValidator):
49
+ """
50
+ @classdesc 通用约束适配器
51
+
52
+ 将任意 Domain Constraint 包装为 Service Validator,
53
+ 自动处理 datasets 映射、预检、参数构建和错误格式转换。
54
+
55
+ 使用示例:
56
+ # 简单约束(无额外参数)
57
+ adapter = ConstraintAdapter(
58
+ constraint_cls=UniqueConstraint,
59
+ column_param="column",
60
+ )
61
+
62
+ # 带参数映射和预检
63
+ adapter = ConstraintAdapter(
64
+ constraint_cls=RegexConstraint,
65
+ column_param="column",
66
+ kwargs_mapping={"regex_pattern": "pattern", ...},
67
+ pre_checks=[PreCheck.column_exists(), PreCheck.param_required("regex_pattern")],
68
+ )
69
+
70
+ # 带自定义 datasets 构建(如外键双表)
71
+ adapter = ConstraintAdapter(
72
+ constraint_cls=ForeignKeyConstraints,
73
+ column_param="from_column",
74
+ datasets_builder=PreCheck.build_fk_datasets,
75
+ ...
76
+ )
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ constraint_cls: type[Constraint],
82
+ column_param: str = "column",
83
+ extra_params: dict[str, Any] | None = None,
84
+ kwargs_mapping: dict[str, str] | None = None,
85
+ error_formatter: Callable[[dict], dict] | None = None,
86
+ pre_checks: list[PreCheckFn] | None = None,
87
+ kwargs_builder: KwargsBuilderFn | None = None,
88
+ datasets_builder: DatasetsBuilderFn | None = None,
89
+ constraint_kwargs_keys: list[str] | None = None,
90
+ ):
91
+ self.constraint_cls = constraint_cls
92
+ self.column_param = column_param
93
+ self.extra_params = extra_params or {}
94
+ self.kwargs_mapping = kwargs_mapping or {}
95
+ self.error_formatter = error_formatter
96
+ self.pre_checks = pre_checks or []
97
+ self.kwargs_builder = kwargs_builder
98
+ self.datasets_builder = datasets_builder
99
+ self.constraint_kwargs_keys = constraint_kwargs_keys or []
100
+
101
+ def validate(self, df: pd.DataFrame, column: str, **kwargs: Any) -> ValidationResult:
102
+ start_time = time.time()
103
+
104
+ for check in self.pre_checks:
105
+ error_msg = check(df, column, kwargs)
106
+ if error_msg:
107
+ return ValidationResult(
108
+ is_valid=False,
109
+ error_count=1,
110
+ total_rows=len(df),
111
+ error_rows=[{"row_index": 0, "cell_value": None, "error_message": error_msg}],
112
+ validation_time=f"{time.time() - start_time:.3f}s",
113
+ )
114
+
115
+ params: dict[str, Any]
116
+ if self.kwargs_builder:
117
+ params = self.kwargs_builder(column, kwargs)
118
+ else:
119
+ params = {"table": "temp", self.column_param: column}
120
+ params.update(self.extra_params)
121
+ for validator_kwarg, constraint_param in self.kwargs_mapping.items():
122
+ if validator_kwarg in kwargs:
123
+ params[constraint_param] = kwargs[validator_kwarg]
124
+
125
+ constraint = self.constraint_cls(**params)
126
+
127
+ constraint_kwargs = {}
128
+ for key in self.constraint_kwargs_keys:
129
+ if key in kwargs:
130
+ constraint_kwargs[key] = kwargs[key]
131
+
132
+ if self.datasets_builder:
133
+ datasets = self.datasets_builder(df, column, kwargs)
134
+ return self._delegate_validation(
135
+ df,
136
+ column,
137
+ constraint,
138
+ error_formatter=self.error_formatter,
139
+ datasets=datasets,
140
+ constraint_kwargs=constraint_kwargs or None,
141
+ )
142
+
143
+ return self._delegate_validation(
144
+ df,
145
+ column,
146
+ constraint,
147
+ error_formatter=self.error_formatter,
148
+ constraint_kwargs=constraint_kwargs or None,
149
+ )
150
+
151
+
152
+ class PreCheck:
153
+ """内置预检工厂方法"""
154
+
155
+ @staticmethod
156
+ def column_exists() -> PreCheckFn:
157
+ def check(df: pd.DataFrame, column: str, kwargs: dict) -> str | None:
158
+ if column not in df.columns:
159
+ return f"列 '{column}' 不存在"
160
+ return None
161
+
162
+ return check
163
+
164
+ @staticmethod
165
+ def param_required(*keys: str) -> PreCheckFn:
166
+ def check(df: pd.DataFrame, column: str, kwargs: dict) -> str | None:
167
+ for key in keys:
168
+ if not kwargs.get(key):
169
+ return f"参数 '{key}' 不能为空"
170
+ return None
171
+
172
+ return check
173
+
174
+ @staticmethod
175
+ def param_required_any(*key_groups: tuple[str, ...]) -> PreCheckFn:
176
+ def check(df: pd.DataFrame, column: str, kwargs: dict) -> str | None:
177
+ for group in key_groups:
178
+ if any(kwargs.get(k) for k in group):
179
+ return None
180
+ return "校验配置不完整"
181
+
182
+ return check
@@ -0,0 +1,332 @@
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 基础校验器抽象类 - Base Validator
18
+
19
+ 功能概述:
20
+ - 定义所有具体校验器的通用接口和基础功能
21
+ - 提供校验结果的标准格式化和错误处理
22
+ - 采用抽象基类模式(Abstract Base Class),定义校验器的标准行为
23
+
24
+ 架构设计:
25
+ - 抽象基类模式: 所有具体校验器继承 BaseValidator
26
+ - 模板方法模式: 定义 validate 方法的标准校验流程
27
+ - 静态方法封装: 错误格式化逻辑复用
28
+
29
+ 继承体系:
30
+ BaseValidator (抽象基类)
31
+ ├── RegexValidator
32
+ ├── UniqueValidator
33
+ ├── NotNullValidator
34
+ ├── AllowedValuesValidator
35
+ ├── RangeValidator
36
+ ├── ForeignKeyValidator
37
+ ├── ConditionalValidator
38
+ ├── ScriptedValidator
39
+ ├── CharsetValidator
40
+ └── DateLogicValidator
41
+
42
+ 数据流:
43
+ UnifiedValidationService.validate()
44
+ ↓ [调用]
45
+ 具体校验器.validate(df, column, **kwargs)
46
+ ↓ [执行]
47
+ 返回错误列表 errors
48
+ ↓ [格式化]
49
+ BaseValidator._format_errors(errors, total_rows, time)
50
+ ↓ [返回]
51
+ ValidationResult 对象
52
+
53
+ 输入示例:
54
+ class CustomValidator(BaseValidator):
55
+ def validate(self, df, column, **kwargs):
56
+ errors = []
57
+ for idx, value in df[column].items():
58
+ if not self._custom_check(value):
59
+ errors.append({"row_index": idx, "value": value, "message": "..."})
60
+ return self._format_errors(errors, len(df), time.time() - start_time)
61
+
62
+ 输出示例:
63
+ ValidationResult(
64
+ is_valid=False,
65
+ error_count=1,
66
+ error_rows=[{"row_index": 0, "value": "xxx", "message": "..."}]
67
+ )
68
+ """
69
+
70
+ from __future__ import annotations
71
+
72
+ import logging
73
+ from abc import ABC, abstractmethod
74
+ from collections.abc import Callable
75
+ from typing import TYPE_CHECKING, Any
76
+
77
+ import pandas as pd
78
+
79
+ from ..types import ValidationResult
80
+
81
+ if TYPE_CHECKING:
82
+ from app.shared.domain.constraints.base import Constraint
83
+
84
+ logger = logging.getLogger(__name__)
85
+
86
+
87
+ class BaseValidator(ABC):
88
+ """
89
+ @classdesc 基础校验器抽象基类
90
+
91
+ 所有具体校验器(如 RangeValidator、RegexValidator 等)必须继承此类,
92
+ 并实现 validate 方法定义具体的校验逻辑。
93
+
94
+ 设计原则:
95
+ - 统一接口:所有校验器提供相同的 validate 方法签名
96
+ - 结果标准化:校验结果统一格式化为 ValidationResult
97
+ - 错误格式化:提供通用的错误格式化逻辑
98
+ - 异常处理:统一的异常捕获和日志记录
99
+
100
+ 示例:
101
+ class RangeValidator(BaseValidator):
102
+ def validate(self, df, column, **kwargs):
103
+ # 具体校验逻辑
104
+ return ValidationResult(...)
105
+ """
106
+
107
+ def validate_with_error_handling(self, df: pd.DataFrame, column: str, **kwargs: Any) -> ValidationResult:
108
+ """
109
+ 带异常处理的校验方法包装器
110
+
111
+ 捕获并记录校验过程中的异常,返回标准化的错误结果。
112
+ 子类应重写 validate 方法,而不是此方法。
113
+
114
+ Args:
115
+ df: 待校验的 DataFrame
116
+ column: 待校验的列名
117
+ **kwargs: 校验参数
118
+
119
+ Returns:
120
+ ValidationResult: 校验结果(成功或失败)
121
+ """
122
+ try:
123
+ return self.validate(df, column, **kwargs)
124
+ except Exception as e:
125
+ logger.error(f"Validation error in {self.__class__.__name__}: {e}", exc_info=True)
126
+ return ValidationResult(
127
+ is_valid=False,
128
+ error_count=1,
129
+ total_rows=len(df),
130
+ error_rows=[
131
+ {
132
+ "row_index": 0,
133
+ "cell_value": None,
134
+ "error_message": f"\u6821\u9a8c\u6267\u884c\u5931\u8d25: {str(e)}",
135
+ }
136
+ ],
137
+ validation_time="0.000s",
138
+ )
139
+
140
+ @abstractmethod
141
+ def validate(self, df: pd.DataFrame, column: str, **kwargs: Any) -> ValidationResult:
142
+ """
143
+ @methoddesc 执行数据校验
144
+
145
+ 校验 DataFrame 中指定列的数据,返回标准化的校验结果。
146
+ 子类必须实现此方法定义具体的校验逻辑。
147
+
148
+ @param df: 待校验的 DataFrame 对象
149
+ @param column: 待校验的列名
150
+ @param kwargs: 子类特定的校验参数(如 min、max、pattern 等)
151
+
152
+ @return ValidationResult: 标准化校验结果,包含:
153
+ - is_valid: 校验是否通过
154
+ - error_count: 错误行数
155
+ - total_rows: 总行数
156
+ - match_count: 匹配行数
157
+ - error_rows: 错误详情列表
158
+ - validation_time: 校验耗时
159
+
160
+ @sideeffect:
161
+ - 可能读取 DataFrame 数据
162
+ - 可能抛出 ValueError(列不存在等)
163
+
164
+ @raises ValueError: 列名不存在或数据类型错误
165
+ """
166
+ pass
167
+
168
+ def _delegate_validation(
169
+ self,
170
+ df: pd.DataFrame,
171
+ column: str,
172
+ constraint: Constraint,
173
+ error_formatter: Callable[..., Any] | None = None,
174
+ datasets: dict[str, pd.DataFrame] | None = None,
175
+ constraint_kwargs: dict[str, Any] | None = None,
176
+ ) -> ValidationResult:
177
+ """
178
+ 委托校验通用模板
179
+
180
+ 将单列 DataFrame 校验委托给 Domain Constraint 的通用流程。
181
+ 适用于大多数通过 table="temp" 技巧委托给 Constraint 的 Validator。
182
+
183
+ Args:
184
+ df: 待校验的 DataFrame
185
+ column: 待校验的列名
186
+ constraint: Domain Constraint 实例
187
+ error_formatter: 可选的错误格式化回调函数(err -> dict)
188
+ datasets: 可选的自定义数据集字典,默认 {"temp": df}
189
+ constraint_kwargs: 可选的额外参数传递给 constraint.validate()
190
+
191
+ Returns:
192
+ ValidationResult: 标准化校验结果
193
+ """
194
+ import time
195
+
196
+ start_time = time.time()
197
+ if datasets is None:
198
+ datasets = {"temp": df}
199
+ if constraint_kwargs is None:
200
+ constraint_kwargs = {}
201
+ result = constraint.validate(datasets, **constraint_kwargs)
202
+ errors = result.get("errors", [])
203
+
204
+ formatted_errors = []
205
+ for err in errors:
206
+ if error_formatter:
207
+ formatted_errors.append(error_formatter(err))
208
+ else:
209
+ formatted_err = {
210
+ "row_index": err.get("row_index"),
211
+ "cell_value": err.get("value"),
212
+ "error_message": err.get("message"),
213
+ }
214
+ # 透传 table/column/error_type 上下文
215
+ for extra_key in ("table", "column", "error_type"):
216
+ if extra_key in err:
217
+ formatted_err[extra_key] = err[extra_key]
218
+ formatted_errors.append(formatted_err)
219
+
220
+ return self._format_errors(formatted_errors, len(df), time.time() - start_time)
221
+
222
+ @staticmethod
223
+ def _format_errors(errors: list[dict], total_rows: int, validation_time: float) -> ValidationResult:
224
+ """
225
+ @methoddesc 格式化校验错误为标准结果
226
+
227
+ 将校验过程中收集的错误信息转换为标准化的 ValidationResult 对象。
228
+ 处理数据类型转换(浮点数、None 值等)并生成可读的错误详情。
229
+
230
+ @param errors: 原始错误列表,每个元素包含:
231
+ - value 或 cell_value: 单元格原始值
232
+ - message 或 error_message: 错误描述
233
+ - row_index: 行索引(可选)
234
+ @param total_rows: 校验的总行数
235
+ @param validation_time: 校验耗时(秒)
236
+
237
+ @return ValidationResult: 标准化校验结果
238
+
239
+ @sideeffect:
240
+ - 行索引类型转换(支持字符串和数值)
241
+ - 单元格值保留原始值(不做取整/round 改写,展示格式化由前端负责)
242
+
243
+ 处理逻辑:
244
+ Step 1: 计算错误数量和匹配数量
245
+ Step 2: 遍历错误列表,格式化每个错误:
246
+ - 单元格值: 原样保留(数据质量工具需展示文件原始值以便对账)
247
+ - 行索引处理: 转换为 int,无效值默认为 0
248
+ - 错误消息: 兼容多种字段名
249
+ Step 3: 构建 ValidationResult 对象并返回
250
+ """
251
+ # Step 1: 计算校验统计
252
+ # 计算错误行数
253
+ error_count = len(errors)
254
+ # 判断校验是否通过(无错误即为通过)
255
+ is_valid = error_count == 0
256
+ # 计算匹配行数(总行数 - 错误行数)
257
+ match_count = total_rows - error_count
258
+
259
+ # Step 2: 格式化错误列表
260
+ formatted_errors = []
261
+ for err in errors:
262
+ # 获取单元格值,兼容多种字段名
263
+ # 【关键数据流】err 可能是 {"value": ...} 或 {"cell_value": ...}
264
+ # 原样保留(含浮点数的原始精度):错误详情用于和源文件对账,
265
+ # 取整/round 改写会掩盖真实数据问题;可读格式化由前端展示层负责。
266
+ cell_value = err.get("value") if "value" in err else err.get("cell_value")
267
+
268
+ # 处理行索引:支持字符串和数值类型
269
+ # 【副作用】统一行索引为整数类型
270
+ row_index = err.get("row_index")
271
+ # None 值默认为 0
272
+ if row_index is None:
273
+ row_index = 0
274
+ try:
275
+ # 尝试转换为整数
276
+ row_index = int(row_index)
277
+ except (TypeError, ValueError):
278
+ # 转换失败时默认为 0
279
+ row_index = 0
280
+
281
+ # 格式化单个错误记录
282
+ # 【关键数据流】统一错误格式,便于前端展示
283
+ formatted_err = {
284
+ "row_index": row_index,
285
+ "cell_value": cell_value,
286
+ "error_message": err.get("message", err.get("error_message")),
287
+ }
288
+ # 透传 table/column/error_type 上下文(对跨表约束如 ForeignKey 至关重要)
289
+ for extra_key in ("table", "column", "error_type"):
290
+ if extra_key in err:
291
+ formatted_err[extra_key] = err[extra_key]
292
+ formatted_errors.append(formatted_err)
293
+
294
+ # Step 3: 构建并返回校验结果
295
+ # 【副作用】创建 ValidationResult 对象
296
+ return ValidationResult(
297
+ is_valid=is_valid,
298
+ error_count=error_count,
299
+ total_rows=total_rows,
300
+ match_count=match_count,
301
+ error_rows=formatted_errors,
302
+ validation_time=f"{validation_time:.3f}s",
303
+ )
304
+
305
+
306
+ # ==============================================================================
307
+ # _format_errors 使用示例
308
+ # ==============================================================================
309
+ # # 原始错误列表
310
+ # errors = [
311
+ # {"row_index": 0, "value": "invalid@email", "message": "邮箱格式错误"},
312
+ # {"row_index": 3, "cell_value": "bad@format", "error_message": "格式不正确"},
313
+ # {"row_index": 5, "value": 1.5, "message": "数值超范围"} # 浮点数会被处理
314
+ # ]
315
+ #
316
+ # # 调用格式化方法
317
+ # result = BaseValidator._format_errors(errors, total_rows=100, validation_time=0.025)
318
+ #
319
+ # # 返回结果
320
+ # # ValidationResult(
321
+ # # is_valid=False,
322
+ # # error_count=3,
323
+ # # total_rows=100,
324
+ # # match_count=97,
325
+ # # error_rows=[
326
+ # # {"row_index": 0, "cell_value": "invalid@email", "error_message": "邮箱格式错误"},
327
+ # # {"row_index": 3, "cell_value": "bad@format", "error_message": "格式不正确"},
328
+ # # {"row_index": 5, "cell_value": 1.5, "error_message": "数值超范围"}
329
+ # # ],
330
+ # # validation_time="0.025s"
331
+ # # )
332
+ # ==============================================================================