aiecs 1.5.1__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.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -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 +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -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 +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Report Tool - A multi-format report generation tool supporting HTML, PDF, Excel, PowerPoint, Markdown, Word, and image-based reports.
|
|
3
|
+
|
|
4
|
+
This module provides a comprehensive report generation tool that can be used to create various types of reports
|
|
5
|
+
in different formats. It supports template-based rendering, data visualization, and batch processing.
|
|
6
|
+
|
|
7
|
+
Author: Your Organization
|
|
8
|
+
Version: 1.0.0
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import bleach
|
|
13
|
+
from typing import Dict, Any, List, Optional, Union, Tuple, Set
|
|
14
|
+
from jinja2 import FileSystemLoader, sandbox
|
|
15
|
+
|
|
16
|
+
# from weasyprint import HTML # TODO: Re-enable when deployment issues
|
|
17
|
+
# are resolved
|
|
18
|
+
import pandas as pd
|
|
19
|
+
from pptx import Presentation
|
|
20
|
+
from pptx.util import Pt
|
|
21
|
+
from docx import Document
|
|
22
|
+
from docx.shared import Pt as DocxPt
|
|
23
|
+
import matplotlib.pyplot as plt
|
|
24
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
25
|
+
import tempfile
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
from aiecs.tools.base_tool import BaseTool
|
|
29
|
+
from aiecs.tools import register_tool
|
|
30
|
+
from aiecs.tools.temp_file_manager import TempFileManager
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Exceptions
|
|
34
|
+
class ReportToolError(Exception):
|
|
35
|
+
"""Base exception for ReportTool errors."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FileOperationError(ReportToolError):
|
|
39
|
+
"""Raised when file operations fail."""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Helper function for HTML sanitization
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def sanitize_html(
|
|
46
|
+
html_content: str,
|
|
47
|
+
allowed_tags: Set[str],
|
|
48
|
+
allowed_attributes: Dict[str, List[str]],
|
|
49
|
+
) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Sanitize HTML content to prevent XSS attacks.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
html_content (str): The HTML content to sanitize.
|
|
55
|
+
allowed_tags (Set[str]): Set of allowed HTML tags.
|
|
56
|
+
allowed_attributes (Dict[str, List[str]]): Dictionary of allowed attributes for each tag.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
str: Sanitized HTML content.
|
|
60
|
+
"""
|
|
61
|
+
return bleach.clean(
|
|
62
|
+
html_content,
|
|
63
|
+
tags=allowed_tags,
|
|
64
|
+
attributes=allowed_attributes,
|
|
65
|
+
strip=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Type alias for dataset entries
|
|
70
|
+
DatasetType = Dict[str, Union[pd.DataFrame, List[Dict[str, Any]]]]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@register_tool("report")
|
|
74
|
+
class ReportTool(BaseTool):
|
|
75
|
+
"""
|
|
76
|
+
Multi-format report generation tool supporting HTML, Excel, PowerPoint, Markdown, Word, and image-based reports.
|
|
77
|
+
|
|
78
|
+
NOTE: PDF generation is temporarily disabled due to weasyprint deployment complexity.
|
|
79
|
+
|
|
80
|
+
Operations:
|
|
81
|
+
- generate_html: Render HTML report using Jinja2.
|
|
82
|
+
- generate_pdf: Currently disabled - will be re-enabled in future release.
|
|
83
|
+
- generate_excel: Create Excel workbook with multiple sheets and styling.
|
|
84
|
+
- generate_pptx: Create PowerPoint presentation with customizable slides.
|
|
85
|
+
- generate_markdown: Render Markdown report using Jinja2.
|
|
86
|
+
- generate_word: Create Word document with customizable styles.
|
|
87
|
+
- generate_image: Generate charts (bar, line, pie) using Matplotlib.
|
|
88
|
+
- batch_generate: Generate multiple reports in parallel.
|
|
89
|
+
|
|
90
|
+
Inherits from BaseTool.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
# Configuration schema
|
|
94
|
+
class Config(BaseModel):
|
|
95
|
+
"""Configuration for the report tool"""
|
|
96
|
+
|
|
97
|
+
model_config = ConfigDict(env_prefix="REPORT_TOOL_")
|
|
98
|
+
|
|
99
|
+
templates_dir: str = Field(
|
|
100
|
+
default=os.getcwd(), description="Directory for Jinja2 templates"
|
|
101
|
+
)
|
|
102
|
+
default_output_dir: str = Field(
|
|
103
|
+
default=os.path.join(tempfile.gettempdir(), "reports"),
|
|
104
|
+
description="Default directory for output files",
|
|
105
|
+
)
|
|
106
|
+
allowed_extensions: List[str] = Field(
|
|
107
|
+
default=[
|
|
108
|
+
".html",
|
|
109
|
+
".pdf",
|
|
110
|
+
".xlsx",
|
|
111
|
+
".pptx",
|
|
112
|
+
".docx",
|
|
113
|
+
".md",
|
|
114
|
+
".png",
|
|
115
|
+
],
|
|
116
|
+
description="Allowed file extensions for outputs",
|
|
117
|
+
)
|
|
118
|
+
pdf_page_size: str = Field(default="A4", description="Default PDF page size")
|
|
119
|
+
default_font: str = Field(default="Arial", description="Default font for documents")
|
|
120
|
+
default_font_size: int = Field(default=12, description="Default font size in points")
|
|
121
|
+
allowed_html_tags: Set[str] = Field(
|
|
122
|
+
default={
|
|
123
|
+
"h1",
|
|
124
|
+
"h2",
|
|
125
|
+
"h3",
|
|
126
|
+
"h4",
|
|
127
|
+
"h5",
|
|
128
|
+
"h6",
|
|
129
|
+
"p",
|
|
130
|
+
"br",
|
|
131
|
+
"a",
|
|
132
|
+
"ul",
|
|
133
|
+
"ol",
|
|
134
|
+
"li",
|
|
135
|
+
"strong",
|
|
136
|
+
"em",
|
|
137
|
+
"b",
|
|
138
|
+
"i",
|
|
139
|
+
"table",
|
|
140
|
+
"tr",
|
|
141
|
+
"td",
|
|
142
|
+
"th",
|
|
143
|
+
"thead",
|
|
144
|
+
"tbody",
|
|
145
|
+
"span",
|
|
146
|
+
"div",
|
|
147
|
+
"img",
|
|
148
|
+
"hr",
|
|
149
|
+
"code",
|
|
150
|
+
"pre",
|
|
151
|
+
},
|
|
152
|
+
description="Allowed HTML tags for sanitization",
|
|
153
|
+
)
|
|
154
|
+
allowed_html_attributes: Dict[str, List[str]] = Field(
|
|
155
|
+
default={
|
|
156
|
+
"a": ["href", "title", "target"],
|
|
157
|
+
"img": ["src", "alt", "title", "width", "height"],
|
|
158
|
+
"td": ["colspan", "rowspan", "align"],
|
|
159
|
+
"th": ["colspan", "rowspan", "align"],
|
|
160
|
+
"*": ["class", "id", "style"],
|
|
161
|
+
},
|
|
162
|
+
description="Allowed HTML attributes for sanitization",
|
|
163
|
+
)
|
|
164
|
+
temp_files_max_age: int = Field(
|
|
165
|
+
default=3600,
|
|
166
|
+
description="Maximum age of temporary files in seconds",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
|
170
|
+
"""
|
|
171
|
+
Initialize ReportTool with settings and resources.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
config (Dict, optional): Configuration overrides for ReportTool.
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
ValueError: If config contains invalid settings.
|
|
178
|
+
"""
|
|
179
|
+
super().__init__(config)
|
|
180
|
+
|
|
181
|
+
# Parse configuration
|
|
182
|
+
self.config = self.Config(**(config or {}))
|
|
183
|
+
|
|
184
|
+
self.logger = logging.getLogger(__name__)
|
|
185
|
+
if not self.logger.handlers:
|
|
186
|
+
handler = logging.StreamHandler()
|
|
187
|
+
handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
|
188
|
+
self.logger.addHandler(handler)
|
|
189
|
+
self.logger.setLevel(logging.INFO)
|
|
190
|
+
self._jinja_env = sandbox.SandboxedEnvironment(
|
|
191
|
+
loader=FileSystemLoader(self.config.templates_dir), autoescape=True
|
|
192
|
+
)
|
|
193
|
+
self._temp_manager = TempFileManager(
|
|
194
|
+
self.config.default_output_dir, self.config.temp_files_max_age
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def generate_html(
|
|
198
|
+
self,
|
|
199
|
+
template_path: Optional[str],
|
|
200
|
+
template_str: Optional[str],
|
|
201
|
+
context: Dict[str, Any],
|
|
202
|
+
output_path: str,
|
|
203
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
204
|
+
) -> str:
|
|
205
|
+
"""
|
|
206
|
+
Render an HTML report using a Jinja2 template.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
template_path (Optional[str]): Path to the template file.
|
|
210
|
+
template_str (Optional[str]): Template string content.
|
|
211
|
+
context (Dict[str, Any]): Template context data.
|
|
212
|
+
output_path (str): Path to save the HTML file.
|
|
213
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
str: Path to the generated HTML file.
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
FileOperationError: If template file is not found or writing fails.
|
|
220
|
+
"""
|
|
221
|
+
try:
|
|
222
|
+
if template_path:
|
|
223
|
+
os.path.join(self.config.templates_dir, template_path)
|
|
224
|
+
tmpl = self._jinja_env.get_template(template_path)
|
|
225
|
+
else:
|
|
226
|
+
tmpl = self._jinja_env.from_string(template_str)
|
|
227
|
+
html = tmpl.render(**context)
|
|
228
|
+
csrf_meta = "<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; script-src 'self'; object-src 'none'\">\n"
|
|
229
|
+
csrf_meta += '<meta name="referrer" content="no-referrer">\n'
|
|
230
|
+
if "<head>" in html:
|
|
231
|
+
html = html.replace("<head>", "<head>\n" + csrf_meta)
|
|
232
|
+
else:
|
|
233
|
+
html = csrf_meta + html
|
|
234
|
+
html = sanitize_html(
|
|
235
|
+
html,
|
|
236
|
+
self.config.allowed_html_tags,
|
|
237
|
+
self.config.allowed_html_attributes,
|
|
238
|
+
)
|
|
239
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
240
|
+
f.write(html)
|
|
241
|
+
self._temp_manager.register_file(output_path)
|
|
242
|
+
return output_path
|
|
243
|
+
except Exception as e:
|
|
244
|
+
raise FileOperationError(f"Failed to generate HTML: {str(e)}")
|
|
245
|
+
|
|
246
|
+
def generate_pdf(
|
|
247
|
+
self,
|
|
248
|
+
html: Optional[str],
|
|
249
|
+
html_schema: Optional[Dict],
|
|
250
|
+
output_path: str,
|
|
251
|
+
page_size: Optional[str] = None,
|
|
252
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
253
|
+
) -> str:
|
|
254
|
+
"""
|
|
255
|
+
Generate a PDF report from HTML content or a Jinja2 template.
|
|
256
|
+
|
|
257
|
+
NOTE: PDF generation is currently disabled due to weasyprint deployment complexity.
|
|
258
|
+
This feature will be re-enabled in a future release.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
html (Optional[str]): HTML content.
|
|
262
|
+
html_schema (Optional[Dict]): Dict for HTML generation.
|
|
263
|
+
output_path (str): Path to save the PDF file.
|
|
264
|
+
page_size (Optional[str]): PDF page size.
|
|
265
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
str: Path to the generated PDF file.
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
FileOperationError: PDF generation is currently disabled.
|
|
272
|
+
"""
|
|
273
|
+
raise FileOperationError(
|
|
274
|
+
"PDF generation is currently disabled due to weasyprint deployment complexity. "
|
|
275
|
+
"Please use generate_html() to create HTML reports instead. "
|
|
276
|
+
"PDF functionality will be restored in a future release."
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# TODO: Re-enable when weasyprint deployment issues are resolved
|
|
280
|
+
# try:
|
|
281
|
+
# if not html and html_schema:
|
|
282
|
+
# html_path = self.generate_html(**html_schema)
|
|
283
|
+
# with open(html_path, 'r', encoding='utf-8') as f:
|
|
284
|
+
# html = f.read()
|
|
285
|
+
# HTML(string=html).write_pdf(
|
|
286
|
+
# output_path,
|
|
287
|
+
# stylesheets=[{'page_size': page_size or self.settings.pdf_page_size}]
|
|
288
|
+
# )
|
|
289
|
+
# self._temp_manager.register_file(output_path)
|
|
290
|
+
# return output_path
|
|
291
|
+
# except Exception as e:
|
|
292
|
+
# raise FileOperationError(f"Failed to generate PDF: {str(e)}")
|
|
293
|
+
|
|
294
|
+
def generate_excel(
|
|
295
|
+
self,
|
|
296
|
+
sheets: Dict[str, Union[pd.DataFrame, List[Dict[str, Any]]]],
|
|
297
|
+
output_path: str,
|
|
298
|
+
styles: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
299
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
300
|
+
) -> str:
|
|
301
|
+
"""
|
|
302
|
+
Generate an Excel workbook with multiple sheets and optional styling.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
sheets (Dict[str, Union[pd.DataFrame, List[Dict[str, Any]]]]): Sheet data.
|
|
306
|
+
output_path (str): Path to save the Excel file.
|
|
307
|
+
styles (Optional[Dict[str, Dict[str, Any]]]): Cell styling.
|
|
308
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
str: Path to the generated Excel file.
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
FileOperationError: If Excel generation fails.
|
|
315
|
+
"""
|
|
316
|
+
try:
|
|
317
|
+
writer = pd.ExcelWriter(output_path, engine="xlsxwriter")
|
|
318
|
+
workbook = writer.book
|
|
319
|
+
for name, data in sheets.items():
|
|
320
|
+
df = data if isinstance(data, pd.DataFrame) else pd.DataFrame(data)
|
|
321
|
+
df.to_excel(writer, sheet_name=name[:31], index=False)
|
|
322
|
+
if styles and name in styles:
|
|
323
|
+
worksheet = writer.sheets[name[:31]]
|
|
324
|
+
for cell, style in styles[name].items():
|
|
325
|
+
format_dict = {}
|
|
326
|
+
if style.get("bold"):
|
|
327
|
+
format_dict["bold"] = True
|
|
328
|
+
if style.get("font_size"):
|
|
329
|
+
format_dict["font_size"] = style["font_size"]
|
|
330
|
+
if style.get("bg_color"):
|
|
331
|
+
format_dict["bg_color"] = style["bg_color"]
|
|
332
|
+
worksheet.write(
|
|
333
|
+
cell,
|
|
334
|
+
df.loc[int(cell[1:]) - 1, cell[0]],
|
|
335
|
+
workbook.add_format(format_dict),
|
|
336
|
+
)
|
|
337
|
+
writer.close()
|
|
338
|
+
self._temp_manager.register_file(output_path)
|
|
339
|
+
return output_path
|
|
340
|
+
except Exception as e:
|
|
341
|
+
raise FileOperationError(f"Failed to generate Excel: {str(e)}")
|
|
342
|
+
|
|
343
|
+
def generate_pptx(
|
|
344
|
+
self,
|
|
345
|
+
slides: List[Dict],
|
|
346
|
+
output_path: str,
|
|
347
|
+
default_font: Optional[str] = None,
|
|
348
|
+
default_font_size: Optional[int] = None,
|
|
349
|
+
default_font_color: Optional[Tuple[int, int, int]] = None,
|
|
350
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
351
|
+
) -> str:
|
|
352
|
+
"""
|
|
353
|
+
Generate a PowerPoint presentation with customizable slides.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
slides (List[Dict]): List of slide data.
|
|
357
|
+
output_path (str): Path to save the PPTX file.
|
|
358
|
+
default_font (Optional[str]): Default font for slides.
|
|
359
|
+
default_font_size (Optional[int]): Default font size.
|
|
360
|
+
default_font_color (Optional[Tuple[int, int, int]]): Default font color.
|
|
361
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
str: Path to the generated PPTX file.
|
|
365
|
+
|
|
366
|
+
Raises:
|
|
367
|
+
FileOperationError: If PPTX generation fails.
|
|
368
|
+
"""
|
|
369
|
+
try:
|
|
370
|
+
prs = Presentation()
|
|
371
|
+
for slide in slides:
|
|
372
|
+
s = prs.slides.add_slide(prs.slide_layouts[1])
|
|
373
|
+
title_shape = s.shapes.title
|
|
374
|
+
title_shape.text = slide["title"]
|
|
375
|
+
font = slide.get("font") or default_font or self.config.default_font
|
|
376
|
+
font_size = (
|
|
377
|
+
slide.get("font_size") or default_font_size or self.config.default_font_size
|
|
378
|
+
)
|
|
379
|
+
slide.get("font_color") or default_font_color or (0, 0, 0)
|
|
380
|
+
title_shape.text_frame.paragraphs[0].font.name = font
|
|
381
|
+
title_shape.text_frame.paragraphs[0].font.size = Pt(font_size)
|
|
382
|
+
# Set font color safely - skip color setting for now to avoid library issues
|
|
383
|
+
# Font color setting in python-pptx can be problematic,
|
|
384
|
+
# focusing on core functionality
|
|
385
|
+
body = s.shapes.placeholders[1].text_frame
|
|
386
|
+
for bullet in slide["bullets"]:
|
|
387
|
+
p = body.add_paragraph()
|
|
388
|
+
p.text = bullet
|
|
389
|
+
p.level = 0
|
|
390
|
+
p.font.name = font
|
|
391
|
+
p.font.size = Pt(font_size)
|
|
392
|
+
# Skip font color setting for bullet points to avoid
|
|
393
|
+
# library issues
|
|
394
|
+
prs.save(output_path)
|
|
395
|
+
self._temp_manager.register_file(output_path)
|
|
396
|
+
return output_path
|
|
397
|
+
except Exception as e:
|
|
398
|
+
raise FileOperationError(f"Failed to generate PPTX: {str(e)}")
|
|
399
|
+
|
|
400
|
+
def generate_markdown(
|
|
401
|
+
self,
|
|
402
|
+
template_path: Optional[str],
|
|
403
|
+
template_str: Optional[str],
|
|
404
|
+
context: Dict[str, Any],
|
|
405
|
+
output_path: str,
|
|
406
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
407
|
+
) -> str:
|
|
408
|
+
"""
|
|
409
|
+
Render a Markdown report using a Jinja2 template.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
template_path (Optional[str]): Path to the template file.
|
|
413
|
+
template_str (Optional[str]): Template string content.
|
|
414
|
+
context (Dict[str, Any]): Template context data.
|
|
415
|
+
output_path (str): Path to save the Markdown file.
|
|
416
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
str: Path to the generated Markdown file.
|
|
420
|
+
|
|
421
|
+
Raises:
|
|
422
|
+
FileOperationError: If rendering or writing fails.
|
|
423
|
+
"""
|
|
424
|
+
try:
|
|
425
|
+
if template_path:
|
|
426
|
+
tmpl = self._jinja_env.get_template(template_path)
|
|
427
|
+
else:
|
|
428
|
+
tmpl = self._jinja_env.from_string(template_str)
|
|
429
|
+
markdown_content = tmpl.render(**context)
|
|
430
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
431
|
+
f.write(markdown_content)
|
|
432
|
+
self._temp_manager.register_file(output_path)
|
|
433
|
+
return output_path
|
|
434
|
+
except Exception as e:
|
|
435
|
+
raise FileOperationError(f"Failed to generate Markdown: {str(e)}")
|
|
436
|
+
|
|
437
|
+
def generate_word(
|
|
438
|
+
self,
|
|
439
|
+
template_path: Optional[str],
|
|
440
|
+
template_str: Optional[str],
|
|
441
|
+
context: Dict[str, Any],
|
|
442
|
+
output_path: str,
|
|
443
|
+
font: Optional[str] = None,
|
|
444
|
+
font_size: Optional[int] = None,
|
|
445
|
+
font_color: Optional[Tuple[int, int, int]] = None,
|
|
446
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
447
|
+
) -> str:
|
|
448
|
+
"""
|
|
449
|
+
Generate a Word document from a Jinja2 template with customizable styles.
|
|
450
|
+
|
|
451
|
+
Args:
|
|
452
|
+
template_path (Optional[str]): Path to the template file.
|
|
453
|
+
template_str (Optional[str]): Template string content.
|
|
454
|
+
context (Dict[str, Any]): Template context data.
|
|
455
|
+
output_path (str): Path to save the DOCX file.
|
|
456
|
+
font (Optional[str]): Font for the document.
|
|
457
|
+
font_size (Optional[int]): Font size.
|
|
458
|
+
font_color (Optional[Tuple[int, int, int]]): Font color.
|
|
459
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
str: Path to the generated DOCX file.
|
|
463
|
+
|
|
464
|
+
Raises:
|
|
465
|
+
FileOperationError: If Word generation fails.
|
|
466
|
+
"""
|
|
467
|
+
try:
|
|
468
|
+
if template_path:
|
|
469
|
+
tmpl = self._jinja_env.get_template(template_path)
|
|
470
|
+
else:
|
|
471
|
+
tmpl = self._jinja_env.from_string(template_str)
|
|
472
|
+
content = tmpl.render(**context)
|
|
473
|
+
doc = Document()
|
|
474
|
+
font = font or self.config.default_font
|
|
475
|
+
font_size = font_size or self.config.default_font_size
|
|
476
|
+
font_color = font_color or (0, 0, 0)
|
|
477
|
+
for line in content.splitlines():
|
|
478
|
+
p = doc.add_paragraph()
|
|
479
|
+
run = p.add_run(line)
|
|
480
|
+
run.font.name = font
|
|
481
|
+
run.font.size = DocxPt(font_size)
|
|
482
|
+
# Skip font color setting for Word documents to avoid library
|
|
483
|
+
# issues
|
|
484
|
+
doc.save(output_path)
|
|
485
|
+
self._temp_manager.register_file(output_path)
|
|
486
|
+
return output_path
|
|
487
|
+
except Exception as e:
|
|
488
|
+
raise FileOperationError(f"Failed to generate Word: {str(e)}")
|
|
489
|
+
|
|
490
|
+
def generate_image(
|
|
491
|
+
self,
|
|
492
|
+
chart_type: str,
|
|
493
|
+
data: Union[pd.DataFrame, List[Dict[str, Any]]],
|
|
494
|
+
output_path: str,
|
|
495
|
+
x_col: Optional[str] = None,
|
|
496
|
+
y_col: Optional[str] = None,
|
|
497
|
+
labels: Optional[List[str]] = None,
|
|
498
|
+
title: Optional[str] = None,
|
|
499
|
+
width: int = 8,
|
|
500
|
+
height: int = 6,
|
|
501
|
+
template_variables: Optional[Dict[str, str]] = None,
|
|
502
|
+
) -> str:
|
|
503
|
+
"""
|
|
504
|
+
Generate a chart (bar, line, pie) using Matplotlib.
|
|
505
|
+
|
|
506
|
+
Args:
|
|
507
|
+
chart_type (str): Type of chart ('bar', 'line', 'pie').
|
|
508
|
+
data (Union[pd.DataFrame, List[Dict[str, Any]]]): Chart data.
|
|
509
|
+
output_path (str): Path to save the image file.
|
|
510
|
+
x_col (Optional[str]): X-axis column name.
|
|
511
|
+
y_col (Optional[str]): Y-axis column name.
|
|
512
|
+
labels (Optional[List[str]]): Labels for pie chart.
|
|
513
|
+
title (Optional[str]): Chart title.
|
|
514
|
+
width (int): Chart width.
|
|
515
|
+
height (int): Chart height.
|
|
516
|
+
template_variables (Optional[Dict[str, str]]): Variables for dynamic output path.
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
str: Path to the generated image file.
|
|
520
|
+
|
|
521
|
+
Raises:
|
|
522
|
+
FileOperationError: If chart generation fails.
|
|
523
|
+
"""
|
|
524
|
+
try:
|
|
525
|
+
df = data if isinstance(data, pd.DataFrame) else pd.DataFrame(data)
|
|
526
|
+
plt.figure(figsize=(width, height))
|
|
527
|
+
if chart_type == "bar":
|
|
528
|
+
df.plot.bar(x=x_col, y=y_col, title=title)
|
|
529
|
+
elif chart_type == "line":
|
|
530
|
+
df.plot.line(x=x_col, y=y_col, title=title)
|
|
531
|
+
elif chart_type == "pie":
|
|
532
|
+
plt.pie(
|
|
533
|
+
df[y_col],
|
|
534
|
+
labels=df[x_col] if x_col else labels,
|
|
535
|
+
autopct="%1.1f%%",
|
|
536
|
+
)
|
|
537
|
+
plt.title(title)
|
|
538
|
+
plt.savefig(output_path)
|
|
539
|
+
plt.close()
|
|
540
|
+
self._temp_manager.register_file(output_path)
|
|
541
|
+
return output_path
|
|
542
|
+
except Exception as e:
|
|
543
|
+
raise FileOperationError(f"Failed to generate image: {str(e)}")
|
|
544
|
+
|
|
545
|
+
def batch_generate(
|
|
546
|
+
self,
|
|
547
|
+
operation: str,
|
|
548
|
+
contexts: List[Dict[str, Any]],
|
|
549
|
+
output_paths: List[str],
|
|
550
|
+
datasets: Optional[List[DatasetType]] = None,
|
|
551
|
+
slides: Optional[List[List[Dict]]] = None,
|
|
552
|
+
) -> List[str]:
|
|
553
|
+
"""
|
|
554
|
+
Generate multiple reports in parallel for different contexts or datasets.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
operation (str): Operation to perform.
|
|
558
|
+
contexts (List[Dict[str, Any]]): Contexts for HTML, Markdown, Word, PDF.
|
|
559
|
+
output_paths (List[str]): Paths for generated files.
|
|
560
|
+
datasets (Optional[List[DatasetType]]): Datasets for Excel, Image.
|
|
561
|
+
slides (Optional[List[List[Dict]]]): Slides for PPTX.
|
|
562
|
+
|
|
563
|
+
Returns:
|
|
564
|
+
List[str]: List of generated file paths.
|
|
565
|
+
|
|
566
|
+
Raises:
|
|
567
|
+
FileOperationError: If batch generation fails.
|
|
568
|
+
"""
|
|
569
|
+
try:
|
|
570
|
+
tasks = []
|
|
571
|
+
input_data = contexts or datasets or slides
|
|
572
|
+
for i, output_path in enumerate(output_paths):
|
|
573
|
+
op_params = {"output_path": output_path}
|
|
574
|
+
if operation in (
|
|
575
|
+
"generate_html",
|
|
576
|
+
"generate_markdown",
|
|
577
|
+
"generate_word",
|
|
578
|
+
):
|
|
579
|
+
op_params.update(input_data[i])
|
|
580
|
+
op_params["template_path"] = input_data[i].get("template_path")
|
|
581
|
+
op_params["template_str"] = input_data[i].get("template_str")
|
|
582
|
+
if operation == "generate_word":
|
|
583
|
+
op_params["font"] = input_data[i].get("font")
|
|
584
|
+
op_params["font_size"] = input_data[i].get("font_size")
|
|
585
|
+
op_params["font_color"] = input_data[i].get("font_color")
|
|
586
|
+
elif operation == "generate_excel":
|
|
587
|
+
op_params["sheets"] = input_data[i]
|
|
588
|
+
op_params["styles"] = input_data[i].get("styles")
|
|
589
|
+
elif operation == "generate_pptx":
|
|
590
|
+
op_params["slides"] = input_data[i]
|
|
591
|
+
op_params["default_font"] = (
|
|
592
|
+
input_data[i][0].get("font") if input_data[i] else None
|
|
593
|
+
)
|
|
594
|
+
op_params["default_font_size"] = (
|
|
595
|
+
input_data[i][0].get("font_size") if input_data[i] else None
|
|
596
|
+
)
|
|
597
|
+
op_params["default_font_color"] = (
|
|
598
|
+
input_data[i][0].get("font_color") if input_data[i] else None
|
|
599
|
+
)
|
|
600
|
+
elif operation == "generate_image":
|
|
601
|
+
op_params.update(input_data[i])
|
|
602
|
+
elif operation == "generate_pdf":
|
|
603
|
+
op_params["html"] = input_data[i].get("html")
|
|
604
|
+
op_params["html_schema"] = (
|
|
605
|
+
input_data[i] if input_data[i].get("context") else None
|
|
606
|
+
)
|
|
607
|
+
op_params["page_size"] = input_data[i].get("page_size")
|
|
608
|
+
tasks.append({"op": operation, "kwargs": op_params})
|
|
609
|
+
# Execute tasks synchronously for batch generation
|
|
610
|
+
results = []
|
|
611
|
+
for task in tasks:
|
|
612
|
+
op_name = task["op"]
|
|
613
|
+
kwargs = task["kwargs"]
|
|
614
|
+
|
|
615
|
+
if op_name == "generate_html":
|
|
616
|
+
result = self.generate_html(**kwargs)
|
|
617
|
+
elif op_name == "generate_excel":
|
|
618
|
+
result = self.generate_excel(**kwargs)
|
|
619
|
+
elif op_name == "generate_pptx":
|
|
620
|
+
result = self.generate_pptx(**kwargs)
|
|
621
|
+
elif op_name == "generate_markdown":
|
|
622
|
+
result = self.generate_markdown(**kwargs)
|
|
623
|
+
elif op_name == "generate_word":
|
|
624
|
+
result = self.generate_word(**kwargs)
|
|
625
|
+
elif op_name == "generate_image":
|
|
626
|
+
result = self.generate_image(**kwargs)
|
|
627
|
+
elif op_name == "generate_pdf":
|
|
628
|
+
result = self.generate_pdf(**kwargs)
|
|
629
|
+
else:
|
|
630
|
+
raise FileOperationError(f"Unsupported operation: {op_name}")
|
|
631
|
+
|
|
632
|
+
results.append(result)
|
|
633
|
+
return results
|
|
634
|
+
except Exception as e:
|
|
635
|
+
raise FileOperationError(f"Failed to generate batch reports: {str(e)}")
|