aiecs 1.0.8__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (45) hide show
  1. aiecs/__init__.py +1 -1
  2. aiecs/aiecs_client.py +159 -1
  3. aiecs/config/config.py +4 -0
  4. aiecs/domain/context/__init__.py +24 -0
  5. aiecs/main.py +20 -2
  6. aiecs/scripts/dependance_check/__init__.py +18 -0
  7. aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +50 -8
  8. aiecs/scripts/dependance_patch/__init__.py +8 -0
  9. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +12 -0
  10. aiecs/scripts/tools_develop/README.md +340 -0
  11. aiecs/scripts/tools_develop/__init__.py +16 -0
  12. aiecs/scripts/tools_develop/check_type_annotations.py +263 -0
  13. aiecs/scripts/tools_develop/validate_tool_schemas.py +346 -0
  14. aiecs/tools/__init__.py +33 -14
  15. aiecs/tools/docs/__init__.py +103 -0
  16. aiecs/tools/docs/ai_document_orchestrator.py +543 -0
  17. aiecs/tools/docs/ai_document_writer_orchestrator.py +2199 -0
  18. aiecs/tools/docs/content_insertion_tool.py +1214 -0
  19. aiecs/tools/docs/document_creator_tool.py +1161 -0
  20. aiecs/tools/docs/document_layout_tool.py +1090 -0
  21. aiecs/tools/docs/document_parser_tool.py +904 -0
  22. aiecs/tools/docs/document_writer_tool.py +1583 -0
  23. aiecs/tools/langchain_adapter.py +102 -51
  24. aiecs/tools/schema_generator.py +265 -0
  25. aiecs/tools/task_tools/image_tool.py +1 -1
  26. aiecs/tools/task_tools/office_tool.py +9 -0
  27. aiecs/tools/task_tools/scraper_tool.py +1 -1
  28. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/METADATA +1 -1
  29. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/RECORD +44 -28
  30. aiecs-1.1.0.dist-info/entry_points.txt +9 -0
  31. aiecs-1.0.8.dist-info/entry_points.txt +0 -7
  32. /aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +0 -0
  33. /aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +0 -0
  34. /aiecs/scripts/{dependency_checker.py → dependance_check/dependency_checker.py} +0 -0
  35. /aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +0 -0
  36. /aiecs/scripts/{quick_dependency_check.py → dependance_check/quick_dependency_check.py} +0 -0
  37. /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
  38. /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
  39. /aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +0 -0
  40. /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
  41. /aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +0 -0
  42. /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
  43. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/WHEEL +0 -0
  44. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/licenses/LICENSE +0 -0
  45. {aiecs-1.0.8.dist-info → aiecs-1.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1161 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Document Creator Tool
4
+
5
+ This tool is responsible for creating new documents from templates,
6
+ initializing document structure, and managing document metadata.
7
+
8
+ Key Features:
9
+ 1. Template-based document creation
10
+ 2. Document structure initialization
11
+ 3. Metadata management (title, author, date, etc.)
12
+ 4. Style configuration and presets
13
+ 5. Multi-format support (MD, HTML, DOCX, PDF, etc.)
14
+ """
15
+
16
+ import os
17
+ import json
18
+ import uuid
19
+ import tempfile
20
+ import logging
21
+ from datetime import datetime
22
+ from typing import Dict, Any, List, Optional, Union
23
+ from enum import Enum
24
+ from pathlib import Path
25
+
26
+ from pydantic import BaseModel, Field, ValidationError
27
+ from pydantic_settings import BaseSettings
28
+
29
+ from aiecs.tools.base_tool import BaseTool
30
+ from aiecs.tools import register_tool
31
+
32
+
33
+ class DocumentType(str, Enum):
34
+ """Supported document types"""
35
+ REPORT = "report"
36
+ ARTICLE = "article"
37
+ PRESENTATION = "presentation"
38
+ MANUAL = "manual"
39
+ LETTER = "letter"
40
+ PROPOSAL = "proposal"
41
+ ACADEMIC = "academic"
42
+ TECHNICAL = "technical"
43
+ CREATIVE = "creative"
44
+ CUSTOM = "custom"
45
+
46
+
47
+ class DocumentFormat(str, Enum):
48
+ """Supported output formats"""
49
+ MARKDOWN = "markdown"
50
+ HTML = "html"
51
+ DOCX = "docx"
52
+ PDF = "pdf"
53
+ LATEX = "latex"
54
+ PLAIN_TEXT = "txt"
55
+ JSON = "json"
56
+ XML = "xml"
57
+
58
+
59
+ class TemplateType(str, Enum):
60
+ """Document template types"""
61
+ BLANK = "blank"
62
+ BUSINESS_REPORT = "business_report"
63
+ TECHNICAL_DOC = "technical_doc"
64
+ ACADEMIC_PAPER = "academic_paper"
65
+ PROJECT_PROPOSAL = "project_proposal"
66
+ USER_MANUAL = "user_manual"
67
+ PRESENTATION = "presentation"
68
+ NEWSLETTER = "newsletter"
69
+ INVOICE = "invoice"
70
+ CUSTOM = "custom"
71
+
72
+
73
+ class StylePreset(str, Enum):
74
+ """Style presets for documents"""
75
+ DEFAULT = "default"
76
+ CORPORATE = "corporate"
77
+ ACADEMIC = "academic"
78
+ MODERN = "modern"
79
+ CLASSIC = "classic"
80
+ MINIMAL = "minimal"
81
+ COLORFUL = "colorful"
82
+ PROFESSIONAL = "professional"
83
+
84
+
85
+ class DocumentCreatorSettings(BaseSettings):
86
+ """Configuration for DocumentCreatorTool"""
87
+ templates_dir: str = os.path.join(tempfile.gettempdir(), 'document_templates')
88
+ output_dir: str = os.path.join(tempfile.gettempdir(), 'created_documents')
89
+ default_format: DocumentFormat = DocumentFormat.MARKDOWN
90
+ default_style: StylePreset = StylePreset.DEFAULT
91
+ auto_backup: bool = True
92
+ include_metadata: bool = True
93
+ generate_toc: bool = True
94
+
95
+ class Config:
96
+ env_prefix = "DOC_CREATOR_"
97
+
98
+
99
+ class DocumentCreatorError(Exception):
100
+ """Base exception for Document Creator errors"""
101
+ pass
102
+
103
+
104
+ class TemplateError(DocumentCreatorError):
105
+ """Raised when template operations fail"""
106
+ pass
107
+
108
+
109
+ class DocumentCreationError(DocumentCreatorError):
110
+ """Raised when document creation fails"""
111
+ pass
112
+
113
+
114
+ @register_tool("document_creator")
115
+ class DocumentCreatorTool(BaseTool):
116
+ """
117
+ Document Creator Tool for creating new documents from templates
118
+
119
+ This tool provides:
120
+ 1. Template management and selection
121
+ 2. Document structure initialization
122
+ 3. Metadata configuration
123
+ 4. Style and format setup
124
+ 5. Multi-format document creation
125
+
126
+ Integrates with:
127
+ - DocumentWriterTool for content writing
128
+ - DocumentLayoutTool for layout configuration
129
+ - ContentInsertionTool for complex content
130
+ """
131
+
132
+ def __init__(self, config: Optional[Dict] = None):
133
+ """Initialize Document Creator Tool with settings"""
134
+ super().__init__(config)
135
+ self.settings = DocumentCreatorSettings()
136
+ if config:
137
+ try:
138
+ self.settings = self.settings.model_validate({**self.settings.model_dump(), **config})
139
+ except ValidationError as e:
140
+ raise ValueError(f"Invalid settings: {e}")
141
+
142
+ self.logger = logging.getLogger(__name__)
143
+
144
+ # Initialize directories
145
+ self._init_directories()
146
+
147
+ # Initialize templates
148
+ self._init_templates()
149
+
150
+ # Initialize document tracking
151
+ self._documents_created = []
152
+
153
+ def _init_directories(self):
154
+ """Initialize required directories"""
155
+ os.makedirs(self.settings.templates_dir, exist_ok=True)
156
+ os.makedirs(self.settings.output_dir, exist_ok=True)
157
+
158
+ def _init_templates(self):
159
+ """Initialize built-in templates"""
160
+ self.templates = {
161
+ TemplateType.BLANK: self._get_blank_template(),
162
+ TemplateType.BUSINESS_REPORT: self._get_business_report_template(),
163
+ TemplateType.TECHNICAL_DOC: self._get_technical_doc_template(),
164
+ TemplateType.ACADEMIC_PAPER: self._get_academic_paper_template(),
165
+ TemplateType.PROJECT_PROPOSAL: self._get_project_proposal_template(),
166
+ TemplateType.USER_MANUAL: self._get_user_manual_template(),
167
+ TemplateType.PRESENTATION: self._get_presentation_template(),
168
+ TemplateType.NEWSLETTER: self._get_newsletter_template(),
169
+ TemplateType.INVOICE: self._get_invoice_template()
170
+ }
171
+
172
+ # Schema definitions
173
+ class CreateDocumentSchema(BaseModel):
174
+ """Schema for create_document operation"""
175
+ document_type: DocumentType = Field(description="Type of document to create")
176
+ template_type: TemplateType = Field(description="Template to use")
177
+ output_format: DocumentFormat = Field(description="Output format")
178
+ metadata: Dict[str, Any] = Field(description="Document metadata")
179
+ style_preset: Optional[StylePreset] = Field(default=None, description="Style preset")
180
+ output_path: Optional[str] = Field(default=None, description="Custom output path")
181
+
182
+ class CreateFromTemplateSchema(BaseModel):
183
+ """Schema for create_from_template operation"""
184
+ template_name: str = Field(description="Name of template to use")
185
+ template_variables: Dict[str, Any] = Field(description="Variables to fill in template")
186
+ output_format: DocumentFormat = Field(description="Output format")
187
+ output_path: Optional[str] = Field(default=None, description="Custom output path")
188
+
189
+ class SetupStructureSchema(BaseModel):
190
+ """Schema for setup_document_structure operation"""
191
+ document_path: str = Field(description="Path to document")
192
+ sections: List[Dict[str, Any]] = Field(description="Document sections configuration")
193
+ generate_toc: bool = Field(default=True, description="Generate table of contents")
194
+ numbering_style: Optional[str] = Field(default=None, description="Section numbering style")
195
+
196
+ class ConfigureMetadataSchema(BaseModel):
197
+ """Schema for configure_metadata operation"""
198
+ document_path: str = Field(description="Path to document")
199
+ metadata: Dict[str, Any] = Field(description="Metadata to configure")
200
+ format_specific: bool = Field(default=True, description="Use format-specific metadata")
201
+
202
+ def create_document(self,
203
+ document_type: DocumentType,
204
+ template_type: TemplateType,
205
+ output_format: DocumentFormat,
206
+ metadata: Dict[str, Any],
207
+ style_preset: Optional[StylePreset] = None,
208
+ output_path: Optional[str] = None) -> Dict[str, Any]:
209
+ """
210
+ Create a new document from template
211
+
212
+ Args:
213
+ document_type: Type of document to create
214
+ template_type: Template to use
215
+ output_format: Output format for the document
216
+ metadata: Document metadata (title, author, etc.)
217
+ style_preset: Style preset to apply
218
+ output_path: Custom output path
219
+
220
+ Returns:
221
+ Dict containing document creation results
222
+ """
223
+ try:
224
+ start_time = datetime.now()
225
+ document_id = str(uuid.uuid4())
226
+
227
+ self.logger.info(f"Creating document {document_id}: {document_type} using {template_type}")
228
+
229
+ # Step 1: Validate and prepare template
230
+ template = self._get_template(template_type)
231
+
232
+ # Step 2: Generate output path
233
+ if not output_path:
234
+ output_path = self._generate_output_path(document_type, output_format, document_id)
235
+
236
+ # Step 3: Process metadata
237
+ processed_metadata = self._process_metadata(metadata, output_format)
238
+
239
+ # Step 4: Apply style preset
240
+ style_config = self._get_style_config(style_preset or self.settings.default_style)
241
+
242
+ # Step 5: Create document from template
243
+ document_content = self._create_document_from_template(
244
+ template,
245
+ processed_metadata,
246
+ style_config,
247
+ output_format
248
+ )
249
+
250
+ # Step 6: Write document to file
251
+ self._write_document_file(output_path, document_content, output_format)
252
+
253
+ # Step 7: Track created document
254
+ document_info = {
255
+ "document_id": document_id,
256
+ "document_type": document_type,
257
+ "template_type": template_type,
258
+ "output_format": output_format,
259
+ "output_path": output_path,
260
+ "metadata": processed_metadata,
261
+ "style_preset": style_preset,
262
+ "creation_metadata": {
263
+ "created_at": start_time.isoformat(),
264
+ "file_size": os.path.getsize(output_path) if os.path.exists(output_path) else 0,
265
+ "duration": (datetime.now() - start_time).total_seconds()
266
+ }
267
+ }
268
+
269
+ self._documents_created.append(document_info)
270
+
271
+ self.logger.info(f"Document {document_id} created successfully at {output_path}")
272
+ return document_info
273
+
274
+ except Exception as e:
275
+ raise DocumentCreationError(f"Failed to create document: {str(e)}")
276
+
277
+ def create_from_template(self,
278
+ template_name: str,
279
+ template_variables: Dict[str, Any],
280
+ output_format: DocumentFormat,
281
+ output_path: Optional[str] = None) -> Dict[str, Any]:
282
+ """
283
+ Create document from custom template with variables
284
+
285
+ Args:
286
+ template_name: Name of template file
287
+ template_variables: Variables to substitute in template
288
+ output_format: Output format
289
+ output_path: Custom output path
290
+
291
+ Returns:
292
+ Dict containing creation results
293
+ """
294
+ try:
295
+ # Load custom template
296
+ template_path = os.path.join(self.settings.templates_dir, template_name)
297
+ if not os.path.exists(template_path):
298
+ raise TemplateError(f"Template not found: {template_name}")
299
+
300
+ with open(template_path, 'r', encoding='utf-8') as f:
301
+ template_content = f.read()
302
+
303
+ # Process template variables
304
+ processed_content = self._process_template_variables(template_content, template_variables)
305
+
306
+ # Generate output path if not provided
307
+ if not output_path:
308
+ output_path = self._generate_output_path("custom", output_format, str(uuid.uuid4()))
309
+
310
+ # Write processed content
311
+ self._write_document_file(output_path, processed_content, output_format)
312
+
313
+ return {
314
+ "template_name": template_name,
315
+ "output_path": output_path,
316
+ "output_format": output_format,
317
+ "variables_used": template_variables,
318
+ "creation_time": datetime.now().isoformat()
319
+ }
320
+
321
+ except Exception as e:
322
+ raise DocumentCreationError(f"Failed to create from template: {str(e)}")
323
+
324
+ def setup_document_structure(self,
325
+ document_path: str,
326
+ sections: List[Dict[str, Any]],
327
+ generate_toc: bool = True,
328
+ numbering_style: Optional[str] = None) -> Dict[str, Any]:
329
+ """
330
+ Setup document structure with sections and headers
331
+
332
+ Args:
333
+ document_path: Path to document
334
+ sections: List of section configurations
335
+ generate_toc: Whether to generate table of contents
336
+ numbering_style: Section numbering style
337
+
338
+ Returns:
339
+ Dict containing structure setup results
340
+ """
341
+ try:
342
+ self.logger.info(f"Setting up structure for document: {document_path}")
343
+
344
+ # Read existing document
345
+ if os.path.exists(document_path):
346
+ with open(document_path, 'r', encoding='utf-8') as f:
347
+ content = f.read()
348
+ else:
349
+ content = ""
350
+
351
+ # Generate structure
352
+ structure_content = self._generate_document_structure(
353
+ sections,
354
+ generate_toc,
355
+ numbering_style
356
+ )
357
+
358
+ # Combine with existing content
359
+ final_content = self._combine_structure_with_content(structure_content, content)
360
+
361
+ # Write back to file
362
+ with open(document_path, 'w', encoding='utf-8') as f:
363
+ f.write(final_content)
364
+
365
+ return {
366
+ "document_path": document_path,
367
+ "sections_created": len(sections),
368
+ "toc_generated": generate_toc,
369
+ "numbering_style": numbering_style,
370
+ "structure_setup_time": datetime.now().isoformat()
371
+ }
372
+
373
+ except Exception as e:
374
+ raise DocumentCreationError(f"Failed to setup document structure: {str(e)}")
375
+
376
+ def configure_metadata(self,
377
+ document_path: str,
378
+ metadata: Dict[str, Any],
379
+ format_specific: bool = True) -> Dict[str, Any]:
380
+ """
381
+ Configure document metadata
382
+
383
+ Args:
384
+ document_path: Path to document
385
+ metadata: Metadata to configure
386
+ format_specific: Use format-specific metadata syntax
387
+
388
+ Returns:
389
+ Dict containing metadata configuration results
390
+ """
391
+ try:
392
+ # Detect document format
393
+ file_format = self._detect_document_format(document_path)
394
+
395
+ # Generate metadata content
396
+ if format_specific:
397
+ metadata_content = self._generate_format_specific_metadata(metadata, file_format)
398
+ else:
399
+ metadata_content = self._generate_generic_metadata(metadata)
400
+
401
+ # Insert metadata into document
402
+ self._insert_metadata_into_document(document_path, metadata_content, file_format)
403
+
404
+ return {
405
+ "document_path": document_path,
406
+ "metadata_configured": metadata,
407
+ "format": file_format,
408
+ "format_specific": format_specific,
409
+ "configuration_time": datetime.now().isoformat()
410
+ }
411
+
412
+ except Exception as e:
413
+ raise DocumentCreationError(f"Failed to configure metadata: {str(e)}")
414
+
415
+ def list_templates(self) -> Dict[str, Any]:
416
+ """
417
+ List available document templates
418
+
419
+ Returns:
420
+ Dict containing available templates
421
+ """
422
+ built_in_templates = list(self.templates.keys())
423
+
424
+ # Scan for custom templates
425
+ custom_templates = []
426
+ if os.path.exists(self.settings.templates_dir):
427
+ for file in os.listdir(self.settings.templates_dir):
428
+ if file.endswith(('.md', '.html', '.txt', '.json')):
429
+ custom_templates.append(file)
430
+
431
+ return {
432
+ "built_in_templates": [t.value for t in built_in_templates],
433
+ "custom_templates": custom_templates,
434
+ "templates_directory": self.settings.templates_dir,
435
+ "total_templates": len(built_in_templates) + len(custom_templates)
436
+ }
437
+
438
+ def get_template_info(self, template_type: TemplateType) -> Dict[str, Any]:
439
+ """
440
+ Get information about a specific template
441
+
442
+ Args:
443
+ template_type: Type of template
444
+
445
+ Returns:
446
+ Dict containing template information
447
+ """
448
+ if template_type not in self.templates:
449
+ raise TemplateError(f"Template not found: {template_type}")
450
+
451
+ template = self.templates[template_type]
452
+
453
+ return {
454
+ "template_type": template_type.value,
455
+ "name": template.get("name", ""),
456
+ "description": template.get("description", ""),
457
+ "sections": template.get("sections", []),
458
+ "variables": template.get("variables", []),
459
+ "supported_formats": template.get("supported_formats", []),
460
+ "style_presets": template.get("style_presets", [])
461
+ }
462
+
463
+ def get_created_documents(self) -> List[Dict[str, Any]]:
464
+ """
465
+ Get list of documents created in this session
466
+
467
+ Returns:
468
+ List of created document information
469
+ """
470
+ return self._documents_created.copy()
471
+
472
+ # Template definitions
473
+ def _get_blank_template(self) -> Dict[str, Any]:
474
+ """Get blank document template"""
475
+ return {
476
+ "name": "Blank Document",
477
+ "description": "Empty document with basic structure",
478
+ "content": "",
479
+ "sections": [],
480
+ "variables": [],
481
+ "supported_formats": ["markdown", "html", "txt", "docx"],
482
+ "metadata_template": {
483
+ "title": "New Document",
484
+ "author": "Author",
485
+ "date": datetime.now().strftime("%Y-%m-%d")
486
+ }
487
+ }
488
+
489
+ def _get_business_report_template(self) -> Dict[str, Any]:
490
+ """Get business report template"""
491
+ return {
492
+ "name": "Business Report",
493
+ "description": "Professional business report template",
494
+ "content": """# {title}
495
+
496
+ **Date:** {date}
497
+ **Author:** {author}
498
+ **Department:** {department}
499
+
500
+ ## Executive Summary
501
+
502
+ {executive_summary}
503
+
504
+ ## Introduction
505
+
506
+ {introduction}
507
+
508
+ ## Analysis
509
+
510
+ ### Key Findings
511
+
512
+ {key_findings}
513
+
514
+ ### Data Analysis
515
+
516
+ {data_analysis}
517
+
518
+ ## Recommendations
519
+
520
+ {recommendations}
521
+
522
+ ## Conclusion
523
+
524
+ {conclusion}
525
+
526
+ ## Appendices
527
+
528
+ {appendices}
529
+ """,
530
+ "sections": [
531
+ {"name": "Executive Summary", "level": 2, "required": True},
532
+ {"name": "Introduction", "level": 2, "required": True},
533
+ {"name": "Analysis", "level": 2, "required": True},
534
+ {"name": "Recommendations", "level": 2, "required": True},
535
+ {"name": "Conclusion", "level": 2, "required": True}
536
+ ],
537
+ "variables": [
538
+ "title", "date", "author", "department",
539
+ "executive_summary", "introduction", "key_findings",
540
+ "data_analysis", "recommendations", "conclusion", "appendices"
541
+ ],
542
+ "supported_formats": ["markdown", "html", "docx", "pdf"],
543
+ "style_presets": ["corporate", "professional", "modern"]
544
+ }
545
+
546
+ def _get_technical_doc_template(self) -> Dict[str, Any]:
547
+ """Get technical documentation template"""
548
+ return {
549
+ "name": "Technical Documentation",
550
+ "description": "Technical documentation with code examples",
551
+ "content": """# {title}
552
+
553
+ **Version:** {version}
554
+ **Last Updated:** {date}
555
+ **Author:** {author}
556
+
557
+ ## Overview
558
+
559
+ {overview}
560
+
561
+ ## Prerequisites
562
+
563
+ {prerequisites}
564
+
565
+ ## Installation
566
+
567
+ {installation}
568
+
569
+ ## Configuration
570
+
571
+ {configuration}
572
+
573
+ ## Usage
574
+
575
+ {usage}
576
+
577
+ ## API Reference
578
+
579
+ {api_reference}
580
+
581
+ ## Examples
582
+
583
+ {examples}
584
+
585
+ ## Troubleshooting
586
+
587
+ {troubleshooting}
588
+
589
+ ## Changelog
590
+
591
+ {changelog}
592
+ """,
593
+ "sections": [
594
+ {"name": "Overview", "level": 2, "required": True},
595
+ {"name": "Prerequisites", "level": 2, "required": False},
596
+ {"name": "Installation", "level": 2, "required": True},
597
+ {"name": "Configuration", "level": 2, "required": False},
598
+ {"name": "Usage", "level": 2, "required": True},
599
+ {"name": "API Reference", "level": 2, "required": False},
600
+ {"name": "Examples", "level": 2, "required": True},
601
+ {"name": "Troubleshooting", "level": 2, "required": False}
602
+ ],
603
+ "variables": [
604
+ "title", "version", "date", "author", "overview",
605
+ "prerequisites", "installation", "configuration", "usage",
606
+ "api_reference", "examples", "troubleshooting", "changelog"
607
+ ],
608
+ "supported_formats": ["markdown", "html", "pdf"],
609
+ "style_presets": ["technical", "modern", "minimal"]
610
+ }
611
+
612
+ def _get_academic_paper_template(self) -> Dict[str, Any]:
613
+ """Get academic paper template"""
614
+ return {
615
+ "name": "Academic Paper",
616
+ "description": "Academic research paper template",
617
+ "content": """# {title}
618
+
619
+ **Author:** {author}
620
+ **Institution:** {institution}
621
+ **Email:** {email}
622
+ **Date:** {date}
623
+
624
+ ## Abstract
625
+
626
+ {abstract}
627
+
628
+ **Keywords:** {keywords}
629
+
630
+ ## 1. Introduction
631
+
632
+ {introduction}
633
+
634
+ ## 2. Literature Review
635
+
636
+ {literature_review}
637
+
638
+ ## 3. Methodology
639
+
640
+ {methodology}
641
+
642
+ ## 4. Results
643
+
644
+ {results}
645
+
646
+ ## 5. Discussion
647
+
648
+ {discussion}
649
+
650
+ ## 6. Conclusion
651
+
652
+ {conclusion}
653
+
654
+ ## References
655
+
656
+ {references}
657
+
658
+ ## Appendices
659
+
660
+ {appendices}
661
+ """,
662
+ "sections": [
663
+ {"name": "Abstract", "level": 2, "required": True},
664
+ {"name": "Introduction", "level": 2, "required": True},
665
+ {"name": "Literature Review", "level": 2, "required": True},
666
+ {"name": "Methodology", "level": 2, "required": True},
667
+ {"name": "Results", "level": 2, "required": True},
668
+ {"name": "Discussion", "level": 2, "required": True},
669
+ {"name": "Conclusion", "level": 2, "required": True},
670
+ {"name": "References", "level": 2, "required": True}
671
+ ],
672
+ "variables": [
673
+ "title", "author", "institution", "email", "date",
674
+ "abstract", "keywords", "introduction", "literature_review",
675
+ "methodology", "results", "discussion", "conclusion",
676
+ "references", "appendices"
677
+ ],
678
+ "supported_formats": ["markdown", "latex", "pdf"],
679
+ "style_presets": ["academic", "classic", "formal"]
680
+ }
681
+
682
+ def _get_project_proposal_template(self) -> Dict[str, Any]:
683
+ """Get project proposal template"""
684
+ return {
685
+ "name": "Project Proposal",
686
+ "description": "Project proposal and planning template",
687
+ "content": """# {project_name}
688
+
689
+ **Proposal Date:** {date}
690
+ **Project Manager:** {project_manager}
691
+ **Department:** {department}
692
+ **Budget:** {budget}
693
+
694
+ ## Project Overview
695
+
696
+ {project_overview}
697
+
698
+ ## Objectives
699
+
700
+ {objectives}
701
+
702
+ ## Scope
703
+
704
+ ### In Scope
705
+ {in_scope}
706
+
707
+ ### Out of Scope
708
+ {out_scope}
709
+
710
+ ## Timeline
711
+
712
+ {timeline}
713
+
714
+ ## Resources Required
715
+
716
+ {resources}
717
+
718
+ ## Budget Breakdown
719
+
720
+ {budget_breakdown}
721
+
722
+ ## Risk Assessment
723
+
724
+ {risk_assessment}
725
+
726
+ ## Success Criteria
727
+
728
+ {success_criteria}
729
+
730
+ ## Next Steps
731
+
732
+ {next_steps}
733
+ """,
734
+ "variables": [
735
+ "project_name", "date", "project_manager", "department", "budget",
736
+ "project_overview", "objectives", "in_scope", "out_scope",
737
+ "timeline", "resources", "budget_breakdown", "risk_assessment",
738
+ "success_criteria", "next_steps"
739
+ ],
740
+ "supported_formats": ["markdown", "html", "docx", "pdf"],
741
+ "style_presets": ["professional", "corporate", "modern"]
742
+ }
743
+
744
+ def _get_user_manual_template(self) -> Dict[str, Any]:
745
+ """Get user manual template"""
746
+ return {
747
+ "name": "User Manual",
748
+ "description": "User manual and guide template",
749
+ "content": """# {product_name} User Manual
750
+
751
+ **Version:** {version}
752
+ **Date:** {date}
753
+ **Support:** {support_contact}
754
+
755
+ ## Table of Contents
756
+
757
+ 1. [Getting Started](#getting-started)
758
+ 2. [Basic Features](#basic-features)
759
+ 3. [Advanced Features](#advanced-features)
760
+ 4. [Troubleshooting](#troubleshooting)
761
+ 5. [FAQ](#faq)
762
+
763
+ ## Getting Started
764
+
765
+ {getting_started}
766
+
767
+ ## Basic Features
768
+
769
+ {basic_features}
770
+
771
+ ## Advanced Features
772
+
773
+ {advanced_features}
774
+
775
+ ## Troubleshooting
776
+
777
+ {troubleshooting}
778
+
779
+ ## FAQ
780
+
781
+ {faq}
782
+
783
+ ## Contact Support
784
+
785
+ {support_info}
786
+ """,
787
+ "variables": [
788
+ "product_name", "version", "date", "support_contact",
789
+ "getting_started", "basic_features", "advanced_features",
790
+ "troubleshooting", "faq", "support_info"
791
+ ],
792
+ "supported_formats": ["markdown", "html", "pdf"],
793
+ "style_presets": ["user-friendly", "modern", "minimal"]
794
+ }
795
+
796
+ def _get_presentation_template(self) -> Dict[str, Any]:
797
+ """Get presentation template"""
798
+ return {
799
+ "name": "Presentation",
800
+ "description": "Slide presentation template",
801
+ "content": """# {title}
802
+
803
+ ---
804
+
805
+ ## Slide 1: Title Slide
806
+
807
+ ### {title}
808
+ **Presenter:** {presenter}
809
+ **Date:** {date}
810
+ **Organization:** {organization}
811
+
812
+ ---
813
+
814
+ ## Slide 2: Agenda
815
+
816
+ {agenda}
817
+
818
+ ---
819
+
820
+ ## Slide 3: Introduction
821
+
822
+ {introduction}
823
+
824
+ ---
825
+
826
+ ## Slide 4: Main Content
827
+
828
+ {main_content}
829
+
830
+ ---
831
+
832
+ ## Slide 5: Conclusion
833
+
834
+ {conclusion}
835
+
836
+ ---
837
+
838
+ ## Slide 6: Questions
839
+
840
+ {questions}
841
+
842
+ ---
843
+
844
+ ## Slide 7: Thank You
845
+
846
+ **Contact Information:**
847
+ {contact_info}
848
+ """,
849
+ "variables": [
850
+ "title", "presenter", "date", "organization",
851
+ "agenda", "introduction", "main_content", "conclusion",
852
+ "questions", "contact_info"
853
+ ],
854
+ "supported_formats": ["markdown", "html"],
855
+ "style_presets": ["presentation", "modern", "colorful"]
856
+ }
857
+
858
+ def _get_newsletter_template(self) -> Dict[str, Any]:
859
+ """Get newsletter template"""
860
+ return {
861
+ "name": "Newsletter",
862
+ "description": "Newsletter and bulletin template",
863
+ "content": """# {newsletter_name}
864
+
865
+ **Issue #{issue_number}** | {date}
866
+
867
+ ## Headlines
868
+
869
+ {headlines}
870
+
871
+ ## Feature Article
872
+
873
+ {feature_article}
874
+
875
+ ## News Briefs
876
+
877
+ {news_briefs}
878
+
879
+ ## Upcoming Events
880
+
881
+ {upcoming_events}
882
+
883
+ ## Community Spotlight
884
+
885
+ {community_spotlight}
886
+
887
+ ## Contact Us
888
+
889
+ {contact_info}
890
+ """,
891
+ "variables": [
892
+ "newsletter_name", "issue_number", "date",
893
+ "headlines", "feature_article", "news_briefs",
894
+ "upcoming_events", "community_spotlight", "contact_info"
895
+ ],
896
+ "supported_formats": ["markdown", "html"],
897
+ "style_presets": ["newsletter", "colorful", "modern"]
898
+ }
899
+
900
+ def _get_invoice_template(self) -> Dict[str, Any]:
901
+ """Get invoice template"""
902
+ return {
903
+ "name": "Invoice",
904
+ "description": "Business invoice template",
905
+ "content": """# INVOICE
906
+
907
+ **Invoice #:** {invoice_number}
908
+ **Date:** {date}
909
+ **Due Date:** {due_date}
910
+
911
+ ## Bill To:
912
+ {client_info}
913
+
914
+ ## Bill From:
915
+ {company_info}
916
+
917
+ ## Items
918
+
919
+ {items_table}
920
+
921
+ ## Summary
922
+
923
+ **Subtotal:** {subtotal}
924
+ **Tax:** {tax}
925
+ **Total:** {total}
926
+
927
+ ## Payment Terms
928
+
929
+ {payment_terms}
930
+
931
+ ## Notes
932
+
933
+ {notes}
934
+ """,
935
+ "variables": [
936
+ "invoice_number", "date", "due_date", "client_info",
937
+ "company_info", "items_table", "subtotal", "tax",
938
+ "total", "payment_terms", "notes"
939
+ ],
940
+ "supported_formats": ["markdown", "html", "pdf"],
941
+ "style_presets": ["professional", "corporate", "minimal"]
942
+ }
943
+
944
+ # Helper methods
945
+ def _get_template(self, template_type: TemplateType) -> Dict[str, Any]:
946
+ """Get template by type"""
947
+ if template_type not in self.templates:
948
+ raise TemplateError(f"Template not found: {template_type}")
949
+ return self.templates[template_type]
950
+
951
+ def _generate_output_path(self, document_type: str, output_format: DocumentFormat, document_id: str) -> str:
952
+ """Generate output path for document"""
953
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
954
+ filename = f"{document_type}_{timestamp}_{document_id[:8]}.{output_format.value}"
955
+ return os.path.join(self.settings.output_dir, filename)
956
+
957
+ def _process_metadata(self, metadata: Dict[str, Any], output_format: DocumentFormat) -> Dict[str, Any]:
958
+ """Process and validate metadata"""
959
+ processed = metadata.copy()
960
+
961
+ # Add default metadata if missing
962
+ if 'date' not in processed:
963
+ processed['date'] = datetime.now().strftime("%Y-%m-%d")
964
+ if 'created_by' not in processed:
965
+ processed['created_by'] = 'AIECS Document Creator'
966
+ if 'format' not in processed:
967
+ processed['format'] = output_format.value
968
+
969
+ return processed
970
+
971
+ def _get_style_config(self, style_preset: StylePreset) -> Dict[str, Any]:
972
+ """Get style configuration for preset"""
973
+ style_configs = {
974
+ StylePreset.DEFAULT: {"font_family": "Arial", "font_size": 12, "colors": {"primary": "#000000"}},
975
+ StylePreset.CORPORATE: {"font_family": "Calibri", "font_size": 11, "colors": {"primary": "#2E5D92"}},
976
+ StylePreset.ACADEMIC: {"font_family": "Times New Roman", "font_size": 12, "colors": {"primary": "#000000"}},
977
+ StylePreset.MODERN: {"font_family": "Helvetica", "font_size": 11, "colors": {"primary": "#333333"}},
978
+ StylePreset.CLASSIC: {"font_family": "Georgia", "font_size": 12, "colors": {"primary": "#1a1a1a"}},
979
+ StylePreset.MINIMAL: {"font_family": "Arial", "font_size": 10, "colors": {"primary": "#444444"}},
980
+ StylePreset.COLORFUL: {"font_family": "Verdana", "font_size": 11, "colors": {"primary": "#2E8B57"}},
981
+ StylePreset.PROFESSIONAL: {"font_family": "Segoe UI", "font_size": 11, "colors": {"primary": "#2F4F4F"}}
982
+ }
983
+ return style_configs.get(style_preset, style_configs[StylePreset.DEFAULT])
984
+
985
+ def _create_document_from_template(self, template: Dict[str, Any], metadata: Dict[str, Any],
986
+ style_config: Dict[str, Any], output_format: DocumentFormat) -> str:
987
+ """Create document content from template"""
988
+ content = template.get("content", "")
989
+
990
+ # Apply metadata to template
991
+ if content and template.get("variables"):
992
+ # Replace template variables with metadata values
993
+ for var in template["variables"]:
994
+ placeholder = f"{{{var}}}"
995
+ value = metadata.get(var, f"[{var}]")
996
+ content = content.replace(placeholder, str(value))
997
+
998
+ # Add metadata header if required
999
+ if self.settings.include_metadata:
1000
+ metadata_header = self._generate_metadata_header(metadata, output_format)
1001
+ content = metadata_header + "\n\n" + content
1002
+
1003
+ return content
1004
+
1005
+ def _generate_metadata_header(self, metadata: Dict[str, Any], output_format: DocumentFormat) -> str:
1006
+ """Generate metadata header for document"""
1007
+ if output_format == DocumentFormat.MARKDOWN:
1008
+ return "---\n" + "\n".join([f"{k}: {v}" for k, v in metadata.items()]) + "\n---"
1009
+ elif output_format == DocumentFormat.HTML:
1010
+ meta_tags = "\n".join([f'<meta name="{k}" content="{v}">' for k, v in metadata.items()])
1011
+ return f"<!-- Document Metadata -->\n{meta_tags}\n<!-- End Metadata -->"
1012
+ else:
1013
+ return f"# Document Metadata\n" + "\n".join([f"{k}: {v}" for k, v in metadata.items()])
1014
+
1015
+ def _write_document_file(self, output_path: str, content: str, output_format: DocumentFormat):
1016
+ """Write document content to file"""
1017
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
1018
+
1019
+ if output_format in [DocumentFormat.MARKDOWN, DocumentFormat.HTML, DocumentFormat.PLAIN_TEXT, DocumentFormat.LATEX]:
1020
+ with open(output_path, 'w', encoding='utf-8') as f:
1021
+ f.write(content)
1022
+ elif output_format == DocumentFormat.JSON:
1023
+ with open(output_path, 'w', encoding='utf-8') as f:
1024
+ json.dump({"content": content}, f, indent=2, ensure_ascii=False)
1025
+ else:
1026
+ # For other formats, write as text for now
1027
+ with open(output_path, 'w', encoding='utf-8') as f:
1028
+ f.write(content)
1029
+
1030
+ def _process_template_variables(self, template_content: str, variables: Dict[str, Any]) -> str:
1031
+ """Process template variables in content"""
1032
+ result = template_content
1033
+ for key, value in variables.items():
1034
+ placeholder = f"{{{key}}}"
1035
+ result = result.replace(placeholder, str(value))
1036
+ return result
1037
+
1038
+ def _generate_document_structure(self, sections: List[Dict[str, Any]],
1039
+ generate_toc: bool, numbering_style: Optional[str]) -> str:
1040
+ """Generate document structure from sections"""
1041
+ structure_parts = []
1042
+
1043
+ # Generate table of contents
1044
+ if generate_toc:
1045
+ toc = self._generate_table_of_contents(sections, numbering_style)
1046
+ structure_parts.append(toc)
1047
+
1048
+ # Generate section headers
1049
+ for i, section in enumerate(sections, 1):
1050
+ level = section.get("level", 2)
1051
+ title = section.get("title", f"Section {i}")
1052
+
1053
+ if numbering_style == "numeric":
1054
+ header = f"{'#' * level} {i}. {title}"
1055
+ elif numbering_style == "alpha":
1056
+ alpha = chr(ord('A') + i - 1) if i <= 26 else f"Section{i}"
1057
+ header = f"{'#' * level} {alpha}. {title}"
1058
+ else:
1059
+ header = f"{'#' * level} {title}"
1060
+
1061
+ structure_parts.append(header)
1062
+ structure_parts.append("") # Empty line
1063
+
1064
+ # Add placeholder content
1065
+ placeholder = section.get("placeholder", f"Content for {title} goes here...")
1066
+ structure_parts.append(placeholder)
1067
+ structure_parts.append("") # Empty line
1068
+
1069
+ return "\n".join(structure_parts)
1070
+
1071
+ def _generate_table_of_contents(self, sections: List[Dict[str, Any]], numbering_style: Optional[str]) -> str:
1072
+ """Generate table of contents"""
1073
+ toc_parts = ["# Table of Contents", ""]
1074
+
1075
+ for i, section in enumerate(sections, 1):
1076
+ title = section.get("title", f"Section {i}")
1077
+ level = section.get("level", 2)
1078
+ indent = " " * (level - 1)
1079
+
1080
+ if numbering_style == "numeric":
1081
+ toc_line = f"{indent}- {i}. {title}"
1082
+ elif numbering_style == "alpha":
1083
+ alpha = chr(ord('A') + i - 1) if i <= 26 else f"Section{i}"
1084
+ toc_line = f"{indent}- {alpha}. {title}"
1085
+ else:
1086
+ toc_line = f"{indent}- {title}"
1087
+
1088
+ toc_parts.append(toc_line)
1089
+
1090
+ toc_parts.extend(["", "---", ""])
1091
+ return "\n".join(toc_parts)
1092
+
1093
+ def _combine_structure_with_content(self, structure: str, existing_content: str) -> str:
1094
+ """Combine generated structure with existing content"""
1095
+ if not existing_content.strip():
1096
+ return structure
1097
+
1098
+ # If existing content has structure markers, replace them
1099
+ if "# Table of Contents" in existing_content:
1100
+ # Replace existing structure
1101
+ lines = existing_content.split("\n")
1102
+ content_start = -1
1103
+ for i, line in enumerate(lines):
1104
+ if line.startswith("---") and i > 0:
1105
+ content_start = i + 1
1106
+ break
1107
+
1108
+ if content_start > 0:
1109
+ existing_body = "\n".join(lines[content_start:])
1110
+ return structure + "\n" + existing_body
1111
+
1112
+ return structure + "\n\n" + existing_content
1113
+
1114
+ def _detect_document_format(self, document_path: str) -> DocumentFormat:
1115
+ """Detect document format from file extension"""
1116
+ ext = os.path.splitext(document_path)[1].lower()
1117
+ format_map = {
1118
+ '.md': DocumentFormat.MARKDOWN,
1119
+ '.markdown': DocumentFormat.MARKDOWN,
1120
+ '.html': DocumentFormat.HTML,
1121
+ '.htm': DocumentFormat.HTML,
1122
+ '.txt': DocumentFormat.PLAIN_TEXT,
1123
+ '.json': DocumentFormat.JSON,
1124
+ '.xml': DocumentFormat.XML,
1125
+ '.tex': DocumentFormat.LATEX,
1126
+ '.docx': DocumentFormat.DOCX,
1127
+ '.pdf': DocumentFormat.PDF
1128
+ }
1129
+ return format_map.get(ext, DocumentFormat.PLAIN_TEXT)
1130
+
1131
+ def _generate_format_specific_metadata(self, metadata: Dict[str, Any], file_format: DocumentFormat) -> str:
1132
+ """Generate format-specific metadata"""
1133
+ if file_format == DocumentFormat.MARKDOWN:
1134
+ return "---\n" + "\n".join([f"{k}: {v}" for k, v in metadata.items()]) + "\n---"
1135
+ elif file_format == DocumentFormat.HTML:
1136
+ meta_tags = "\n".join([f'<meta name="{k}" content="{v}">' for k, v in metadata.items()])
1137
+ return f"<head>\n{meta_tags}\n</head>"
1138
+ elif file_format == DocumentFormat.LATEX:
1139
+ return "\n".join([f"\\{k}{{{v}}}" for k, v in metadata.items()])
1140
+ else:
1141
+ return self._generate_generic_metadata(metadata)
1142
+
1143
+ def _generate_generic_metadata(self, metadata: Dict[str, Any]) -> str:
1144
+ """Generate generic metadata"""
1145
+ return "% " + "\n% ".join([f"{k}: {v}" for k, v in metadata.items()])
1146
+
1147
+ def _insert_metadata_into_document(self, document_path: str, metadata_content: str, file_format: DocumentFormat):
1148
+ """Insert metadata into document"""
1149
+ with open(document_path, 'r', encoding='utf-8') as f:
1150
+ content = f.read()
1151
+
1152
+ # Insert metadata at the beginning
1153
+ if file_format == DocumentFormat.HTML and "<head>" in content:
1154
+ # Insert into existing head section
1155
+ content = content.replace("<head>", f"<head>\n{metadata_content}")
1156
+ else:
1157
+ # Insert at the beginning
1158
+ content = metadata_content + "\n\n" + content
1159
+
1160
+ with open(document_path, 'w', encoding='utf-8') as f:
1161
+ f.write(content)