aiecs 1.0.1__py3-none-any.whl → 1.7.17__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.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

Files changed (340) hide show
  1. aiecs/__init__.py +13 -16
  2. aiecs/__main__.py +7 -7
  3. aiecs/aiecs_client.py +269 -75
  4. aiecs/application/executors/operation_executor.py +79 -54
  5. aiecs/application/knowledge_graph/__init__.py +7 -0
  6. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  7. aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
  8. aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
  11. aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
  12. aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
  13. aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
  14. aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
  15. aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
  16. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  17. aiecs/application/knowledge_graph/extractors/base.py +98 -0
  18. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
  19. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
  20. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
  21. aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
  22. aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
  23. aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
  24. aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
  25. aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
  26. aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
  27. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
  28. aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
  29. aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
  30. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
  31. aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
  32. aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
  33. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
  34. aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
  35. aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
  36. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  37. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
  38. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
  39. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  40. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
  41. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  42. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  43. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
  44. aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
  45. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
  46. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  47. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  48. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
  49. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
  50. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
  51. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
  52. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
  53. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
  54. aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
  55. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
  56. aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
  57. aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
  58. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
  59. aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
  60. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  61. aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
  62. aiecs/application/knowledge_graph/search/reranker.py +293 -0
  63. aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
  64. aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
  65. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  66. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
  67. aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
  68. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  69. aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
  70. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  71. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
  72. aiecs/common/__init__.py +9 -0
  73. aiecs/common/knowledge_graph/__init__.py +17 -0
  74. aiecs/common/knowledge_graph/runnable.py +471 -0
  75. aiecs/config/__init__.py +20 -5
  76. aiecs/config/config.py +762 -31
  77. aiecs/config/graph_config.py +131 -0
  78. aiecs/config/tool_config.py +435 -0
  79. aiecs/core/__init__.py +29 -13
  80. aiecs/core/interface/__init__.py +2 -2
  81. aiecs/core/interface/execution_interface.py +22 -22
  82. aiecs/core/interface/storage_interface.py +37 -88
  83. aiecs/core/registry/__init__.py +31 -0
  84. aiecs/core/registry/service_registry.py +92 -0
  85. aiecs/domain/__init__.py +270 -1
  86. aiecs/domain/agent/__init__.py +191 -0
  87. aiecs/domain/agent/base_agent.py +3949 -0
  88. aiecs/domain/agent/exceptions.py +99 -0
  89. aiecs/domain/agent/graph_aware_mixin.py +569 -0
  90. aiecs/domain/agent/hybrid_agent.py +1731 -0
  91. aiecs/domain/agent/integration/__init__.py +29 -0
  92. aiecs/domain/agent/integration/context_compressor.py +216 -0
  93. aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
  94. aiecs/domain/agent/integration/protocols.py +281 -0
  95. aiecs/domain/agent/integration/retry_policy.py +218 -0
  96. aiecs/domain/agent/integration/role_config.py +213 -0
  97. aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
  98. aiecs/domain/agent/lifecycle.py +291 -0
  99. aiecs/domain/agent/llm_agent.py +692 -0
  100. aiecs/domain/agent/memory/__init__.py +12 -0
  101. aiecs/domain/agent/memory/conversation.py +1124 -0
  102. aiecs/domain/agent/migration/__init__.py +14 -0
  103. aiecs/domain/agent/migration/conversion.py +163 -0
  104. aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
  105. aiecs/domain/agent/models.py +894 -0
  106. aiecs/domain/agent/observability.py +479 -0
  107. aiecs/domain/agent/persistence.py +449 -0
  108. aiecs/domain/agent/prompts/__init__.py +29 -0
  109. aiecs/domain/agent/prompts/builder.py +159 -0
  110. aiecs/domain/agent/prompts/formatters.py +187 -0
  111. aiecs/domain/agent/prompts/template.py +255 -0
  112. aiecs/domain/agent/registry.py +253 -0
  113. aiecs/domain/agent/tool_agent.py +444 -0
  114. aiecs/domain/agent/tools/__init__.py +15 -0
  115. aiecs/domain/agent/tools/schema_generator.py +377 -0
  116. aiecs/domain/community/__init__.py +155 -0
  117. aiecs/domain/community/agent_adapter.py +469 -0
  118. aiecs/domain/community/analytics.py +432 -0
  119. aiecs/domain/community/collaborative_workflow.py +648 -0
  120. aiecs/domain/community/communication_hub.py +634 -0
  121. aiecs/domain/community/community_builder.py +320 -0
  122. aiecs/domain/community/community_integration.py +796 -0
  123. aiecs/domain/community/community_manager.py +803 -0
  124. aiecs/domain/community/decision_engine.py +849 -0
  125. aiecs/domain/community/exceptions.py +231 -0
  126. aiecs/domain/community/models/__init__.py +33 -0
  127. aiecs/domain/community/models/community_models.py +234 -0
  128. aiecs/domain/community/resource_manager.py +461 -0
  129. aiecs/domain/community/shared_context_manager.py +589 -0
  130. aiecs/domain/context/__init__.py +40 -10
  131. aiecs/domain/context/context_engine.py +1910 -0
  132. aiecs/domain/context/conversation_models.py +87 -53
  133. aiecs/domain/context/graph_memory.py +582 -0
  134. aiecs/domain/execution/model.py +12 -4
  135. aiecs/domain/knowledge_graph/__init__.py +19 -0
  136. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  137. aiecs/domain/knowledge_graph/models/entity.py +148 -0
  138. aiecs/domain/knowledge_graph/models/evidence.py +178 -0
  139. aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
  140. aiecs/domain/knowledge_graph/models/path.py +171 -0
  141. aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
  142. aiecs/domain/knowledge_graph/models/query.py +261 -0
  143. aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
  144. aiecs/domain/knowledge_graph/models/relation.py +202 -0
  145. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  146. aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
  147. aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
  148. aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
  149. aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
  150. aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
  151. aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
  152. aiecs/domain/task/dsl_processor.py +172 -56
  153. aiecs/domain/task/model.py +20 -8
  154. aiecs/domain/task/task_context.py +27 -24
  155. aiecs/infrastructure/__init__.py +0 -2
  156. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  157. aiecs/infrastructure/graph_storage/base.py +837 -0
  158. aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
  159. aiecs/infrastructure/graph_storage/cache.py +424 -0
  160. aiecs/infrastructure/graph_storage/distributed.py +223 -0
  161. aiecs/infrastructure/graph_storage/error_handling.py +380 -0
  162. aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
  163. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  164. aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
  165. aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
  166. aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
  167. aiecs/infrastructure/graph_storage/metrics.py +344 -0
  168. aiecs/infrastructure/graph_storage/migration.py +400 -0
  169. aiecs/infrastructure/graph_storage/pagination.py +483 -0
  170. aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
  171. aiecs/infrastructure/graph_storage/postgres.py +1563 -0
  172. aiecs/infrastructure/graph_storage/property_storage.py +353 -0
  173. aiecs/infrastructure/graph_storage/protocols.py +76 -0
  174. aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
  175. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  176. aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
  177. aiecs/infrastructure/graph_storage/streaming.py +487 -0
  178. aiecs/infrastructure/graph_storage/tenant.py +412 -0
  179. aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
  180. aiecs/infrastructure/messaging/websocket_manager.py +51 -35
  181. aiecs/infrastructure/monitoring/__init__.py +22 -0
  182. aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
  183. aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
  184. aiecs/infrastructure/monitoring/structured_logger.py +3 -7
  185. aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
  186. aiecs/infrastructure/persistence/__init__.py +14 -1
  187. aiecs/infrastructure/persistence/context_engine_client.py +184 -0
  188. aiecs/infrastructure/persistence/database_manager.py +67 -43
  189. aiecs/infrastructure/persistence/file_storage.py +180 -103
  190. aiecs/infrastructure/persistence/redis_client.py +74 -21
  191. aiecs/llm/__init__.py +73 -25
  192. aiecs/llm/callbacks/__init__.py +11 -0
  193. aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
  194. aiecs/llm/client_factory.py +230 -37
  195. aiecs/llm/client_resolver.py +155 -0
  196. aiecs/llm/clients/__init__.py +38 -0
  197. aiecs/llm/clients/base_client.py +328 -0
  198. aiecs/llm/clients/google_function_calling_mixin.py +415 -0
  199. aiecs/llm/clients/googleai_client.py +314 -0
  200. aiecs/llm/clients/openai_client.py +158 -0
  201. aiecs/llm/clients/openai_compatible_mixin.py +367 -0
  202. aiecs/llm/clients/vertex_client.py +1186 -0
  203. aiecs/llm/clients/xai_client.py +201 -0
  204. aiecs/llm/config/__init__.py +51 -0
  205. aiecs/llm/config/config_loader.py +272 -0
  206. aiecs/llm/config/config_validator.py +206 -0
  207. aiecs/llm/config/model_config.py +143 -0
  208. aiecs/llm/protocols.py +149 -0
  209. aiecs/llm/utils/__init__.py +10 -0
  210. aiecs/llm/utils/validate_config.py +89 -0
  211. aiecs/main.py +140 -121
  212. aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
  213. aiecs/scripts/aid/__init__.py +19 -0
  214. aiecs/scripts/aid/module_checker.py +499 -0
  215. aiecs/scripts/aid/version_manager.py +235 -0
  216. aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
  217. aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
  218. aiecs/scripts/dependance_check/__init__.py +15 -0
  219. aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
  220. aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
  221. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
  222. aiecs/scripts/dependance_patch/__init__.py +7 -0
  223. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  224. aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
  225. aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
  226. aiecs/scripts/knowledge_graph/__init__.py +3 -0
  227. aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
  228. aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
  229. aiecs/scripts/tools_develop/README.md +671 -0
  230. aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
  231. aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
  232. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  233. aiecs/scripts/tools_develop/__init__.py +21 -0
  234. aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
  235. aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
  236. aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
  237. aiecs/scripts/tools_develop/schema_coverage.py +511 -0
  238. aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
  239. aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
  240. aiecs/scripts/tools_develop/verify_tools.py +352 -0
  241. aiecs/tasks/__init__.py +0 -1
  242. aiecs/tasks/worker.py +115 -47
  243. aiecs/tools/__init__.py +194 -72
  244. aiecs/tools/apisource/__init__.py +99 -0
  245. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  246. aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
  247. aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
  248. aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
  249. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  250. aiecs/tools/apisource/monitoring/metrics.py +330 -0
  251. aiecs/tools/apisource/providers/__init__.py +112 -0
  252. aiecs/tools/apisource/providers/base.py +671 -0
  253. aiecs/tools/apisource/providers/census.py +397 -0
  254. aiecs/tools/apisource/providers/fred.py +535 -0
  255. aiecs/tools/apisource/providers/newsapi.py +409 -0
  256. aiecs/tools/apisource/providers/worldbank.py +352 -0
  257. aiecs/tools/apisource/reliability/__init__.py +12 -0
  258. aiecs/tools/apisource/reliability/error_handler.py +363 -0
  259. aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
  260. aiecs/tools/apisource/tool.py +832 -0
  261. aiecs/tools/apisource/utils/__init__.py +9 -0
  262. aiecs/tools/apisource/utils/validators.py +334 -0
  263. aiecs/tools/base_tool.py +415 -21
  264. aiecs/tools/docs/__init__.py +121 -0
  265. aiecs/tools/docs/ai_document_orchestrator.py +607 -0
  266. aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
  267. aiecs/tools/docs/content_insertion_tool.py +1320 -0
  268. aiecs/tools/docs/document_creator_tool.py +1464 -0
  269. aiecs/tools/docs/document_layout_tool.py +1160 -0
  270. aiecs/tools/docs/document_parser_tool.py +1016 -0
  271. aiecs/tools/docs/document_writer_tool.py +2008 -0
  272. aiecs/tools/knowledge_graph/__init__.py +17 -0
  273. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
  274. aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
  275. aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
  276. aiecs/tools/langchain_adapter.py +300 -138
  277. aiecs/tools/schema_generator.py +455 -0
  278. aiecs/tools/search_tool/__init__.py +100 -0
  279. aiecs/tools/search_tool/analyzers.py +581 -0
  280. aiecs/tools/search_tool/cache.py +264 -0
  281. aiecs/tools/search_tool/constants.py +128 -0
  282. aiecs/tools/search_tool/context.py +224 -0
  283. aiecs/tools/search_tool/core.py +778 -0
  284. aiecs/tools/search_tool/deduplicator.py +119 -0
  285. aiecs/tools/search_tool/error_handler.py +242 -0
  286. aiecs/tools/search_tool/metrics.py +343 -0
  287. aiecs/tools/search_tool/rate_limiter.py +172 -0
  288. aiecs/tools/search_tool/schemas.py +275 -0
  289. aiecs/tools/statistics/__init__.py +80 -0
  290. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
  291. aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
  292. aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
  293. aiecs/tools/statistics/data_loader_tool.py +555 -0
  294. aiecs/tools/statistics/data_profiler_tool.py +638 -0
  295. aiecs/tools/statistics/data_transformer_tool.py +580 -0
  296. aiecs/tools/statistics/data_visualizer_tool.py +498 -0
  297. aiecs/tools/statistics/model_trainer_tool.py +507 -0
  298. aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
  299. aiecs/tools/task_tools/__init__.py +49 -36
  300. aiecs/tools/task_tools/chart_tool.py +200 -184
  301. aiecs/tools/task_tools/classfire_tool.py +268 -267
  302. aiecs/tools/task_tools/image_tool.py +220 -141
  303. aiecs/tools/task_tools/office_tool.py +226 -146
  304. aiecs/tools/task_tools/pandas_tool.py +477 -121
  305. aiecs/tools/task_tools/report_tool.py +390 -142
  306. aiecs/tools/task_tools/research_tool.py +149 -79
  307. aiecs/tools/task_tools/scraper_tool.py +339 -145
  308. aiecs/tools/task_tools/stats_tool.py +448 -209
  309. aiecs/tools/temp_file_manager.py +26 -24
  310. aiecs/tools/tool_executor/__init__.py +18 -16
  311. aiecs/tools/tool_executor/tool_executor.py +364 -52
  312. aiecs/utils/LLM_output_structor.py +74 -48
  313. aiecs/utils/__init__.py +14 -3
  314. aiecs/utils/base_callback.py +0 -3
  315. aiecs/utils/cache_provider.py +696 -0
  316. aiecs/utils/execution_utils.py +50 -31
  317. aiecs/utils/prompt_loader.py +1 -0
  318. aiecs/utils/token_usage_repository.py +37 -11
  319. aiecs/ws/socket_server.py +14 -4
  320. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/METADATA +52 -15
  321. aiecs-1.7.17.dist-info/RECORD +337 -0
  322. aiecs-1.7.17.dist-info/entry_points.txt +13 -0
  323. aiecs/config/registry.py +0 -19
  324. aiecs/domain/context/content_engine.py +0 -982
  325. aiecs/llm/base_client.py +0 -99
  326. aiecs/llm/openai_client.py +0 -125
  327. aiecs/llm/vertex_client.py +0 -186
  328. aiecs/llm/xai_client.py +0 -184
  329. aiecs/scripts/dependency_checker.py +0 -857
  330. aiecs/scripts/quick_dependency_check.py +0 -269
  331. aiecs/tools/task_tools/search_api.py +0 -7
  332. aiecs-1.0.1.dist-info/RECORD +0 -90
  333. aiecs-1.0.1.dist-info/entry_points.txt +0 -7
  334. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  335. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  336. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  337. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  338. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/WHEEL +0 -0
  339. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/licenses/LICENSE +0 -0
  340. {aiecs-1.0.1.dist-info → aiecs-1.7.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1160 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Document Layout Tool
4
+
5
+ This tool is responsible for document layout, page formatting, and
6
+ visual presentation of documents across different formats.
7
+
8
+ Key Features:
9
+ 1. Page layout management (margins, orientation, size)
10
+ 2. Multi-column layouts and text flow
11
+ 3. Headers, footers, and page numbering
12
+ 4. Section breaks and page breaks
13
+ 5. Typography and spacing control
14
+ 6. Format-specific layout optimization
15
+ """
16
+
17
+ import os
18
+ import uuid
19
+ import tempfile
20
+ import logging
21
+ from datetime import datetime
22
+ from typing import Dict, Any, List, Optional
23
+ from enum import Enum
24
+
25
+ from pydantic import BaseModel, Field
26
+ from pydantic_settings import BaseSettings, SettingsConfigDict
27
+
28
+ from aiecs.tools.base_tool import BaseTool
29
+ from aiecs.tools import register_tool
30
+
31
+
32
+ class PageSize(str, Enum):
33
+ """Standard page sizes"""
34
+
35
+ A4 = "a4"
36
+ A3 = "a3"
37
+ A5 = "a5"
38
+ LETTER = "letter"
39
+ LEGAL = "legal"
40
+ TABLOID = "tabloid"
41
+ CUSTOM = "custom"
42
+
43
+
44
+ class PageOrientation(str, Enum):
45
+ """Page orientations"""
46
+
47
+ PORTRAIT = "portrait"
48
+ LANDSCAPE = "landscape"
49
+
50
+
51
+ class LayoutType(str, Enum):
52
+ """Document layout types"""
53
+
54
+ SINGLE_COLUMN = "single_column"
55
+ TWO_COLUMN = "two_column"
56
+ THREE_COLUMN = "three_column"
57
+ MULTI_COLUMN = "multi_column"
58
+ MAGAZINE = "magazine"
59
+ NEWSPAPER = "newspaper"
60
+ ACADEMIC = "academic"
61
+ CUSTOM = "custom"
62
+
63
+
64
+ class AlignmentType(str, Enum):
65
+ """Text alignment types"""
66
+
67
+ LEFT = "left"
68
+ CENTER = "center"
69
+ RIGHT = "right"
70
+ JUSTIFY = "justify"
71
+
72
+
73
+ class BreakType(str, Enum):
74
+ """Break types"""
75
+
76
+ PAGE_BREAK = "page_break"
77
+ SECTION_BREAK = "section_break"
78
+ COLUMN_BREAK = "column_break"
79
+ LINE_BREAK = "line_break"
80
+
81
+
82
+ class HeaderFooterPosition(str, Enum):
83
+ """Header/footer positions"""
84
+
85
+ HEADER_LEFT = "header_left"
86
+ HEADER_CENTER = "header_center"
87
+ HEADER_RIGHT = "header_right"
88
+ FOOTER_LEFT = "footer_left"
89
+ FOOTER_CENTER = "footer_center"
90
+ FOOTER_RIGHT = "footer_right"
91
+
92
+
93
+ class DocumentLayoutError(Exception):
94
+ """Base exception for Document Layout errors"""
95
+
96
+
97
+ class LayoutConfigurationError(DocumentLayoutError):
98
+ """Raised when layout configuration fails"""
99
+
100
+
101
+ class PageSetupError(DocumentLayoutError):
102
+ """Raised when page setup fails"""
103
+
104
+
105
+ @register_tool("document_layout")
106
+ class DocumentLayoutTool(BaseTool):
107
+ """
108
+ Document Layout Tool for managing document presentation and formatting
109
+
110
+ This tool provides:
111
+ 1. Page setup and formatting
112
+ 2. Multi-column layouts
113
+ 3. Headers, footers, and page numbering
114
+ 4. Typography and spacing control
115
+ 5. Break management (page, section, column)
116
+ 6. Format-specific layout optimization
117
+
118
+ Integrates with:
119
+ - DocumentCreatorTool for initial document setup
120
+ - DocumentWriterTool for content placement
121
+ - ContentInsertionTool for complex content positioning
122
+ """
123
+
124
+ # Configuration schema
125
+ class Config(BaseSettings):
126
+ """Configuration for the document layout tool
127
+
128
+ Automatically reads from environment variables with DOC_LAYOUT_ prefix.
129
+ Example: DOC_LAYOUT_TEMP_DIR -> temp_dir
130
+ """
131
+
132
+ model_config = SettingsConfigDict(env_prefix="DOC_LAYOUT_")
133
+
134
+ temp_dir: str = Field(
135
+ default=os.path.join(tempfile.gettempdir(), "document_layouts"),
136
+ description="Temporary directory for layout processing",
137
+ )
138
+ default_page_size: str = Field(default="a4", description="Default page size")
139
+ default_orientation: str = Field(default="portrait", description="Default page orientation")
140
+ default_margins: Dict[str, float] = Field(
141
+ default={"top": 2.5, "bottom": 2.5, "left": 2.5, "right": 2.5},
142
+ description="Default page margins in centimeters (top, bottom, left, right)",
143
+ )
144
+ auto_adjust_layout: bool = Field(
145
+ default=True,
146
+ description="Whether to automatically adjust layout for optimal presentation",
147
+ )
148
+ preserve_formatting: bool = Field(
149
+ default=True,
150
+ description="Whether to preserve existing formatting when applying layouts",
151
+ )
152
+
153
+ def __init__(self, config: Optional[Dict] = None, **kwargs):
154
+ """Initialize Document Layout Tool with settings
155
+
156
+ Configuration is automatically loaded by BaseTool from:
157
+ 1. Explicit config dict (highest priority)
158
+ 2. YAML config files (config/tools/document_layout.yaml)
159
+ 3. Environment variables (via dotenv from .env files)
160
+ 4. Tool defaults (lowest priority)
161
+
162
+ Args:
163
+ config: Optional configuration overrides
164
+ **kwargs: Additional arguments passed to BaseTool (e.g., tool_name)
165
+ """
166
+ super().__init__(config, **kwargs)
167
+
168
+ # Configuration is automatically loaded by BaseTool into self._config_obj
169
+ # Access config via self._config_obj (BaseSettings instance)
170
+ self.config = self._config_obj if self._config_obj else self.Config()
171
+
172
+ self.logger = logging.getLogger(__name__)
173
+
174
+ # Initialize directories
175
+ self._init_directories()
176
+
177
+ # Initialize layout presets
178
+ self._init_layout_presets()
179
+
180
+ # Track layout operations
181
+ self._layout_operations: List[Any] = []
182
+
183
+ def _init_directories(self):
184
+ """Initialize required directories"""
185
+ os.makedirs(self.config.temp_dir, exist_ok=True)
186
+
187
+ def _init_layout_presets(self):
188
+ """Initialize built-in layout presets"""
189
+ self.layout_presets = {
190
+ "default": self._get_default_layout(),
191
+ "academic_paper": self._get_academic_paper_layout(),
192
+ "business_report": self._get_business_report_layout(),
193
+ "magazine": self._get_magazine_layout(),
194
+ "newspaper": self._get_newspaper_layout(),
195
+ "presentation": self._get_presentation_layout(),
196
+ "technical_doc": self._get_technical_doc_layout(),
197
+ "letter": self._get_letter_layout(),
198
+ "invoice": self._get_invoice_layout(),
199
+ "brochure": self._get_brochure_layout(),
200
+ }
201
+
202
+ # Schema definitions
203
+ class Set_page_layoutSchema(BaseModel):
204
+ """Schema for set_page_layout operation"""
205
+
206
+ document_path: str = Field(description="Path to document")
207
+ page_size: PageSize = Field(description="Page size")
208
+ orientation: PageOrientation = Field(description="Page orientation")
209
+ margins: Dict[str, float] = Field(description="Page margins (top, bottom, left, right)")
210
+ layout_preset: Optional[str] = Field(default=None, description="Layout preset name")
211
+
212
+ class Create_multi_column_layoutSchema(BaseModel):
213
+ """Schema for create_multi_column_layout operation"""
214
+
215
+ document_path: str = Field(description="Path to document")
216
+ num_columns: int = Field(description="Number of columns")
217
+ column_gap: float = Field(default=1.0, description="Gap between columns (cm)")
218
+ column_widths: Optional[List[float]] = Field(default=None, description="Custom column widths")
219
+ balance_columns: bool = Field(default=True, description="Balance column heights")
220
+
221
+ class Setup_headers_footersSchema(BaseModel):
222
+ """Schema for setup_headers_footers operation"""
223
+
224
+ document_path: str = Field(description="Path to document")
225
+ header_config: Optional[Dict[str, Any]] = Field(default=None, description="Header configuration")
226
+ footer_config: Optional[Dict[str, Any]] = Field(default=None, description="Footer configuration")
227
+ page_numbering: bool = Field(default=True, description="Include page numbering")
228
+ numbering_style: str = Field(default="numeric", description="Page numbering style")
229
+
230
+ class Insert_breakSchema(BaseModel):
231
+ """Schema for insert_break operation"""
232
+
233
+ document_path: str = Field(description="Path to document")
234
+ break_type: BreakType = Field(description="Type of break to insert")
235
+ position: Optional[Dict[str, Any]] = Field(default=None, description="Position to insert break")
236
+ break_options: Optional[Dict[str, Any]] = Field(default=None, description="Break-specific options")
237
+
238
+ class Configure_typographySchema(BaseModel):
239
+ """Schema for configure_typography operation"""
240
+
241
+ document_path: str = Field(description="Path to document")
242
+ font_config: Dict[str, Any] = Field(description="Font configuration")
243
+ spacing_config: Optional[Dict[str, Any]] = Field(default=None, description="Spacing configuration")
244
+ alignment: Optional[AlignmentType] = Field(default=None, description="Text alignment")
245
+
246
+ class Optimize_layout_for_contentSchema(BaseModel):
247
+ """Schema for optimize_layout_for_content operation"""
248
+
249
+ document_path: str = Field(description="Path to document")
250
+ content_analysis: Dict[str, Any] = Field(description="Analysis of document content")
251
+ optimization_goals: List[str] = Field(description="List of optimization goals")
252
+
253
+ def set_page_layout(
254
+ self,
255
+ document_path: str,
256
+ page_size: PageSize,
257
+ orientation: PageOrientation,
258
+ margins: Dict[str, float],
259
+ layout_preset: Optional[str] = None,
260
+ ) -> Dict[str, Any]:
261
+ """
262
+ Set page layout configuration for document
263
+
264
+ Args:
265
+ document_path: Path to document
266
+ page_size: Page size (A4, Letter, etc.)
267
+ orientation: Page orientation (portrait/landscape)
268
+ margins: Page margins in cm (top, bottom, left, right)
269
+ layout_preset: Optional layout preset to apply
270
+
271
+ Returns:
272
+ Dict containing layout configuration results
273
+ """
274
+ try:
275
+ start_time = datetime.now()
276
+ operation_id = str(uuid.uuid4())
277
+
278
+ self.logger.info(f"Setting page layout {operation_id} for: {document_path}")
279
+
280
+ # Validate margins
281
+ required_margins = ["top", "bottom", "left", "right"]
282
+ for margin in required_margins:
283
+ if margin not in margins:
284
+ raise LayoutConfigurationError(f"Missing margin: {margin}")
285
+
286
+ # Apply layout preset if specified
287
+ if layout_preset:
288
+ preset_config = self._get_layout_preset(layout_preset)
289
+ if preset_config:
290
+ page_size = preset_config.get("page_size", page_size)
291
+ orientation = preset_config.get("orientation", orientation)
292
+ margins.update(preset_config.get("margins", {}))
293
+
294
+ # Create layout configuration
295
+ layout_config = {
296
+ "page_size": page_size,
297
+ "orientation": orientation,
298
+ "margins": margins,
299
+ "layout_preset": layout_preset,
300
+ "dimensions": self._calculate_page_dimensions(page_size, orientation, margins),
301
+ }
302
+
303
+ # Apply layout to document
304
+ self._apply_page_layout_to_document(document_path, layout_config)
305
+
306
+ # Track operation
307
+ operation_info = {
308
+ "operation_id": operation_id,
309
+ "operation_type": "set_page_layout",
310
+ "document_path": document_path,
311
+ "layout_config": layout_config,
312
+ "timestamp": start_time.isoformat(),
313
+ "duration": (datetime.now() - start_time).total_seconds(),
314
+ }
315
+
316
+ self._layout_operations.append(operation_info)
317
+
318
+ self.logger.info(f"Page layout {operation_id} applied successfully")
319
+ return operation_info
320
+
321
+ except Exception as e:
322
+ raise PageSetupError(f"Failed to set page layout: {str(e)}")
323
+
324
+ def create_multi_column_layout(
325
+ self,
326
+ document_path: str,
327
+ num_columns: int,
328
+ column_gap: float = 1.0,
329
+ column_widths: Optional[List[float]] = None,
330
+ balance_columns: bool = True,
331
+ ) -> Dict[str, Any]:
332
+ """
333
+ Create multi-column layout for document
334
+
335
+ Args:
336
+ document_path: Path to document
337
+ num_columns: Number of columns
338
+ column_gap: Gap between columns in cm
339
+ column_widths: Custom column widths (if None, equal widths)
340
+ balance_columns: Whether to balance column heights
341
+
342
+ Returns:
343
+ Dict containing multi-column layout results
344
+ """
345
+ try:
346
+ start_time = datetime.now()
347
+ operation_id = str(uuid.uuid4())
348
+
349
+ self.logger.info(f"Creating {num_columns}-column layout {operation_id} for: {document_path}")
350
+
351
+ # Validate parameters
352
+ if num_columns < 1:
353
+ raise LayoutConfigurationError("Number of columns must be at least 1")
354
+ if column_widths and len(column_widths) != num_columns:
355
+ raise LayoutConfigurationError("Column widths count must match number of columns")
356
+
357
+ # Calculate column configuration
358
+ column_config = self._calculate_column_configuration(num_columns, column_gap, column_widths, balance_columns)
359
+
360
+ # Apply multi-column layout
361
+ self._apply_multi_column_layout(document_path, column_config)
362
+
363
+ operation_info = {
364
+ "operation_id": operation_id,
365
+ "operation_type": "create_multi_column_layout",
366
+ "document_path": document_path,
367
+ "column_config": column_config,
368
+ "timestamp": start_time.isoformat(),
369
+ "duration": (datetime.now() - start_time).total_seconds(),
370
+ }
371
+
372
+ self._layout_operations.append(operation_info)
373
+
374
+ self.logger.info(f"Multi-column layout {operation_id} created successfully")
375
+ return operation_info
376
+
377
+ except Exception as e:
378
+ raise LayoutConfigurationError(f"Failed to create multi-column layout: {str(e)}")
379
+
380
+ def setup_headers_footers(
381
+ self,
382
+ document_path: str,
383
+ header_config: Optional[Dict[str, Any]] = None,
384
+ footer_config: Optional[Dict[str, Any]] = None,
385
+ page_numbering: bool = True,
386
+ numbering_style: str = "numeric",
387
+ ) -> Dict[str, Any]:
388
+ """
389
+ Setup headers and footers for document
390
+
391
+ Args:
392
+ document_path: Path to document
393
+ header_config: Header configuration
394
+ footer_config: Footer configuration
395
+ page_numbering: Include page numbering
396
+ numbering_style: Page numbering style (numeric, roman, alpha)
397
+
398
+ Returns:
399
+ Dict containing header/footer setup results
400
+ """
401
+ try:
402
+ start_time = datetime.now()
403
+ operation_id = str(uuid.uuid4())
404
+
405
+ self.logger.info(f"Setting up headers/footers {operation_id} for: {document_path}")
406
+
407
+ # Process header configuration
408
+ processed_header = self._process_header_footer_config(header_config, "header", page_numbering, numbering_style)
409
+
410
+ # Process footer configuration
411
+ processed_footer = self._process_header_footer_config(footer_config, "footer", page_numbering, numbering_style)
412
+
413
+ # Apply headers and footers
414
+ self._apply_headers_footers(document_path, processed_header, processed_footer)
415
+
416
+ operation_info = {
417
+ "operation_id": operation_id,
418
+ "operation_type": "setup_headers_footers",
419
+ "document_path": document_path,
420
+ "header_config": processed_header,
421
+ "footer_config": processed_footer,
422
+ "page_numbering": page_numbering,
423
+ "numbering_style": numbering_style,
424
+ "timestamp": start_time.isoformat(),
425
+ "duration": (datetime.now() - start_time).total_seconds(),
426
+ }
427
+
428
+ self._layout_operations.append(operation_info)
429
+
430
+ self.logger.info(f"Headers/footers {operation_id} setup successfully")
431
+ return operation_info
432
+
433
+ except Exception as e:
434
+ raise LayoutConfigurationError(f"Failed to setup headers/footers: {str(e)}")
435
+
436
+ def insert_break(
437
+ self,
438
+ document_path: str,
439
+ break_type: BreakType,
440
+ position: Optional[Dict[str, Any]] = None,
441
+ break_options: Optional[Dict[str, Any]] = None,
442
+ ) -> Dict[str, Any]:
443
+ """
444
+ Insert page, section, or column break
445
+
446
+ Args:
447
+ document_path: Path to document
448
+ break_type: Type of break to insert
449
+ position: Position to insert break (line, offset, etc.)
450
+ break_options: Break-specific options
451
+
452
+ Returns:
453
+ Dict containing break insertion results
454
+ """
455
+ try:
456
+ start_time = datetime.now()
457
+ operation_id = str(uuid.uuid4())
458
+
459
+ self.logger.info(f"Inserting {break_type} break {operation_id} in: {document_path}")
460
+
461
+ # Determine break markup based on type and format
462
+ break_markup = self._generate_break_markup(break_type, break_options)
463
+
464
+ # Insert break at specified position
465
+ self._insert_break_at_position(document_path, break_markup, position)
466
+
467
+ operation_info = {
468
+ "operation_id": operation_id,
469
+ "operation_type": "insert_break",
470
+ "document_path": document_path,
471
+ "break_type": break_type,
472
+ "position": position,
473
+ "break_options": break_options,
474
+ "break_markup": break_markup,
475
+ "timestamp": start_time.isoformat(),
476
+ "duration": (datetime.now() - start_time).total_seconds(),
477
+ }
478
+
479
+ self._layout_operations.append(operation_info)
480
+
481
+ self.logger.info(f"Break {operation_id} inserted successfully")
482
+ return operation_info
483
+
484
+ except Exception as e:
485
+ raise LayoutConfigurationError(f"Failed to insert break: {str(e)}")
486
+
487
+ def configure_typography(
488
+ self,
489
+ document_path: str,
490
+ font_config: Dict[str, Any],
491
+ spacing_config: Optional[Dict[str, Any]] = None,
492
+ alignment: Optional[AlignmentType] = None,
493
+ ) -> Dict[str, Any]:
494
+ """
495
+ Configure typography and text formatting
496
+
497
+ Args:
498
+ document_path: Path to document
499
+ font_config: Font configuration (family, size, weight, etc.)
500
+ spacing_config: Spacing configuration (line height, paragraph spacing)
501
+ alignment: Text alignment
502
+
503
+ Returns:
504
+ Dict containing typography configuration results
505
+ """
506
+ try:
507
+ start_time = datetime.now()
508
+ operation_id = str(uuid.uuid4())
509
+
510
+ self.logger.info(f"Configuring typography {operation_id} for: {document_path}")
511
+
512
+ # Process typography configuration
513
+ typography_config = self._process_typography_config(font_config, spacing_config, alignment)
514
+
515
+ # Apply typography settings
516
+ self._apply_typography_settings(document_path, typography_config)
517
+
518
+ operation_info = {
519
+ "operation_id": operation_id,
520
+ "operation_type": "configure_typography",
521
+ "document_path": document_path,
522
+ "typography_config": typography_config,
523
+ "timestamp": start_time.isoformat(),
524
+ "duration": (datetime.now() - start_time).total_seconds(),
525
+ }
526
+
527
+ self._layout_operations.append(operation_info)
528
+
529
+ self.logger.info(f"Typography {operation_id} configured successfully")
530
+ return operation_info
531
+
532
+ except Exception as e:
533
+ raise LayoutConfigurationError(f"Failed to configure typography: {str(e)}")
534
+
535
+ def optimize_layout_for_content(
536
+ self,
537
+ document_path: str,
538
+ content_analysis: Dict[str, Any],
539
+ optimization_goals: List[str],
540
+ ) -> Dict[str, Any]:
541
+ """
542
+ Optimize document layout based on content analysis
543
+
544
+ Args:
545
+ document_path: Path to document
546
+ content_analysis: Analysis of document content
547
+ optimization_goals: List of optimization goals
548
+
549
+ Returns:
550
+ Dict containing layout optimization results
551
+ """
552
+ try:
553
+ start_time = datetime.now()
554
+ operation_id = str(uuid.uuid4())
555
+
556
+ self.logger.info(f"Optimizing layout {operation_id} for: {document_path}")
557
+
558
+ # Analyze current layout
559
+ current_layout = self._analyze_current_layout(document_path)
560
+
561
+ # Generate optimization recommendations
562
+ optimization_plan = self._generate_optimization_plan(current_layout, content_analysis, optimization_goals)
563
+
564
+ # Apply optimizations
565
+ optimization_results = self._apply_layout_optimizations(document_path, optimization_plan)
566
+
567
+ operation_info = {
568
+ "operation_id": operation_id,
569
+ "operation_type": "optimize_layout_for_content",
570
+ "document_path": document_path,
571
+ "content_analysis": content_analysis,
572
+ "optimization_goals": optimization_goals,
573
+ "optimization_plan": optimization_plan,
574
+ "optimization_results": optimization_results,
575
+ "timestamp": start_time.isoformat(),
576
+ "duration": (datetime.now() - start_time).total_seconds(),
577
+ }
578
+
579
+ self._layout_operations.append(operation_info)
580
+
581
+ self.logger.info(f"Layout optimization {operation_id} completed successfully")
582
+ return operation_info
583
+
584
+ except Exception as e:
585
+ raise LayoutConfigurationError(f"Failed to optimize layout: {str(e)}")
586
+
587
+ def get_layout_presets(self) -> Dict[str, Any]:
588
+ """
589
+ Get available layout presets
590
+
591
+ Returns:
592
+ Dict containing available layout presets
593
+ """
594
+ return {
595
+ "presets": list(self.layout_presets.keys()),
596
+ "preset_details": {name: preset.get("description", "") for name, preset in self.layout_presets.items()},
597
+ }
598
+
599
+ def get_layout_operations(self) -> List[Dict[str, Any]]:
600
+ """
601
+ Get list of layout operations performed
602
+
603
+ Returns:
604
+ List of layout operation information
605
+ """
606
+ return self._layout_operations.copy()
607
+
608
+ # Layout preset definitions
609
+ def _get_default_layout(self) -> Dict[str, Any]:
610
+ """Get default layout configuration"""
611
+ return {
612
+ "description": "Standard single-column layout",
613
+ "page_size": PageSize.A4,
614
+ "orientation": PageOrientation.PORTRAIT,
615
+ "margins": {"top": 2.5, "bottom": 2.5, "left": 2.5, "right": 2.5},
616
+ "columns": 1,
617
+ "font": {"family": "Arial", "size": 12},
618
+ "spacing": {"line_height": 1.5, "paragraph_spacing": 6},
619
+ }
620
+
621
+ def _get_academic_paper_layout(self) -> Dict[str, Any]:
622
+ """Get academic paper layout configuration"""
623
+ return {
624
+ "description": "Academic paper with double spacing",
625
+ "page_size": PageSize.A4,
626
+ "orientation": PageOrientation.PORTRAIT,
627
+ "margins": {"top": 2.5, "bottom": 2.5, "left": 3.0, "right": 2.5},
628
+ "columns": 1,
629
+ "font": {"family": "Times New Roman", "size": 12},
630
+ "spacing": {"line_height": 2.0, "paragraph_spacing": 0},
631
+ "headers_footers": {
632
+ "header_right": "{author_name}",
633
+ "footer_center": "{page_number}",
634
+ },
635
+ }
636
+
637
+ def _get_business_report_layout(self) -> Dict[str, Any]:
638
+ """Get business report layout configuration"""
639
+ return {
640
+ "description": "Professional business report layout",
641
+ "page_size": PageSize.A4,
642
+ "orientation": PageOrientation.PORTRAIT,
643
+ "margins": {"top": 2.0, "bottom": 2.0, "left": 2.5, "right": 2.5},
644
+ "columns": 1,
645
+ "font": {"family": "Calibri", "size": 11},
646
+ "spacing": {"line_height": 1.15, "paragraph_spacing": 6},
647
+ "headers_footers": {
648
+ "header_left": "{document_title}",
649
+ "header_right": "{date}",
650
+ "footer_center": "Page {page_number} of {total_pages}",
651
+ "footer_right": "{company_name}",
652
+ },
653
+ }
654
+
655
+ def _get_magazine_layout(self) -> Dict[str, Any]:
656
+ """Get magazine layout configuration"""
657
+ return {
658
+ "description": "Multi-column magazine layout",
659
+ "page_size": PageSize.A4,
660
+ "orientation": PageOrientation.PORTRAIT,
661
+ "margins": {"top": 1.5, "bottom": 1.5, "left": 1.5, "right": 1.5},
662
+ "columns": 2,
663
+ "column_gap": 0.8,
664
+ "font": {"family": "Georgia", "size": 10},
665
+ "spacing": {"line_height": 1.3, "paragraph_spacing": 4},
666
+ }
667
+
668
+ def _get_newspaper_layout(self) -> Dict[str, Any]:
669
+ """Get newspaper layout configuration"""
670
+ return {
671
+ "description": "Multi-column newspaper layout",
672
+ "page_size": PageSize.TABLOID,
673
+ "orientation": PageOrientation.PORTRAIT,
674
+ "margins": {"top": 1.0, "bottom": 1.0, "left": 1.0, "right": 1.0},
675
+ "columns": 4,
676
+ "column_gap": 0.5,
677
+ "font": {"family": "Arial", "size": 9},
678
+ "spacing": {"line_height": 1.2, "paragraph_spacing": 3},
679
+ }
680
+
681
+ def _get_presentation_layout(self) -> Dict[str, Any]:
682
+ """Get presentation layout configuration"""
683
+ return {
684
+ "description": "Landscape presentation layout",
685
+ "page_size": PageSize.A4,
686
+ "orientation": PageOrientation.LANDSCAPE,
687
+ "margins": {"top": 2.0, "bottom": 2.0, "left": 2.0, "right": 2.0},
688
+ "columns": 1,
689
+ "font": {"family": "Helvetica", "size": 14},
690
+ "spacing": {"line_height": 1.4, "paragraph_spacing": 12},
691
+ }
692
+
693
+ def _get_technical_doc_layout(self) -> Dict[str, Any]:
694
+ """Get technical documentation layout configuration"""
695
+ return {
696
+ "description": "Technical documentation with wide margins for notes",
697
+ "page_size": PageSize.A4,
698
+ "orientation": PageOrientation.PORTRAIT,
699
+ "margins": {"top": 2.0, "bottom": 2.0, "left": 3.5, "right": 2.0},
700
+ "columns": 1,
701
+ "font": {"family": "Consolas", "size": 10},
702
+ "spacing": {"line_height": 1.4, "paragraph_spacing": 8},
703
+ }
704
+
705
+ def _get_letter_layout(self) -> Dict[str, Any]:
706
+ """Get letter layout configuration"""
707
+ return {
708
+ "description": "Standard business letter layout",
709
+ "page_size": PageSize.LETTER,
710
+ "orientation": PageOrientation.PORTRAIT,
711
+ "margins": {"top": 2.5, "bottom": 2.5, "left": 2.5, "right": 2.5},
712
+ "columns": 1,
713
+ "font": {"family": "Times New Roman", "size": 12},
714
+ "spacing": {"line_height": 1.0, "paragraph_spacing": 12},
715
+ }
716
+
717
+ def _get_invoice_layout(self) -> Dict[str, Any]:
718
+ """Get invoice layout configuration"""
719
+ return {
720
+ "description": "Invoice and billing document layout",
721
+ "page_size": PageSize.A4,
722
+ "orientation": PageOrientation.PORTRAIT,
723
+ "margins": {"top": 1.5, "bottom": 1.5, "left": 2.0, "right": 2.0},
724
+ "columns": 1,
725
+ "font": {"family": "Arial", "size": 10},
726
+ "spacing": {"line_height": 1.2, "paragraph_spacing": 4},
727
+ }
728
+
729
+ def _get_brochure_layout(self) -> Dict[str, Any]:
730
+ """Get brochure layout configuration"""
731
+ return {
732
+ "description": "Tri-fold brochure layout",
733
+ "page_size": PageSize.A4,
734
+ "orientation": PageOrientation.LANDSCAPE,
735
+ "margins": {"top": 1.0, "bottom": 1.0, "left": 1.0, "right": 1.0},
736
+ "columns": 3,
737
+ "column_gap": 0.5,
738
+ "font": {"family": "Verdana", "size": 9},
739
+ "spacing": {"line_height": 1.3, "paragraph_spacing": 6},
740
+ }
741
+
742
+ # Helper methods
743
+ def _get_layout_preset(self, preset_name: str) -> Optional[Dict[str, Any]]:
744
+ """Get layout preset by name"""
745
+ return self.layout_presets.get(preset_name)
746
+
747
+ def _calculate_page_dimensions(
748
+ self,
749
+ page_size: PageSize,
750
+ orientation: PageOrientation,
751
+ margins: Dict[str, float],
752
+ ) -> Dict[str, Any]:
753
+ """Calculate page dimensions including margins"""
754
+ # Standard page sizes in cm
755
+ page_sizes = {
756
+ PageSize.A4: (21.0, 29.7),
757
+ PageSize.A3: (29.7, 42.0),
758
+ PageSize.A5: (14.8, 21.0),
759
+ PageSize.LETTER: (21.59, 27.94),
760
+ PageSize.LEGAL: (21.59, 35.56),
761
+ PageSize.TABLOID: (27.94, 43.18),
762
+ }
763
+
764
+ width, height = page_sizes.get(page_size, (21.0, 29.7))
765
+
766
+ if orientation == PageOrientation.LANDSCAPE:
767
+ width, height = height, width
768
+
769
+ content_width = width - margins["left"] - margins["right"]
770
+ content_height = height - margins["top"] - margins["bottom"]
771
+
772
+ return {
773
+ "page_width": width,
774
+ "page_height": height,
775
+ "content_width": content_width,
776
+ "content_height": content_height,
777
+ "margins": margins,
778
+ }
779
+
780
+ def _calculate_column_configuration(
781
+ self,
782
+ num_columns: int,
783
+ column_gap: float,
784
+ column_widths: Optional[List[float]],
785
+ balance_columns: bool,
786
+ ) -> Dict[str, Any]:
787
+ """Calculate column configuration"""
788
+ config: Dict[str, Any] = {
789
+ "num_columns": num_columns,
790
+ "column_gap": column_gap,
791
+ "balance_columns": balance_columns,
792
+ }
793
+
794
+ if column_widths:
795
+ config["column_widths"] = column_widths
796
+ config["custom_widths"] = True
797
+ else:
798
+ # Equal column widths
799
+ config["custom_widths"] = False
800
+
801
+ return config
802
+
803
+ def _apply_page_layout_to_document(self, document_path: str, layout_config: Dict[str, Any]):
804
+ """Apply page layout configuration to document"""
805
+ # Detect document format
806
+ file_format = self._detect_document_format(document_path)
807
+
808
+ # Generate layout markup based on format
809
+ if file_format == "markdown":
810
+ layout_markup = self._generate_markdown_layout_markup(layout_config)
811
+ elif file_format == "html":
812
+ layout_markup = self._generate_html_layout_markup(layout_config)
813
+ elif file_format == "latex":
814
+ layout_markup = self._generate_latex_layout_markup(layout_config)
815
+ else:
816
+ layout_markup = self._generate_generic_layout_markup(layout_config)
817
+
818
+ # Insert layout markup into document
819
+ self._insert_layout_markup(document_path, layout_markup, "page_layout")
820
+
821
+ def _apply_multi_column_layout(self, document_path: str, column_config: Dict[str, Any]):
822
+ """Apply multi-column layout to document"""
823
+ file_format = self._detect_document_format(document_path)
824
+
825
+ if file_format == "html":
826
+ column_markup = self._generate_html_column_markup(column_config)
827
+ elif file_format == "latex":
828
+ column_markup = self._generate_latex_column_markup(column_config)
829
+ else:
830
+ column_markup = self._generate_generic_column_markup(column_config)
831
+
832
+ self._insert_layout_markup(document_path, column_markup, "multi_column")
833
+
834
+ def _apply_headers_footers(
835
+ self,
836
+ document_path: str,
837
+ header_config: Dict[str, Any],
838
+ footer_config: Dict[str, Any],
839
+ ):
840
+ """Apply headers and footers to document"""
841
+ file_format = self._detect_document_format(document_path)
842
+
843
+ header_markup = self._generate_header_footer_markup(header_config, "header", file_format)
844
+ footer_markup = self._generate_header_footer_markup(footer_config, "footer", file_format)
845
+
846
+ self._insert_layout_markup(document_path, header_markup, "headers")
847
+ self._insert_layout_markup(document_path, footer_markup, "footers")
848
+
849
+ def _process_header_footer_config(
850
+ self,
851
+ config: Optional[Dict[str, Any]],
852
+ hf_type: str,
853
+ page_numbering: bool,
854
+ numbering_style: str,
855
+ ) -> Dict[str, Any]:
856
+ """Process header or footer configuration"""
857
+ processed = config.copy() if config else {}
858
+
859
+ # Add page numbering if requested
860
+ if page_numbering:
861
+ numbering_text = self._generate_page_numbering_text(numbering_style)
862
+ if hf_type == "footer" and "center" not in processed:
863
+ processed["center"] = numbering_text
864
+ elif hf_type == "header" and "right" not in processed:
865
+ processed["right"] = numbering_text
866
+
867
+ return processed
868
+
869
+ def _generate_page_numbering_text(self, style: str) -> str:
870
+ """Generate page numbering text based on style"""
871
+ if style == "roman":
872
+ return "{page_roman}"
873
+ elif style == "alpha":
874
+ return "{page_alpha}"
875
+ elif style == "with_total":
876
+ return "Page {page} of {total_pages}"
877
+ else: # numeric
878
+ return "{page}"
879
+
880
+ def _generate_break_markup(self, break_type: BreakType, options: Optional[Dict[str, Any]]) -> str:
881
+ """Generate break markup based on type"""
882
+ if break_type == BreakType.PAGE_BREAK:
883
+ return "\n<!-- PAGE BREAK -->\n\\newpage\n"
884
+ elif break_type == BreakType.SECTION_BREAK:
885
+ return "\n<!-- SECTION BREAK -->\n\\clearpage\n"
886
+ elif break_type == BreakType.COLUMN_BREAK:
887
+ return "\n<!-- COLUMN BREAK -->\n\\columnbreak\n"
888
+ elif break_type == BreakType.LINE_BREAK:
889
+ return "\n<!-- LINE BREAK -->\n\\linebreak\n"
890
+ else:
891
+ return "\n"
892
+
893
+ def _insert_break_at_position(
894
+ self,
895
+ document_path: str,
896
+ break_markup: str,
897
+ position: Optional[Dict[str, Any]],
898
+ ):
899
+ """Insert break markup at specified position"""
900
+ try:
901
+ with open(document_path, "r", encoding="utf-8") as f:
902
+ content = f.read()
903
+
904
+ if position:
905
+ if "line" in position:
906
+ lines = content.split("\n")
907
+ line_num = position["line"]
908
+ if 0 <= line_num <= len(lines):
909
+ lines.insert(line_num, break_markup.strip())
910
+ content = "\n".join(lines)
911
+ elif "offset" in position:
912
+ offset = position["offset"]
913
+ content = content[:offset] + break_markup + content[offset:]
914
+ else:
915
+ # Append at end
916
+ content += break_markup
917
+
918
+ with open(document_path, "w", encoding="utf-8") as f:
919
+ f.write(content)
920
+
921
+ except Exception as e:
922
+ raise LayoutConfigurationError(f"Failed to insert break: {str(e)}")
923
+
924
+ def _process_typography_config(
925
+ self,
926
+ font_config: Dict[str, Any],
927
+ spacing_config: Optional[Dict[str, Any]],
928
+ alignment: Optional[AlignmentType],
929
+ ) -> Dict[str, Any]:
930
+ """Process typography configuration"""
931
+ config = {
932
+ "font": font_config,
933
+ "spacing": spacing_config or {},
934
+ "alignment": alignment,
935
+ }
936
+
937
+ # Validate font configuration
938
+ required_font_keys = ["family", "size"]
939
+ for key in required_font_keys:
940
+ if key not in font_config:
941
+ raise LayoutConfigurationError(f"Missing font configuration: {key}")
942
+
943
+ return config
944
+
945
+ def _apply_typography_settings(self, document_path: str, typography_config: Dict[str, Any]):
946
+ """Apply typography settings to document"""
947
+ file_format = self._detect_document_format(document_path)
948
+
949
+ if file_format == "html":
950
+ typography_markup = self._generate_html_typography_markup(typography_config)
951
+ elif file_format == "latex":
952
+ typography_markup = self._generate_latex_typography_markup(typography_config)
953
+ else:
954
+ typography_markup = self._generate_generic_typography_markup(typography_config)
955
+
956
+ self._insert_layout_markup(document_path, typography_markup, "typography")
957
+
958
+ def _analyze_current_layout(self, document_path: str) -> Dict[str, Any]:
959
+ """Analyze current document layout"""
960
+ try:
961
+ with open(document_path, "r", encoding="utf-8") as f:
962
+ content = f.read()
963
+
964
+ return {
965
+ "content_length": len(content),
966
+ "line_count": len(content.split("\n")),
967
+ "word_count": len(content.split()),
968
+ "has_headers": "header" in content.lower(),
969
+ "has_columns": "column" in content.lower(),
970
+ "file_format": self._detect_document_format(document_path),
971
+ }
972
+ except Exception:
973
+ return {"error": "Failed to analyze layout"}
974
+
975
+ def _generate_optimization_plan(
976
+ self,
977
+ current_layout: Dict[str, Any],
978
+ content_analysis: Dict[str, Any],
979
+ optimization_goals: List[str],
980
+ ) -> Dict[str, Any]:
981
+ """Generate layout optimization plan"""
982
+ plan: Dict[str, Any] = {
983
+ "optimizations": [],
984
+ "goals": optimization_goals,
985
+ "current_layout": current_layout,
986
+ "content_analysis": content_analysis,
987
+ }
988
+
989
+ # Add optimizations based on goals
990
+ for goal in optimization_goals:
991
+ if goal == "readability":
992
+ plan["optimizations"].append(
993
+ {
994
+ "type": "typography",
995
+ "action": "improve_readability",
996
+ "details": "Increase line height and adjust font size",
997
+ }
998
+ )
999
+ elif goal == "space_efficiency":
1000
+ plan["optimizations"].append(
1001
+ {
1002
+ "type": "layout",
1003
+ "action": "optimize_spacing",
1004
+ "details": "Reduce margins and adjust paragraph spacing",
1005
+ }
1006
+ )
1007
+ elif goal == "professional":
1008
+ plan["optimizations"].append(
1009
+ {
1010
+ "type": "styling",
1011
+ "action": "apply_professional_style",
1012
+ "details": "Use professional fonts and consistent formatting",
1013
+ }
1014
+ )
1015
+
1016
+ return plan
1017
+
1018
+ def _apply_layout_optimizations(self, document_path: str, optimization_plan: Dict[str, Any]) -> Dict[str, Any]:
1019
+ """Apply layout optimizations based on plan"""
1020
+ results: Dict[str, Any] = {
1021
+ "optimizations_applied": [],
1022
+ "success_count": 0,
1023
+ "error_count": 0,
1024
+ }
1025
+
1026
+ for optimization in optimization_plan.get("optimizations", []):
1027
+ try:
1028
+ # Apply optimization based on type
1029
+ if optimization["type"] == "typography":
1030
+ self._apply_typography_optimization(document_path, optimization)
1031
+ elif optimization["type"] == "layout":
1032
+ self._apply_layout_optimization(document_path, optimization)
1033
+ elif optimization["type"] == "styling":
1034
+ self._apply_styling_optimization(document_path, optimization)
1035
+
1036
+ results["optimizations_applied"].append(optimization)
1037
+ success_count = results.get("success_count", 0)
1038
+ if isinstance(success_count, (int, float)):
1039
+ results["success_count"] = success_count + 1
1040
+
1041
+ except Exception as e:
1042
+ error_count = results.get("error_count", 0)
1043
+ if isinstance(error_count, (int, float)):
1044
+ results["error_count"] = error_count + 1
1045
+ self.logger.warning(f"Failed to apply optimization {optimization['type']}: {e}")
1046
+
1047
+ return results
1048
+
1049
+ def _apply_typography_optimization(self, document_path: str, optimization: Dict[str, Any]):
1050
+ """Apply typography optimization"""
1051
+ # Simplified implementation
1052
+
1053
+ def _apply_layout_optimization(self, document_path: str, optimization: Dict[str, Any]):
1054
+ """Apply layout optimization"""
1055
+ # Simplified implementation
1056
+
1057
+ def _apply_styling_optimization(self, document_path: str, optimization: Dict[str, Any]):
1058
+ """Apply styling optimization"""
1059
+ # Simplified implementation
1060
+
1061
+ def _detect_document_format(self, document_path: str) -> str:
1062
+ """Detect document format from file extension"""
1063
+ ext = os.path.splitext(document_path)[1].lower()
1064
+ format_map = {
1065
+ ".md": "markdown",
1066
+ ".markdown": "markdown",
1067
+ ".html": "html",
1068
+ ".htm": "html",
1069
+ ".tex": "latex",
1070
+ ".latex": "latex",
1071
+ ".txt": "text",
1072
+ }
1073
+ return format_map.get(ext, "text")
1074
+
1075
+ def _generate_markdown_layout_markup(self, layout_config: Dict[str, Any]) -> str:
1076
+ """Generate Markdown layout markup"""
1077
+ return f"<!-- Layout: {layout_config['page_size']} {layout_config['orientation']} -->\n"
1078
+
1079
+ def _generate_html_layout_markup(self, layout_config: Dict[str, Any]) -> str:
1080
+ """Generate HTML layout markup"""
1081
+ margins = layout_config["margins"]
1082
+ return f"""<style>
1083
+ @page {{
1084
+ size: {layout_config['page_size']};
1085
+ margin: {margins['top']}cm {margins['right']}cm {margins['bottom']}cm {margins['left']}cm;
1086
+ }}
1087
+ </style>"""
1088
+
1089
+ def _generate_latex_layout_markup(self, layout_config: Dict[str, Any]) -> str:
1090
+ """Generate LaTeX layout markup"""
1091
+ margins = layout_config["margins"]
1092
+ return f"""\\usepackage[top={margins['top']}cm,bottom={margins['bottom']}cm,left={margins['left']}cm,right={margins['right']}cm]{{geometry}}
1093
+ \\usepackage[{layout_config['orientation']}]{{geometry}}"""
1094
+
1095
+ def _generate_generic_layout_markup(self, layout_config: Dict[str, Any]) -> str:
1096
+ """Generate generic layout markup"""
1097
+ return f"# Layout Configuration\nPage: {layout_config['page_size']} {layout_config['orientation']}\n"
1098
+
1099
+ def _generate_html_column_markup(self, column_config: Dict[str, Any]) -> str:
1100
+ """Generate HTML column markup"""
1101
+ num_cols = column_config["num_columns"]
1102
+ gap = column_config["column_gap"]
1103
+ return f"""<style>
1104
+ .multi-column {{
1105
+ column-count: {num_cols};
1106
+ column-gap: {gap}cm;
1107
+ }}
1108
+ </style>
1109
+ <div class="multi-column">"""
1110
+
1111
+ def _generate_latex_column_markup(self, column_config: Dict[str, Any]) -> str:
1112
+ """Generate LaTeX column markup"""
1113
+ return f"\\begin{{multicols}}{{{column_config['num_columns']}}}"
1114
+
1115
+ def _generate_generic_column_markup(self, column_config: Dict[str, Any]) -> str:
1116
+ """Generate generic column markup"""
1117
+ return f"<!-- {column_config['num_columns']} columns -->\n"
1118
+
1119
+ def _generate_header_footer_markup(self, config: Dict[str, Any], hf_type: str, file_format: str) -> str:
1120
+ """Generate header/footer markup"""
1121
+ if file_format == "html":
1122
+ return f"<!-- {hf_type.upper()}: {config} -->\n"
1123
+ elif file_format == "latex":
1124
+ return f"% {hf_type.upper()}: {config}\n"
1125
+ else:
1126
+ return f"# {hf_type.upper()}: {config}\n"
1127
+
1128
+ def _generate_html_typography_markup(self, typography_config: Dict[str, Any]) -> str:
1129
+ """Generate HTML typography markup"""
1130
+ font = typography_config["font"]
1131
+ return f"""<style>
1132
+ body {{
1133
+ font-family: '{font['family']}';
1134
+ font-size: {font['size']}pt;
1135
+ }}
1136
+ </style>"""
1137
+
1138
+ def _generate_latex_typography_markup(self, typography_config: Dict[str, Any]) -> str:
1139
+ """Generate LaTeX typography markup"""
1140
+ font = typography_config["font"]
1141
+ return f"\\usepackage{{fontspec}}\n\\setmainfont{{{font['family']}}}\n"
1142
+
1143
+ def _generate_generic_typography_markup(self, typography_config: Dict[str, Any]) -> str:
1144
+ """Generate generic typography markup"""
1145
+ return f"# Typography: {typography_config['font']}\n"
1146
+
1147
+ def _insert_layout_markup(self, document_path: str, markup: str, markup_type: str):
1148
+ """Insert layout markup into document"""
1149
+ try:
1150
+ with open(document_path, "r", encoding="utf-8") as f:
1151
+ content = f.read()
1152
+
1153
+ # Insert at the beginning of document
1154
+ content = markup + "\n" + content
1155
+
1156
+ with open(document_path, "w", encoding="utf-8") as f:
1157
+ f.write(content)
1158
+
1159
+ except Exception as e:
1160
+ raise LayoutConfigurationError(f"Failed to insert {markup_type} markup: {str(e)}")