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.
- aiecs/__init__.py +13 -16
- aiecs/__main__.py +7 -7
- aiecs/aiecs_client.py +269 -75
- aiecs/application/executors/operation_executor.py +79 -54
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
- aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
- aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
- aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +98 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
- aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
- aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
- aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
- aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
- aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
- aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
- aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
- aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
- aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
- aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +341 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +913 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
- aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
- aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
- aiecs/application/knowledge_graph/search/reranker.py +293 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +471 -0
- aiecs/config/__init__.py +20 -5
- aiecs/config/config.py +762 -31
- aiecs/config/graph_config.py +131 -0
- aiecs/config/tool_config.py +399 -0
- aiecs/core/__init__.py +29 -13
- aiecs/core/interface/__init__.py +2 -2
- aiecs/core/interface/execution_interface.py +22 -22
- aiecs/core/interface/storage_interface.py +37 -88
- aiecs/core/registry/__init__.py +31 -0
- aiecs/core/registry/service_registry.py +92 -0
- aiecs/domain/__init__.py +270 -1
- aiecs/domain/agent/__init__.py +191 -0
- aiecs/domain/agent/base_agent.py +3870 -0
- aiecs/domain/agent/exceptions.py +99 -0
- aiecs/domain/agent/graph_aware_mixin.py +569 -0
- aiecs/domain/agent/hybrid_agent.py +1435 -0
- aiecs/domain/agent/integration/__init__.py +29 -0
- aiecs/domain/agent/integration/context_compressor.py +216 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
- aiecs/domain/agent/integration/protocols.py +281 -0
- aiecs/domain/agent/integration/retry_policy.py +218 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
- aiecs/domain/agent/lifecycle.py +291 -0
- aiecs/domain/agent/llm_agent.py +692 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +1124 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +163 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
- aiecs/domain/agent/models.py +884 -0
- aiecs/domain/agent/observability.py +479 -0
- aiecs/domain/agent/persistence.py +449 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +159 -0
- aiecs/domain/agent/prompts/formatters.py +187 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +253 -0
- aiecs/domain/agent/tool_agent.py +444 -0
- aiecs/domain/agent/tools/__init__.py +15 -0
- aiecs/domain/agent/tools/schema_generator.py +364 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +469 -0
- aiecs/domain/community/analytics.py +432 -0
- aiecs/domain/community/collaborative_workflow.py +648 -0
- aiecs/domain/community/communication_hub.py +634 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +796 -0
- aiecs/domain/community/community_manager.py +803 -0
- aiecs/domain/community/decision_engine.py +849 -0
- aiecs/domain/community/exceptions.py +231 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +234 -0
- aiecs/domain/community/resource_manager.py +461 -0
- aiecs/domain/community/shared_context_manager.py +589 -0
- aiecs/domain/context/__init__.py +40 -10
- aiecs/domain/context/context_engine.py +1910 -0
- aiecs/domain/context/conversation_models.py +87 -53
- aiecs/domain/context/graph_memory.py +582 -0
- aiecs/domain/execution/model.py +12 -4
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +148 -0
- aiecs/domain/knowledge_graph/models/evidence.py +178 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
- aiecs/domain/knowledge_graph/models/path.py +171 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
- aiecs/domain/knowledge_graph/models/query.py +261 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
- aiecs/domain/knowledge_graph/models/relation.py +202 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
- aiecs/domain/task/dsl_processor.py +172 -56
- aiecs/domain/task/model.py +20 -8
- aiecs/domain/task/task_context.py +27 -24
- aiecs/infrastructure/__init__.py +0 -2
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +837 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
- aiecs/infrastructure/graph_storage/cache.py +424 -0
- aiecs/infrastructure/graph_storage/distributed.py +223 -0
- aiecs/infrastructure/graph_storage/error_handling.py +380 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
- aiecs/infrastructure/graph_storage/metrics.py +344 -0
- aiecs/infrastructure/graph_storage/migration.py +400 -0
- aiecs/infrastructure/graph_storage/pagination.py +483 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
- aiecs/infrastructure/graph_storage/postgres.py +1563 -0
- aiecs/infrastructure/graph_storage/property_storage.py +353 -0
- aiecs/infrastructure/graph_storage/protocols.py +76 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
- aiecs/infrastructure/graph_storage/streaming.py +487 -0
- aiecs/infrastructure/graph_storage/tenant.py +412 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
- aiecs/infrastructure/messaging/websocket_manager.py +51 -35
- aiecs/infrastructure/monitoring/__init__.py +22 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
- aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
- aiecs/infrastructure/monitoring/structured_logger.py +3 -7
- aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
- aiecs/infrastructure/persistence/__init__.py +14 -1
- aiecs/infrastructure/persistence/context_engine_client.py +184 -0
- aiecs/infrastructure/persistence/database_manager.py +67 -43
- aiecs/infrastructure/persistence/file_storage.py +180 -103
- aiecs/infrastructure/persistence/redis_client.py +74 -21
- aiecs/llm/__init__.py +73 -25
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
- aiecs/llm/client_factory.py +224 -36
- aiecs/llm/client_resolver.py +155 -0
- aiecs/llm/clients/__init__.py +38 -0
- aiecs/llm/clients/base_client.py +324 -0
- aiecs/llm/clients/google_function_calling_mixin.py +457 -0
- aiecs/llm/clients/googleai_client.py +241 -0
- aiecs/llm/clients/openai_client.py +158 -0
- aiecs/llm/clients/openai_compatible_mixin.py +367 -0
- aiecs/llm/clients/vertex_client.py +897 -0
- aiecs/llm/clients/xai_client.py +201 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +272 -0
- aiecs/llm/config/config_validator.py +206 -0
- aiecs/llm/config/model_config.py +143 -0
- aiecs/llm/protocols.py +149 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +89 -0
- aiecs/main.py +140 -121
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/module_checker.py +499 -0
- aiecs/scripts/aid/version_manager.py +235 -0
- aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
- aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
- aiecs/scripts/dependance_check/__init__.py +15 -0
- aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
- aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
- aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
- aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
- aiecs/scripts/knowledge_graph/__init__.py +3 -0
- aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
- aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
- aiecs/scripts/tools_develop/README.md +671 -0
- aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
- aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
- aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
- aiecs/scripts/tools_develop/schema_coverage.py +511 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
- aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
- aiecs/scripts/tools_develop/verify_tools.py +352 -0
- aiecs/tasks/__init__.py +0 -1
- aiecs/tasks/worker.py +115 -47
- aiecs/tools/__init__.py +194 -72
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +330 -0
- aiecs/tools/apisource/providers/__init__.py +112 -0
- aiecs/tools/apisource/providers/base.py +671 -0
- aiecs/tools/apisource/providers/census.py +397 -0
- aiecs/tools/apisource/providers/fred.py +535 -0
- aiecs/tools/apisource/providers/newsapi.py +409 -0
- aiecs/tools/apisource/providers/worldbank.py +352 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +363 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
- aiecs/tools/apisource/tool.py +832 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +334 -0
- aiecs/tools/base_tool.py +415 -21
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +607 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
- aiecs/tools/docs/content_insertion_tool.py +1320 -0
- aiecs/tools/docs/document_creator_tool.py +1323 -0
- aiecs/tools/docs/document_layout_tool.py +1160 -0
- aiecs/tools/docs/document_parser_tool.py +1011 -0
- aiecs/tools/docs/document_writer_tool.py +1829 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
- aiecs/tools/langchain_adapter.py +300 -138
- aiecs/tools/schema_generator.py +455 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +581 -0
- aiecs/tools/search_tool/cache.py +264 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +224 -0
- aiecs/tools/search_tool/core.py +778 -0
- aiecs/tools/search_tool/deduplicator.py +119 -0
- aiecs/tools/search_tool/error_handler.py +242 -0
- aiecs/tools/search_tool/metrics.py +343 -0
- aiecs/tools/search_tool/rate_limiter.py +172 -0
- aiecs/tools/search_tool/schemas.py +275 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
- aiecs/tools/statistics/data_loader_tool.py +555 -0
- aiecs/tools/statistics/data_profiler_tool.py +638 -0
- aiecs/tools/statistics/data_transformer_tool.py +580 -0
- aiecs/tools/statistics/data_visualizer_tool.py +498 -0
- aiecs/tools/statistics/model_trainer_tool.py +507 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
- aiecs/tools/task_tools/__init__.py +49 -36
- aiecs/tools/task_tools/chart_tool.py +200 -184
- aiecs/tools/task_tools/classfire_tool.py +268 -267
- aiecs/tools/task_tools/image_tool.py +175 -131
- aiecs/tools/task_tools/office_tool.py +226 -146
- aiecs/tools/task_tools/pandas_tool.py +477 -121
- aiecs/tools/task_tools/report_tool.py +390 -142
- aiecs/tools/task_tools/research_tool.py +149 -79
- aiecs/tools/task_tools/scraper_tool.py +339 -145
- aiecs/tools/task_tools/stats_tool.py +448 -209
- aiecs/tools/temp_file_manager.py +26 -24
- aiecs/tools/tool_executor/__init__.py +18 -16
- aiecs/tools/tool_executor/tool_executor.py +364 -52
- aiecs/utils/LLM_output_structor.py +74 -48
- aiecs/utils/__init__.py +14 -3
- aiecs/utils/base_callback.py +0 -3
- aiecs/utils/cache_provider.py +696 -0
- aiecs/utils/execution_utils.py +50 -31
- aiecs/utils/prompt_loader.py +1 -0
- aiecs/utils/token_usage_repository.py +37 -11
- aiecs/ws/socket_server.py +14 -4
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/METADATA +52 -15
- aiecs-1.7.6.dist-info/RECORD +337 -0
- aiecs-1.7.6.dist-info/entry_points.txt +13 -0
- aiecs/config/registry.py +0 -19
- aiecs/domain/context/content_engine.py +0 -982
- aiecs/llm/base_client.py +0 -99
- aiecs/llm/openai_client.py +0 -125
- aiecs/llm/vertex_client.py +0 -186
- aiecs/llm/xai_client.py +0 -184
- aiecs/scripts/dependency_checker.py +0 -857
- aiecs/scripts/quick_dependency_check.py +0 -269
- aiecs/tools/task_tools/search_api.py +0 -7
- aiecs-1.0.1.dist-info/RECORD +0 -90
- aiecs-1.0.1.dist-info/entry_points.txt +0 -7
- /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
- /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
- /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
- /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/WHEEL +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,2350 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
import tempfile
|
|
5
|
+
from typing import Dict, Any, List, Optional
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
11
|
+
|
|
12
|
+
from aiecs.tools.base_tool import BaseTool
|
|
13
|
+
from aiecs.tools import register_tool
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ContentGenerationMode(str, Enum):
|
|
17
|
+
"""AI content generation modes"""
|
|
18
|
+
|
|
19
|
+
GENERATE = "generate" # 生成全新内容
|
|
20
|
+
ENHANCE = "enhance" # 增强现有内容
|
|
21
|
+
REWRITE = "rewrite" # 重写内容
|
|
22
|
+
TRANSLATE = "translate" # 翻译内容
|
|
23
|
+
CONVERT_FORMAT = "convert_format" # 格式转换
|
|
24
|
+
TEMPLATE_FILL = "template_fill" # 模板填充
|
|
25
|
+
FORMAT_CONTENT = "format_content" # 格式化内容
|
|
26
|
+
EDIT_CONTENT = "edit_content" # 编辑内容
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AIEditOperation(str, Enum):
|
|
30
|
+
"""AI-driven editing operations"""
|
|
31
|
+
|
|
32
|
+
SMART_FORMAT = "smart_format" # AI智能格式化
|
|
33
|
+
STYLE_ENHANCE = "style_enhance" # 样式增强
|
|
34
|
+
CONTENT_RESTRUCTURE = "content_restructure" # 内容重构
|
|
35
|
+
INTELLIGENT_HIGHLIGHT = "intelligent_highlight" # 智能高亮
|
|
36
|
+
AUTO_BOLD_KEYWORDS = "auto_bold_keywords" # 自动加粗关键词
|
|
37
|
+
SMART_PARAGRAPH = "smart_paragraph" # 智能段落优化
|
|
38
|
+
AI_PROOFREADING = "ai_proofreading" # AI校对
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class WriteStrategy(str, Enum):
|
|
42
|
+
"""Document writing strategies"""
|
|
43
|
+
|
|
44
|
+
IMMEDIATE = "immediate" # 立即写入
|
|
45
|
+
REVIEW = "review" # 审核后写入
|
|
46
|
+
DRAFT = "draft" # 保存为草稿
|
|
47
|
+
STAGED = "staged" # 分阶段写入
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AIProvider(str, Enum):
|
|
51
|
+
"""Supported AI providers"""
|
|
52
|
+
|
|
53
|
+
OPENAI = "openai"
|
|
54
|
+
VERTEX_AI = "vertex_ai"
|
|
55
|
+
XAI = "xai"
|
|
56
|
+
LOCAL = "local"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AIDocumentWriterOrchestratorError(Exception):
|
|
60
|
+
"""Base exception for AI Document Writer Orchestrator errors"""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ContentGenerationError(AIDocumentWriterOrchestratorError):
|
|
64
|
+
"""Raised when content generation fails"""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class WriteOrchestrationError(AIDocumentWriterOrchestratorError):
|
|
68
|
+
"""Raised when write orchestration fails"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@register_tool("ai_document_writer_orchestrator")
|
|
72
|
+
class AIDocumentWriterOrchestrator(BaseTool):
|
|
73
|
+
"""
|
|
74
|
+
AI-powered document writing orchestrator that:
|
|
75
|
+
1. Coordinates AI content generation with document writing
|
|
76
|
+
2. Manages complex writing workflows
|
|
77
|
+
3. Provides intelligent content enhancement and formatting
|
|
78
|
+
4. Handles review and approval processes
|
|
79
|
+
5. Supports template-based document generation
|
|
80
|
+
|
|
81
|
+
Integrates with:
|
|
82
|
+
- DocumentWriterTool for document writing operations
|
|
83
|
+
- Various AI providers for content generation
|
|
84
|
+
- Existing AIECS infrastructure
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# Configuration schema
|
|
88
|
+
class Config(BaseSettings):
|
|
89
|
+
"""Configuration for the AI document writer orchestrator tool
|
|
90
|
+
|
|
91
|
+
Automatically reads from environment variables with AI_DOC_WRITER_ prefix.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
model_config = SettingsConfigDict(env_prefix="AI_DOC_WRITER_")
|
|
95
|
+
|
|
96
|
+
default_ai_provider: str = Field(default="openai", description="Default AI provider to use")
|
|
97
|
+
max_content_length: int = Field(
|
|
98
|
+
default=50000,
|
|
99
|
+
description="Maximum content length for AI generation",
|
|
100
|
+
)
|
|
101
|
+
max_concurrent_writes: int = Field(default=5, description="Maximum concurrent write operations")
|
|
102
|
+
default_temperature: float = Field(default=0.3, description="Default temperature for AI model")
|
|
103
|
+
max_tokens: int = Field(default=4000, description="Maximum tokens for AI response")
|
|
104
|
+
timeout: int = Field(default=60, description="Timeout in seconds for AI operations")
|
|
105
|
+
enable_draft_mode: bool = Field(default=True, description="Whether to enable draft mode")
|
|
106
|
+
enable_content_review: bool = Field(default=True, description="Whether to enable content review")
|
|
107
|
+
auto_backup_on_ai_write: bool = Field(
|
|
108
|
+
default=True,
|
|
109
|
+
description="Whether to automatically backup before AI writes",
|
|
110
|
+
)
|
|
111
|
+
temp_dir: str = Field(
|
|
112
|
+
default=tempfile.gettempdir(),
|
|
113
|
+
description="Temporary directory for processing",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def __init__(self, config: Optional[Dict] = None, **kwargs):
|
|
117
|
+
"""Initialize AI Document Writer Orchestrator with settings
|
|
118
|
+
|
|
119
|
+
Configuration is automatically loaded by BaseTool from:
|
|
120
|
+
1. Explicit config dict (highest priority)
|
|
121
|
+
2. YAML config files (config/tools/ai_document_writer_orchestrator.yaml)
|
|
122
|
+
3. Environment variables (via dotenv from .env files)
|
|
123
|
+
4. Tool defaults (lowest priority)
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
config: Optional configuration overrides
|
|
127
|
+
**kwargs: Additional arguments passed to BaseTool (e.g., tool_name)
|
|
128
|
+
"""
|
|
129
|
+
super().__init__(config, **kwargs)
|
|
130
|
+
|
|
131
|
+
# Configuration is automatically loaded by BaseTool into self._config_obj
|
|
132
|
+
# Access config via self._config_obj (BaseSettings instance)
|
|
133
|
+
self.config = self._config_obj if self._config_obj else self.Config()
|
|
134
|
+
|
|
135
|
+
self.logger = logging.getLogger(__name__)
|
|
136
|
+
|
|
137
|
+
# Initialize document writer
|
|
138
|
+
self._init_document_writer()
|
|
139
|
+
|
|
140
|
+
# Initialize document creation tools
|
|
141
|
+
self._init_document_creation_tools()
|
|
142
|
+
|
|
143
|
+
# Initialize AI providers
|
|
144
|
+
self._init_ai_providers()
|
|
145
|
+
|
|
146
|
+
# Initialize content generation templates
|
|
147
|
+
self._init_content_templates()
|
|
148
|
+
|
|
149
|
+
def _init_document_writer(self):
|
|
150
|
+
"""Initialize document writer tool"""
|
|
151
|
+
try:
|
|
152
|
+
from aiecs.tools.docs.document_writer_tool import (
|
|
153
|
+
DocumentWriterTool,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
self.document_writer = DocumentWriterTool()
|
|
157
|
+
except ImportError:
|
|
158
|
+
self.logger.error("DocumentWriterTool not available")
|
|
159
|
+
self.document_writer = None
|
|
160
|
+
|
|
161
|
+
def _init_document_creation_tools(self):
|
|
162
|
+
"""Initialize document creation and layout tools"""
|
|
163
|
+
self.creation_tools = {}
|
|
164
|
+
|
|
165
|
+
# Initialize DocumentCreatorTool
|
|
166
|
+
try:
|
|
167
|
+
from aiecs.tools.docs.document_creator_tool import (
|
|
168
|
+
DocumentCreatorTool,
|
|
169
|
+
DocumentFormat,
|
|
170
|
+
DocumentType,
|
|
171
|
+
TemplateType,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
self.creation_tools["creator"] = DocumentCreatorTool()
|
|
175
|
+
# Store classes for later use
|
|
176
|
+
self.DocumentFormat = DocumentFormat
|
|
177
|
+
self.DocumentType = DocumentType
|
|
178
|
+
self.TemplateType = TemplateType
|
|
179
|
+
self.logger.info("DocumentCreatorTool initialized successfully")
|
|
180
|
+
except ImportError:
|
|
181
|
+
self.logger.warning("DocumentCreatorTool not available")
|
|
182
|
+
|
|
183
|
+
# Initialize DocumentLayoutTool
|
|
184
|
+
try:
|
|
185
|
+
from aiecs.tools.docs.document_layout_tool import (
|
|
186
|
+
DocumentLayoutTool,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
self.creation_tools["layout"] = DocumentLayoutTool()
|
|
190
|
+
self.logger.info("DocumentLayoutTool initialized successfully")
|
|
191
|
+
except ImportError:
|
|
192
|
+
self.logger.warning("DocumentLayoutTool not available")
|
|
193
|
+
|
|
194
|
+
# Initialize ContentInsertionTool
|
|
195
|
+
try:
|
|
196
|
+
from aiecs.tools.docs.content_insertion_tool import (
|
|
197
|
+
ContentInsertionTool,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
self.creation_tools["content"] = ContentInsertionTool()
|
|
201
|
+
self.logger.info("ContentInsertionTool initialized successfully")
|
|
202
|
+
except ImportError:
|
|
203
|
+
self.logger.warning("ContentInsertionTool not available")
|
|
204
|
+
|
|
205
|
+
def _init_ai_providers(self):
|
|
206
|
+
"""Initialize AI providers"""
|
|
207
|
+
self.ai_providers = {}
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
# Initialize AIECS client for AI operations
|
|
211
|
+
from aiecs import AIECS
|
|
212
|
+
|
|
213
|
+
self.aiecs_client = AIECS()
|
|
214
|
+
self.ai_providers["aiecs"] = self.aiecs_client
|
|
215
|
+
except ImportError:
|
|
216
|
+
self.logger.warning("AIECS client not available")
|
|
217
|
+
self.aiecs_client = None
|
|
218
|
+
|
|
219
|
+
def _init_content_templates(self):
|
|
220
|
+
"""Initialize content generation templates"""
|
|
221
|
+
self.content_templates = {
|
|
222
|
+
ContentGenerationMode.GENERATE: {
|
|
223
|
+
"system_prompt": "You are an expert content writer. Generate high-quality, well-structured content based on the given requirements.",
|
|
224
|
+
"user_prompt_template": (
|
|
225
|
+
"Generate content for: {content_type}\n\nRequirements:\n{requirements}\n\n"
|
|
226
|
+
"Target audience: {audience}\n\nPlease provide well-structured, engaging content that meets these requirements."
|
|
227
|
+
),
|
|
228
|
+
},
|
|
229
|
+
ContentGenerationMode.ENHANCE: {
|
|
230
|
+
"system_prompt": "You are an expert content editor. Enhance and improve existing content while maintaining its core message.",
|
|
231
|
+
"user_prompt_template": (
|
|
232
|
+
"Enhance the following content:\n\n{existing_content}\n\nImprovement goals:\n{enhancement_goals}\n\n"
|
|
233
|
+
"Please provide an enhanced version that is more engaging, clear, and effective."
|
|
234
|
+
),
|
|
235
|
+
},
|
|
236
|
+
ContentGenerationMode.REWRITE: {
|
|
237
|
+
"system_prompt": "You are an expert content rewriter. Rewrite content to improve clarity, style, and effectiveness.",
|
|
238
|
+
"user_prompt_template": (
|
|
239
|
+
"Rewrite the following content:\n\n{existing_content}\n\nRewriting goals:\n{rewrite_goals}\n\n"
|
|
240
|
+
"Target style: {target_style}\n\nPlease provide a completely rewritten version that maintains "
|
|
241
|
+
"the core information but improves presentation."
|
|
242
|
+
),
|
|
243
|
+
},
|
|
244
|
+
ContentGenerationMode.TRANSLATE: {
|
|
245
|
+
"system_prompt": "You are an expert translator. Provide accurate, natural translations that preserve meaning and context.",
|
|
246
|
+
"user_prompt_template": (
|
|
247
|
+
"Translate the following content to {target_language}:\n\n{content}\n\n" "Please provide a natural, accurate translation that preserves the original meaning and tone."
|
|
248
|
+
),
|
|
249
|
+
},
|
|
250
|
+
ContentGenerationMode.CONVERT_FORMAT: {
|
|
251
|
+
"system_prompt": "You are an expert document formatter. Convert content between different formats while preserving structure and meaning.",
|
|
252
|
+
"user_prompt_template": (
|
|
253
|
+
"Convert the following content from {source_format} to {target_format}:\n\n{content}\n\n"
|
|
254
|
+
"Please maintain the structure and ensure the converted format is properly formatted and readable."
|
|
255
|
+
),
|
|
256
|
+
},
|
|
257
|
+
ContentGenerationMode.TEMPLATE_FILL: {
|
|
258
|
+
"system_prompt": "You are an expert template processor. Fill templates with appropriate content based on provided data.",
|
|
259
|
+
"user_prompt_template": (
|
|
260
|
+
"Fill the following template with the provided data:\n\nTemplate:\n{template}\n\nData:\n{data}\n\n"
|
|
261
|
+
"Please generate complete, coherent content that properly fills all template sections."
|
|
262
|
+
),
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# Schema definitions
|
|
267
|
+
class Ai_write_documentSchema(BaseModel):
|
|
268
|
+
"""Schema for ai_write_document operation"""
|
|
269
|
+
|
|
270
|
+
target_path: str = Field(description="Target file path")
|
|
271
|
+
content_requirements: str = Field(description="Content requirements and specifications")
|
|
272
|
+
generation_mode: ContentGenerationMode = Field(description="Content generation mode")
|
|
273
|
+
document_format: str = Field(description="Target document format")
|
|
274
|
+
write_strategy: WriteStrategy = Field(default=WriteStrategy.IMMEDIATE, description="Write strategy")
|
|
275
|
+
ai_provider: Optional[AIProvider] = Field(default=None, description="AI provider to use")
|
|
276
|
+
generation_params: Optional[Dict[str, Any]] = Field(default=None, description="AI generation parameters")
|
|
277
|
+
write_params: Optional[Dict[str, Any]] = Field(default=None, description="Document write parameters")
|
|
278
|
+
|
|
279
|
+
class Enhance_documentSchema(BaseModel):
|
|
280
|
+
"""Schema for enhance_document operation"""
|
|
281
|
+
|
|
282
|
+
source_path: str = Field(description="Source document path")
|
|
283
|
+
target_path: Optional[str] = Field(default=None, description="Target path (if different)")
|
|
284
|
+
enhancement_goals: str = Field(description="Enhancement goals and requirements")
|
|
285
|
+
ai_provider: Optional[AIProvider] = Field(default=None, description="AI provider to use")
|
|
286
|
+
preserve_format: bool = Field(default=True, description="Preserve original format")
|
|
287
|
+
|
|
288
|
+
class Batch_ai_writeSchema(BaseModel):
|
|
289
|
+
"""Schema for batch_ai_write operation"""
|
|
290
|
+
|
|
291
|
+
write_requests: List[Dict[str, Any]] = Field(description="List of write requests")
|
|
292
|
+
coordination_strategy: str = Field(default="parallel", description="Coordination strategy")
|
|
293
|
+
max_concurrent: Optional[int] = Field(default=None, description="Maximum concurrent operations")
|
|
294
|
+
|
|
295
|
+
class Ai_edit_documentSchema(BaseModel):
|
|
296
|
+
"""Schema for ai_edit_document operation"""
|
|
297
|
+
|
|
298
|
+
target_path: str = Field(description="Target document path")
|
|
299
|
+
edit_operation: AIEditOperation = Field(description="AI editing operation to perform")
|
|
300
|
+
edit_instructions: str = Field(description="Specific editing instructions")
|
|
301
|
+
ai_provider: Optional[AIProvider] = Field(default=None, description="AI provider to use")
|
|
302
|
+
preserve_structure: bool = Field(default=True, description="Preserve document structure")
|
|
303
|
+
format_options: Optional[Dict[str, Any]] = Field(default=None, description="Format-specific options")
|
|
304
|
+
|
|
305
|
+
class Smart_format_documentSchema(BaseModel):
|
|
306
|
+
"""Schema for smart_format_document operation"""
|
|
307
|
+
|
|
308
|
+
target_path: str = Field(description="Target document path")
|
|
309
|
+
format_goals: str = Field(description="Formatting goals and requirements")
|
|
310
|
+
target_format: str = Field(description="Target document format")
|
|
311
|
+
style_preferences: Optional[Dict[str, Any]] = Field(default=None, description="Style preferences")
|
|
312
|
+
|
|
313
|
+
class Analyze_document_contentSchema(BaseModel):
|
|
314
|
+
"""Schema for analyze_document_content operation"""
|
|
315
|
+
|
|
316
|
+
source_path: str = Field(description="Source document path")
|
|
317
|
+
analysis_type: str = Field(description="Type of analysis to perform")
|
|
318
|
+
analysis_params: Optional[Dict[str, Any]] = Field(default=None, description="Analysis parameters")
|
|
319
|
+
|
|
320
|
+
class Create_rich_documentSchema(BaseModel):
|
|
321
|
+
"""Schema for create_rich_document operation"""
|
|
322
|
+
|
|
323
|
+
document_template: str = Field(description="Document template type")
|
|
324
|
+
content_plan: Dict[str, Any] = Field(description="Content planning configuration")
|
|
325
|
+
layout_config: Optional[Dict[str, Any]] = Field(default=None, description="Layout configuration")
|
|
326
|
+
output_path: Optional[str] = Field(default=None, description="Custom output path")
|
|
327
|
+
ai_assistance: bool = Field(
|
|
328
|
+
default=True,
|
|
329
|
+
description="Use AI assistance for content generation",
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
class Generate_document_with_chartsSchema(BaseModel):
|
|
333
|
+
"""Schema for generate_document_with_charts operation"""
|
|
334
|
+
|
|
335
|
+
requirements: str = Field(description="Document requirements and specifications")
|
|
336
|
+
data_sources: List[Dict[str, Any]] = Field(description="Data sources for charts and tables")
|
|
337
|
+
document_type: str = Field(description="Type of document to generate")
|
|
338
|
+
include_analysis: bool = Field(default=True, description="Include data analysis sections")
|
|
339
|
+
chart_preferences: Optional[Dict[str, Any]] = Field(default=None, description="Chart style preferences")
|
|
340
|
+
|
|
341
|
+
class Optimize_document_layoutSchema(BaseModel):
|
|
342
|
+
"""Schema for optimize_document_layout operation"""
|
|
343
|
+
|
|
344
|
+
document_path: str = Field(description="Path to document to optimize")
|
|
345
|
+
optimization_goals: List[str] = Field(description="Layout optimization goals")
|
|
346
|
+
preserve_content: bool = Field(default=True, description="Preserve existing content")
|
|
347
|
+
layout_style: Optional[str] = Field(default=None, description="Target layout style")
|
|
348
|
+
|
|
349
|
+
class Batch_content_insertionSchema(BaseModel):
|
|
350
|
+
"""Schema for batch_content_insertion operation"""
|
|
351
|
+
|
|
352
|
+
document_path: str = Field(description="Target document path")
|
|
353
|
+
content_plan: List[Dict[str, Any]] = Field(description="Content insertion plan")
|
|
354
|
+
insertion_strategy: str = Field(default="sequential", description="Insertion strategy")
|
|
355
|
+
ai_optimization: bool = Field(default=True, description="Use AI for content optimization")
|
|
356
|
+
|
|
357
|
+
class Create_content_templateSchema(BaseModel):
|
|
358
|
+
"""Schema for create_content_template operation"""
|
|
359
|
+
|
|
360
|
+
template_name: str = Field(description="Name of the template")
|
|
361
|
+
template_content: str = Field(description="Template content with variables")
|
|
362
|
+
template_variables: List[str] = Field(description="List of template variables")
|
|
363
|
+
metadata: Optional[Dict[str, Any]] = Field(default=None, description="Additional template metadata")
|
|
364
|
+
|
|
365
|
+
class Use_content_templateSchema(BaseModel):
|
|
366
|
+
"""Schema for use_content_template operation"""
|
|
367
|
+
|
|
368
|
+
template_name: str = Field(description="Name of the template to use")
|
|
369
|
+
template_data: Dict[str, Any] = Field(description="Data to fill template variables")
|
|
370
|
+
target_path: str = Field(description="Target document path")
|
|
371
|
+
ai_enhancement: bool = Field(default=True, description="Whether to enhance with AI")
|
|
372
|
+
|
|
373
|
+
def ai_write_document(
|
|
374
|
+
self,
|
|
375
|
+
target_path: str,
|
|
376
|
+
content_requirements: str,
|
|
377
|
+
generation_mode: ContentGenerationMode,
|
|
378
|
+
document_format: str = "txt",
|
|
379
|
+
write_strategy: WriteStrategy = WriteStrategy.IMMEDIATE,
|
|
380
|
+
ai_provider: Optional[AIProvider] = None,
|
|
381
|
+
generation_params: Optional[Dict[str, Any]] = None,
|
|
382
|
+
write_params: Optional[Dict[str, Any]] = None,
|
|
383
|
+
) -> Dict[str, Any]:
|
|
384
|
+
"""
|
|
385
|
+
Generate content using AI and write to document
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
target_path: Target file path
|
|
389
|
+
content_requirements: Content requirements and specifications
|
|
390
|
+
generation_mode: Content generation mode
|
|
391
|
+
document_format: Target document format
|
|
392
|
+
write_strategy: Write strategy (immediate, review, draft, staged)
|
|
393
|
+
ai_provider: AI provider to use
|
|
394
|
+
generation_params: AI generation parameters
|
|
395
|
+
write_params: Document write parameters
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
Dict containing generation and write results
|
|
399
|
+
"""
|
|
400
|
+
try:
|
|
401
|
+
start_time = datetime.now()
|
|
402
|
+
# Use microsecond precision for unique IDs
|
|
403
|
+
operation_id = f"ai_write_{int(start_time.timestamp() * 1000000)}"
|
|
404
|
+
|
|
405
|
+
self.logger.info(f"Starting AI write operation {operation_id}: {target_path}")
|
|
406
|
+
|
|
407
|
+
# Step 1: Generate content using AI
|
|
408
|
+
provider = ai_provider or AIProvider(self.config.default_ai_provider)
|
|
409
|
+
ai_result = self._generate_content_with_ai(
|
|
410
|
+
content_requirements,
|
|
411
|
+
generation_mode,
|
|
412
|
+
document_format,
|
|
413
|
+
provider,
|
|
414
|
+
generation_params or {},
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# Step 2: Process generated content
|
|
418
|
+
processed_content = self._process_generated_content(
|
|
419
|
+
ai_result["generated_content"],
|
|
420
|
+
document_format,
|
|
421
|
+
generation_mode,
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
# Step 3: Handle write strategy
|
|
425
|
+
write_result = self._execute_write_strategy(
|
|
426
|
+
target_path,
|
|
427
|
+
processed_content,
|
|
428
|
+
document_format,
|
|
429
|
+
write_strategy,
|
|
430
|
+
write_params or {},
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
# Step 4: Post-processing
|
|
434
|
+
post_process_result = self._post_process_ai_write(
|
|
435
|
+
operation_id,
|
|
436
|
+
target_path,
|
|
437
|
+
ai_result,
|
|
438
|
+
write_result,
|
|
439
|
+
write_strategy,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
result = {
|
|
443
|
+
"operation_id": operation_id,
|
|
444
|
+
"target_path": target_path,
|
|
445
|
+
"generation_mode": generation_mode,
|
|
446
|
+
"document_format": document_format,
|
|
447
|
+
"write_strategy": write_strategy,
|
|
448
|
+
"ai_provider": ai_provider or self.config.default_ai_provider,
|
|
449
|
+
"ai_result": ai_result,
|
|
450
|
+
"write_result": write_result,
|
|
451
|
+
"post_process_result": post_process_result,
|
|
452
|
+
"processing_metadata": {
|
|
453
|
+
"start_time": start_time.isoformat(),
|
|
454
|
+
"end_time": datetime.now().isoformat(),
|
|
455
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
456
|
+
},
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
self.logger.info(f"AI write operation {operation_id} completed successfully")
|
|
460
|
+
return result
|
|
461
|
+
|
|
462
|
+
except Exception as e:
|
|
463
|
+
raise WriteOrchestrationError(f"AI write operation failed: {str(e)}")
|
|
464
|
+
|
|
465
|
+
async def ai_write_document_async(
|
|
466
|
+
self,
|
|
467
|
+
target_path: str,
|
|
468
|
+
content_requirements: str,
|
|
469
|
+
generation_mode: ContentGenerationMode,
|
|
470
|
+
document_format: str = "txt",
|
|
471
|
+
write_strategy: WriteStrategy = WriteStrategy.IMMEDIATE,
|
|
472
|
+
ai_provider: Optional[AIProvider] = None,
|
|
473
|
+
generation_params: Optional[Dict[str, Any]] = None,
|
|
474
|
+
write_params: Optional[Dict[str, Any]] = None,
|
|
475
|
+
) -> Dict[str, Any]:
|
|
476
|
+
"""Async version of ai_write_document"""
|
|
477
|
+
return await asyncio.to_thread(
|
|
478
|
+
self.ai_write_document,
|
|
479
|
+
target_path=target_path,
|
|
480
|
+
content_requirements=content_requirements,
|
|
481
|
+
generation_mode=generation_mode,
|
|
482
|
+
document_format=document_format,
|
|
483
|
+
write_strategy=write_strategy,
|
|
484
|
+
ai_provider=ai_provider,
|
|
485
|
+
generation_params=generation_params,
|
|
486
|
+
write_params=write_params,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
def enhance_document(
|
|
490
|
+
self,
|
|
491
|
+
source_path: str,
|
|
492
|
+
enhancement_goals: str,
|
|
493
|
+
target_path: Optional[str] = None,
|
|
494
|
+
ai_provider: Optional[AIProvider] = None,
|
|
495
|
+
preserve_format: bool = True,
|
|
496
|
+
) -> Dict[str, Any]:
|
|
497
|
+
"""
|
|
498
|
+
Enhance existing document using AI
|
|
499
|
+
|
|
500
|
+
Args:
|
|
501
|
+
source_path: Source document path
|
|
502
|
+
enhancement_goals: Enhancement goals and requirements
|
|
503
|
+
target_path: Target path (if different from source)
|
|
504
|
+
ai_provider: AI provider to use
|
|
505
|
+
preserve_format: Preserve original document format
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
Dict containing enhancement results
|
|
509
|
+
"""
|
|
510
|
+
try:
|
|
511
|
+
start_time = datetime.now()
|
|
512
|
+
|
|
513
|
+
# Step 1: Read existing document
|
|
514
|
+
existing_content = self._read_existing_document(source_path)
|
|
515
|
+
|
|
516
|
+
# Step 2: Generate enhanced content
|
|
517
|
+
provider = ai_provider or AIProvider(self.config.default_ai_provider)
|
|
518
|
+
ai_result = self._enhance_content_with_ai(
|
|
519
|
+
existing_content,
|
|
520
|
+
enhancement_goals,
|
|
521
|
+
provider,
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
# Step 3: Write enhanced content
|
|
525
|
+
target = target_path or source_path
|
|
526
|
+
write_mode = "overwrite" if target == source_path else "create"
|
|
527
|
+
|
|
528
|
+
if self.config.auto_backup_on_ai_write and target == source_path:
|
|
529
|
+
write_mode = "backup_write"
|
|
530
|
+
|
|
531
|
+
write_result = self.document_writer.write_document(
|
|
532
|
+
target_path=target,
|
|
533
|
+
content=ai_result["enhanced_content"],
|
|
534
|
+
format=existing_content["format"],
|
|
535
|
+
mode=write_mode,
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
result = {
|
|
539
|
+
"source_path": source_path,
|
|
540
|
+
"target_path": target,
|
|
541
|
+
"enhancement_goals": enhancement_goals,
|
|
542
|
+
"preserve_format": preserve_format,
|
|
543
|
+
"original_content": existing_content,
|
|
544
|
+
"ai_result": ai_result,
|
|
545
|
+
"write_result": write_result,
|
|
546
|
+
"processing_metadata": {
|
|
547
|
+
"start_time": start_time.isoformat(),
|
|
548
|
+
"end_time": datetime.now().isoformat(),
|
|
549
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
550
|
+
},
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return result
|
|
554
|
+
|
|
555
|
+
except Exception as e:
|
|
556
|
+
raise WriteOrchestrationError(f"Document enhancement failed: {str(e)}")
|
|
557
|
+
|
|
558
|
+
def batch_ai_write(
|
|
559
|
+
self,
|
|
560
|
+
write_requests: List[Dict[str, Any]],
|
|
561
|
+
coordination_strategy: str = "parallel",
|
|
562
|
+
max_concurrent: Optional[int] = None,
|
|
563
|
+
) -> Dict[str, Any]:
|
|
564
|
+
"""
|
|
565
|
+
Batch AI write operations with coordination
|
|
566
|
+
|
|
567
|
+
Args:
|
|
568
|
+
write_requests: List of write request dictionaries
|
|
569
|
+
coordination_strategy: Coordination strategy (parallel, sequential, smart)
|
|
570
|
+
max_concurrent: Maximum concurrent operations
|
|
571
|
+
|
|
572
|
+
Returns:
|
|
573
|
+
Dict containing batch processing results
|
|
574
|
+
"""
|
|
575
|
+
try:
|
|
576
|
+
start_time = datetime.now()
|
|
577
|
+
batch_id = f"batch_ai_write_{int(start_time.timestamp())}"
|
|
578
|
+
max_concurrent = max_concurrent or self.config.max_concurrent_writes
|
|
579
|
+
|
|
580
|
+
self.logger.info(f"Starting batch AI write {batch_id}: {len(write_requests)} requests")
|
|
581
|
+
|
|
582
|
+
if coordination_strategy == "parallel":
|
|
583
|
+
results = asyncio.run(self._batch_write_parallel(write_requests, max_concurrent))
|
|
584
|
+
elif coordination_strategy == "sequential":
|
|
585
|
+
results = self._batch_write_sequential(write_requests)
|
|
586
|
+
elif coordination_strategy == "smart":
|
|
587
|
+
results = asyncio.run(self._batch_write_smart(write_requests, max_concurrent))
|
|
588
|
+
else:
|
|
589
|
+
raise ValueError(f"Unknown coordination strategy: {coordination_strategy}")
|
|
590
|
+
|
|
591
|
+
batch_result = {
|
|
592
|
+
"batch_id": batch_id,
|
|
593
|
+
"coordination_strategy": coordination_strategy,
|
|
594
|
+
"total_requests": len(write_requests),
|
|
595
|
+
"successful_requests": len([r for r in results if r.get("status") == "success"]),
|
|
596
|
+
"failed_requests": len([r for r in results if r.get("status") == "error"]),
|
|
597
|
+
"results": results,
|
|
598
|
+
"batch_metadata": {
|
|
599
|
+
"start_time": start_time.isoformat(),
|
|
600
|
+
"end_time": datetime.now().isoformat(),
|
|
601
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
602
|
+
},
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return batch_result
|
|
606
|
+
|
|
607
|
+
except Exception as e:
|
|
608
|
+
raise WriteOrchestrationError(f"Batch AI write failed: {str(e)}")
|
|
609
|
+
|
|
610
|
+
def ai_edit_document(
|
|
611
|
+
self,
|
|
612
|
+
target_path: str,
|
|
613
|
+
edit_operation: AIEditOperation,
|
|
614
|
+
edit_instructions: str,
|
|
615
|
+
ai_provider: Optional[AIProvider] = None,
|
|
616
|
+
preserve_structure: bool = True,
|
|
617
|
+
format_options: Optional[Dict[str, Any]] = None,
|
|
618
|
+
) -> Dict[str, Any]:
|
|
619
|
+
"""
|
|
620
|
+
Perform AI-driven editing operations on documents
|
|
621
|
+
|
|
622
|
+
Args:
|
|
623
|
+
target_path: Target document path
|
|
624
|
+
edit_operation: AI editing operation to perform
|
|
625
|
+
edit_instructions: Specific editing instructions
|
|
626
|
+
ai_provider: AI provider to use
|
|
627
|
+
preserve_structure: Preserve document structure
|
|
628
|
+
format_options: Format-specific options
|
|
629
|
+
|
|
630
|
+
Returns:
|
|
631
|
+
Dict containing editing results
|
|
632
|
+
"""
|
|
633
|
+
try:
|
|
634
|
+
start_time = datetime.now()
|
|
635
|
+
operation_id = f"ai_edit_{int(start_time.timestamp())}"
|
|
636
|
+
|
|
637
|
+
self.logger.info(f"Starting AI edit operation {operation_id}: {edit_operation} on {target_path}")
|
|
638
|
+
|
|
639
|
+
if not self.document_writer:
|
|
640
|
+
raise WriteOrchestrationError("DocumentWriterTool not available")
|
|
641
|
+
|
|
642
|
+
# Step 1: Read current document content
|
|
643
|
+
current_content = self._read_document_for_editing(target_path)
|
|
644
|
+
|
|
645
|
+
# Step 2: Analyze content for editing
|
|
646
|
+
analysis_result = self._analyze_document_for_editing(current_content, edit_operation, edit_instructions)
|
|
647
|
+
|
|
648
|
+
# Step 3: Generate editing instructions using AI
|
|
649
|
+
ai_edit_plan = self._generate_ai_edit_plan(
|
|
650
|
+
current_content,
|
|
651
|
+
edit_operation,
|
|
652
|
+
edit_instructions,
|
|
653
|
+
analysis_result,
|
|
654
|
+
ai_provider or AIProvider(self.config.default_ai_provider),
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
# Step 4: Execute editing operations
|
|
658
|
+
edit_results = self._execute_ai_editing_plan(target_path, ai_edit_plan, format_options)
|
|
659
|
+
|
|
660
|
+
# Step 5: Post-process and validate
|
|
661
|
+
validation_result = self._validate_ai_editing_result(target_path, current_content, edit_results, preserve_structure)
|
|
662
|
+
|
|
663
|
+
result = {
|
|
664
|
+
"operation_id": operation_id,
|
|
665
|
+
"target_path": target_path,
|
|
666
|
+
"edit_operation": edit_operation,
|
|
667
|
+
"edit_instructions": edit_instructions,
|
|
668
|
+
"preserve_structure": preserve_structure,
|
|
669
|
+
"analysis_result": analysis_result,
|
|
670
|
+
"ai_edit_plan": ai_edit_plan,
|
|
671
|
+
"edit_results": edit_results,
|
|
672
|
+
"validation_result": validation_result,
|
|
673
|
+
"processing_metadata": {
|
|
674
|
+
"start_time": start_time.isoformat(),
|
|
675
|
+
"end_time": datetime.now().isoformat(),
|
|
676
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
677
|
+
},
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
self.logger.info(f"AI edit operation {operation_id} completed successfully")
|
|
681
|
+
return result
|
|
682
|
+
|
|
683
|
+
except Exception as e:
|
|
684
|
+
raise WriteOrchestrationError(f"AI edit operation failed: {str(e)}")
|
|
685
|
+
|
|
686
|
+
def smart_format_document(
|
|
687
|
+
self,
|
|
688
|
+
target_path: str,
|
|
689
|
+
format_goals: str,
|
|
690
|
+
target_format: str,
|
|
691
|
+
style_preferences: Optional[Dict[str, Any]] = None,
|
|
692
|
+
) -> Dict[str, Any]:
|
|
693
|
+
"""
|
|
694
|
+
Intelligently format document using AI analysis
|
|
695
|
+
|
|
696
|
+
Args:
|
|
697
|
+
target_path: Target document path
|
|
698
|
+
format_goals: Formatting goals and requirements
|
|
699
|
+
target_format: Target document format
|
|
700
|
+
style_preferences: Style preferences
|
|
701
|
+
|
|
702
|
+
Returns:
|
|
703
|
+
Dict containing formatting results
|
|
704
|
+
"""
|
|
705
|
+
try:
|
|
706
|
+
start_time = datetime.now()
|
|
707
|
+
|
|
708
|
+
if not self.document_writer:
|
|
709
|
+
raise WriteOrchestrationError("DocumentWriterTool not available")
|
|
710
|
+
|
|
711
|
+
# Step 1: Analyze document structure
|
|
712
|
+
structure_analysis = self._analyze_document_structure(target_path, target_format)
|
|
713
|
+
|
|
714
|
+
# Step 2: Generate smart formatting plan
|
|
715
|
+
format_plan = self._generate_smart_format_plan(
|
|
716
|
+
structure_analysis,
|
|
717
|
+
format_goals,
|
|
718
|
+
target_format,
|
|
719
|
+
style_preferences,
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
# Step 3: Execute formatting operations
|
|
723
|
+
format_results = self._execute_smart_formatting(target_path, format_plan, target_format)
|
|
724
|
+
|
|
725
|
+
result = {
|
|
726
|
+
"target_path": target_path,
|
|
727
|
+
"format_goals": format_goals,
|
|
728
|
+
"target_format": target_format,
|
|
729
|
+
"structure_analysis": structure_analysis,
|
|
730
|
+
"format_plan": format_plan,
|
|
731
|
+
"format_results": format_results,
|
|
732
|
+
"processing_metadata": {
|
|
733
|
+
"start_time": start_time.isoformat(),
|
|
734
|
+
"end_time": datetime.now().isoformat(),
|
|
735
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
736
|
+
},
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
return result
|
|
740
|
+
|
|
741
|
+
except Exception as e:
|
|
742
|
+
raise WriteOrchestrationError(f"Smart formatting failed: {str(e)}")
|
|
743
|
+
|
|
744
|
+
def analyze_document_content(
|
|
745
|
+
self,
|
|
746
|
+
source_path: str,
|
|
747
|
+
analysis_type: str,
|
|
748
|
+
analysis_params: Optional[Dict[str, Any]] = None,
|
|
749
|
+
) -> Dict[str, Any]:
|
|
750
|
+
"""
|
|
751
|
+
Perform AI-driven content analysis
|
|
752
|
+
|
|
753
|
+
Args:
|
|
754
|
+
source_path: Source document path
|
|
755
|
+
analysis_type: Type of analysis to perform
|
|
756
|
+
analysis_params: Analysis parameters
|
|
757
|
+
|
|
758
|
+
Returns:
|
|
759
|
+
Dict containing analysis results
|
|
760
|
+
"""
|
|
761
|
+
try:
|
|
762
|
+
if not self.document_writer:
|
|
763
|
+
raise WriteOrchestrationError("DocumentWriterTool not available")
|
|
764
|
+
|
|
765
|
+
# Read document content
|
|
766
|
+
content = self._read_document_for_editing(source_path)
|
|
767
|
+
|
|
768
|
+
# Perform analysis based on type
|
|
769
|
+
if analysis_type == "structure":
|
|
770
|
+
format_param = analysis_params.get("format", "txt") if analysis_params else "txt"
|
|
771
|
+
result = self._analyze_document_structure(source_path, format_param)
|
|
772
|
+
elif analysis_type == "readability":
|
|
773
|
+
result = self._analyze_readability(content, analysis_params)
|
|
774
|
+
elif analysis_type == "keywords":
|
|
775
|
+
result = self._analyze_keywords(content, analysis_params)
|
|
776
|
+
elif analysis_type == "formatting_issues":
|
|
777
|
+
result = self._analyze_formatting_issues(content, analysis_params)
|
|
778
|
+
elif analysis_type == "content_quality":
|
|
779
|
+
result = self._analyze_content_quality(content, analysis_params)
|
|
780
|
+
else:
|
|
781
|
+
raise ValueError(f"Unsupported analysis type: {analysis_type}")
|
|
782
|
+
|
|
783
|
+
return {
|
|
784
|
+
"source_path": source_path,
|
|
785
|
+
"analysis_type": analysis_type,
|
|
786
|
+
"analysis_result": result,
|
|
787
|
+
"content_metadata": {
|
|
788
|
+
"content_length": len(content),
|
|
789
|
+
"analysis_timestamp": datetime.now().isoformat(),
|
|
790
|
+
},
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
except Exception as e:
|
|
794
|
+
raise WriteOrchestrationError(f"Document analysis failed: {str(e)}")
|
|
795
|
+
|
|
796
|
+
# Helper methods for AI editing operations
|
|
797
|
+
def _read_document_for_editing(self, file_path: str) -> str:
|
|
798
|
+
"""Read document content for editing operations"""
|
|
799
|
+
try:
|
|
800
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
801
|
+
return f.read()
|
|
802
|
+
except Exception as e:
|
|
803
|
+
raise WriteOrchestrationError(f"Cannot read document {file_path}: {str(e)}")
|
|
804
|
+
|
|
805
|
+
def _analyze_document_for_editing(self, content: str, operation: AIEditOperation, instructions: str) -> Dict[str, Any]:
|
|
806
|
+
"""Analyze document content for editing operations"""
|
|
807
|
+
analysis = {
|
|
808
|
+
"content_length": len(content),
|
|
809
|
+
"line_count": len(content.split("\n")),
|
|
810
|
+
"word_count": len(content.split()),
|
|
811
|
+
"operation": operation,
|
|
812
|
+
"instructions": instructions,
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
# Specific analysis based on operation type
|
|
816
|
+
if operation == AIEditOperation.SMART_FORMAT:
|
|
817
|
+
analysis["formatting_issues"] = self._detect_formatting_issues(content)
|
|
818
|
+
elif operation == AIEditOperation.AUTO_BOLD_KEYWORDS:
|
|
819
|
+
analysis["potential_keywords"] = self._extract_potential_keywords(content)
|
|
820
|
+
elif operation == AIEditOperation.INTELLIGENT_HIGHLIGHT:
|
|
821
|
+
analysis["important_sections"] = self._identify_important_sections(content)
|
|
822
|
+
elif operation == AIEditOperation.CONTENT_RESTRUCTURE:
|
|
823
|
+
analysis["structure_analysis"] = self._analyze_content_structure(content)
|
|
824
|
+
|
|
825
|
+
return analysis
|
|
826
|
+
|
|
827
|
+
def _generate_ai_edit_plan(
|
|
828
|
+
self,
|
|
829
|
+
content: str,
|
|
830
|
+
operation: AIEditOperation,
|
|
831
|
+
instructions: str,
|
|
832
|
+
analysis: Dict[str, Any],
|
|
833
|
+
ai_provider: AIProvider,
|
|
834
|
+
) -> Dict[str, Any]:
|
|
835
|
+
"""Generate AI editing plan"""
|
|
836
|
+
try:
|
|
837
|
+
if not self.aiecs_client:
|
|
838
|
+
# Fallback to rule-based editing plan
|
|
839
|
+
return self._generate_fallback_edit_plan(content, operation, instructions, analysis)
|
|
840
|
+
|
|
841
|
+
# Prepare AI prompt for editing plan
|
|
842
|
+
system_prompt = f"""You are an expert document editor. Create a detailed editing plan based on the operation type and user instructions.
|
|
843
|
+
|
|
844
|
+
Operation: {operation}
|
|
845
|
+
Analysis: {analysis}
|
|
846
|
+
|
|
847
|
+
Provide a structured editing plan with specific actions, positions, and formatting details."""
|
|
848
|
+
|
|
849
|
+
user_prompt = f"""Content to edit:
|
|
850
|
+
{content[:2000]}...
|
|
851
|
+
|
|
852
|
+
Instructions: {instructions}
|
|
853
|
+
|
|
854
|
+
Please provide a detailed editing plan with:
|
|
855
|
+
1. Specific edit operations
|
|
856
|
+
2. Text positions (line numbers, character offsets)
|
|
857
|
+
3. Format options
|
|
858
|
+
4. Expected outcomes"""
|
|
859
|
+
|
|
860
|
+
# Generate editing plan using AI
|
|
861
|
+
# Combine system and user prompts
|
|
862
|
+
combined_prompt = f"{system_prompt}\n\n{user_prompt}"
|
|
863
|
+
ai_response = self._call_ai_provider(
|
|
864
|
+
combined_prompt,
|
|
865
|
+
ai_provider,
|
|
866
|
+
{"max_tokens": 2000, "temperature": 0.3},
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
# Parse AI response into structured plan
|
|
870
|
+
edit_plan = self._parse_ai_edit_response(ai_response, operation)
|
|
871
|
+
|
|
872
|
+
return edit_plan
|
|
873
|
+
|
|
874
|
+
except Exception as e:
|
|
875
|
+
self.logger.warning(f"AI edit plan generation failed: {e}, using fallback")
|
|
876
|
+
return self._generate_fallback_edit_plan(content, operation, instructions, analysis)
|
|
877
|
+
|
|
878
|
+
def _execute_ai_editing_plan(
|
|
879
|
+
self,
|
|
880
|
+
target_path: str,
|
|
881
|
+
edit_plan: Dict[str, Any],
|
|
882
|
+
format_options: Optional[Dict[str, Any]],
|
|
883
|
+
) -> List[Dict[str, Any]]:
|
|
884
|
+
"""Execute the AI-generated editing plan"""
|
|
885
|
+
edit_results = []
|
|
886
|
+
|
|
887
|
+
try:
|
|
888
|
+
for edit_action in edit_plan.get("edit_actions", []):
|
|
889
|
+
operation_type = edit_action.get("operation")
|
|
890
|
+
|
|
891
|
+
if operation_type in [
|
|
892
|
+
"bold",
|
|
893
|
+
"italic",
|
|
894
|
+
"underline",
|
|
895
|
+
"strikethrough",
|
|
896
|
+
"highlight",
|
|
897
|
+
]:
|
|
898
|
+
# Text formatting operations
|
|
899
|
+
result = self.document_writer.edit_document(
|
|
900
|
+
target_path=target_path,
|
|
901
|
+
operation=operation_type,
|
|
902
|
+
selection=edit_action.get("selection"),
|
|
903
|
+
format_options=format_options or edit_action.get("format_options", {}),
|
|
904
|
+
)
|
|
905
|
+
elif operation_type == "find_replace":
|
|
906
|
+
# Find and replace operations
|
|
907
|
+
result = self.document_writer.find_replace(
|
|
908
|
+
target_path=target_path,
|
|
909
|
+
find_text=edit_action.get("find_text"),
|
|
910
|
+
replace_text=edit_action.get("replace_text"),
|
|
911
|
+
replace_all=edit_action.get("replace_all", False),
|
|
912
|
+
case_sensitive=edit_action.get("case_sensitive", True),
|
|
913
|
+
regex_mode=edit_action.get("regex_mode", False),
|
|
914
|
+
)
|
|
915
|
+
elif operation_type == "format_text":
|
|
916
|
+
# Format specific text
|
|
917
|
+
result = self.document_writer.format_text(
|
|
918
|
+
target_path=target_path,
|
|
919
|
+
text_to_format=edit_action.get("text_to_format"),
|
|
920
|
+
format_type=edit_action.get("format_type"),
|
|
921
|
+
format_options=format_options or edit_action.get("format_options", {}),
|
|
922
|
+
)
|
|
923
|
+
else:
|
|
924
|
+
# General edit operations
|
|
925
|
+
result = self.document_writer.edit_document(
|
|
926
|
+
target_path=target_path,
|
|
927
|
+
operation=edit_action.get("operation"),
|
|
928
|
+
content=edit_action.get("content"),
|
|
929
|
+
position=edit_action.get("position"),
|
|
930
|
+
selection=edit_action.get("selection"),
|
|
931
|
+
format_options=format_options or edit_action.get("format_options", {}),
|
|
932
|
+
)
|
|
933
|
+
|
|
934
|
+
edit_results.append({"action": edit_action, "result": result, "success": True})
|
|
935
|
+
|
|
936
|
+
except Exception as e:
|
|
937
|
+
edit_results.append({"action": edit_action, "error": str(e), "success": False})
|
|
938
|
+
|
|
939
|
+
return edit_results
|
|
940
|
+
|
|
941
|
+
def _validate_ai_editing_result(
|
|
942
|
+
self,
|
|
943
|
+
target_path: str,
|
|
944
|
+
original_content: str,
|
|
945
|
+
edit_results: List[Dict[str, Any]],
|
|
946
|
+
preserve_structure: bool,
|
|
947
|
+
) -> Dict[str, Any]:
|
|
948
|
+
"""Validate AI editing results"""
|
|
949
|
+
try:
|
|
950
|
+
# Read edited content
|
|
951
|
+
edited_content = self._read_document_for_editing(target_path)
|
|
952
|
+
|
|
953
|
+
validation: Dict[str, Any] = {
|
|
954
|
+
"original_length": len(original_content),
|
|
955
|
+
"edited_length": len(edited_content),
|
|
956
|
+
"successful_operations": sum(1 for r in edit_results if r.get("success")),
|
|
957
|
+
"failed_operations": sum(1 for r in edit_results if not r.get("success")),
|
|
958
|
+
"content_changed": original_content != edited_content,
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if preserve_structure:
|
|
962
|
+
structure_check = self._check_structure_preservation(original_content, edited_content)
|
|
963
|
+
validation["structure_check"] = structure_check
|
|
964
|
+
# Extract structure preservation status from check results
|
|
965
|
+
# Structure is considered preserved if headers are preserved and similarity is above threshold
|
|
966
|
+
validation["structure_preserved"] = (
|
|
967
|
+
structure_check.get("headers_preserved", False) and
|
|
968
|
+
structure_check.get("structure_similarity", 0.0) > 0.8
|
|
969
|
+
)
|
|
970
|
+
else:
|
|
971
|
+
validation["structure_preserved"] = None # Not checked when preserve_structure is False
|
|
972
|
+
|
|
973
|
+
return validation
|
|
974
|
+
|
|
975
|
+
except Exception as e:
|
|
976
|
+
return {"validation_error": str(e)}
|
|
977
|
+
|
|
978
|
+
# Additional helper methods for specific operations
|
|
979
|
+
def _generate_fallback_edit_plan(
|
|
980
|
+
self,
|
|
981
|
+
content: str,
|
|
982
|
+
operation: AIEditOperation,
|
|
983
|
+
instructions: str,
|
|
984
|
+
analysis: Dict[str, Any],
|
|
985
|
+
) -> Dict[str, Any]:
|
|
986
|
+
"""Generate fallback editing plan when AI is not available"""
|
|
987
|
+
plan: Dict[str, Any] = {"edit_actions": []}
|
|
988
|
+
|
|
989
|
+
if operation == AIEditOperation.AUTO_BOLD_KEYWORDS:
|
|
990
|
+
# Auto-bold common keywords
|
|
991
|
+
keywords = ["重要", "关键", "注意", "警告", "错误", "成功"]
|
|
992
|
+
for keyword in keywords:
|
|
993
|
+
if keyword in content:
|
|
994
|
+
plan["edit_actions"].append(
|
|
995
|
+
{
|
|
996
|
+
"operation": "format_text",
|
|
997
|
+
"text_to_format": keyword,
|
|
998
|
+
"format_type": "bold",
|
|
999
|
+
"format_options": {"format_type": "markdown"},
|
|
1000
|
+
}
|
|
1001
|
+
)
|
|
1002
|
+
|
|
1003
|
+
elif operation == AIEditOperation.SMART_FORMAT:
|
|
1004
|
+
# Basic formatting improvements
|
|
1005
|
+
plan["edit_actions"].append(
|
|
1006
|
+
{
|
|
1007
|
+
"operation": "find_replace",
|
|
1008
|
+
"find_text": " ",
|
|
1009
|
+
"replace_text": " ",
|
|
1010
|
+
"replace_all": True,
|
|
1011
|
+
"description": "Remove double spaces",
|
|
1012
|
+
}
|
|
1013
|
+
)
|
|
1014
|
+
|
|
1015
|
+
return plan
|
|
1016
|
+
|
|
1017
|
+
def _detect_formatting_issues(self, content: str) -> List[str]:
|
|
1018
|
+
"""Detect common formatting issues"""
|
|
1019
|
+
issues = []
|
|
1020
|
+
|
|
1021
|
+
if " " in content:
|
|
1022
|
+
issues.append("Multiple consecutive spaces")
|
|
1023
|
+
if "\n\n\n" in content:
|
|
1024
|
+
issues.append("Multiple consecutive line breaks")
|
|
1025
|
+
if content.count("**") % 2 != 0:
|
|
1026
|
+
issues.append("Unmatched bold markdown markers")
|
|
1027
|
+
|
|
1028
|
+
return issues
|
|
1029
|
+
|
|
1030
|
+
def _extract_potential_keywords(self, content: str) -> List[str]:
|
|
1031
|
+
"""Extract potential keywords for bolding"""
|
|
1032
|
+
# Simple keyword extraction - could be enhanced with NLP
|
|
1033
|
+
import re
|
|
1034
|
+
|
|
1035
|
+
words = re.findall(r"\b[A-Z][a-z]+\b", content) # Capitalized words
|
|
1036
|
+
return list(set(words))[:10] # Top 10 unique words
|
|
1037
|
+
|
|
1038
|
+
def _identify_important_sections(self, content: str) -> List[Dict[str, Any]]:
|
|
1039
|
+
"""Identify sections that might need highlighting"""
|
|
1040
|
+
sections = []
|
|
1041
|
+
lines = content.split("\n")
|
|
1042
|
+
|
|
1043
|
+
for i, line in enumerate(lines):
|
|
1044
|
+
if any(keyword in line.lower() for keyword in ["重要", "注意", "警告", "关键"]):
|
|
1045
|
+
sections.append(
|
|
1046
|
+
{
|
|
1047
|
+
"line": i,
|
|
1048
|
+
"content": line,
|
|
1049
|
+
"reason": "Contains important keywords",
|
|
1050
|
+
}
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1053
|
+
return sections
|
|
1054
|
+
|
|
1055
|
+
def _analyze_content_structure(self, content: str) -> Dict[str, Any]:
|
|
1056
|
+
"""Analyze content structure"""
|
|
1057
|
+
lines = content.split("\n")
|
|
1058
|
+
return {
|
|
1059
|
+
"total_lines": len(lines),
|
|
1060
|
+
"empty_lines": sum(1 for line in lines if not line.strip()),
|
|
1061
|
+
"header_lines": sum(1 for line in lines if line.startswith("#")),
|
|
1062
|
+
"list_items": sum(1 for line in lines if line.strip().startswith(("-", "*", "+"))),
|
|
1063
|
+
"paragraphs": len([line for line in lines if line.strip() and not line.startswith("#")]),
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
def _parse_ai_edit_response(self, ai_response: str, operation: AIEditOperation) -> Dict[str, Any]:
|
|
1067
|
+
"""Parse AI response into structured editing plan"""
|
|
1068
|
+
# This is a simplified parser - could be enhanced with more
|
|
1069
|
+
# sophisticated parsing
|
|
1070
|
+
plan: Dict[str, Any] = {"edit_actions": []}
|
|
1071
|
+
|
|
1072
|
+
# Try to extract structured actions from AI response
|
|
1073
|
+
# For now, return a basic plan
|
|
1074
|
+
plan["ai_response"] = ai_response
|
|
1075
|
+
plan["operation"] = operation
|
|
1076
|
+
|
|
1077
|
+
return plan
|
|
1078
|
+
|
|
1079
|
+
def _check_structure_preservation(self, original: str, edited: str) -> Dict[str, Any]:
|
|
1080
|
+
"""Check if document structure is preserved after editing"""
|
|
1081
|
+
original_structure = self._analyze_content_structure(original)
|
|
1082
|
+
edited_structure = self._analyze_content_structure(edited)
|
|
1083
|
+
|
|
1084
|
+
return {
|
|
1085
|
+
"headers_preserved": original_structure["header_lines"] == edited_structure["header_lines"],
|
|
1086
|
+
"structure_similarity": self._calculate_structure_similarity(original_structure, edited_structure),
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
def _calculate_structure_similarity(self, struct1: Dict, struct2: Dict) -> float:
|
|
1090
|
+
"""Calculate similarity between two document structures"""
|
|
1091
|
+
# Simple similarity calculation
|
|
1092
|
+
if struct1["total_lines"] == 0:
|
|
1093
|
+
return 1.0 if struct2["total_lines"] == 0 else 0.0
|
|
1094
|
+
|
|
1095
|
+
similarity = 1.0 - abs(struct1["total_lines"] - struct2["total_lines"]) / max(struct1["total_lines"], struct2["total_lines"])
|
|
1096
|
+
return max(0.0, similarity)
|
|
1097
|
+
|
|
1098
|
+
def _analyze_document_structure(self, file_path: str, format_type: str) -> Dict[str, Any]:
|
|
1099
|
+
"""Analyze document structure for formatting"""
|
|
1100
|
+
content = self._read_document_for_editing(file_path)
|
|
1101
|
+
return self._analyze_content_structure(content)
|
|
1102
|
+
|
|
1103
|
+
def _generate_smart_format_plan(
|
|
1104
|
+
self,
|
|
1105
|
+
structure: Dict[str, Any],
|
|
1106
|
+
goals: str,
|
|
1107
|
+
target_format: str,
|
|
1108
|
+
style_prefs: Optional[Dict[str, Any]],
|
|
1109
|
+
) -> Dict[str, Any]:
|
|
1110
|
+
"""Generate smart formatting plan"""
|
|
1111
|
+
return {
|
|
1112
|
+
"format_actions": [],
|
|
1113
|
+
"structure_analysis": structure,
|
|
1114
|
+
"goals": goals,
|
|
1115
|
+
"target_format": target_format,
|
|
1116
|
+
"style_preferences": style_prefs or {},
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
def _execute_smart_formatting(self, target_path: str, plan: Dict[str, Any], target_format: str) -> Dict[str, Any]:
|
|
1120
|
+
"""Execute smart formatting plan"""
|
|
1121
|
+
return {
|
|
1122
|
+
"target_path": target_path,
|
|
1123
|
+
"plan_executed": plan,
|
|
1124
|
+
"target_format": target_format,
|
|
1125
|
+
"formatting_completed": True,
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
def _analyze_readability(self, content: str, params: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
1129
|
+
"""Analyze content readability"""
|
|
1130
|
+
words = content.split()
|
|
1131
|
+
sentences = content.split(".")
|
|
1132
|
+
|
|
1133
|
+
return {
|
|
1134
|
+
"word_count": len(words),
|
|
1135
|
+
"sentence_count": len(sentences),
|
|
1136
|
+
"avg_words_per_sentence": len(words) / max(len(sentences), 1),
|
|
1137
|
+
"readability_score": "good", # Simplified
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
def _analyze_keywords(self, content: str, params: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
1141
|
+
"""Analyze content keywords"""
|
|
1142
|
+
words = content.lower().split()
|
|
1143
|
+
word_freq: Dict[str, int] = {}
|
|
1144
|
+
for word in words:
|
|
1145
|
+
word_freq[word] = word_freq.get(word, 0) + 1
|
|
1146
|
+
|
|
1147
|
+
# Get top keywords
|
|
1148
|
+
top_keywords = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:10]
|
|
1149
|
+
|
|
1150
|
+
return {
|
|
1151
|
+
"total_words": len(words),
|
|
1152
|
+
"unique_words": len(word_freq),
|
|
1153
|
+
"top_keywords": top_keywords,
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
def _analyze_formatting_issues(self, content: str, params: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
1157
|
+
"""Analyze formatting issues in content"""
|
|
1158
|
+
issues = self._detect_formatting_issues(content)
|
|
1159
|
+
|
|
1160
|
+
return {
|
|
1161
|
+
"issues_found": len(issues),
|
|
1162
|
+
"issue_list": issues,
|
|
1163
|
+
"content_length": len(content),
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
def _analyze_content_quality(self, content: str, params: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
|
1167
|
+
"""Analyze overall content quality"""
|
|
1168
|
+
return {
|
|
1169
|
+
"content_length": len(content),
|
|
1170
|
+
"structure_score": 0.8, # Simplified scoring
|
|
1171
|
+
"readability_score": 0.7,
|
|
1172
|
+
"formatting_score": 0.9,
|
|
1173
|
+
"overall_quality": 0.8,
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
def create_rich_document(
|
|
1177
|
+
self,
|
|
1178
|
+
document_template: str,
|
|
1179
|
+
content_plan: Dict[str, Any],
|
|
1180
|
+
layout_config: Optional[Dict[str, Any]] = None,
|
|
1181
|
+
output_path: Optional[str] = None,
|
|
1182
|
+
ai_assistance: bool = True,
|
|
1183
|
+
) -> Dict[str, Any]:
|
|
1184
|
+
"""
|
|
1185
|
+
Create rich document with comprehensive content and layout
|
|
1186
|
+
|
|
1187
|
+
Args:
|
|
1188
|
+
document_template: Document template type
|
|
1189
|
+
content_plan: Content planning configuration
|
|
1190
|
+
layout_config: Layout configuration
|
|
1191
|
+
output_path: Custom output path
|
|
1192
|
+
ai_assistance: Use AI assistance for content generation
|
|
1193
|
+
|
|
1194
|
+
Returns:
|
|
1195
|
+
Dict containing rich document creation results
|
|
1196
|
+
"""
|
|
1197
|
+
try:
|
|
1198
|
+
start_time = datetime.now()
|
|
1199
|
+
operation_id = f"create_rich_{int(start_time.timestamp())}"
|
|
1200
|
+
|
|
1201
|
+
self.logger.info(f"Starting rich document creation {operation_id}")
|
|
1202
|
+
|
|
1203
|
+
# Check tool availability
|
|
1204
|
+
creator = self.creation_tools.get("creator")
|
|
1205
|
+
layout_tool = self.creation_tools.get("layout")
|
|
1206
|
+
content_tool = self.creation_tools.get("content")
|
|
1207
|
+
|
|
1208
|
+
if not creator:
|
|
1209
|
+
raise WriteOrchestrationError("DocumentCreatorTool not available")
|
|
1210
|
+
|
|
1211
|
+
# Step 1: Create document from template
|
|
1212
|
+
document_metadata = content_plan.get("metadata", {})
|
|
1213
|
+
document_format_str = content_plan.get("format", "markdown")
|
|
1214
|
+
|
|
1215
|
+
# Convert string to DocumentFormat enum
|
|
1216
|
+
try:
|
|
1217
|
+
document_format = self.DocumentFormat(document_format_str)
|
|
1218
|
+
except (ValueError, AttributeError):
|
|
1219
|
+
# Fallback if DocumentFormat not available
|
|
1220
|
+
from aiecs.tools.docs.document_creator_tool import (
|
|
1221
|
+
DocumentFormat,
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
document_format = DocumentFormat.MARKDOWN
|
|
1225
|
+
|
|
1226
|
+
# Get enum classes
|
|
1227
|
+
try:
|
|
1228
|
+
DocumentType = self.DocumentType
|
|
1229
|
+
TemplateType = self.TemplateType
|
|
1230
|
+
except AttributeError:
|
|
1231
|
+
from aiecs.tools.docs.document_creator_tool import (
|
|
1232
|
+
DocumentType,
|
|
1233
|
+
TemplateType,
|
|
1234
|
+
)
|
|
1235
|
+
|
|
1236
|
+
# Parse document_type with fallback
|
|
1237
|
+
doc_type_str = content_plan.get("document_type", "custom")
|
|
1238
|
+
try:
|
|
1239
|
+
doc_type = DocumentType(doc_type_str)
|
|
1240
|
+
except ValueError:
|
|
1241
|
+
# Try to find a matching type or use a sensible default
|
|
1242
|
+
if "technical" in doc_type_str.lower():
|
|
1243
|
+
doc_type = DocumentType.TECHNICAL
|
|
1244
|
+
elif "report" in doc_type_str.lower():
|
|
1245
|
+
doc_type = DocumentType.REPORT
|
|
1246
|
+
elif "article" in doc_type_str.lower():
|
|
1247
|
+
doc_type = DocumentType.ARTICLE
|
|
1248
|
+
else:
|
|
1249
|
+
doc_type = DocumentType.TECHNICAL # Default fallback
|
|
1250
|
+
self.logger.warning(f"Unknown document type '{doc_type_str}', using {doc_type.value}")
|
|
1251
|
+
|
|
1252
|
+
# Parse template_type with fallback
|
|
1253
|
+
try:
|
|
1254
|
+
tmpl_type = TemplateType(document_template)
|
|
1255
|
+
except ValueError:
|
|
1256
|
+
# Default to basic template
|
|
1257
|
+
tmpl_type = TemplateType.BASIC
|
|
1258
|
+
self.logger.warning(f"Unknown template type '{document_template}', using basic")
|
|
1259
|
+
|
|
1260
|
+
creation_result = creator.create_document(
|
|
1261
|
+
document_type=doc_type,
|
|
1262
|
+
template_type=tmpl_type,
|
|
1263
|
+
output_format=document_format,
|
|
1264
|
+
metadata=document_metadata,
|
|
1265
|
+
output_path=output_path,
|
|
1266
|
+
)
|
|
1267
|
+
|
|
1268
|
+
document_path = creation_result["output_path"]
|
|
1269
|
+
|
|
1270
|
+
# Step 2: Setup document structure
|
|
1271
|
+
if content_plan.get("sections"):
|
|
1272
|
+
creator.setup_document_structure(
|
|
1273
|
+
document_path=document_path,
|
|
1274
|
+
sections=content_plan["sections"],
|
|
1275
|
+
generate_toc=content_plan.get("generate_toc", True),
|
|
1276
|
+
numbering_style=content_plan.get("numbering_style"),
|
|
1277
|
+
)
|
|
1278
|
+
|
|
1279
|
+
# Step 3: Apply layout configuration
|
|
1280
|
+
if layout_tool and layout_config:
|
|
1281
|
+
layout_tool.set_page_layout(document_path=document_path, **layout_config)
|
|
1282
|
+
|
|
1283
|
+
# Setup headers/footers if specified
|
|
1284
|
+
if layout_config.get("headers_footers"):
|
|
1285
|
+
layout_tool.setup_headers_footers(
|
|
1286
|
+
document_path=document_path,
|
|
1287
|
+
**layout_config["headers_footers"],
|
|
1288
|
+
)
|
|
1289
|
+
|
|
1290
|
+
# Step 4: Generate and insert content with AI assistance
|
|
1291
|
+
content_results = []
|
|
1292
|
+
if ai_assistance and content_plan.get("content_items"):
|
|
1293
|
+
content_results = self._generate_and_insert_content_items(document_path, content_plan["content_items"])
|
|
1294
|
+
|
|
1295
|
+
# Step 5: Insert complex content (charts, tables, images)
|
|
1296
|
+
insertion_results = []
|
|
1297
|
+
if content_tool and content_plan.get("insertions"):
|
|
1298
|
+
insertion_results = self._batch_insert_complex_content(document_path, content_plan["insertions"], content_tool)
|
|
1299
|
+
|
|
1300
|
+
# Step 6: Final optimization
|
|
1301
|
+
if ai_assistance:
|
|
1302
|
+
self._optimize_rich_document(document_path, content_plan.get("optimization_goals", []))
|
|
1303
|
+
|
|
1304
|
+
result = {
|
|
1305
|
+
"operation_id": operation_id,
|
|
1306
|
+
"document_path": document_path,
|
|
1307
|
+
"document_template": document_template,
|
|
1308
|
+
"content_plan": content_plan,
|
|
1309
|
+
"layout_config": layout_config,
|
|
1310
|
+
"creation_result": creation_result,
|
|
1311
|
+
"content_results": content_results,
|
|
1312
|
+
"insertion_results": insertion_results,
|
|
1313
|
+
"ai_assistance_used": ai_assistance,
|
|
1314
|
+
"processing_metadata": {
|
|
1315
|
+
"start_time": start_time.isoformat(),
|
|
1316
|
+
"end_time": datetime.now().isoformat(),
|
|
1317
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
1318
|
+
},
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
self.logger.info(f"Rich document creation {operation_id} completed successfully")
|
|
1322
|
+
return result
|
|
1323
|
+
|
|
1324
|
+
except Exception as e:
|
|
1325
|
+
raise WriteOrchestrationError(f"Rich document creation failed: {str(e)}")
|
|
1326
|
+
|
|
1327
|
+
def generate_document_with_charts(
|
|
1328
|
+
self,
|
|
1329
|
+
requirements: str,
|
|
1330
|
+
data_sources: List[Dict[str, Any]],
|
|
1331
|
+
document_type: str,
|
|
1332
|
+
include_analysis: bool = True,
|
|
1333
|
+
chart_preferences: Optional[Dict[str, Any]] = None,
|
|
1334
|
+
) -> Dict[str, Any]:
|
|
1335
|
+
"""
|
|
1336
|
+
Generate document with AI-driven charts and data visualization
|
|
1337
|
+
|
|
1338
|
+
Args:
|
|
1339
|
+
requirements: Document requirements and specifications
|
|
1340
|
+
data_sources: Data sources for charts and tables
|
|
1341
|
+
document_type: Type of document to generate
|
|
1342
|
+
include_analysis: Include data analysis sections
|
|
1343
|
+
chart_preferences: Chart style preferences
|
|
1344
|
+
|
|
1345
|
+
Returns:
|
|
1346
|
+
Dict containing document generation results
|
|
1347
|
+
"""
|
|
1348
|
+
try:
|
|
1349
|
+
start_time = datetime.now()
|
|
1350
|
+
operation_id = f"gen_charts_{int(start_time.timestamp())}"
|
|
1351
|
+
|
|
1352
|
+
self.logger.info(f"Starting document generation with charts {operation_id}")
|
|
1353
|
+
|
|
1354
|
+
# Step 1: Analyze data sources and generate content plan
|
|
1355
|
+
content_plan = self._analyze_data_and_create_plan(data_sources, requirements, document_type, include_analysis)
|
|
1356
|
+
|
|
1357
|
+
# Step 2: Generate charts from data sources
|
|
1358
|
+
chart_results = self._generate_charts_from_data(data_sources, chart_preferences)
|
|
1359
|
+
|
|
1360
|
+
# Step 3: Create document with integrated charts
|
|
1361
|
+
rich_doc_result = self.create_rich_document(
|
|
1362
|
+
document_template=self._select_template_for_data_document(document_type),
|
|
1363
|
+
content_plan=content_plan,
|
|
1364
|
+
ai_assistance=True,
|
|
1365
|
+
)
|
|
1366
|
+
|
|
1367
|
+
# Step 4: Insert generated charts
|
|
1368
|
+
chart_insertion_results = self._insert_generated_charts(rich_doc_result["document_path"], chart_results, content_plan)
|
|
1369
|
+
|
|
1370
|
+
# Step 5: Generate AI analysis content
|
|
1371
|
+
if include_analysis:
|
|
1372
|
+
self._generate_ai_analysis_content(
|
|
1373
|
+
rich_doc_result["document_path"],
|
|
1374
|
+
data_sources,
|
|
1375
|
+
chart_results,
|
|
1376
|
+
)
|
|
1377
|
+
|
|
1378
|
+
result = {
|
|
1379
|
+
"operation_id": operation_id,
|
|
1380
|
+
"document_path": rich_doc_result["document_path"],
|
|
1381
|
+
"requirements": requirements,
|
|
1382
|
+
"data_sources": data_sources,
|
|
1383
|
+
"document_type": document_type,
|
|
1384
|
+
"content_plan": content_plan,
|
|
1385
|
+
"chart_results": chart_results,
|
|
1386
|
+
"rich_doc_result": rich_doc_result,
|
|
1387
|
+
"chart_insertion_results": chart_insertion_results,
|
|
1388
|
+
"include_analysis": include_analysis,
|
|
1389
|
+
"processing_metadata": {
|
|
1390
|
+
"start_time": start_time.isoformat(),
|
|
1391
|
+
"end_time": datetime.now().isoformat(),
|
|
1392
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
1393
|
+
},
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
self.logger.info(f"Document with charts generation {operation_id} completed successfully")
|
|
1397
|
+
return result
|
|
1398
|
+
|
|
1399
|
+
except Exception as e:
|
|
1400
|
+
raise WriteOrchestrationError(f"Document with charts generation failed: {str(e)}")
|
|
1401
|
+
|
|
1402
|
+
def optimize_document_layout(
|
|
1403
|
+
self,
|
|
1404
|
+
document_path: str,
|
|
1405
|
+
optimization_goals: List[str],
|
|
1406
|
+
preserve_content: bool = True,
|
|
1407
|
+
layout_style: Optional[str] = None,
|
|
1408
|
+
) -> Dict[str, Any]:
|
|
1409
|
+
"""
|
|
1410
|
+
Optimize document layout using AI analysis
|
|
1411
|
+
|
|
1412
|
+
Args:
|
|
1413
|
+
document_path: Path to document to optimize
|
|
1414
|
+
optimization_goals: Layout optimization goals
|
|
1415
|
+
preserve_content: Preserve existing content
|
|
1416
|
+
layout_style: Target layout style
|
|
1417
|
+
|
|
1418
|
+
Returns:
|
|
1419
|
+
Dict containing layout optimization results
|
|
1420
|
+
"""
|
|
1421
|
+
try:
|
|
1422
|
+
start_time = datetime.now()
|
|
1423
|
+
operation_id = f"optimize_layout_{int(start_time.timestamp())}"
|
|
1424
|
+
|
|
1425
|
+
self.logger.info(f"Starting layout optimization {operation_id} for: {document_path}")
|
|
1426
|
+
|
|
1427
|
+
layout_tool = self.creation_tools.get("layout")
|
|
1428
|
+
if not layout_tool:
|
|
1429
|
+
raise WriteOrchestrationError("DocumentLayoutTool not available")
|
|
1430
|
+
|
|
1431
|
+
# Step 1: Analyze current document content
|
|
1432
|
+
content_analysis = self.analyze_document_content(source_path=document_path, analysis_type="structure")
|
|
1433
|
+
|
|
1434
|
+
# Step 2: Generate optimization plan
|
|
1435
|
+
optimization_plan = self._generate_layout_optimization_plan(
|
|
1436
|
+
document_path,
|
|
1437
|
+
content_analysis,
|
|
1438
|
+
optimization_goals,
|
|
1439
|
+
layout_style,
|
|
1440
|
+
)
|
|
1441
|
+
|
|
1442
|
+
# Step 3: Apply optimizations
|
|
1443
|
+
optimization_results = layout_tool.optimize_layout_for_content(
|
|
1444
|
+
document_path=document_path,
|
|
1445
|
+
content_analysis=content_analysis["analysis_result"],
|
|
1446
|
+
optimization_goals=optimization_goals,
|
|
1447
|
+
)
|
|
1448
|
+
|
|
1449
|
+
# Step 4: Validate optimization results
|
|
1450
|
+
if preserve_content:
|
|
1451
|
+
self._validate_content_preservation(document_path, content_analysis)
|
|
1452
|
+
|
|
1453
|
+
result = {
|
|
1454
|
+
"operation_id": operation_id,
|
|
1455
|
+
"document_path": document_path,
|
|
1456
|
+
"optimization_goals": optimization_goals,
|
|
1457
|
+
"layout_style": layout_style,
|
|
1458
|
+
"content_analysis": content_analysis,
|
|
1459
|
+
"optimization_plan": optimization_plan,
|
|
1460
|
+
"optimization_results": optimization_results,
|
|
1461
|
+
"preserve_content": preserve_content,
|
|
1462
|
+
"processing_metadata": {
|
|
1463
|
+
"start_time": start_time.isoformat(),
|
|
1464
|
+
"end_time": datetime.now().isoformat(),
|
|
1465
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
1466
|
+
},
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
self.logger.info(f"Layout optimization {operation_id} completed successfully")
|
|
1470
|
+
return result
|
|
1471
|
+
|
|
1472
|
+
except Exception as e:
|
|
1473
|
+
raise WriteOrchestrationError(f"Layout optimization failed: {str(e)}")
|
|
1474
|
+
|
|
1475
|
+
def batch_content_insertion(
|
|
1476
|
+
self,
|
|
1477
|
+
document_path: str,
|
|
1478
|
+
content_plan: List[Dict[str, Any]],
|
|
1479
|
+
insertion_strategy: str = "sequential",
|
|
1480
|
+
ai_optimization: bool = True,
|
|
1481
|
+
) -> Dict[str, Any]:
|
|
1482
|
+
"""
|
|
1483
|
+
Batch insertion of multiple content types with AI coordination
|
|
1484
|
+
|
|
1485
|
+
Args:
|
|
1486
|
+
document_path: Target document path
|
|
1487
|
+
content_plan: Content insertion plan
|
|
1488
|
+
insertion_strategy: Insertion strategy (sequential, parallel, optimized)
|
|
1489
|
+
ai_optimization: Use AI for content optimization
|
|
1490
|
+
|
|
1491
|
+
Returns:
|
|
1492
|
+
Dict containing batch insertion results
|
|
1493
|
+
"""
|
|
1494
|
+
try:
|
|
1495
|
+
start_time = datetime.now()
|
|
1496
|
+
operation_id = f"batch_insert_{int(start_time.timestamp())}"
|
|
1497
|
+
|
|
1498
|
+
self.logger.info(f"Starting batch content insertion {operation_id} for: {document_path}")
|
|
1499
|
+
|
|
1500
|
+
content_tool = self.creation_tools.get("content")
|
|
1501
|
+
if not content_tool:
|
|
1502
|
+
raise WriteOrchestrationError("ContentInsertionTool not available")
|
|
1503
|
+
|
|
1504
|
+
# Step 1: Optimize insertion order if AI optimization is enabled
|
|
1505
|
+
if ai_optimization:
|
|
1506
|
+
optimized_plan = self._optimize_content_insertion_plan(document_path, content_plan)
|
|
1507
|
+
else:
|
|
1508
|
+
optimized_plan = content_plan
|
|
1509
|
+
|
|
1510
|
+
# Step 2: Execute insertions based on strategy
|
|
1511
|
+
if insertion_strategy == "sequential":
|
|
1512
|
+
insertion_results = self._execute_sequential_insertions(document_path, optimized_plan, content_tool)
|
|
1513
|
+
elif insertion_strategy == "parallel":
|
|
1514
|
+
insertion_results = self._execute_parallel_insertions(document_path, optimized_plan, content_tool)
|
|
1515
|
+
else: # optimized
|
|
1516
|
+
insertion_results = self._execute_optimized_insertions(document_path, optimized_plan, content_tool)
|
|
1517
|
+
|
|
1518
|
+
# Step 3: Post-insertion optimization
|
|
1519
|
+
if ai_optimization:
|
|
1520
|
+
self._post_insertion_optimization(document_path, insertion_results)
|
|
1521
|
+
|
|
1522
|
+
result = {
|
|
1523
|
+
"operation_id": operation_id,
|
|
1524
|
+
"document_path": document_path,
|
|
1525
|
+
"content_plan": content_plan,
|
|
1526
|
+
"optimized_plan": optimized_plan,
|
|
1527
|
+
"insertion_strategy": insertion_strategy,
|
|
1528
|
+
"ai_optimization": ai_optimization,
|
|
1529
|
+
"insertion_results": insertion_results,
|
|
1530
|
+
"processing_metadata": {
|
|
1531
|
+
"start_time": start_time.isoformat(),
|
|
1532
|
+
"end_time": datetime.now().isoformat(),
|
|
1533
|
+
"duration": (datetime.now() - start_time).total_seconds(),
|
|
1534
|
+
},
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
self.logger.info(f"Batch content insertion {operation_id} completed successfully")
|
|
1538
|
+
return result
|
|
1539
|
+
|
|
1540
|
+
except Exception as e:
|
|
1541
|
+
raise WriteOrchestrationError(f"Batch content insertion failed: {str(e)}")
|
|
1542
|
+
|
|
1543
|
+
# Helper methods for new functionality
|
|
1544
|
+
def _generate_and_insert_content_items(self, document_path: str, content_items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
1545
|
+
"""Generate and insert content items with AI assistance"""
|
|
1546
|
+
results = []
|
|
1547
|
+
|
|
1548
|
+
for item in content_items:
|
|
1549
|
+
try:
|
|
1550
|
+
# Generate content based on type
|
|
1551
|
+
if item.get("type") == "ai_generated":
|
|
1552
|
+
generated_content = self._generate_content_with_ai(
|
|
1553
|
+
item.get("requirements", ""),
|
|
1554
|
+
ContentGenerationMode.GENERATE,
|
|
1555
|
+
"markdown",
|
|
1556
|
+
AIProvider(self.config.default_ai_provider),
|
|
1557
|
+
item.get("generation_params", {}),
|
|
1558
|
+
)
|
|
1559
|
+
|
|
1560
|
+
# Insert generated content
|
|
1561
|
+
if self.document_writer:
|
|
1562
|
+
write_result = self.document_writer.write_document(
|
|
1563
|
+
target_path=document_path,
|
|
1564
|
+
content=generated_content["generated_content"],
|
|
1565
|
+
format="markdown",
|
|
1566
|
+
mode="append",
|
|
1567
|
+
)
|
|
1568
|
+
|
|
1569
|
+
results.append(
|
|
1570
|
+
{
|
|
1571
|
+
"item": item,
|
|
1572
|
+
"generated_content": generated_content,
|
|
1573
|
+
"write_result": write_result,
|
|
1574
|
+
"success": True,
|
|
1575
|
+
}
|
|
1576
|
+
)
|
|
1577
|
+
|
|
1578
|
+
except Exception as e:
|
|
1579
|
+
results.append({"item": item, "error": str(e), "success": False})
|
|
1580
|
+
self.logger.warning(f"Failed to generate/insert content item: {e}")
|
|
1581
|
+
|
|
1582
|
+
return results
|
|
1583
|
+
|
|
1584
|
+
def _batch_insert_complex_content(
|
|
1585
|
+
self,
|
|
1586
|
+
document_path: str,
|
|
1587
|
+
insertions: List[Dict[str, Any]],
|
|
1588
|
+
content_tool,
|
|
1589
|
+
) -> List[Dict[str, Any]]:
|
|
1590
|
+
"""Batch insert complex content using ContentInsertionTool"""
|
|
1591
|
+
try:
|
|
1592
|
+
# Use the content tool's batch insertion capability
|
|
1593
|
+
return content_tool.batch_insert_content(document_path=document_path, content_items=insertions)
|
|
1594
|
+
except Exception as e:
|
|
1595
|
+
self.logger.warning(f"Batch insertion failed: {e}")
|
|
1596
|
+
return []
|
|
1597
|
+
|
|
1598
|
+
def _optimize_rich_document(self, document_path: str, optimization_goals: List[str]) -> Dict[str, Any]:
|
|
1599
|
+
"""Optimize rich document based on goals"""
|
|
1600
|
+
try:
|
|
1601
|
+
if "layout" in self.creation_tools:
|
|
1602
|
+
return self.creation_tools["layout"].optimize_layout_for_content(
|
|
1603
|
+
document_path=document_path,
|
|
1604
|
+
content_analysis={"content_length": 0}, # Simplified
|
|
1605
|
+
optimization_goals=optimization_goals,
|
|
1606
|
+
)
|
|
1607
|
+
except Exception as e:
|
|
1608
|
+
self.logger.warning(f"Document optimization failed: {e}")
|
|
1609
|
+
|
|
1610
|
+
return {"optimization_applied": False}
|
|
1611
|
+
|
|
1612
|
+
def _analyze_data_and_create_plan(
|
|
1613
|
+
self,
|
|
1614
|
+
data_sources: List[Dict[str, Any]],
|
|
1615
|
+
requirements: str,
|
|
1616
|
+
document_type: str,
|
|
1617
|
+
include_analysis: bool,
|
|
1618
|
+
) -> Dict[str, Any]:
|
|
1619
|
+
"""Analyze data sources and create content plan"""
|
|
1620
|
+
plan = {
|
|
1621
|
+
"document_type": document_type,
|
|
1622
|
+
"format": "markdown",
|
|
1623
|
+
"metadata": {
|
|
1624
|
+
"title": f"{document_type.title()} Report",
|
|
1625
|
+
"author": "AI Document Generator",
|
|
1626
|
+
"date": datetime.now().strftime("%Y-%m-%d"),
|
|
1627
|
+
},
|
|
1628
|
+
"sections": [
|
|
1629
|
+
{"title": "Executive Summary", "level": 2, "required": True},
|
|
1630
|
+
{"title": "Data Overview", "level": 2, "required": True},
|
|
1631
|
+
{"title": "Visualizations", "level": 2, "required": True},
|
|
1632
|
+
],
|
|
1633
|
+
"generate_toc": True,
|
|
1634
|
+
"insertions": [],
|
|
1635
|
+
}
|
|
1636
|
+
# Explicitly type plan to allow append operations
|
|
1637
|
+
plan_dict: Dict[str, Any] = plan
|
|
1638
|
+
|
|
1639
|
+
if include_analysis:
|
|
1640
|
+
plan_dict["sections"].append({"title": "Analysis", "level": 2, "required": True})
|
|
1641
|
+
plan_dict["sections"].append({"title": "Insights", "level": 2, "required": True})
|
|
1642
|
+
|
|
1643
|
+
# Add chart insertions for each data source
|
|
1644
|
+
for i, data_source in enumerate(data_sources):
|
|
1645
|
+
plan_dict["insertions"].append(
|
|
1646
|
+
{
|
|
1647
|
+
"content_type": "chart",
|
|
1648
|
+
"chart_data": data_source.get("data", {}),
|
|
1649
|
+
"chart_type": data_source.get("chart_type", "bar"),
|
|
1650
|
+
"position": {"marker": f"<!-- CHART_{i+1} -->"},
|
|
1651
|
+
"caption": f"Chart {i+1}: {data_source.get('title', 'Data Visualization')}",
|
|
1652
|
+
}
|
|
1653
|
+
)
|
|
1654
|
+
|
|
1655
|
+
return plan_dict
|
|
1656
|
+
|
|
1657
|
+
def _generate_charts_from_data(
|
|
1658
|
+
self,
|
|
1659
|
+
data_sources: List[Dict[str, Any]],
|
|
1660
|
+
preferences: Optional[Dict[str, Any]],
|
|
1661
|
+
) -> List[Dict[str, Any]]:
|
|
1662
|
+
"""Generate charts from data sources"""
|
|
1663
|
+
results: List[Dict[str, Any]] = []
|
|
1664
|
+
|
|
1665
|
+
if "content" not in self.creation_tools:
|
|
1666
|
+
return results
|
|
1667
|
+
|
|
1668
|
+
content_tool = self.creation_tools["content"]
|
|
1669
|
+
|
|
1670
|
+
for data_source in data_sources:
|
|
1671
|
+
try:
|
|
1672
|
+
chart_result = content_tool._generate_chart(
|
|
1673
|
+
chart_data=data_source.get("data", {}),
|
|
1674
|
+
chart_type=data_source.get("chart_type", "bar"),
|
|
1675
|
+
config=preferences,
|
|
1676
|
+
)
|
|
1677
|
+
results.append(
|
|
1678
|
+
{
|
|
1679
|
+
"data_source": data_source,
|
|
1680
|
+
"chart_result": chart_result,
|
|
1681
|
+
"success": True,
|
|
1682
|
+
}
|
|
1683
|
+
)
|
|
1684
|
+
except Exception as e:
|
|
1685
|
+
results.append(
|
|
1686
|
+
{
|
|
1687
|
+
"data_source": data_source,
|
|
1688
|
+
"error": str(e),
|
|
1689
|
+
"success": False,
|
|
1690
|
+
}
|
|
1691
|
+
)
|
|
1692
|
+
|
|
1693
|
+
return results
|
|
1694
|
+
|
|
1695
|
+
def _select_template_for_data_document(self, document_type: str) -> str:
|
|
1696
|
+
"""Select appropriate template for data document"""
|
|
1697
|
+
type_template_map = {
|
|
1698
|
+
"report": "business_report",
|
|
1699
|
+
"analysis": "technical_doc",
|
|
1700
|
+
"presentation": "presentation",
|
|
1701
|
+
"academic": "academic_paper",
|
|
1702
|
+
}
|
|
1703
|
+
return type_template_map.get(document_type, "business_report")
|
|
1704
|
+
|
|
1705
|
+
def _insert_generated_charts(
|
|
1706
|
+
self,
|
|
1707
|
+
document_path: str,
|
|
1708
|
+
chart_results: List[Dict[str, Any]],
|
|
1709
|
+
content_plan: Dict[str, Any],
|
|
1710
|
+
) -> List[Dict[str, Any]]:
|
|
1711
|
+
"""Insert generated charts into document"""
|
|
1712
|
+
results: List[Dict[str, Any]] = []
|
|
1713
|
+
|
|
1714
|
+
if "content" not in self.creation_tools:
|
|
1715
|
+
return results
|
|
1716
|
+
|
|
1717
|
+
content_tool = self.creation_tools["content"]
|
|
1718
|
+
|
|
1719
|
+
for i, chart_result in enumerate(chart_results):
|
|
1720
|
+
if chart_result.get("success"):
|
|
1721
|
+
try:
|
|
1722
|
+
insertion_result = content_tool.insert_chart(
|
|
1723
|
+
document_path=document_path,
|
|
1724
|
+
chart_data=chart_result["data_source"].get("data", {}),
|
|
1725
|
+
chart_type=chart_result["data_source"].get("chart_type", "bar"),
|
|
1726
|
+
position={"marker": f"<!-- CHART_{i+1} -->"},
|
|
1727
|
+
caption=f"Chart {i+1}: {chart_result['data_source'].get('title', 'Data Visualization')}",
|
|
1728
|
+
)
|
|
1729
|
+
results.append(insertion_result)
|
|
1730
|
+
except Exception as e:
|
|
1731
|
+
self.logger.warning(f"Failed to insert chart {i+1}: {e}")
|
|
1732
|
+
|
|
1733
|
+
return results
|
|
1734
|
+
|
|
1735
|
+
def _generate_ai_analysis_content(
|
|
1736
|
+
self,
|
|
1737
|
+
document_path: str,
|
|
1738
|
+
data_sources: List[Dict[str, Any]],
|
|
1739
|
+
chart_results: List[Dict[str, Any]],
|
|
1740
|
+
) -> Dict[str, Any]:
|
|
1741
|
+
"""Generate AI-driven analysis content"""
|
|
1742
|
+
try:
|
|
1743
|
+
# Generate analysis based on data
|
|
1744
|
+
analysis_prompt = f"""
|
|
1745
|
+
Analyze the following data sources and provide insights:
|
|
1746
|
+
Data Sources: {len(data_sources)} datasets
|
|
1747
|
+
Charts Generated: {len([r for r in chart_results if r.get('success')])}
|
|
1748
|
+
|
|
1749
|
+
Please provide:
|
|
1750
|
+
1. Key findings from the data
|
|
1751
|
+
2. Trends and patterns observed
|
|
1752
|
+
3. Recommendations based on the analysis
|
|
1753
|
+
"""
|
|
1754
|
+
|
|
1755
|
+
analysis_result = self._generate_content_with_ai(
|
|
1756
|
+
analysis_prompt,
|
|
1757
|
+
ContentGenerationMode.GENERATE,
|
|
1758
|
+
"markdown",
|
|
1759
|
+
AIProvider(self.config.default_ai_provider),
|
|
1760
|
+
{},
|
|
1761
|
+
)
|
|
1762
|
+
|
|
1763
|
+
# Insert analysis content into document
|
|
1764
|
+
if self.document_writer:
|
|
1765
|
+
write_result = self.document_writer.write_document(
|
|
1766
|
+
target_path=document_path,
|
|
1767
|
+
content=analysis_result["generated_content"],
|
|
1768
|
+
format="markdown",
|
|
1769
|
+
mode="append",
|
|
1770
|
+
)
|
|
1771
|
+
|
|
1772
|
+
return {
|
|
1773
|
+
"analysis_generated": True,
|
|
1774
|
+
"analysis_content": analysis_result,
|
|
1775
|
+
"write_result": write_result,
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
except Exception as e:
|
|
1779
|
+
self.logger.warning(f"Failed to generate AI analysis: {e}")
|
|
1780
|
+
|
|
1781
|
+
return {"analysis_generated": False}
|
|
1782
|
+
|
|
1783
|
+
def _generate_layout_optimization_plan(
|
|
1784
|
+
self,
|
|
1785
|
+
document_path: str,
|
|
1786
|
+
content_analysis: Dict[str, Any],
|
|
1787
|
+
optimization_goals: List[str],
|
|
1788
|
+
layout_style: Optional[str],
|
|
1789
|
+
) -> Dict[str, Any]:
|
|
1790
|
+
"""Generate layout optimization plan"""
|
|
1791
|
+
return {
|
|
1792
|
+
"document_path": document_path,
|
|
1793
|
+
"optimization_goals": optimization_goals,
|
|
1794
|
+
"layout_style": layout_style,
|
|
1795
|
+
"content_analysis": content_analysis,
|
|
1796
|
+
"recommended_actions": [
|
|
1797
|
+
"Optimize spacing",
|
|
1798
|
+
"Improve typography",
|
|
1799
|
+
"Enhance readability",
|
|
1800
|
+
],
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
def _validate_content_preservation(self, document_path: str, original_analysis: Dict[str, Any]) -> Dict[str, Any]:
|
|
1804
|
+
"""Validate that content was preserved during optimization"""
|
|
1805
|
+
try:
|
|
1806
|
+
# Re-analyze document after optimization
|
|
1807
|
+
new_analysis = self.analyze_document_content(source_path=document_path, analysis_type="structure")
|
|
1808
|
+
|
|
1809
|
+
# Compare analyses
|
|
1810
|
+
original_length = original_analysis.get("analysis_result", {}).get("content_length", 0)
|
|
1811
|
+
new_length = new_analysis.get("analysis_result", {}).get("content_length", 0)
|
|
1812
|
+
|
|
1813
|
+
content_preserved = abs(original_length - new_length) / max(original_length, 1) < 0.1
|
|
1814
|
+
|
|
1815
|
+
return {
|
|
1816
|
+
"content_preserved": content_preserved,
|
|
1817
|
+
"original_length": original_length,
|
|
1818
|
+
"new_length": new_length,
|
|
1819
|
+
"difference_ratio": abs(original_length - new_length) / max(original_length, 1),
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
except Exception as e:
|
|
1823
|
+
return {"validation_error": str(e)}
|
|
1824
|
+
|
|
1825
|
+
def _optimize_content_insertion_plan(self, document_path: str, content_plan: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
1826
|
+
"""Optimize content insertion plan using AI"""
|
|
1827
|
+
# For now, return original plan
|
|
1828
|
+
# In a full implementation, this would use AI to optimize the order
|
|
1829
|
+
return content_plan
|
|
1830
|
+
|
|
1831
|
+
def _execute_sequential_insertions(self, document_path: str, plan: List[Dict[str, Any]], content_tool) -> Dict[str, Any]:
|
|
1832
|
+
"""Execute content insertions sequentially"""
|
|
1833
|
+
return content_tool.batch_insert_content(document_path=document_path, content_items=plan)
|
|
1834
|
+
|
|
1835
|
+
def _execute_parallel_insertions(self, document_path: str, plan: List[Dict[str, Any]], content_tool) -> Dict[str, Any]:
|
|
1836
|
+
"""Execute content insertions in parallel (simplified to sequential for now)"""
|
|
1837
|
+
return self._execute_sequential_insertions(document_path, plan, content_tool)
|
|
1838
|
+
|
|
1839
|
+
def _execute_optimized_insertions(self, document_path: str, plan: List[Dict[str, Any]], content_tool) -> Dict[str, Any]:
|
|
1840
|
+
"""Execute optimized content insertions"""
|
|
1841
|
+
return self._execute_sequential_insertions(document_path, plan, content_tool)
|
|
1842
|
+
|
|
1843
|
+
def _post_insertion_optimization(self, document_path: str, insertion_results: Dict[str, Any]) -> Dict[str, Any]:
|
|
1844
|
+
"""Perform post-insertion optimization"""
|
|
1845
|
+
return {
|
|
1846
|
+
"optimization_performed": True,
|
|
1847
|
+
"document_path": document_path,
|
|
1848
|
+
"insertion_results": insertion_results,
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
def create_content_template(
|
|
1852
|
+
self,
|
|
1853
|
+
template_name: str,
|
|
1854
|
+
template_content: str,
|
|
1855
|
+
template_variables: List[str],
|
|
1856
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
1857
|
+
) -> Dict[str, Any]:
|
|
1858
|
+
"""
|
|
1859
|
+
Create reusable content template
|
|
1860
|
+
|
|
1861
|
+
Args:
|
|
1862
|
+
template_name: Name of the template
|
|
1863
|
+
template_content: Template content with variables
|
|
1864
|
+
template_variables: List of template variables
|
|
1865
|
+
metadata: Additional template metadata
|
|
1866
|
+
|
|
1867
|
+
Returns:
|
|
1868
|
+
Dict containing template information
|
|
1869
|
+
"""
|
|
1870
|
+
template_info = {
|
|
1871
|
+
"name": template_name,
|
|
1872
|
+
"content": template_content,
|
|
1873
|
+
"variables": template_variables,
|
|
1874
|
+
"metadata": metadata or {},
|
|
1875
|
+
"created_at": datetime.now().isoformat(),
|
|
1876
|
+
"version": "1.0",
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
# Save template
|
|
1880
|
+
temp_dir = tempfile.gettempdir()
|
|
1881
|
+
template_file = os.path.join(temp_dir, f"template_{template_name}.json")
|
|
1882
|
+
with open(template_file, "w") as f:
|
|
1883
|
+
import json
|
|
1884
|
+
|
|
1885
|
+
json.dump(template_info, f, indent=2)
|
|
1886
|
+
|
|
1887
|
+
return template_info
|
|
1888
|
+
|
|
1889
|
+
def use_content_template(
|
|
1890
|
+
self,
|
|
1891
|
+
template_name: str,
|
|
1892
|
+
template_data: Dict[str, Any],
|
|
1893
|
+
target_path: str,
|
|
1894
|
+
ai_enhancement: bool = True,
|
|
1895
|
+
) -> Dict[str, Any]:
|
|
1896
|
+
"""
|
|
1897
|
+
Use content template to generate document
|
|
1898
|
+
|
|
1899
|
+
Args:
|
|
1900
|
+
template_name: Name of the template to use
|
|
1901
|
+
template_data: Data to fill template variables
|
|
1902
|
+
target_path: Target document path
|
|
1903
|
+
ai_enhancement: Whether to enhance with AI
|
|
1904
|
+
|
|
1905
|
+
Returns:
|
|
1906
|
+
Dict containing template usage results
|
|
1907
|
+
"""
|
|
1908
|
+
try:
|
|
1909
|
+
# Load template
|
|
1910
|
+
template_file = os.path.join(self.config.temp_dir, f"template_{template_name}.json")
|
|
1911
|
+
with open(template_file, "r") as f:
|
|
1912
|
+
import json
|
|
1913
|
+
|
|
1914
|
+
template_info = json.load(f)
|
|
1915
|
+
|
|
1916
|
+
# Fill template
|
|
1917
|
+
filled_content = self._fill_template(template_info["content"], template_data)
|
|
1918
|
+
|
|
1919
|
+
# Enhance with AI if requested
|
|
1920
|
+
if ai_enhancement:
|
|
1921
|
+
ai_result = self._generate_content_with_ai(
|
|
1922
|
+
f"Template: {template_name}",
|
|
1923
|
+
ContentGenerationMode.TEMPLATE_FILL,
|
|
1924
|
+
"txt",
|
|
1925
|
+
AIProvider(self.config.default_ai_provider),
|
|
1926
|
+
{
|
|
1927
|
+
"template": template_info["content"],
|
|
1928
|
+
"data": template_data,
|
|
1929
|
+
},
|
|
1930
|
+
)
|
|
1931
|
+
filled_content = ai_result["generated_content"]
|
|
1932
|
+
|
|
1933
|
+
# Write document
|
|
1934
|
+
write_result = self.document_writer.write_document(
|
|
1935
|
+
target_path=target_path,
|
|
1936
|
+
content=filled_content,
|
|
1937
|
+
format="txt",
|
|
1938
|
+
mode="create",
|
|
1939
|
+
)
|
|
1940
|
+
|
|
1941
|
+
return {
|
|
1942
|
+
"template_name": template_name,
|
|
1943
|
+
"template_data": template_data,
|
|
1944
|
+
"target_path": target_path,
|
|
1945
|
+
"ai_enhancement": ai_enhancement,
|
|
1946
|
+
"filled_content": filled_content,
|
|
1947
|
+
"write_result": write_result,
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
except Exception as e:
|
|
1951
|
+
raise WriteOrchestrationError(f"Template usage failed: {str(e)}")
|
|
1952
|
+
|
|
1953
|
+
def _generate_content_with_ai(
|
|
1954
|
+
self,
|
|
1955
|
+
requirements: str,
|
|
1956
|
+
generation_mode: ContentGenerationMode,
|
|
1957
|
+
document_format: str,
|
|
1958
|
+
ai_provider: AIProvider,
|
|
1959
|
+
generation_params: Dict[str, Any],
|
|
1960
|
+
) -> Dict[str, Any]:
|
|
1961
|
+
"""Generate content using AI based on requirements"""
|
|
1962
|
+
|
|
1963
|
+
try:
|
|
1964
|
+
# Get content generation template
|
|
1965
|
+
template = self.content_templates.get(generation_mode)
|
|
1966
|
+
if not template:
|
|
1967
|
+
raise ContentGenerationError(f"No template found for generation mode: {generation_mode}")
|
|
1968
|
+
|
|
1969
|
+
# Prepare AI prompt
|
|
1970
|
+
prompt_params = {
|
|
1971
|
+
"content_type": document_format,
|
|
1972
|
+
"requirements": requirements,
|
|
1973
|
+
"audience": generation_params.get("audience", "general"),
|
|
1974
|
+
**generation_params,
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
prompt = self._format_content_prompt(template, prompt_params)
|
|
1978
|
+
|
|
1979
|
+
# Call AI provider
|
|
1980
|
+
ai_response = self._call_ai_provider(prompt, ai_provider, generation_params)
|
|
1981
|
+
|
|
1982
|
+
return {
|
|
1983
|
+
"generation_mode": generation_mode,
|
|
1984
|
+
"requirements": requirements,
|
|
1985
|
+
"prompt_used": prompt,
|
|
1986
|
+
"generated_content": ai_response,
|
|
1987
|
+
"ai_provider": ai_provider,
|
|
1988
|
+
"generation_params": generation_params,
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
except Exception as e:
|
|
1992
|
+
raise ContentGenerationError(f"AI content generation failed: {str(e)}")
|
|
1993
|
+
|
|
1994
|
+
def _enhance_content_with_ai(
|
|
1995
|
+
self,
|
|
1996
|
+
existing_content: Dict[str, Any],
|
|
1997
|
+
enhancement_goals: str,
|
|
1998
|
+
ai_provider: AIProvider,
|
|
1999
|
+
) -> Dict[str, Any]:
|
|
2000
|
+
"""Enhance existing content using AI"""
|
|
2001
|
+
|
|
2002
|
+
try:
|
|
2003
|
+
template = self.content_templates[ContentGenerationMode.ENHANCE]
|
|
2004
|
+
|
|
2005
|
+
prompt_params = {
|
|
2006
|
+
"existing_content": existing_content["content"],
|
|
2007
|
+
"enhancement_goals": enhancement_goals,
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
prompt = self._format_content_prompt(template, prompt_params)
|
|
2011
|
+
ai_response = self._call_ai_provider(prompt, ai_provider, {})
|
|
2012
|
+
|
|
2013
|
+
return {
|
|
2014
|
+
"original_content": existing_content["content"],
|
|
2015
|
+
"enhancement_goals": enhancement_goals,
|
|
2016
|
+
"enhanced_content": ai_response,
|
|
2017
|
+
"ai_provider": ai_provider,
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
except Exception as e:
|
|
2021
|
+
raise ContentGenerationError(f"AI content enhancement failed: {str(e)}")
|
|
2022
|
+
|
|
2023
|
+
def _process_generated_content(
|
|
2024
|
+
self,
|
|
2025
|
+
content: str,
|
|
2026
|
+
document_format: str,
|
|
2027
|
+
generation_mode: ContentGenerationMode,
|
|
2028
|
+
) -> str:
|
|
2029
|
+
"""Process generated content for specific format"""
|
|
2030
|
+
|
|
2031
|
+
# Format-specific processing
|
|
2032
|
+
if document_format.lower() == "markdown":
|
|
2033
|
+
# Ensure proper markdown formatting
|
|
2034
|
+
content = self._ensure_markdown_formatting(content)
|
|
2035
|
+
elif document_format.lower() == "html":
|
|
2036
|
+
# Ensure proper HTML structure
|
|
2037
|
+
content = self._ensure_html_structure(content)
|
|
2038
|
+
elif document_format.lower() == "json":
|
|
2039
|
+
# Validate and format JSON
|
|
2040
|
+
content = self._ensure_json_format(content)
|
|
2041
|
+
|
|
2042
|
+
return content
|
|
2043
|
+
|
|
2044
|
+
def _execute_write_strategy(
|
|
2045
|
+
self,
|
|
2046
|
+
target_path: str,
|
|
2047
|
+
content: str,
|
|
2048
|
+
document_format: str,
|
|
2049
|
+
write_strategy: WriteStrategy,
|
|
2050
|
+
write_params: Dict[str, Any],
|
|
2051
|
+
) -> Dict[str, Any]:
|
|
2052
|
+
"""Execute write strategy"""
|
|
2053
|
+
|
|
2054
|
+
if not self.document_writer:
|
|
2055
|
+
raise WriteOrchestrationError("DocumentWriterTool not available")
|
|
2056
|
+
|
|
2057
|
+
if write_strategy == WriteStrategy.IMMEDIATE:
|
|
2058
|
+
# Write immediately
|
|
2059
|
+
return self.document_writer.write_document(
|
|
2060
|
+
target_path=target_path,
|
|
2061
|
+
content=content,
|
|
2062
|
+
format=document_format,
|
|
2063
|
+
mode="create",
|
|
2064
|
+
**write_params,
|
|
2065
|
+
)
|
|
2066
|
+
|
|
2067
|
+
elif write_strategy == WriteStrategy.DRAFT:
|
|
2068
|
+
# Save as draft
|
|
2069
|
+
draft_path = f"{target_path}.draft"
|
|
2070
|
+
return self.document_writer.write_document(
|
|
2071
|
+
target_path=draft_path,
|
|
2072
|
+
content=content,
|
|
2073
|
+
format=document_format,
|
|
2074
|
+
mode="create",
|
|
2075
|
+
**write_params,
|
|
2076
|
+
)
|
|
2077
|
+
|
|
2078
|
+
elif write_strategy == WriteStrategy.REVIEW:
|
|
2079
|
+
# Save for review
|
|
2080
|
+
review_path = f"{target_path}.review"
|
|
2081
|
+
return self.document_writer.write_document(
|
|
2082
|
+
target_path=review_path,
|
|
2083
|
+
content=content,
|
|
2084
|
+
format=document_format,
|
|
2085
|
+
mode="create",
|
|
2086
|
+
**write_params,
|
|
2087
|
+
)
|
|
2088
|
+
|
|
2089
|
+
elif write_strategy == WriteStrategy.STAGED:
|
|
2090
|
+
# Staged write (implement custom logic)
|
|
2091
|
+
return self._execute_staged_write(target_path, content, document_format, write_params)
|
|
2092
|
+
|
|
2093
|
+
else:
|
|
2094
|
+
raise ValueError(f"Unknown write strategy: {write_strategy}")
|
|
2095
|
+
|
|
2096
|
+
def _execute_staged_write(
|
|
2097
|
+
self,
|
|
2098
|
+
target_path: str,
|
|
2099
|
+
content: str,
|
|
2100
|
+
document_format: str,
|
|
2101
|
+
write_params: Dict[str, Any],
|
|
2102
|
+
) -> Dict[str, Any]:
|
|
2103
|
+
"""Execute staged write operation"""
|
|
2104
|
+
|
|
2105
|
+
# Split content into stages (simplified implementation)
|
|
2106
|
+
content_parts = content.split("\n\n") # Split by paragraphs
|
|
2107
|
+
stage_results = []
|
|
2108
|
+
|
|
2109
|
+
for i, part in enumerate(content_parts):
|
|
2110
|
+
stage_path = f"{target_path}.stage_{i+1}"
|
|
2111
|
+
stage_result = self.document_writer.write_document(
|
|
2112
|
+
target_path=stage_path,
|
|
2113
|
+
content=part,
|
|
2114
|
+
format=document_format,
|
|
2115
|
+
mode="create",
|
|
2116
|
+
**write_params,
|
|
2117
|
+
)
|
|
2118
|
+
stage_results.append(stage_result)
|
|
2119
|
+
|
|
2120
|
+
return {
|
|
2121
|
+
"strategy": "staged",
|
|
2122
|
+
"total_stages": len(content_parts),
|
|
2123
|
+
"stage_results": stage_results,
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
def _read_existing_document(self, source_path: str) -> Dict[str, Any]:
|
|
2127
|
+
"""Read existing document for enhancement"""
|
|
2128
|
+
|
|
2129
|
+
try:
|
|
2130
|
+
# Try to use document parser for reading
|
|
2131
|
+
try:
|
|
2132
|
+
from aiecs.tools.docs.document_parser_tool import (
|
|
2133
|
+
DocumentParserTool,
|
|
2134
|
+
)
|
|
2135
|
+
|
|
2136
|
+
parser = DocumentParserTool()
|
|
2137
|
+
parse_result = parser.parse_document(source_path)
|
|
2138
|
+
|
|
2139
|
+
return {
|
|
2140
|
+
"content": parse_result["content"],
|
|
2141
|
+
"format": parse_result["document_type"],
|
|
2142
|
+
"metadata": parse_result.get("metadata", {}),
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
except ImportError:
|
|
2146
|
+
# Fallback to simple file reading
|
|
2147
|
+
with open(source_path, "r", encoding="utf-8") as f:
|
|
2148
|
+
content = f.read()
|
|
2149
|
+
|
|
2150
|
+
file_ext = os.path.splitext(source_path)[1].lower()
|
|
2151
|
+
return {
|
|
2152
|
+
"content": content,
|
|
2153
|
+
"format": file_ext.lstrip(".") or "txt",
|
|
2154
|
+
"metadata": {},
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
except Exception as e:
|
|
2158
|
+
raise WriteOrchestrationError(f"Failed to read existing document: {str(e)}")
|
|
2159
|
+
|
|
2160
|
+
def _call_ai_provider(self, prompt: str, ai_provider: AIProvider, params: Dict[str, Any]) -> str:
|
|
2161
|
+
"""Call AI provider with prompt"""
|
|
2162
|
+
|
|
2163
|
+
try:
|
|
2164
|
+
if self.aiecs_client:
|
|
2165
|
+
# Use AIECS client for AI operations
|
|
2166
|
+
from aiecs.domain.task.task_context import TaskContext
|
|
2167
|
+
|
|
2168
|
+
task_context = TaskContext(
|
|
2169
|
+
data={
|
|
2170
|
+
"user_id": "test_user",
|
|
2171
|
+
"chat_id": f"content_gen_{datetime.now().timestamp()}",
|
|
2172
|
+
"metadata": params,
|
|
2173
|
+
"aiPreference": params.get("ai_provider", "default"),
|
|
2174
|
+
}
|
|
2175
|
+
)
|
|
2176
|
+
|
|
2177
|
+
result = self.aiecs_client.process_task(task_context)
|
|
2178
|
+
return result.get("response", "")
|
|
2179
|
+
else:
|
|
2180
|
+
# Fallback to mock response
|
|
2181
|
+
return self._generate_mock_content(prompt, params)
|
|
2182
|
+
|
|
2183
|
+
except Exception as e:
|
|
2184
|
+
raise ContentGenerationError(f"AI provider call failed: {str(e)}")
|
|
2185
|
+
|
|
2186
|
+
def _generate_mock_content(self, prompt: str, params: Dict[str, Any]) -> str:
|
|
2187
|
+
"""Generate mock content for testing"""
|
|
2188
|
+
self.logger.warning("Using mock content generation - implement actual AI provider integration")
|
|
2189
|
+
|
|
2190
|
+
# Generate simple mock content based on prompt
|
|
2191
|
+
if "requirements" in params:
|
|
2192
|
+
return f"Generated content based on: {params['requirements']}\n\nThis is mock content for testing purposes."
|
|
2193
|
+
else:
|
|
2194
|
+
return f"Mock generated content for prompt: {prompt[:100]}..."
|
|
2195
|
+
|
|
2196
|
+
def _format_content_prompt(self, template: Dict[str, str], params: Dict[str, Any]) -> str:
|
|
2197
|
+
"""Format content generation prompt using template"""
|
|
2198
|
+
|
|
2199
|
+
user_prompt = template["user_prompt_template"]
|
|
2200
|
+
|
|
2201
|
+
# Replace placeholders
|
|
2202
|
+
for key, value in params.items():
|
|
2203
|
+
placeholder = f"{{{key}}}"
|
|
2204
|
+
if placeholder in user_prompt:
|
|
2205
|
+
user_prompt = user_prompt.replace(placeholder, str(value))
|
|
2206
|
+
|
|
2207
|
+
return user_prompt
|
|
2208
|
+
|
|
2209
|
+
def _fill_template(self, template_content: str, template_data: Dict[str, Any]) -> str:
|
|
2210
|
+
"""Fill template with provided data"""
|
|
2211
|
+
|
|
2212
|
+
filled_content = template_content
|
|
2213
|
+
for key, value in template_data.items():
|
|
2214
|
+
placeholder = f"{{{key}}}"
|
|
2215
|
+
filled_content = filled_content.replace(placeholder, str(value))
|
|
2216
|
+
|
|
2217
|
+
return filled_content
|
|
2218
|
+
|
|
2219
|
+
# Content formatting helpers
|
|
2220
|
+
def _ensure_markdown_formatting(self, content: str) -> str:
|
|
2221
|
+
"""Ensure proper markdown formatting"""
|
|
2222
|
+
# Add basic markdown formatting if missing
|
|
2223
|
+
lines = content.split("\n")
|
|
2224
|
+
formatted_lines = []
|
|
2225
|
+
|
|
2226
|
+
for line in lines:
|
|
2227
|
+
line = line.strip()
|
|
2228
|
+
if line and not line.startswith("#") and not line.startswith("-") and not line.startswith("*"):
|
|
2229
|
+
# Add paragraph spacing
|
|
2230
|
+
formatted_lines.append(line + "\n")
|
|
2231
|
+
else:
|
|
2232
|
+
formatted_lines.append(line)
|
|
2233
|
+
|
|
2234
|
+
return "\n".join(formatted_lines)
|
|
2235
|
+
|
|
2236
|
+
def _ensure_html_structure(self, content: str) -> str:
|
|
2237
|
+
"""Ensure proper HTML structure"""
|
|
2238
|
+
if not content.strip().startswith("<html"):
|
|
2239
|
+
content = f"<html><body>{content}</body></html>"
|
|
2240
|
+
return content
|
|
2241
|
+
|
|
2242
|
+
def _ensure_json_format(self, content: str) -> str:
|
|
2243
|
+
"""Ensure proper JSON format"""
|
|
2244
|
+
try:
|
|
2245
|
+
import json
|
|
2246
|
+
|
|
2247
|
+
# Try to parse and reformat
|
|
2248
|
+
parsed = json.loads(content)
|
|
2249
|
+
return json.dumps(parsed, indent=2, ensure_ascii=False)
|
|
2250
|
+
except json.JSONDecodeError:
|
|
2251
|
+
# Wrap in basic JSON structure
|
|
2252
|
+
return json.dumps({"content": content}, indent=2, ensure_ascii=False)
|
|
2253
|
+
|
|
2254
|
+
# Batch processing methods
|
|
2255
|
+
async def _batch_write_parallel(self, write_requests: List[Dict[str, Any]], max_concurrent: int) -> List[Dict[str, Any]]:
|
|
2256
|
+
"""Process write requests in parallel"""
|
|
2257
|
+
|
|
2258
|
+
semaphore = asyncio.Semaphore(max_concurrent)
|
|
2259
|
+
|
|
2260
|
+
async def process_single_request(
|
|
2261
|
+
request: Dict[str, Any],
|
|
2262
|
+
) -> Dict[str, Any]:
|
|
2263
|
+
async with semaphore:
|
|
2264
|
+
try:
|
|
2265
|
+
result = await self.ai_write_document_async(**request)
|
|
2266
|
+
return {
|
|
2267
|
+
"status": "success",
|
|
2268
|
+
"request": request,
|
|
2269
|
+
"result": result,
|
|
2270
|
+
}
|
|
2271
|
+
except Exception as e:
|
|
2272
|
+
return {
|
|
2273
|
+
"status": "error",
|
|
2274
|
+
"request": request,
|
|
2275
|
+
"error": str(e),
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
tasks = [process_single_request(req) for req in write_requests]
|
|
2279
|
+
return await asyncio.gather(*tasks)
|
|
2280
|
+
|
|
2281
|
+
def _batch_write_sequential(self, write_requests: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
2282
|
+
"""Process write requests sequentially"""
|
|
2283
|
+
|
|
2284
|
+
results = []
|
|
2285
|
+
for request in write_requests:
|
|
2286
|
+
try:
|
|
2287
|
+
result = self.ai_write_document(**request)
|
|
2288
|
+
results.append({"status": "success", "request": request, "result": result})
|
|
2289
|
+
except Exception as e:
|
|
2290
|
+
results.append({"status": "error", "request": request, "error": str(e)})
|
|
2291
|
+
|
|
2292
|
+
return results
|
|
2293
|
+
|
|
2294
|
+
async def _batch_write_smart(self, write_requests: List[Dict[str, Any]], max_concurrent: int) -> List[Dict[str, Any]]:
|
|
2295
|
+
"""Smart batch processing with dependency awareness"""
|
|
2296
|
+
|
|
2297
|
+
# Analyze dependencies (simplified implementation)
|
|
2298
|
+
independent_requests = []
|
|
2299
|
+
dependent_requests = []
|
|
2300
|
+
|
|
2301
|
+
for request in write_requests:
|
|
2302
|
+
# Check if request depends on others (simplified logic)
|
|
2303
|
+
if any(req.get("target_path") == request.get("source_path") for req in write_requests):
|
|
2304
|
+
dependent_requests.append(request)
|
|
2305
|
+
else:
|
|
2306
|
+
independent_requests.append(request)
|
|
2307
|
+
|
|
2308
|
+
# Process independent requests in parallel
|
|
2309
|
+
results = []
|
|
2310
|
+
if independent_requests:
|
|
2311
|
+
parallel_results = await self._batch_write_parallel(independent_requests, max_concurrent)
|
|
2312
|
+
results.extend(parallel_results)
|
|
2313
|
+
|
|
2314
|
+
# Process dependent requests sequentially
|
|
2315
|
+
if dependent_requests:
|
|
2316
|
+
sequential_results = self._batch_write_sequential(dependent_requests)
|
|
2317
|
+
results.extend(sequential_results)
|
|
2318
|
+
|
|
2319
|
+
return results
|
|
2320
|
+
|
|
2321
|
+
def _post_process_ai_write(
|
|
2322
|
+
self,
|
|
2323
|
+
operation_id: str,
|
|
2324
|
+
target_path: str,
|
|
2325
|
+
ai_result: Dict[str, Any],
|
|
2326
|
+
write_result: Dict[str, Any],
|
|
2327
|
+
write_strategy: WriteStrategy,
|
|
2328
|
+
) -> Dict[str, Any]:
|
|
2329
|
+
"""Post-process AI write operation"""
|
|
2330
|
+
|
|
2331
|
+
post_process_info = {
|
|
2332
|
+
"operation_id": operation_id,
|
|
2333
|
+
"target_path": target_path,
|
|
2334
|
+
"write_strategy": write_strategy,
|
|
2335
|
+
"content_length": len(ai_result.get("generated_content", "")),
|
|
2336
|
+
"write_success": write_result.get("write_result", {}).get("path") is not None,
|
|
2337
|
+
"timestamp": datetime.now().isoformat(),
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
# Log operation
|
|
2341
|
+
try:
|
|
2342
|
+
log_file = os.path.join(self.config.temp_dir, "ai_write_operations.log")
|
|
2343
|
+
with open(log_file, "a") as f:
|
|
2344
|
+
import json
|
|
2345
|
+
|
|
2346
|
+
f.write(json.dumps(post_process_info) + "\n")
|
|
2347
|
+
except Exception as e:
|
|
2348
|
+
self.logger.warning(f"Operation logging failed: {e}")
|
|
2349
|
+
|
|
2350
|
+
return post_process_info
|