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,440 @@
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
+ - 支持 Excel(.xlsx/.xls)、CSV 和 JSON 文件格式
22
+ - JSON 文件支持 JSONPath 提取、多种格式解析和 record_path 规范化
23
+ - 集成路径安全校验,限制只允许访问允许的目录范围
24
+ - 支持工作表切换预览(Excel)
25
+
26
+ 架构设计:
27
+ - 基于 FastAPI APIRouter 组织路由,挂载到 /preview 前缀下
28
+ - 使用 pandas 读取 Excel/CSV,使用策略模式解析 JSON
29
+ - 依赖 JSONPathExtractor 和 parser 策略实现灵活的 JSON 数据处理
30
+ - 通过 validate_file_access 实现统一的路径安全控制
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ import logging
36
+ import os
37
+ from typing import Any
38
+
39
+ import pandas as pd
40
+ from fastapi import HTTPException
41
+
42
+ from app.api.routers.preview.models import FilePathPreviewRequest, FilePreviewResponse, SheetSwitchRequest
43
+ from app.shared.core.data_source.loaders.excel_loader import get_excel_sheet_names
44
+ from app.shared.core.data_source.loaders.extractor import JSONPathExtractor
45
+ from app.shared.core.data_source.loaders.strategies import get_parser
46
+ from app.shared.services.preview.loader import load_preview_data
47
+ from app.shared.services.preview.path_validation import validate_file_access
48
+
49
+ from .router import router
50
+
51
+ logger = logging.getLogger(__name__)
52
+
53
+
54
+ def _infer_json_type(value: Any) -> str:
55
+ """推断 JSON 值的类型(用于前端类型标记展示)。"""
56
+ if value is None:
57
+ return "null"
58
+ if isinstance(value, bool):
59
+ return "boolean"
60
+ if isinstance(value, int) or isinstance(value, float):
61
+ return "number"
62
+ if isinstance(value, str):
63
+ return "string"
64
+ if isinstance(value, list):
65
+ return "array"
66
+ if isinstance(value, dict):
67
+ return "object"
68
+ return "string"
69
+
70
+
71
+ @router.post(
72
+ "/file/path",
73
+ response_model=FilePreviewResponse,
74
+ summary="基于文件路径预览文件内容",
75
+ responses={
76
+ 400: {"description": "不支持的文件类型"},
77
+ 404: {"description": "工作表不存在"},
78
+ 500: {"description": "读取文件失败"},
79
+ },
80
+ )
81
+ def preview_file_by_path(request: FilePathPreviewRequest) -> FilePreviewResponse:
82
+ """
83
+ @methoddesc 基于文件路径预览文件内容
84
+
85
+ 业务用途:
86
+ - 接收前端给定的绝对文件路径,校验访问权限后解析数据
87
+ - 支持 Excel 多 Sheet 切换(通过 sheet_name 字段)
88
+
89
+ 参数:
90
+ request: 包含 file_path / max_rows / max_cols / sheet_name 的请求体
91
+
92
+ 返回:
93
+ FilePreviewResponse: 包含解析数据、Sheet 列表、文件类型等的响应
94
+
95
+ 异常:
96
+ HTTPException: 文件不可访问(403) / 工作表不存在(404) / 读取失败(500)
97
+ """
98
+ logger.info("=" * 50)
99
+ logger.info(f"[PREVIEW] 收到路径预览请求: {request.file_path}")
100
+ logger.info(f"[PREVIEW] max_rows: {request.max_rows}, max_cols: {request.max_cols}")
101
+ if request.sheet_name:
102
+ logger.info(f"[PREVIEW] 指定工作表: {request.sheet_name}")
103
+ logger.info("=" * 50)
104
+
105
+ try:
106
+ file_path = request.file_path
107
+ max_rows = request.max_rows
108
+ max_cols = request.max_cols
109
+ sheet_name = request.sheet_name
110
+
111
+ validate_file_access(file_path)
112
+
113
+ file_ext = os.path.splitext(file_path)[1].lower()
114
+ file_name = os.path.basename(file_path)
115
+
116
+ if file_ext in [".xlsx", ".xls"]:
117
+ file_type = "excel"
118
+ elif file_ext == ".csv":
119
+ file_type = "csv"
120
+ elif file_ext in [".json", ".jsonl", ".ndjson"]:
121
+ file_type = "json"
122
+ else:
123
+ raise HTTPException(status_code=400, detail=f"不支持的文件类型: {file_ext}")
124
+
125
+ if file_type == "excel":
126
+ try:
127
+ # 工作表列表读取:引擎按扩展名自适应(.xls→xlrd)、句柄确保关闭。
128
+ # 原实现硬编码 openpyxl 且从不 close——.xls 必然 500、Windows 下数据文件被锁。
129
+ sheet_names = get_excel_sheet_names(file_path)
130
+
131
+ if sheet_name:
132
+ if sheet_name in sheet_names:
133
+ current_sheet = sheet_name
134
+ else:
135
+ raise HTTPException(
136
+ status_code=404,
137
+ detail=f"工作表 '{sheet_name}' 不存在,可用工作表: {sheet_names}",
138
+ )
139
+ else:
140
+ current_sheet = sheet_names[0] if sheet_names else "Sheet1"
141
+
142
+ logger.info(f"[PREVIEW] 工作表列表: {sheet_names}, 当前工作表: {current_sheet}")
143
+
144
+ df, loaded_sheet_names = load_preview_data(
145
+ file_path=file_path,
146
+ file_type="excel",
147
+ max_rows=max_rows,
148
+ sheet_name=current_sheet,
149
+ )
150
+
151
+ data = []
152
+ for _, row in df.iterrows():
153
+ row_data = [str(cell) for cell in row.tolist()[:max_cols]]
154
+ data.append(row_data)
155
+
156
+ logger.info(
157
+ f"[PREVIEW] Excel 文件读取成功: {file_name}, 行数: {len(df)}, 列数: {len(data[0]) if data else 0}"
158
+ )
159
+
160
+ return FilePreviewResponse(
161
+ success=True,
162
+ data=data,
163
+ file_type=file_type,
164
+ file_name=file_name,
165
+ total_rows=len(df),
166
+ total_cols=len(data[0]) if data else 0,
167
+ sheets=loaded_sheet_names,
168
+ current_sheet=current_sheet,
169
+ )
170
+
171
+ except Exception as e:
172
+ logger.info(f"[PREVIEW] 读取 Excel 文件失败: {e}")
173
+ import traceback
174
+
175
+ traceback.print_exc()
176
+ raise HTTPException(status_code=500, detail=f"读取Excel文件失败: {str(e)}") from e
177
+
178
+ if file_type == "csv":
179
+ try:
180
+ df, _ = load_preview_data(
181
+ file_path=file_path,
182
+ file_type="csv",
183
+ max_rows=max_rows,
184
+ )
185
+
186
+ data = []
187
+ for _, row in df.iterrows():
188
+ row_data = [str(cell) for cell in row.tolist()[:max_cols]]
189
+ data.append(row_data)
190
+
191
+ logger.info(
192
+ f"[PREVIEW] CSV 文件读取成功: {file_name}, 行数: {len(df)}, 列数: {len(data[0]) if data else 0}"
193
+ )
194
+
195
+ return FilePreviewResponse(
196
+ success=True,
197
+ data=data,
198
+ file_type=file_type,
199
+ file_name=file_name,
200
+ total_rows=len(df),
201
+ total_cols=len(data[0]) if data else 0,
202
+ sheets=None,
203
+ current_sheet=None,
204
+ )
205
+
206
+ except Exception as e:
207
+ logger.info(f"[PREVIEW] 读取 CSV 文件失败: {e}")
208
+ import traceback
209
+
210
+ traceback.print_exc()
211
+ raise HTTPException(status_code=500, detail=f"读取CSV文件失败: {str(e)}") from e
212
+
213
+ if file_type == "json":
214
+ try:
215
+ import json as json_module
216
+
217
+ with open(file_path, encoding="utf-8") as f:
218
+ content = f.read()
219
+
220
+ # 1. 如果指定了 json_path,先使用 JSONPath 提取数据
221
+ if request.json_path:
222
+ try:
223
+ raw_data = json_module.loads(content)
224
+ extractor = JSONPathExtractor()
225
+ extracted = extractor.extract(raw_data, request.json_path)
226
+ if not extracted:
227
+ raise HTTPException(
228
+ status_code=400, detail=f"JSONPath '{request.json_path}' 未匹配到任何数据"
229
+ )
230
+ # 提取后的数据作为 records 使用
231
+ records = extracted if isinstance(extracted, list) else [extracted]
232
+ except json_module.JSONDecodeError as e:
233
+ raise HTTPException(status_code=400, detail=f"JSON 解析失败: {e.msg}") from e
234
+ else:
235
+ # 2. 根据 json_format 选择合适的 parser(前端已统一为后端格式,直接透传)
236
+ # D8: format 必填(auto 已废弃),默认 array(顶层数组)
237
+ format_type = request.json_format or "array"
238
+
239
+ try:
240
+ parser = get_parser(format_type)
241
+ except ValueError as e:
242
+ raise HTTPException(status_code=400, detail=str(e)) from e
243
+
244
+ records = parser.parse(content)
245
+
246
+ # 3. 应用 record_path 参数(如果指定)
247
+ if request.record_path and records:
248
+ try:
249
+ records = pd.json_normalize(records, record_path=request.record_path).to_dict("records")
250
+ except (KeyError, TypeError) as e:
251
+ raise HTTPException(
252
+ status_code=400,
253
+ detail=f"提取路径「{request.record_path}」在文件中不存在,请检查预览设置中的路径写法({str(e)})",
254
+ ) from e
255
+
256
+ # 限制返回的记录数
257
+ limited_records = records[:max_rows] if records else []
258
+
259
+ # JSON 类型推断和结构统计
260
+ type_inference: dict[str, str] | None = None
261
+ field_count: int | None = None
262
+ nest_depth: int | None = None
263
+
264
+ if records and isinstance(records, list) and len(records) > 0:
265
+ first_record = records[0]
266
+ if isinstance(first_record, dict):
267
+ # 推断每个字段的类型(遍历所有记录取最精确类型)
268
+ type_inference = {}
269
+ for key in first_record.keys():
270
+ types_found: set[str] = set()
271
+ for record in records:
272
+ if isinstance(record, dict) and key in record:
273
+ val = record[key]
274
+ types_found.add(_infer_json_type(val))
275
+ # 如果只有一种类型,直接使用;多种类型时优先 object > array > string
276
+ if len(types_found) == 1:
277
+ type_inference[key] = types_found.pop()
278
+ elif "object" in types_found:
279
+ type_inference[key] = "object"
280
+ elif "array" in types_found:
281
+ type_inference[key] = "array"
282
+ else:
283
+ type_inference[key] = "string"
284
+
285
+ field_count = len(first_record)
286
+
287
+ # 计算最大嵌套深度
288
+ def _calc_depth(obj: Any, depth: int = 0) -> int:
289
+ if not isinstance(obj, (dict, list)):
290
+ return depth
291
+ if isinstance(obj, list):
292
+ if not obj:
293
+ return depth
294
+ return max(_calc_depth(item, depth + 1) for item in obj)
295
+ # dict
296
+ values = list(obj.values())
297
+ if not values:
298
+ return depth
299
+ return max(_calc_depth(v, depth + 1) for v in values)
300
+
301
+ nest_depth = _calc_depth(first_record, 0)
302
+
303
+ logger.info(f"[PREVIEW] JSON 文件读取成功: {file_name}, 记录数: {len(limited_records)}")
304
+ if request.json_path:
305
+ logger.info(f"[PREVIEW] 使用 JSONPath: {request.json_path}")
306
+ if request.json_format:
307
+ logger.info(f"[PREVIEW] 使用格式: {request.json_format}")
308
+ if request.record_path:
309
+ logger.info(f"[PREVIEW] 使用 record_path: {request.record_path}")
310
+
311
+ return FilePreviewResponse(
312
+ success=True,
313
+ data=None, # JSON 不使用表格数据
314
+ raw_data=limited_records, # 返回原始 JSON 数据用于树状显示
315
+ file_type=file_type,
316
+ file_name=file_name,
317
+ total_rows=len(records) if records else 0,
318
+ total_cols=None, # JSON 没有固定列数概念
319
+ sheets=None,
320
+ current_sheet=None,
321
+ type_inference=type_inference,
322
+ field_count=field_count,
323
+ nest_depth=nest_depth,
324
+ )
325
+
326
+ except HTTPException:
327
+ raise
328
+ except Exception as e:
329
+ logger.info(f"[PREVIEW] 读取 JSON 文件失败: {e}")
330
+ import traceback
331
+
332
+ traceback.print_exc()
333
+ raise HTTPException(status_code=500, detail=f"读取JSON文件失败: {str(e)}") from e
334
+
335
+ raise HTTPException(status_code=400, detail=f"不支持的文件类型: {file_type}")
336
+
337
+ except HTTPException:
338
+ raise
339
+ except Exception as e:
340
+ logger.info(f"[PREVIEW] 未知错误: {str(e)}")
341
+ import traceback
342
+
343
+ traceback.print_exc()
344
+ return FilePreviewResponse(
345
+ success=False,
346
+ data=None,
347
+ file_type="unknown",
348
+ file_name="",
349
+ error=f"预览文件时发生错误: {str(e)}",
350
+ )
351
+
352
+
353
+ @router.post(
354
+ "/switch-sheet/path",
355
+ response_model=FilePreviewResponse,
356
+ summary="基于文件路径切换 Excel 工作表",
357
+ responses={
358
+ 400: {"description": "切换工作表只支持 Excel 文件"},
359
+ 404: {"description": "工作表不存在"},
360
+ 500: {"description": "读取文件失败"},
361
+ },
362
+ )
363
+ def switch_sheet_by_path(request: SheetSwitchRequest) -> FilePreviewResponse:
364
+ """
365
+ @methoddesc 基于文件路径切换 Excel 工作表预览
366
+
367
+ 业务用途:
368
+ - 用户在预览界面点击其他 Sheet 时调用
369
+ - 仅支持 .xlsx / .xls;非 Excel 文件返回 400
370
+
371
+ 参数:
372
+ request: 包含 file_path / sheet_name / max_rows / max_cols 的请求体
373
+
374
+ 返回:
375
+ FilePreviewResponse: 新工作表的预览数据
376
+
377
+ 异常:
378
+ HTTPException: 非 Excel 文件(400) / 工作表不存在(404) / 读取失败(500)
379
+ """
380
+ try:
381
+ file_path = request.file_path
382
+ sheet_name = request.sheet_name
383
+ max_rows = request.max_rows
384
+ max_cols = request.max_cols
385
+
386
+ validate_file_access(file_path)
387
+
388
+ file_name = os.path.basename(file_path)
389
+ file_ext = os.path.splitext(file_path)[1].lower()
390
+
391
+ if file_ext not in [".xlsx", ".xls"]:
392
+ raise HTTPException(status_code=400, detail="切换工作表只支持 Excel 文件")
393
+
394
+ try:
395
+ df, sheet_names = load_preview_data(
396
+ file_path=file_path,
397
+ file_type="excel",
398
+ max_rows=max_rows,
399
+ sheet_name=sheet_name,
400
+ )
401
+
402
+ data = []
403
+ for _, row in df.iterrows():
404
+ row_data = [str(cell) for cell in row.tolist()[:max_cols]]
405
+ data.append(row_data)
406
+
407
+ logger.info(f"[PREVIEW] 切换工作表成功: {file_name} -> {sheet_name}, 行数: {len(df)}")
408
+
409
+ return FilePreviewResponse(
410
+ success=True,
411
+ data=data,
412
+ file_type="excel",
413
+ file_name=file_name,
414
+ total_rows=len(df),
415
+ total_cols=len(data[0]) if data else 0,
416
+ sheets=sheet_names,
417
+ current_sheet=sheet_name,
418
+ )
419
+
420
+ except ValueError as e:
421
+ if "Worksheet" in str(e):
422
+ raise HTTPException(status_code=404, detail=f"工作表 '{sheet_name}' 不存在") from e
423
+ raise HTTPException(status_code=500, detail=f"读取工作表失败: {str(e)}") from e
424
+ except Exception as e:
425
+ raise HTTPException(status_code=500, detail=f"读取Excel文件失败: {str(e)}") from e
426
+
427
+ except HTTPException:
428
+ raise
429
+ except Exception as e:
430
+ logger.info(f"[PREVIEW] 切换工作表错误: {str(e)}")
431
+ import traceback
432
+
433
+ traceback.print_exc()
434
+ return FilePreviewResponse(
435
+ success=False,
436
+ data=None,
437
+ file_type="excel",
438
+ file_name="",
439
+ error=f"切换工作表时发生错误: {str(e)}",
440
+ )
@@ -0,0 +1,30 @@
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
+ - 创建并导出文件预览模块的 FastAPI APIRouter 实例
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from fastapi import APIRouter
26
+
27
+ router = APIRouter(prefix="/api/latest/preview", tags=["File Preview"])
28
+
29
+
30
+ __all__ = ["router"]
@@ -0,0 +1,61 @@
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 Project API Router 聚合模块
18
+
19
+ 功能概述:
20
+ - 聚合 project 子模块的所有 FastAPI router
21
+ - 统一设置 prefix="/project" 和 tags=["Project"]
22
+
23
+ 架构设计:
24
+ - 各子模块 router 通过 include_router 合并到主 router
25
+ - 子模块本身使用空 prefix,由主 router 统一添加前缀
26
+ """
27
+
28
+ from fastapi import APIRouter
29
+
30
+ from . import (
31
+ constraint,
32
+ full_config,
33
+ inspection_fix,
34
+ manifest,
35
+ pattern,
36
+ regex,
37
+ schema,
38
+ settings,
39
+ template,
40
+ validation,
41
+ view,
42
+ workspaces,
43
+ )
44
+
45
+ router = APIRouter(
46
+ prefix="/api/latest/project",
47
+ tags=["Project"],
48
+ )
49
+
50
+ router.include_router(view.router)
51
+ router.include_router(workspaces.router)
52
+ router.include_router(manifest.router)
53
+ router.include_router(schema.router)
54
+ router.include_router(constraint.router)
55
+ router.include_router(regex.router)
56
+ router.include_router(pattern.router)
57
+ router.include_router(template.router)
58
+ router.include_router(full_config.router)
59
+ router.include_router(settings.router)
60
+ router.include_router(validation.router)
61
+ router.include_router(inspection_fix.router)
@@ -0,0 +1,111 @@
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 Project API 基础模块
18
+
19
+ 功能概述:
20
+ - 作为 project API 子模块的公共基础设施,集中管理共享导入
21
+ - 提供跨文件共享的辅助函数(如 YAML 加载、文件扫描)
22
+ - 暴露公共 Pydantic 模型定义与 V2 项目相关常量
23
+
24
+ 架构设计:
25
+ - 将共享内容集中到 base.py 以避免循环导入和重复定义
26
+ - 辅助函数使用纯 Python 实现,不依赖 FastAPI 框架,便于单元测试
27
+ - 通过 __all__ 显式控制对外暴露的符号
28
+
29
+ 输入示例:
30
+ from app.api.routers.project.base import ProjectManifestV2, _load_yaml_file
31
+
32
+ 输出示例:
33
+ 可直接使用导入的类型、函数与常量构建 project 相关 API
34
+ """
35
+
36
+ from app.api.models.project import StandardResponse
37
+ from app.api.routers.project.helpers import (
38
+ V2_MANIFEST_FILENAME,
39
+ V2_VIEW_FILENAME,
40
+ V2_WORKSPACES_FILENAME,
41
+ _load_yaml_file,
42
+ _v2_manifest_path,
43
+ _v2_view_path,
44
+ _v2_workspaces_path,
45
+ )
46
+ from app.api.routers.project.models import (
47
+ DisplayNameUpdateRequest,
48
+ FullConfigV2Request,
49
+ ProjectViewV2Model,
50
+ WorkspacesV2Model,
51
+ WorkspaceV2Item,
52
+ )
53
+ from app.api.routers.project.scanner import (
54
+ _scan_constraint_file,
55
+ _scan_regex_node_file,
56
+ _scan_schema_file,
57
+ )
58
+ from app.shared.core.project.constraint.types import ConstraintFileV2
59
+
60
+ # 从 shared 模块导入项目相关类型
61
+ from app.shared.core.project.manifest.types import (
62
+ ConstraintRefV2,
63
+ FileProcessingSettingsV2,
64
+ ProjectManifestV2,
65
+ ProjectSettingsV2,
66
+ RegexNodeRefV2,
67
+ SchemaRefV2,
68
+ ScriptSecuritySettingsV2,
69
+ TransformRefV2,
70
+ ValidationSettingsV2,
71
+ )
72
+ from app.shared.core.project.regex.types import RegexNodeFileV2
73
+ from app.shared.core.project.schema.types import TableSchemaFileV2
74
+ from app.shared.core.project.transform.types import TransformFileV2
75
+
76
+ __all__ = [
77
+ # helpers
78
+ "V2_MANIFEST_FILENAME",
79
+ "V2_VIEW_FILENAME",
80
+ "V2_WORKSPACES_FILENAME",
81
+ "_load_yaml_file",
82
+ "_v2_manifest_path",
83
+ "_v2_view_path",
84
+ "_v2_workspaces_path",
85
+ # scanner
86
+ "_scan_constraint_file",
87
+ "_scan_schema_file",
88
+ "_scan_regex_node_file",
89
+ # models
90
+ "ProjectViewV2Model",
91
+ "FullConfigV2Request",
92
+ "DisplayNameUpdateRequest",
93
+ "StandardResponse",
94
+ "WorkspaceV2Item",
95
+ "WorkspacesV2Model",
96
+ # manifest types
97
+ "ProjectManifestV2",
98
+ "SchemaRefV2",
99
+ "ConstraintRefV2",
100
+ "RegexNodeRefV2",
101
+ "TransformRefV2",
102
+ "ProjectSettingsV2",
103
+ "ValidationSettingsV2",
104
+ "FileProcessingSettingsV2",
105
+ "ScriptSecuritySettingsV2",
106
+ # schema/constraint/regex types
107
+ "TableSchemaFileV2",
108
+ "ConstraintFileV2",
109
+ "RegexNodeFileV2",
110
+ "TransformFileV2",
111
+ ]