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,219 @@
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
+ """@fileoverview 建议工具模块
17
+
18
+ 功能概述:
19
+ - 提供约束类型标准化
20
+ - 根据输入提供相似表名、字段名、约束类型的建议
21
+ - 根据字段类型建议适用的约束
22
+
23
+ 输入示例:
24
+ suggestion = suggest_similar_table("user", schema)
25
+ normalized = normalize_constraint_type("not_null")
26
+
27
+ 输出示例:
28
+ "是否指: users?"
29
+ "NotNull"
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ from typing import Any
35
+
36
+ # 支持的约束类型(标准名 + 别名)。
37
+ # 单一事实源是 actions/registry.py 的 ALL_CONSTRAINT_TYPES;此处保持同步副本。
38
+ # 直接 import registry 会形成循环导入(actions/__init__ → action_validator →
39
+ # _constraint_validator → suggestion_utils → actions 包),故维持副本。
40
+ # 新增约束类型时,两处都必须同步更新。
41
+ VALID_CONSTRAINT_TYPES = {
42
+ "NotNull",
43
+ "Unique",
44
+ "Range",
45
+ "AllowedValues",
46
+ "ForeignKey",
47
+ "Conditional",
48
+ "Scripted",
49
+ "DateLogic",
50
+ "Charset",
51
+ "Composite",
52
+ # 别名兼容
53
+ "NOT_NULL",
54
+ "UNIQUE",
55
+ "RANGE",
56
+ "ALLOWED_VALUES",
57
+ "FOREIGN_KEY",
58
+ "CONDITIONAL",
59
+ "DATE_LOGIC",
60
+ "CHARSET",
61
+ "COMPOSITE",
62
+ "REGEX",
63
+ }
64
+
65
+
66
+ def normalize_constraint_type(constraint_type: str) -> str:
67
+ """
68
+ @methoddesc 标准化约束类型名
69
+
70
+ 将各种别名、下划线命名、小写形式统一转换为标准 PascalCase 命名。
71
+ 例如:"not_null" -> "NotNull", "regex" -> "Scripted"
72
+
73
+ 参数:
74
+ constraint_type: 原始类型名
75
+
76
+ 返回:
77
+ 标准化后的类型名
78
+
79
+ 示例:
80
+ >>> normalize_constraint_type("not_null")
81
+ 'NotNull'
82
+ >>> normalize_constraint_type("regex")
83
+ 'Scripted'
84
+ """
85
+ # 处理下划线命名和小写
86
+ normalized = constraint_type.replace("_", "").lower()
87
+
88
+ # 映射到标准名
89
+ type_mapping = {
90
+ "notnull": "NotNull",
91
+ "unique": "Unique",
92
+ "range": "Range",
93
+ "allowedvalues": "AllowedValues",
94
+ "foreignkey": "ForeignKey",
95
+ "conditional": "Conditional",
96
+ "scripted": "Scripted",
97
+ "datelogic": "DateLogic",
98
+ "charset": "Charset",
99
+ "composite": "Composite",
100
+ "regex": "Scripted", # 别名
101
+ }
102
+
103
+ return type_mapping.get(normalized, constraint_type)
104
+
105
+
106
+ def suggest_similar_table(table_ref: str, schema: dict[str, Any]) -> str | None:
107
+ """
108
+ @methoddesc 建议相似的表名
109
+
110
+ 当用户输入的表名不存在时,通过前缀/包含匹配查找相似表名并给出建议。
111
+
112
+ 参数:
113
+ table_ref: 用户输入的表名或 ID
114
+ schema: 项目结构字典
115
+
116
+ 返回:
117
+ 建议文本字符串,如果没有相似表则返回 None
118
+
119
+ 示例:
120
+ >>> suggest_similar_table("user", schema)
121
+ '是否指: users?'
122
+ """
123
+ all_names = list(schema["table_name_to_id"].keys()) + list(schema["tables"].keys())
124
+
125
+ # 简单的相似度匹配(前缀匹配)
126
+ suggestions = [name for name in all_names if table_ref.lower() in name.lower()]
127
+
128
+ if suggestions:
129
+ return f"是否指: {', '.join(suggestions[:3])}?"
130
+ return "请检查表名拼写或使用 'list tables' 查看可用表"
131
+
132
+
133
+ def suggest_similar_column(column_name: str, table_info: dict[str, Any]) -> str | None:
134
+ """
135
+ @methoddesc 建议相似的字段名
136
+
137
+ 当用户输入的字段名不存在时,通过包含匹配查找相似字段名并给出建议。
138
+
139
+ 参数:
140
+ column_name: 用户输入的字段名
141
+ table_info: 表信息字典
142
+
143
+ 返回:
144
+ 建议文本字符串,如果没有相似字段则返回 None
145
+
146
+ 示例:
147
+ >>> suggest_similar_column("emial", table_info)
148
+ '是否指: email?'
149
+ """
150
+ all_columns = [col["name"] for col in table_info["columns"].values()]
151
+
152
+ # 简单的相似度匹配
153
+ suggestions = [col for col in all_columns if column_name.lower() in col.lower()]
154
+
155
+ if suggestions:
156
+ return f"是否指: {', '.join(suggestions[:3])}?"
157
+
158
+ available = ", ".join(list(table_info["columns"].keys())[:5])
159
+ return f"可用字段: {available}..."
160
+
161
+
162
+ def suggest_similar_constraint_type(constraint_type: str) -> str | None:
163
+ """
164
+ @methoddesc 建议相似的约束类型
165
+
166
+ 当用户输入的约束类型不存在时,通过编辑距离和包含匹配查找相似类型并给出建议。
167
+
168
+ 参数:
169
+ constraint_type: 用户输入的约束类型
170
+
171
+ 返回:
172
+ 建议文本字符串,如果没有相似类型则返回 None
173
+
174
+ 示例:
175
+ >>> suggest_similar_constraint_type("NotNul")
176
+ '是否指: NotNull?'
177
+ """
178
+ # 简单的编辑距离或包含匹配
179
+ normalized = constraint_type.lower().replace("_", "")
180
+ suggestions = []
181
+
182
+ for valid_type in VALID_CONSTRAINT_TYPES:
183
+ valid_normalized = valid_type.lower().replace("_", "")
184
+ if normalized in valid_normalized or valid_normalized in normalized:
185
+ suggestions.append(valid_type)
186
+
187
+ if suggestions:
188
+ return f"是否指: {', '.join(suggestions[:3])}?"
189
+ return "支持的约束类型: NotNull, Unique, Range, AllowedValues, ForeignKey, Conditional, Scripted, DateLogic, Charset, Composite"
190
+
191
+
192
+ def suggest_constraints_for_type(col_type: str) -> str:
193
+ """
194
+ @methoddesc 根据字段类型建议适用的约束
195
+
196
+ 根据字段的数据类型返回推荐使用的约束类型列表,用于类型兼容性校验失败时的用户提示。
197
+
198
+ 参数:
199
+ col_type: 字段类型,如 string、integer、decimal、boolean、date
200
+
201
+ 返回:
202
+ 建议的约束类型字符串
203
+
204
+ 示例:
205
+ >>> suggest_constraints_for_type("string")
206
+ 'NotNull, Unique, AllowedValues, Scripted(Regex)'
207
+ >>> suggest_constraints_for_type("integer")
208
+ 'NotNull, Unique, Range, AllowedValues, ForeignKey'
209
+ """
210
+ type_to_constraints = {
211
+ "string": "NotNull, Unique, AllowedValues, Scripted(Regex)",
212
+ "integer": "NotNull, Unique, Range, AllowedValues, ForeignKey",
213
+ "decimal": "NotNull, Unique, Range, AllowedValues, ForeignKey",
214
+ "float": "NotNull, Unique, Range, AllowedValues",
215
+ "boolean": "NotNull, AllowedValues",
216
+ "date": "NotNull, Range, DateLogic",
217
+ }
218
+
219
+ return type_to_constraints.get(col_type.lower(), "NotNull, Unique")
@@ -0,0 +1,163 @@
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
+ - 调用后端校验引擎执行数据校验
21
+ - 支持全量校验和指定表的过滤校验
22
+ - 格式化校验结果和错误信息
23
+
24
+ 输入示例:
25
+ result = execute_validate_project("/workspace", table_filter="users")
26
+
27
+ 输出示例:
28
+ {
29
+ "success": True,
30
+ "message": "发现 3 个数据错误:\n - users.email: ...",
31
+ "details": {"error_count": 3, "errors": [...], "duration_ms": 150}
32
+ }
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import logging
38
+ import os
39
+ from typing import Any
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+
44
+ def execute_validate_project(workspace_path: str, table_filter: str | list[str] | None = None) -> dict[str, Any]:
45
+ """
46
+ @methoddesc 执行项目数据校验
47
+
48
+ 调用后端校验引擎,根据项目清单和数据目录执行全量或指定表的数据校验。
49
+ 格式化校验结果,最多显示前 10 个错误。
50
+
51
+ 参数:
52
+ workspace_path: 项目工作区路径(包含 project.precis.yaml)
53
+ table_filter: 可选的表名过滤,支持单个表名字符串或表名列表
54
+
55
+ 返回:
56
+ 校验结果字典,包含 success、message、details
57
+ - success=True 表示校验流程执行成功(即使发现数据错误)
58
+ - details 中包含 error_count、errors 列表等
59
+
60
+ 示例:
61
+ >>> result = execute_validate_project("/workspace", table_filter="users")
62
+ >>> result["success"]
63
+ True
64
+ """
65
+ manifest_path = os.path.join(workspace_path, "project.precis.yaml")
66
+ data_dir = workspace_path
67
+
68
+ if not os.path.exists(manifest_path):
69
+ return {"success": False, "message": f"项目配置文件不存在: {manifest_path}", "details": None}
70
+
71
+ try:
72
+ from app.shared.services.validation.executor import ValidationExecutor, ValidationOptions
73
+
74
+ # 使用默认配置执行校验
75
+ options = ValidationOptions(
76
+ timeout_seconds=30,
77
+ allow_unsafe_eval=False,
78
+ table_filter=table_filter,
79
+ )
80
+
81
+ executor = ValidationExecutor(manifest_path)
82
+ result = executor.execute(data_dir, options)
83
+
84
+ errors = result.get("errors", [])
85
+ loading_errors = result.get("loading_errors", [])
86
+ duration_ms = result.get("duration_ms", 0)
87
+
88
+ # 格式化加载警告(loading_errors 为非致命的加载阶段问题)
89
+ loading_section = ""
90
+ if loading_errors:
91
+ loading_details = []
92
+ for le in loading_errors[:10]:
93
+ le_type = le.get("error_type") or le.get("type") or "未知错误"
94
+ le_table = le.get("table", "")
95
+ # message 可能为空(inspect 级错误),优先读 title,与 CLI validate.py 处理一致
96
+ le_message = le.get("title") or le.get("message") or ""
97
+ prefix = f"{le_table}." if le_table else ""
98
+ loading_details.append(f" - [{le_type}] {prefix}{le_message}")
99
+ if len(loading_errors) > 10:
100
+ loading_details.append(f" ... 还有 {len(loading_errors) - 10} 个加载警告")
101
+ loading_section = "加载警告:\n" + "\n".join(loading_details)
102
+
103
+ if errors:
104
+ # 格式化错误信息,最多显示前 10 个
105
+ error_details = []
106
+ for err in errors[:10]:
107
+ # 兼容 error_type(真实数据)和 type(遗留 mock)
108
+ err_type = err.get("error_type") or err.get("type") or "未知错误"
109
+ table = err.get("table", "未知表")
110
+ column = err.get("column", "")
111
+ message = err.get("message", "")
112
+
113
+ if column:
114
+ error_details.append(f" - {table}.{column}: {message} ({err_type})")
115
+ else:
116
+ error_details.append(f" - {table}: {message} ({err_type})")
117
+
118
+ if len(errors) > 10:
119
+ error_details.append(f" ... 还有 {len(errors) - 10} 个错误")
120
+
121
+ full_message = f"发现 {len(errors)} 个数据错误:\n" + "\n".join(error_details)
122
+ if loading_section:
123
+ full_message += "\n" + loading_section
124
+
125
+ return {
126
+ "success": True, # 校验执行成功,只是发现数据错误
127
+ "message": full_message,
128
+ "details": {
129
+ "error_count": len(errors),
130
+ "duration_ms": duration_ms,
131
+ "errors": errors[:20], # 返回前20个错误详情
132
+ "has_errors": True,
133
+ "loading_errors": loading_errors[:20],
134
+ "has_loading_errors": len(loading_errors) > 0,
135
+ "table_filter": table_filter,
136
+ },
137
+ }
138
+ else:
139
+ if loading_section:
140
+ # 无校验错误但存在加载警告
141
+ full_message = f"数据校验通过,但存在 {len(loading_errors)} 个加载警告:\n" + "\n".join(
142
+ loading_section.split("\n")[1:] # 去掉 "加载警告:" 标题行,改用计数前缀
143
+ )
144
+ else:
145
+ full_message = f"数据校验通过(耗时 {duration_ms}ms)"
146
+
147
+ return {
148
+ "success": True,
149
+ "message": full_message,
150
+ "details": {
151
+ "error_count": 0,
152
+ "duration_ms": duration_ms,
153
+ "errors": [],
154
+ "has_errors": False,
155
+ "loading_errors": loading_errors[:20],
156
+ "has_loading_errors": len(loading_errors) > 0,
157
+ "table_filter": table_filter,
158
+ },
159
+ }
160
+
161
+ except Exception as e:
162
+ logger.error(f"执行校验失败: {e}", exc_info=True)
163
+ return {"success": False, "message": f"校验执行失败: {str(e)}", "details": None}