aiecs 1.0.1__py3-none-any.whl → 1.7.6__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 +399 -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 +3870 -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 +1435 -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 +884 -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 +364 -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 +224 -36
  195. aiecs/llm/client_resolver.py +155 -0
  196. aiecs/llm/clients/__init__.py +38 -0
  197. aiecs/llm/clients/base_client.py +324 -0
  198. aiecs/llm/clients/google_function_calling_mixin.py +457 -0
  199. aiecs/llm/clients/googleai_client.py +241 -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 +897 -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 +1323 -0
  269. aiecs/tools/docs/document_layout_tool.py +1160 -0
  270. aiecs/tools/docs/document_parser_tool.py +1011 -0
  271. aiecs/tools/docs/document_writer_tool.py +1829 -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 +175 -131
  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.6.dist-info}/METADATA +52 -15
  321. aiecs-1.7.6.dist-info/RECORD +337 -0
  322. aiecs-1.7.6.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.6.dist-info}/WHEEL +0 -0
  339. {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
  340. {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,684 @@
1
+ """
2
+ AI Report Orchestrator Tool - AI-powered comprehensive report generation
3
+
4
+ This tool provides advanced report generation with:
5
+ - Automated analysis report creation
6
+ - Multiple report types and formats
7
+ - Integration with analysis results
8
+ - Visualization embedding
9
+ - Export to multiple formats
10
+ """
11
+
12
+ import os
13
+ import logging
14
+ import tempfile
15
+ from typing import Dict, Any, List, Optional
16
+ from enum import Enum
17
+ from datetime import datetime
18
+
19
+ from pydantic import BaseModel, Field
20
+ from pydantic_settings import BaseSettings, SettingsConfigDict
21
+
22
+ from aiecs.tools.base_tool import BaseTool
23
+ from aiecs.tools import register_tool
24
+
25
+
26
+ class ReportType(str, Enum):
27
+ """Types of reports"""
28
+
29
+ EXECUTIVE_SUMMARY = "executive_summary"
30
+ TECHNICAL_REPORT = "technical_report"
31
+ BUSINESS_REPORT = "business_report"
32
+ RESEARCH_PAPER = "research_paper"
33
+ DATA_QUALITY_REPORT = "data_quality_report"
34
+
35
+
36
+ class ReportFormat(str, Enum):
37
+ """Report output formats"""
38
+
39
+ MARKDOWN = "markdown"
40
+ HTML = "html"
41
+ PDF = "pdf"
42
+ WORD = "word"
43
+ JSON = "json"
44
+
45
+
46
+ class ReportOrchestratorError(Exception):
47
+ """Base exception for Report Orchestrator errors"""
48
+
49
+
50
+ class ReportGenerationError(ReportOrchestratorError):
51
+ """Raised when report generation fails"""
52
+
53
+
54
+ @register_tool("ai_report_orchestrator")
55
+ class AIReportOrchestratorTool(BaseTool):
56
+ """
57
+ AI-powered analysis report generator that can:
58
+ 1. Generate comprehensive analysis reports
59
+ 2. Customize report structure and style
60
+ 3. Include visualizations and tables
61
+ 4. Export to multiple formats
62
+ 5. Integrate analysis results and insights
63
+
64
+ Integrates with report_tool for document generation.
65
+ """
66
+
67
+ # Configuration schema
68
+ class Config(BaseSettings):
69
+ """Configuration for the AI report orchestrator tool
70
+
71
+ Automatically reads from environment variables with AI_REPORT_ORCHESTRATOR_ prefix.
72
+ Example: AI_REPORT_ORCHESTRATOR_DEFAULT_REPORT_TYPE -> default_report_type
73
+ """
74
+
75
+ model_config = SettingsConfigDict(env_prefix="AI_REPORT_ORCHESTRATOR_")
76
+
77
+ default_report_type: str = Field(
78
+ default="business_report",
79
+ description="Default report type to generate",
80
+ )
81
+ default_format: str = Field(default="markdown", description="Default report output format")
82
+ output_directory: str = Field(
83
+ default=tempfile.gettempdir(),
84
+ description="Directory for report output files",
85
+ )
86
+ include_code: bool = Field(
87
+ default=False,
88
+ description="Whether to include code snippets in reports",
89
+ )
90
+ include_visualizations: bool = Field(
91
+ default=True,
92
+ description="Whether to include visualizations in reports",
93
+ )
94
+ max_insights_per_report: int = Field(
95
+ default=20,
96
+ description="Maximum number of insights to include per report",
97
+ )
98
+
99
+ def __init__(self, config: Optional[Dict[str, Any]] = None, **kwargs):
100
+ """Initialize AI Report Orchestrator Tool
101
+
102
+ Configuration is automatically loaded by BaseTool from:
103
+ 1. Explicit config dict (highest priority)
104
+ 2. YAML config files (config/tools/ai_report_orchestrator.yaml)
105
+ 3. Environment variables (via dotenv from .env files)
106
+ 4. Tool defaults (lowest priority)
107
+
108
+ Args:
109
+ config: Optional configuration overrides
110
+ **kwargs: Additional arguments passed to BaseTool (e.g., tool_name)
111
+ """
112
+ super().__init__(config, **kwargs)
113
+
114
+ # Configuration is automatically loaded by BaseTool into self._config_obj
115
+ # Access config via self._config_obj (BaseSettings instance)
116
+ self.config = self._config_obj if self._config_obj else self.Config()
117
+
118
+ self.logger = logging.getLogger(__name__)
119
+ if not self.logger.handlers:
120
+ handler = logging.StreamHandler()
121
+ handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
122
+ self.logger.addHandler(handler)
123
+ self.logger.setLevel(logging.INFO)
124
+
125
+ self._init_external_tools()
126
+
127
+ # Ensure output directory exists
128
+ os.makedirs(self.config.output_directory, exist_ok=True)
129
+
130
+ def _init_external_tools(self):
131
+ """Initialize external task tools"""
132
+ self.external_tools = {}
133
+
134
+ # Initialize ReportTool for document generation
135
+ try:
136
+ from aiecs.tools.task_tools.report_tool import ReportTool
137
+
138
+ self.external_tools["report"] = ReportTool()
139
+ self.logger.info("ReportTool initialized successfully")
140
+ except ImportError:
141
+ self.logger.warning("ReportTool not available")
142
+ self.external_tools["report"] = None
143
+
144
+ # Schema definitions
145
+ class GenerateReportSchema(BaseModel):
146
+ """Schema for generate_report operation"""
147
+
148
+ analysis_results: Dict[str, Any] = Field(description="Analysis results to include")
149
+ insights: Optional[Dict[str, Any]] = Field(default=None, description="Generated insights")
150
+ report_type: ReportType = Field(default=ReportType.BUSINESS_REPORT, description="Type of report")
151
+ output_format: ReportFormat = Field(default=ReportFormat.MARKDOWN, description="Output format")
152
+ title: Optional[str] = Field(default=None, description="Report title")
153
+ include_code: bool = Field(default=False, description="Include code snippets")
154
+
155
+ class FormatReportSchema(BaseModel):
156
+ """Schema for format_report operation"""
157
+
158
+ report_content: str = Field(description="Report content to format")
159
+ output_format: ReportFormat = Field(description="Desired output format")
160
+ output_path: Optional[str] = Field(default=None, description="Output file path")
161
+
162
+ class ExportReportSchema(BaseModel):
163
+ """Schema for export_report operation"""
164
+
165
+ report_content: str = Field(description="Report content")
166
+ output_format: ReportFormat = Field(description="Export format")
167
+ output_path: str = Field(description="Output file path")
168
+
169
+ def generate_report(
170
+ self,
171
+ analysis_results: Dict[str, Any],
172
+ insights: Optional[Dict[str, Any]] = None,
173
+ report_type: ReportType = ReportType.BUSINESS_REPORT,
174
+ output_format: ReportFormat = ReportFormat.MARKDOWN,
175
+ title: Optional[str] = None,
176
+ include_code: bool = False,
177
+ ) -> Dict[str, Any]:
178
+ """
179
+ Generate comprehensive analysis report.
180
+
181
+ Args:
182
+ analysis_results: Results from data analysis
183
+ insights: Generated insights to include
184
+ report_type: Type of report to generate
185
+ output_format: Output format
186
+ title: Report title
187
+ include_code: Whether to include code snippets
188
+
189
+ Returns:
190
+ Dict containing:
191
+ - report_content: Generated report content
192
+ - sections: Report sections
193
+ - export_path: Path to exported report
194
+ - metadata: Report metadata
195
+ """
196
+ try:
197
+ self.logger.info(f"Generating {report_type.value} report in {output_format.value} format")
198
+
199
+ # Generate report title
200
+ if title is None:
201
+ title = self._generate_title(report_type, analysis_results)
202
+
203
+ # Build report sections
204
+ sections = self._build_report_sections(analysis_results, insights, report_type, include_code)
205
+
206
+ # Compile report content
207
+ report_content = self._compile_report(title, sections, report_type)
208
+
209
+ # Format report for output format
210
+ formatted_content = self._format_content(report_content, output_format)
211
+
212
+ # Export report
213
+ export_path = self._export_report(formatted_content, output_format, title)
214
+
215
+ # Generate metadata
216
+ metadata = {
217
+ "generated_at": datetime.now().isoformat(),
218
+ "report_type": report_type.value,
219
+ "output_format": output_format.value,
220
+ "sections_count": len(sections),
221
+ "word_count": len(report_content.split()),
222
+ }
223
+
224
+ return {
225
+ "report_content": report_content,
226
+ "sections": {s["title"]: s["content"] for s in sections},
227
+ "export_path": export_path,
228
+ "metadata": metadata,
229
+ "title": title,
230
+ }
231
+
232
+ except Exception as e:
233
+ self.logger.error(f"Error generating report: {e}")
234
+ raise ReportGenerationError(f"Report generation failed: {e}")
235
+
236
+ def format_report(
237
+ self,
238
+ report_content: str,
239
+ output_format: ReportFormat,
240
+ output_path: Optional[str] = None,
241
+ ) -> Dict[str, Any]:
242
+ """
243
+ Format report content to specified format.
244
+
245
+ Args:
246
+ report_content: Report content to format
247
+ output_format: Desired output format
248
+ output_path: Optional output file path
249
+
250
+ Returns:
251
+ Dict containing formatted report info
252
+ """
253
+ try:
254
+ formatted_content = self._format_content(report_content, output_format)
255
+
256
+ if output_path:
257
+ with open(output_path, "w", encoding="utf-8") as f:
258
+ f.write(formatted_content)
259
+ export_path = output_path
260
+ else:
261
+ export_path = self._export_report(formatted_content, output_format, "report")
262
+
263
+ return {
264
+ "formatted_content": formatted_content,
265
+ "output_format": output_format.value,
266
+ "export_path": export_path,
267
+ }
268
+
269
+ except Exception as e:
270
+ self.logger.error(f"Error formatting report: {e}")
271
+ raise ReportGenerationError(f"Report formatting failed: {e}")
272
+
273
+ def export_report(
274
+ self,
275
+ report_content: str,
276
+ output_format: ReportFormat,
277
+ output_path: str,
278
+ ) -> Dict[str, Any]:
279
+ """
280
+ Export report to file.
281
+
282
+ Args:
283
+ report_content: Report content
284
+ output_format: Export format
285
+ output_path: Output file path
286
+
287
+ Returns:
288
+ Dict containing export information
289
+ """
290
+ try:
291
+ formatted_content = self._format_content(report_content, output_format)
292
+
293
+ with open(output_path, "w", encoding="utf-8") as f:
294
+ f.write(formatted_content)
295
+
296
+ file_size = os.path.getsize(output_path)
297
+
298
+ return {
299
+ "export_path": output_path,
300
+ "format": output_format.value,
301
+ "file_size_bytes": file_size,
302
+ "success": True,
303
+ }
304
+
305
+ except Exception as e:
306
+ self.logger.error(f"Error exporting report: {e}")
307
+ raise ReportGenerationError(f"Report export failed: {e}")
308
+
309
+ # Internal report generation methods
310
+
311
+ def _generate_title(self, report_type: ReportType, analysis_results: Dict[str, Any]) -> str:
312
+ """Generate appropriate report title"""
313
+ if report_type == ReportType.EXECUTIVE_SUMMARY:
314
+ return "Executive Summary: Data Analysis Report"
315
+ elif report_type == ReportType.TECHNICAL_REPORT:
316
+ return "Technical Data Analysis Report"
317
+ elif report_type == ReportType.BUSINESS_REPORT:
318
+ return "Business Intelligence Report"
319
+ elif report_type == ReportType.RESEARCH_PAPER:
320
+ return "Data Analysis Research Paper"
321
+ elif report_type == ReportType.DATA_QUALITY_REPORT:
322
+ return "Data Quality Assessment Report"
323
+ else:
324
+ return "Data Analysis Report"
325
+
326
+ def _build_report_sections(
327
+ self,
328
+ analysis_results: Dict[str, Any],
329
+ insights: Optional[Dict[str, Any]],
330
+ report_type: ReportType,
331
+ include_code: bool,
332
+ ) -> List[Dict[str, str]]:
333
+ """Build report sections based on type"""
334
+ sections = []
335
+
336
+ # Executive Summary (for all report types)
337
+ sections.append(
338
+ {
339
+ "title": "Executive Summary",
340
+ "content": self._generate_executive_summary(analysis_results, insights),
341
+ }
342
+ )
343
+
344
+ # Methodology section (for technical and research reports)
345
+ if report_type in [
346
+ ReportType.TECHNICAL_REPORT,
347
+ ReportType.RESEARCH_PAPER,
348
+ ]:
349
+ sections.append(
350
+ {
351
+ "title": "Methodology",
352
+ "content": self._generate_methodology_section(analysis_results),
353
+ }
354
+ )
355
+
356
+ # Data Overview
357
+ sections.append(
358
+ {
359
+ "title": "Data Overview",
360
+ "content": self._generate_data_overview(analysis_results),
361
+ }
362
+ )
363
+
364
+ # Findings section
365
+ sections.append(
366
+ {
367
+ "title": "Key Findings",
368
+ "content": self._generate_findings_section(analysis_results, insights),
369
+ }
370
+ )
371
+
372
+ # Statistical Analysis (for technical reports)
373
+ if report_type == ReportType.TECHNICAL_REPORT and "statistical_analysis" in analysis_results:
374
+ sections.append(
375
+ {
376
+ "title": "Statistical Analysis",
377
+ "content": self._generate_statistics_section(analysis_results.get("statistical_analysis", {})),
378
+ }
379
+ )
380
+
381
+ # Insights section
382
+ if insights:
383
+ sections.append(
384
+ {
385
+ "title": "Insights and Patterns",
386
+ "content": self._generate_insights_section(insights),
387
+ }
388
+ )
389
+
390
+ # Recommendations
391
+ sections.append(
392
+ {
393
+ "title": "Recommendations",
394
+ "content": self._generate_recommendations_section(analysis_results, insights),
395
+ }
396
+ )
397
+
398
+ # Conclusion
399
+ sections.append(
400
+ {
401
+ "title": "Conclusion",
402
+ "content": self._generate_conclusion(analysis_results, insights),
403
+ }
404
+ )
405
+
406
+ # Appendix (if code included)
407
+ if include_code:
408
+ sections.append(
409
+ {
410
+ "title": "Appendix: Technical Details",
411
+ "content": self._generate_appendix(analysis_results),
412
+ }
413
+ )
414
+
415
+ return sections
416
+
417
+ def _generate_executive_summary(
418
+ self,
419
+ analysis_results: Dict[str, Any],
420
+ insights: Optional[Dict[str, Any]],
421
+ ) -> str:
422
+ """Generate executive summary"""
423
+ lines = []
424
+
425
+ # Get data profile if available
426
+ data_profile = analysis_results.get("data_profile", {})
427
+ summary = data_profile.get("summary", {})
428
+
429
+ if summary:
430
+ lines.append(f"This report presents a comprehensive analysis of a dataset containing {summary.get('rows', 'N/A')} rows and {summary.get('columns', 'N/A')} columns.")
431
+
432
+ missing_pct = summary.get("missing_percentage", 0)
433
+ if missing_pct > 0:
434
+ lines.append(f"The dataset has {missing_pct:.2f}% missing values.")
435
+
436
+ # Add insight summary
437
+ if insights and "summary" in insights:
438
+ lines.append(f"\n{insights['summary']}")
439
+
440
+ # Add key metrics
441
+ if insights and "priority_insights" in insights:
442
+ top_insights = insights["priority_insights"][:3]
443
+ if top_insights:
444
+ lines.append("\nKey highlights:")
445
+ for i, insight in enumerate(top_insights, 1):
446
+ lines.append(f"{i}. {insight.get('title', 'Insight')}")
447
+
448
+ return "\n".join(lines) if lines else "Analysis completed successfully."
449
+
450
+ def _generate_methodology_section(self, analysis_results: Dict[str, Any]) -> str:
451
+ """Generate methodology section"""
452
+ lines = [
453
+ "The analysis was conducted using a systematic approach:",
454
+ "",
455
+ "1. **Data Loading**: Data was loaded and validated for quality",
456
+ "2. **Data Profiling**: Comprehensive statistical profiling was performed",
457
+ "3. **Data Transformation**: Necessary transformations and cleaning were applied",
458
+ "4. **Statistical Analysis**: Various statistical tests and analyses were conducted",
459
+ "5. **Insight Generation**: Patterns, trends, and anomalies were identified",
460
+ "6. **Visualization**: Key findings were visualized for clarity",
461
+ ]
462
+
463
+ return "\n".join(lines)
464
+
465
+ def _generate_data_overview(self, analysis_results: Dict[str, Any]) -> str:
466
+ """Generate data overview section"""
467
+ lines = []
468
+
469
+ data_profile = analysis_results.get("data_profile", {})
470
+ summary = data_profile.get("summary", {})
471
+
472
+ if summary:
473
+ lines.append("**Dataset Characteristics:**")
474
+ lines.append(f"- Total Records: {summary.get('rows', 'N/A')}")
475
+ lines.append(f"- Total Columns: {summary.get('columns', 'N/A')}")
476
+ lines.append(f"- Numeric Columns: {summary.get('numeric_columns', 'N/A')}")
477
+ lines.append(f"- Categorical Columns: {summary.get('categorical_columns', 'N/A')}")
478
+ lines.append(f"- Missing Values: {summary.get('missing_percentage', 0):.2f}%")
479
+ lines.append(f"- Duplicate Rows: {summary.get('duplicate_rows', 0)}")
480
+ else:
481
+ lines.append("Data overview not available.")
482
+
483
+ return "\n".join(lines)
484
+
485
+ def _generate_findings_section(
486
+ self,
487
+ analysis_results: Dict[str, Any],
488
+ insights: Optional[Dict[str, Any]],
489
+ ) -> str:
490
+ """Generate findings section"""
491
+ lines = []
492
+
493
+ # Extract findings from analysis results
494
+ if "findings" in analysis_results:
495
+ findings = analysis_results["findings"]
496
+ for i, finding in enumerate(findings[:10], 1):
497
+ lines.append(f"{i}. **{finding.get('title', 'Finding')}**: {finding.get('description', 'No description')}")
498
+
499
+ # Add insights if available
500
+ if insights and "insights" in insights:
501
+ insight_list = insights["insights"][: self.config.max_insights_per_report]
502
+ if insight_list and not lines:
503
+ lines.append("**Key Insights:**")
504
+ for insight in insight_list:
505
+ lines.append(f"- {insight.get('title', 'Insight')}: {insight.get('description', '')}")
506
+
507
+ return "\n".join(lines) if lines else "No significant findings to report."
508
+
509
+ def _generate_statistics_section(self, stats_results: Dict[str, Any]) -> str:
510
+ """Generate statistics section"""
511
+ lines = ["**Statistical Analysis Results:**", ""]
512
+
513
+ if "correlation_matrix" in stats_results:
514
+ lines.append("Correlation analysis was performed to identify relationships between variables.")
515
+
516
+ if "hypothesis_tests" in stats_results:
517
+ lines.append("Hypothesis testing was conducted to validate statistical significance.")
518
+
519
+ return "\n".join(lines)
520
+
521
+ def _generate_insights_section(self, insights: Dict[str, Any]) -> str:
522
+ """Generate insights section"""
523
+ lines = []
524
+
525
+ insights.get("insights", [])
526
+ priority_insights = insights.get("priority_insights", [])
527
+
528
+ if priority_insights:
529
+ lines.append("**Priority Insights:**")
530
+ for i, insight in enumerate(priority_insights, 1):
531
+ title = insight.get("title", "Insight")
532
+ description = insight.get("description", "")
533
+ confidence = insight.get("confidence", 0)
534
+ impact = insight.get("impact", "medium")
535
+
536
+ lines.append(f"\n{i}. **{title}** (Confidence: {confidence:.0%}, Impact: {impact})")
537
+ lines.append(f" {description}")
538
+
539
+ if "recommendation" in insight:
540
+ lines.append(f" *Recommendation: {insight['recommendation']}*")
541
+
542
+ return "\n".join(lines) if lines else "No insights generated."
543
+
544
+ def _generate_recommendations_section(
545
+ self,
546
+ analysis_results: Dict[str, Any],
547
+ insights: Optional[Dict[str, Any]],
548
+ ) -> str:
549
+ """Generate recommendations section"""
550
+ lines = []
551
+
552
+ # Get recommendations from analysis results
553
+ if "recommendations" in analysis_results:
554
+ recs = analysis_results["recommendations"]
555
+ for i, rec in enumerate(recs[:10], 1):
556
+ action = rec.get("action", "Action")
557
+ reason = rec.get("reason", "")
558
+ priority = rec.get("priority", "medium")
559
+ lines.append(f"{i}. **{action}** (Priority: {priority})")
560
+ if reason:
561
+ lines.append(f" {reason}")
562
+
563
+ # Get recommendations from data profiler
564
+ data_profile = analysis_results.get("data_profile", {})
565
+ if "recommendations" in data_profile:
566
+ if not lines:
567
+ lines.append("**Data Quality Recommendations:**")
568
+ for rec in data_profile["recommendations"][:5]:
569
+ lines.append(f"- {rec.get('action', 'Action')}: {rec.get('reason', '')}")
570
+
571
+ return "\n".join(lines) if lines else "No specific recommendations at this time."
572
+
573
+ def _generate_conclusion(
574
+ self,
575
+ analysis_results: Dict[str, Any],
576
+ insights: Optional[Dict[str, Any]],
577
+ ) -> str:
578
+ """Generate conclusion"""
579
+ lines = []
580
+
581
+ lines.append("This comprehensive analysis has provided valuable insights into the dataset.")
582
+
583
+ if insights:
584
+ total_insights = insights.get("total_insights", 0)
585
+ lines.append(f"A total of {total_insights} insights were generated through systematic analysis.")
586
+
587
+ lines.append("\nThe findings and recommendations presented in this report should be carefully considered in the context of your specific business objectives and constraints.")
588
+
589
+ return "\n".join(lines)
590
+
591
+ def _generate_appendix(self, analysis_results: Dict[str, Any]) -> str:
592
+ """Generate appendix with technical details"""
593
+ lines = [
594
+ "**Technical Details:**",
595
+ "",
596
+ "This section contains technical information about the analysis process.",
597
+ "",
598
+ "Analysis was performed using the AIECS Data Analysis Orchestrator framework.",
599
+ ]
600
+
601
+ return "\n".join(lines)
602
+
603
+ def _compile_report(
604
+ self,
605
+ title: str,
606
+ sections: List[Dict[str, str]],
607
+ report_type: ReportType,
608
+ ) -> str:
609
+ """Compile report sections into final document"""
610
+ lines = [
611
+ f"# {title}",
612
+ "",
613
+ f"*Report Type: {report_type.value.replace('_', ' ').title()}*",
614
+ f"*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*",
615
+ "",
616
+ "---",
617
+ "",
618
+ ]
619
+
620
+ for section in sections:
621
+ lines.append(f"## {section['title']}")
622
+ lines.append("")
623
+ lines.append(section["content"])
624
+ lines.append("")
625
+ lines.append("---")
626
+ lines.append("")
627
+
628
+ return "\n".join(lines)
629
+
630
+ def _format_content(self, content: str, output_format: ReportFormat) -> str:
631
+ """Format content for specified output format"""
632
+ if output_format == ReportFormat.MARKDOWN:
633
+ return content
634
+ elif output_format == ReportFormat.HTML:
635
+ return self._markdown_to_html(content)
636
+ elif output_format == ReportFormat.JSON:
637
+ return self._content_to_json(content)
638
+ else:
639
+ # For PDF and Word, return markdown (would need additional
640
+ # libraries for conversion)
641
+ self.logger.warning(f"Format {output_format.value} not fully implemented, returning markdown")
642
+ return content
643
+
644
+ def _markdown_to_html(self, markdown_content: str) -> str:
645
+ """Convert markdown to HTML (basic implementation)"""
646
+ html = markdown_content
647
+ # Basic conversions
648
+ html = html.replace("# ", "<h1>").replace("\n", "</h1>\n", 1)
649
+ html = html.replace("## ", "<h2>").replace("\n", "</h2>\n")
650
+ html = html.replace("**", "<strong>").replace("**", "</strong>")
651
+ html = html.replace("*", "<em>").replace("*", "</em>")
652
+ html = f"<html><body>{html}</body></html>"
653
+ return html
654
+
655
+ def _content_to_json(self, content: str) -> str:
656
+ """Convert content to JSON format"""
657
+ import json
658
+
659
+ return json.dumps({"content": content, "format": "markdown"}, indent=2)
660
+
661
+ def _export_report(self, content: str, output_format: ReportFormat, title: str) -> str:
662
+ """Export report to file"""
663
+ # Generate filename
664
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
665
+ safe_title = title.replace(" ", "_").replace(":", "").lower()
666
+
667
+ extension_map = {
668
+ ReportFormat.MARKDOWN: ".md",
669
+ ReportFormat.HTML: ".html",
670
+ ReportFormat.PDF: ".pdf",
671
+ ReportFormat.WORD: ".docx",
672
+ ReportFormat.JSON: ".json",
673
+ }
674
+
675
+ extension = extension_map.get(output_format, ".txt")
676
+ filename = f"{safe_title}_{timestamp}{extension}"
677
+ filepath = os.path.join(self.config.output_directory, filename)
678
+
679
+ # Write file
680
+ with open(filepath, "w", encoding="utf-8") as f:
681
+ f.write(content)
682
+
683
+ self.logger.info(f"Report exported to: {filepath}")
684
+ return filepath