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,371 @@
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
+ # backend/app/cli/shell/formatter.py
17
+ """
18
+ @fileoverview CLI Shell 输出格式化模块
19
+
20
+ 功能概述:
21
+ - 基于 rich 库提供彩色终端输出和格式化工具
22
+ - 支持加载动画 Spinner、表格打印、验证结果格式化
23
+ - 打印欢迎信息与项目信息
24
+ - 保持 Colors/Formatter/Spinner 公共 API 不变,内部实现委托 rich
25
+
26
+ 架构设计:
27
+ - Colors 定义 ANSI 颜色常量(兼容旧代码直接引用)
28
+ - Spinner 基于 rich.progress 实现终端加载动画
29
+ - Formatter 提供静态方法统一各类输出格式,内部使用 rich Console
30
+ """
31
+
32
+ import sys
33
+ from typing import Any
34
+
35
+ from rich.console import Console
36
+ from rich.panel import Panel
37
+ from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn
38
+ from rich.table import Table
39
+ from rich.text import Text
40
+
41
+ _console = Console(stderr=False)
42
+ _stderr_console = Console(stderr=True)
43
+
44
+
45
+ def _supports_unicode() -> bool:
46
+ """检测当前 stdout 是否支持 Unicode 输出。"""
47
+ try:
48
+ encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
49
+ "⠋".encode(encoding)
50
+ return True
51
+ except (UnicodeEncodeError, LookupError):
52
+ return False
53
+
54
+
55
+ class Colors:
56
+ """终端颜色常量。(保留以兼容旧代码直接引用)"""
57
+
58
+ RESET = "\033[0m"
59
+ BOLD = "\033[1m"
60
+ DIM = "\033[2m"
61
+
62
+ BLACK = "\033[30m"
63
+ RED = "\033[31m"
64
+ GREEN = "\033[32m"
65
+ YELLOW = "\033[33m"
66
+ BLUE = "\033[34m"
67
+ MAGENTA = "\033[35m"
68
+ CYAN = "\033[36m"
69
+ WHITE = "\033[37m"
70
+
71
+ BG_BLACK = "\033[40m"
72
+ BG_RED = "\033[41m"
73
+ BG_GREEN = "\033[42m"
74
+ BG_YELLOW = "\033[43m"
75
+ BG_BLUE = "\033[44m"
76
+ BG_MAGENTA = "\033[45m"
77
+ BG_CYAN = "\033[46m"
78
+ BG_WHITE = "\033[47m"
79
+
80
+
81
+ class Spinner:
82
+ """终端加载动画(基于 rich.progress)。"""
83
+
84
+ ANIMATION_INTERVAL = 0.1
85
+
86
+ def __init__(self, message: str = "处理中"):
87
+ self.message = message
88
+ self._success = True
89
+ self._progress: Progress | None = None
90
+ self._task_id: TaskID | None = None
91
+
92
+ def start(self) -> None:
93
+ self._progress = Progress(
94
+ SpinnerColumn(),
95
+ TextColumn("[cyan]{task.description}"),
96
+ console=_console,
97
+ transient=True,
98
+ )
99
+ self._progress.start()
100
+ self._task_id = self._progress.add_task(self.message + "...", total=None)
101
+
102
+ def stop(self, success: bool = True) -> None:
103
+ self._success = success
104
+ if self._progress:
105
+ self._progress.stop()
106
+ self._progress = None
107
+
108
+ mark = "[green]✓[/green]" if success else "[red]✗[/red]"
109
+ suffix = "[green] 完成[/green]" if success else "[red] 失败[/red]"
110
+ _console.print(f"{mark} {self.message}{suffix}")
111
+
112
+
113
+ class Formatter:
114
+ """输出格式化器。"""
115
+
116
+ @staticmethod
117
+ def colorize(text: str, *colors: str) -> str:
118
+ color_codes = "".join(colors)
119
+ return f"{color_codes}{text}{Colors.RESET}"
120
+
121
+ @staticmethod
122
+ def success(text: str) -> str:
123
+ return Formatter.colorize(text, Colors.GREEN)
124
+
125
+ @staticmethod
126
+ def error(text: str) -> str:
127
+ return Formatter.colorize(text, Colors.RED)
128
+
129
+ @staticmethod
130
+ def warning(text: str) -> str:
131
+ return Formatter.colorize(text, Colors.YELLOW)
132
+
133
+ @staticmethod
134
+ def info(text: str) -> str:
135
+ return Formatter.colorize(text, Colors.CYAN)
136
+
137
+ @staticmethod
138
+ def header(text: str) -> str:
139
+ return Formatter.colorize(text, Colors.BOLD)
140
+
141
+ @staticmethod
142
+ def dim(text: str) -> str:
143
+ return Formatter.colorize(text, Colors.DIM)
144
+
145
+ @staticmethod
146
+ def print_header(text: str, width: int = 50) -> None:
147
+ _console.rule(Text(text.strip(), style="bold"), style="cyan", characters="═")
148
+
149
+ @staticmethod
150
+ def print_welcome() -> None:
151
+ print()
152
+
153
+ if _supports_unicode():
154
+ logo = r"""
155
+ [bold cyan]██████╗ ██████╗ ███████╗ ██████╗██╗███████╗
156
+ ██╔══██╗██╔══██╗██╔════╝██╔════╝██║██╔════╝
157
+ ██████╔╝██████╔╝█████╗ ██║ ██║███████╗
158
+ ██╔═══╝ ██╔══██╗██╔══╝ ██║ ██║╚════██║
159
+ ██║ ██║ ██║███████╗╚██████╗██║███████║
160
+ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝╚══════╝[/bold cyan]"""
161
+ else:
162
+ logo = r"""
163
+ [bold cyan] _____ ____ _____ ____ _____
164
+ | __ \| _ \ / ____|/ __ \|_ _|
165
+ | |__) | |_) | | | | | | | |
166
+ | ___/| _ <| | | | | | | |
167
+ | | | |_) | |____| |__| |_| |_
168
+ |_| |____/ \_____|\____/|_____|[/bold cyan]"""
169
+
170
+ subtitle = Text("Precis · Data Validation Engine", style="bold")
171
+ # 版本号单一事实源:根 package.json;运行时解析见 shared/core/app_version.py
172
+ from app.shared.core.app_version import get_app_version
173
+
174
+ _version = get_app_version()
175
+ version_text = Text(f"v{_version} CLI Interactive Shell", style="dim")
176
+
177
+ _console.print(logo)
178
+ _console.print()
179
+ _console.print(
180
+ Panel.fit(
181
+ f"{subtitle}\n{version_text}",
182
+ border_style="cyan",
183
+ padding=(0, 4),
184
+ )
185
+ )
186
+
187
+ print()
188
+ _console.print("[dim]Type 'help' for available commands, 'exit' to exit, 'qq' to force quit[/dim]")
189
+ print()
190
+
191
+ @staticmethod
192
+ def print_error(message: str) -> None:
193
+ _stderr_console.print(f"[bold red]错误:[/bold red] {message}")
194
+
195
+ @staticmethod
196
+ def print_warning(message: str) -> None:
197
+ _console.print(f"[yellow]警告:[/yellow] {message}")
198
+
199
+ @staticmethod
200
+ def print_success(message: str) -> None:
201
+ _console.print(f"[green]{message}[/green]")
202
+
203
+ @staticmethod
204
+ def print_info(message: str) -> None:
205
+ _console.print(f"[cyan]{message}[/cyan]")
206
+
207
+ @staticmethod
208
+ def print_table(headers: list[str], rows: list[list[Any]]) -> None:
209
+ if not headers:
210
+ return
211
+
212
+ table = Table(show_header=True, header_style="bold")
213
+ for h in headers:
214
+ table.add_column(h)
215
+ for row in rows:
216
+ table.add_row(*[str(cell) for cell in row])
217
+ _console.print(table)
218
+
219
+ @staticmethod
220
+ def format_validation_result(errors: list[dict[str, Any]], detailed: bool = True) -> str:
221
+ if not errors:
222
+ mark = "✓" if _supports_unicode() else "[OK]"
223
+ return f"[green]\n{mark} 校验通过,未发现任何错误!\n[/green]"
224
+
225
+ error_counts: dict[str, int] = {}
226
+ for error in errors:
227
+ error_type = error.get("error_type", "UnknownError")
228
+ error_counts[error_type] = error_counts.get(error_type, 0) + 1
229
+
230
+ lines = []
231
+ lines.append("")
232
+ total_errors = len(errors)
233
+
234
+ lines.append(f"[bold] 总计: {total_errors} 个错误[/bold]")
235
+ lines.append("")
236
+
237
+ if error_counts:
238
+ lines.append("[bold] 按类型统计:[/bold]")
239
+ for error_type, count in sorted(error_counts.items()):
240
+ type_display = error_type.replace("Violation", "").replace("Error", "")
241
+ lines.append(f" [yellow]•[/yellow] {type_display}: {count}")
242
+ lines.append("")
243
+
244
+ lines.append("[dim]" + "─" * 60 + "[/dim]")
245
+ lines.append("[bold] 详细错误列表[/bold]")
246
+ lines.append("[dim]" + "─" * 60 + "[/dim]")
247
+ lines.append("")
248
+
249
+ for i, error in enumerate(errors, 1):
250
+ error_type = error.get("error_type", "UnknownError")
251
+ message = error.get("message", "无错误信息")
252
+ table_name = error.get("table", "")
253
+ column = error.get("column", "")
254
+ row_index = error.get("row_index")
255
+ value = error.get("value")
256
+
257
+ type_display = error_type.replace("Violation", "").replace("Error", "")
258
+ type_color = "red" if "Violation" in error_type else "yellow"
259
+
260
+ lines.append(f" [bold][{i}][/bold] [{type_color}]【{type_display}】[/{type_color}]")
261
+
262
+ if table_name:
263
+ lines.append(f" 表: [cyan]{table_name}[/cyan]")
264
+ if column:
265
+ lines.append(f" 列: [cyan]{column}[/cyan]")
266
+ if row_index is not None:
267
+ lines.append(f" 行号: [cyan]{row_index}[/cyan]")
268
+ if value is not None:
269
+ lines.append(f" 值: [yellow]{value}[/yellow]")
270
+
271
+ lines.append(f" [dim]消息:[/dim] {message}")
272
+ lines.append("")
273
+
274
+ lines.append("[cyan]" + "═" * 60 + "[/cyan]")
275
+
276
+ return "\n".join(lines)
277
+
278
+ @staticmethod
279
+ def format_validation_summary(
280
+ validation_details: dict[str, Any] | None,
281
+ raw_datasets: dict[str, Any] | None = None,
282
+ ) -> str:
283
+ """格式化校验摘要:证明 validate 确实加载了数据并执行了约束。
284
+
285
+ 输出加载的表与行数、执行的约束检查数及各项通过/失败状态,
286
+ 用于消除"通过=没跑"的疑虑。
287
+
288
+ Args:
289
+ validation_details: executor 返回的 validation_details 字典,
290
+ 包含 format_checks / constraint_checks 两个列表;
291
+ 为空或结构异常时返回提示性兜底文本
292
+ raw_datasets: executor 返回的原始数据集字典,用于统计每个表的行数;
293
+ 为空时表行数显示为"-"
294
+
295
+ Returns:
296
+ 格式化的校验摘要文本(rich 标记字符串)
297
+ """
298
+ mark_ok = "✓" if _supports_unicode() else "[OK]"
299
+ mark_fail = "✗" if _supports_unicode() else "[FAIL]"
300
+ bullet = "•" if _supports_unicode() else "-"
301
+
302
+ # 兜底:没有 validation_details 时无法证明执行情况,明确提示
303
+ if not validation_details:
304
+ return f"[yellow]{bullet} 未返回校验明细(validation_details 为空),无法确认实际执行的检查项数[/yellow]"
305
+
306
+ # ---- 表/行数统计 ----
307
+ format_checks = validation_details.get("format_checks", []) or []
308
+ table_lines: list[str] = []
309
+ for fc in format_checks:
310
+ table = fc.get("table", "?")
311
+ # 从 raw_datasets 取行数(DataFrame),取不到则显示 "-"
312
+ ds = (raw_datasets or {}).get(table)
313
+ row_count = len(ds) if ds is not None and hasattr(ds, "__len__") else "-"
314
+ source = fc.get("source_file") or ""
315
+ src_hint = f" [dim]({source})[/dim]" if source else ""
316
+ table_lines.append(f" {bullet} {table}: {row_count} 行{src_hint}")
317
+ tables_block = "\n".join(table_lines) if table_lines else " (无)"
318
+
319
+ # ---- 约束检查统计 ----
320
+ constraint_checks = validation_details.get("constraint_checks", []) or []
321
+ total_checks = len(constraint_checks)
322
+ failed_checks = [c for c in constraint_checks if not c.get("passed", True)]
323
+ passed_count = total_checks - len(failed_checks)
324
+
325
+ lines = [
326
+ "",
327
+ "[bold] ┌ 校验摘要 ┐[/bold]",
328
+ f"[bold] 数据表:[/bold] {len(format_checks)} 个",
329
+ tables_block,
330
+ f"[bold] 约束检查:[/bold] {total_checks} 项,"
331
+ + (
332
+ f"全部通过 {mark_ok}"
333
+ if not failed_checks
334
+ else f"{passed_count} 通过 / {len(failed_checks)} 失败 {mark_fail}"
335
+ ),
336
+ ]
337
+
338
+ # 逐项约束结果(描述优先取 executor 提供的 description,否则用类型+表)
339
+ if constraint_checks:
340
+ lines.append("")
341
+ for c in constraint_checks:
342
+ passed = c.get("passed", True)
343
+ ctype = (
344
+ c.get("constraint_type", "Constraint").replace("Constraint", "").removesuffix("s")
345
+ if c.get("constraint_type")
346
+ else "Constraint"
347
+ )
348
+ # description 形如 "非空约束: users.email",直接用作可读标签
349
+ desc = c.get("description") or f"{ctype}: {c.get('table', '?')}"
350
+ tag = f"[green]{mark_ok}[/green]" if passed else f"[red]{mark_fail}[/red]"
351
+ err_cnt = c.get("error_count", 0)
352
+ err_hint = f" [red]({err_cnt} 错误)[/red]" if err_cnt else ""
353
+ lines.append(f" {bullet} {desc} {tag}{err_hint}")
354
+
355
+ return "\n".join(lines)
356
+
357
+ @staticmethod
358
+ def format_project_info(info: dict[str, Any]) -> str:
359
+ lines = []
360
+ lines.append("[bold]\n项目信息:[/bold]")
361
+ lines.append(f" 名称: {info.get('name', '未命名')}")
362
+ lines.append(f" 路径: {info.get('path', '')}")
363
+ lines.append(f" Schema 数量: {info.get('schemas_count', 0)}")
364
+ lines.append(f" 约束数量: {info.get('constraints_count', 0)}")
365
+
366
+ if info.get("tables"):
367
+ lines.append("[bold]\n数据表:[/bold]")
368
+ for table in info["tables"]:
369
+ lines.append(f" - {table}")
370
+
371
+ return "\n".join(lines)