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