amd-gaia 0.15.0__py3-none-any.whl → 0.15.2__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.
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/METADATA +222 -223
- amd_gaia-0.15.2.dist-info/RECORD +182 -0
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/WHEEL +1 -1
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/entry_points.txt +1 -0
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/licenses/LICENSE.md +20 -20
- gaia/__init__.py +29 -29
- gaia/agents/__init__.py +19 -19
- gaia/agents/base/__init__.py +9 -9
- gaia/agents/base/agent.py +2132 -2177
- gaia/agents/base/api_agent.py +119 -120
- gaia/agents/base/console.py +1967 -1841
- gaia/agents/base/errors.py +237 -237
- gaia/agents/base/mcp_agent.py +86 -86
- gaia/agents/base/tools.py +88 -83
- gaia/agents/blender/__init__.py +7 -0
- gaia/agents/blender/agent.py +553 -556
- gaia/agents/blender/agent_simple.py +133 -135
- gaia/agents/blender/app.py +211 -211
- gaia/agents/blender/app_simple.py +41 -41
- gaia/agents/blender/core/__init__.py +16 -16
- gaia/agents/blender/core/materials.py +506 -506
- gaia/agents/blender/core/objects.py +316 -316
- gaia/agents/blender/core/rendering.py +225 -225
- gaia/agents/blender/core/scene.py +220 -220
- gaia/agents/blender/core/view.py +146 -146
- gaia/agents/chat/__init__.py +9 -9
- gaia/agents/chat/agent.py +809 -835
- gaia/agents/chat/app.py +1065 -1058
- gaia/agents/chat/session.py +508 -508
- gaia/agents/chat/tools/__init__.py +15 -15
- gaia/agents/chat/tools/file_tools.py +96 -96
- gaia/agents/chat/tools/rag_tools.py +1744 -1729
- gaia/agents/chat/tools/shell_tools.py +437 -436
- gaia/agents/code/__init__.py +7 -7
- gaia/agents/code/agent.py +549 -549
- gaia/agents/code/cli.py +377 -0
- gaia/agents/code/models.py +135 -135
- gaia/agents/code/orchestration/__init__.py +24 -24
- gaia/agents/code/orchestration/checklist_executor.py +1763 -1763
- gaia/agents/code/orchestration/checklist_generator.py +713 -713
- gaia/agents/code/orchestration/factories/__init__.py +9 -9
- gaia/agents/code/orchestration/factories/base.py +63 -63
- gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -118
- gaia/agents/code/orchestration/factories/python_factory.py +106 -106
- gaia/agents/code/orchestration/orchestrator.py +841 -841
- gaia/agents/code/orchestration/project_analyzer.py +391 -391
- gaia/agents/code/orchestration/steps/__init__.py +67 -67
- gaia/agents/code/orchestration/steps/base.py +188 -188
- gaia/agents/code/orchestration/steps/error_handler.py +314 -314
- gaia/agents/code/orchestration/steps/nextjs.py +828 -828
- gaia/agents/code/orchestration/steps/python.py +307 -307
- gaia/agents/code/orchestration/template_catalog.py +469 -469
- gaia/agents/code/orchestration/workflows/__init__.py +14 -14
- gaia/agents/code/orchestration/workflows/base.py +80 -80
- gaia/agents/code/orchestration/workflows/nextjs.py +186 -186
- gaia/agents/code/orchestration/workflows/python.py +94 -94
- gaia/agents/code/prompts/__init__.py +11 -11
- gaia/agents/code/prompts/base_prompt.py +77 -77
- gaia/agents/code/prompts/code_patterns.py +2034 -2036
- gaia/agents/code/prompts/nextjs_prompt.py +40 -40
- gaia/agents/code/prompts/python_prompt.py +109 -109
- gaia/agents/code/schema_inference.py +365 -365
- gaia/agents/code/system_prompt.py +41 -41
- gaia/agents/code/tools/__init__.py +42 -42
- gaia/agents/code/tools/cli_tools.py +1138 -1138
- gaia/agents/code/tools/code_formatting.py +319 -319
- gaia/agents/code/tools/code_tools.py +769 -769
- gaia/agents/code/tools/error_fixing.py +1347 -1347
- gaia/agents/code/tools/external_tools.py +180 -180
- gaia/agents/code/tools/file_io.py +845 -845
- gaia/agents/code/tools/prisma_tools.py +190 -190
- gaia/agents/code/tools/project_management.py +1016 -1016
- gaia/agents/code/tools/testing.py +321 -321
- gaia/agents/code/tools/typescript_tools.py +122 -122
- gaia/agents/code/tools/validation_parsing.py +461 -461
- gaia/agents/code/tools/validation_tools.py +806 -806
- gaia/agents/code/tools/web_dev_tools.py +1758 -1758
- gaia/agents/code/validators/__init__.py +16 -16
- gaia/agents/code/validators/antipattern_checker.py +241 -241
- gaia/agents/code/validators/ast_analyzer.py +197 -197
- gaia/agents/code/validators/requirements_validator.py +145 -145
- gaia/agents/code/validators/syntax_validator.py +171 -171
- gaia/agents/docker/__init__.py +7 -7
- gaia/agents/docker/agent.py +643 -642
- gaia/agents/emr/__init__.py +8 -8
- gaia/agents/emr/agent.py +1504 -1506
- gaia/agents/emr/cli.py +1322 -1322
- gaia/agents/emr/constants.py +475 -475
- gaia/agents/emr/dashboard/__init__.py +4 -4
- gaia/agents/emr/dashboard/server.py +1972 -1974
- gaia/agents/jira/__init__.py +11 -11
- gaia/agents/jira/agent.py +894 -894
- gaia/agents/jira/jql_templates.py +299 -299
- gaia/agents/routing/__init__.py +7 -7
- gaia/agents/routing/agent.py +567 -570
- gaia/agents/routing/system_prompt.py +75 -75
- gaia/agents/summarize/__init__.py +11 -0
- gaia/agents/summarize/agent.py +885 -0
- gaia/agents/summarize/prompts.py +129 -0
- gaia/api/__init__.py +23 -23
- gaia/api/agent_registry.py +238 -238
- gaia/api/app.py +305 -305
- gaia/api/openai_server.py +575 -575
- gaia/api/schemas.py +186 -186
- gaia/api/sse_handler.py +373 -373
- gaia/apps/__init__.py +4 -4
- gaia/apps/llm/__init__.py +6 -6
- gaia/apps/llm/app.py +184 -169
- gaia/apps/summarize/app.py +116 -633
- gaia/apps/summarize/html_viewer.py +133 -133
- gaia/apps/summarize/pdf_formatter.py +284 -284
- gaia/audio/__init__.py +2 -2
- gaia/audio/audio_client.py +439 -439
- gaia/audio/audio_recorder.py +269 -269
- gaia/audio/kokoro_tts.py +599 -599
- gaia/audio/whisper_asr.py +432 -432
- gaia/chat/__init__.py +16 -16
- gaia/chat/app.py +428 -430
- gaia/chat/prompts.py +522 -522
- gaia/chat/sdk.py +1228 -1225
- gaia/cli.py +5659 -5632
- gaia/database/__init__.py +10 -10
- gaia/database/agent.py +176 -176
- gaia/database/mixin.py +290 -290
- gaia/database/testing.py +64 -64
- gaia/eval/batch_experiment.py +2332 -2332
- gaia/eval/claude.py +542 -542
- gaia/eval/config.py +37 -37
- gaia/eval/email_generator.py +512 -512
- gaia/eval/eval.py +3179 -3179
- gaia/eval/groundtruth.py +1130 -1130
- gaia/eval/transcript_generator.py +582 -582
- gaia/eval/webapp/README.md +167 -167
- gaia/eval/webapp/package-lock.json +875 -875
- gaia/eval/webapp/package.json +20 -20
- gaia/eval/webapp/public/app.js +3402 -3402
- gaia/eval/webapp/public/index.html +87 -87
- gaia/eval/webapp/public/styles.css +3661 -3661
- gaia/eval/webapp/server.js +415 -415
- gaia/eval/webapp/test-setup.js +72 -72
- gaia/installer/__init__.py +23 -0
- gaia/installer/init_command.py +1275 -0
- gaia/installer/lemonade_installer.py +619 -0
- gaia/llm/__init__.py +10 -2
- gaia/llm/base_client.py +60 -0
- gaia/llm/exceptions.py +12 -0
- gaia/llm/factory.py +70 -0
- gaia/llm/lemonade_client.py +3421 -3221
- gaia/llm/lemonade_manager.py +294 -294
- gaia/llm/providers/__init__.py +9 -0
- gaia/llm/providers/claude.py +108 -0
- gaia/llm/providers/lemonade.py +118 -0
- gaia/llm/providers/openai_provider.py +79 -0
- gaia/llm/vlm_client.py +382 -382
- gaia/logger.py +189 -189
- gaia/mcp/agent_mcp_server.py +245 -245
- gaia/mcp/blender_mcp_client.py +138 -138
- gaia/mcp/blender_mcp_server.py +648 -648
- gaia/mcp/context7_cache.py +332 -332
- gaia/mcp/external_services.py +518 -518
- gaia/mcp/mcp_bridge.py +811 -550
- gaia/mcp/servers/__init__.py +6 -6
- gaia/mcp/servers/docker_mcp.py +83 -83
- gaia/perf_analysis.py +361 -0
- gaia/rag/__init__.py +10 -10
- gaia/rag/app.py +293 -293
- gaia/rag/demo.py +304 -304
- gaia/rag/pdf_utils.py +235 -235
- gaia/rag/sdk.py +2194 -2194
- gaia/security.py +183 -163
- gaia/talk/app.py +287 -289
- gaia/talk/sdk.py +538 -538
- gaia/testing/__init__.py +87 -87
- gaia/testing/assertions.py +330 -330
- gaia/testing/fixtures.py +333 -333
- gaia/testing/mocks.py +493 -493
- gaia/util.py +46 -46
- gaia/utils/__init__.py +33 -33
- gaia/utils/file_watcher.py +675 -675
- gaia/utils/parsing.py +223 -223
- gaia/version.py +100 -100
- amd_gaia-0.15.0.dist-info/RECORD +0 -168
- gaia/agents/code/app.py +0 -266
- gaia/llm/llm_client.py +0 -723
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.2.dist-info}/top_level.txt +0 -0
|
@@ -1,284 +1,284 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Copyright(C) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
3
|
-
# SPDX-License-Identifier: MIT
|
|
4
|
-
|
|
5
|
-
"""
|
|
6
|
-
PDF Formatter for summarizer output
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from datetime import datetime
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Any, Dict
|
|
12
|
-
|
|
13
|
-
try:
|
|
14
|
-
from reportlab.lib import colors
|
|
15
|
-
from reportlab.lib.enums import TA_CENTER
|
|
16
|
-
from reportlab.lib.pagesizes import letter
|
|
17
|
-
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
|
18
|
-
from reportlab.lib.units import inch
|
|
19
|
-
from reportlab.platypus import (
|
|
20
|
-
PageBreak,
|
|
21
|
-
Paragraph,
|
|
22
|
-
SimpleDocTemplate,
|
|
23
|
-
Spacer,
|
|
24
|
-
Table,
|
|
25
|
-
TableStyle,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
HAS_REPORTLAB = True
|
|
29
|
-
except ImportError:
|
|
30
|
-
HAS_REPORTLAB = False
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class PDFFormatter:
|
|
34
|
-
"""Format summary results as PDF"""
|
|
35
|
-
|
|
36
|
-
def __init__(self):
|
|
37
|
-
if not HAS_REPORTLAB:
|
|
38
|
-
raise ImportError(
|
|
39
|
-
"PDF output requires reportlab. Install with: uv pip install reportlab"
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
self.styles = getSampleStyleSheet()
|
|
43
|
-
self._setup_custom_styles()
|
|
44
|
-
|
|
45
|
-
def _setup_custom_styles(self):
|
|
46
|
-
"""Setup custom paragraph styles"""
|
|
47
|
-
# Title style
|
|
48
|
-
self.styles.add(
|
|
49
|
-
ParagraphStyle(
|
|
50
|
-
name="CustomTitle",
|
|
51
|
-
parent=self.styles["Heading1"],
|
|
52
|
-
fontSize=24,
|
|
53
|
-
textColor=colors.HexColor("#1a1a1a"),
|
|
54
|
-
spaceAfter=30,
|
|
55
|
-
alignment=TA_CENTER,
|
|
56
|
-
)
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
# Section header style
|
|
60
|
-
self.styles.add(
|
|
61
|
-
ParagraphStyle(
|
|
62
|
-
name="SectionHeader",
|
|
63
|
-
parent=self.styles["Heading2"],
|
|
64
|
-
fontSize=16,
|
|
65
|
-
textColor=colors.HexColor("#2c3e50"),
|
|
66
|
-
spaceAfter=12,
|
|
67
|
-
spaceBefore=20,
|
|
68
|
-
)
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# Metadata style
|
|
72
|
-
self.styles.add(
|
|
73
|
-
ParagraphStyle(
|
|
74
|
-
name="Metadata",
|
|
75
|
-
parent=self.styles["Normal"],
|
|
76
|
-
fontSize=10,
|
|
77
|
-
textColor=colors.HexColor("#7f8c8d"),
|
|
78
|
-
spaceAfter=6,
|
|
79
|
-
)
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
def format_summary_as_pdf(self, result: Dict[str, Any], output_path: Path):
|
|
83
|
-
"""Generate PDF from summary result"""
|
|
84
|
-
doc = SimpleDocTemplate(
|
|
85
|
-
str(output_path),
|
|
86
|
-
pagesize=letter,
|
|
87
|
-
rightMargin=72,
|
|
88
|
-
leftMargin=72,
|
|
89
|
-
topMargin=72,
|
|
90
|
-
bottomMargin=18,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
# Build content
|
|
94
|
-
story = []
|
|
95
|
-
|
|
96
|
-
# Title
|
|
97
|
-
metadata = result.get("metadata", {})
|
|
98
|
-
input_file = Path(metadata.get("input_file", "Unknown")).name
|
|
99
|
-
story.append(
|
|
100
|
-
Paragraph(f"Summary Report: {input_file}", self.styles["CustomTitle"])
|
|
101
|
-
)
|
|
102
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
103
|
-
|
|
104
|
-
# Metadata section
|
|
105
|
-
story.append(Paragraph("Document Information", self.styles["SectionHeader"]))
|
|
106
|
-
meta_items = [
|
|
107
|
-
f"Type: {metadata.get('input_type', 'Unknown').title()}",
|
|
108
|
-
f"Generated: {metadata.get('timestamp', datetime.now().isoformat())}",
|
|
109
|
-
f"Model: {metadata.get('model', 'Unknown')}",
|
|
110
|
-
f"Processing Time: {metadata.get('processing_time_ms', 0)}ms",
|
|
111
|
-
]
|
|
112
|
-
|
|
113
|
-
for item in meta_items:
|
|
114
|
-
story.append(Paragraph(item, self.styles["Metadata"]))
|
|
115
|
-
|
|
116
|
-
story.append(Spacer(1, 0.3 * inch))
|
|
117
|
-
|
|
118
|
-
# Summaries section
|
|
119
|
-
if "summary" in result:
|
|
120
|
-
# Single style output
|
|
121
|
-
self._add_single_summary(
|
|
122
|
-
story, result["summary"], metadata.get("summary_style", "Summary")
|
|
123
|
-
)
|
|
124
|
-
else:
|
|
125
|
-
# Multiple styles output
|
|
126
|
-
summaries = result.get("summaries", {})
|
|
127
|
-
for style, content in summaries.items():
|
|
128
|
-
self._add_summary_section(story, style, content)
|
|
129
|
-
|
|
130
|
-
# Performance section (optional)
|
|
131
|
-
if result.get("performance") or result.get("aggregate_performance"):
|
|
132
|
-
story.append(PageBreak())
|
|
133
|
-
story.append(Paragraph("Performance Metrics", self.styles["SectionHeader"]))
|
|
134
|
-
|
|
135
|
-
# Use detailed performance stats from individual LLM calls first
|
|
136
|
-
perf = result.get("performance", {})
|
|
137
|
-
if not perf:
|
|
138
|
-
perf = result.get("aggregate_performance", {})
|
|
139
|
-
|
|
140
|
-
# Get model info from metadata or performance data
|
|
141
|
-
metadata = result.get("metadata", {})
|
|
142
|
-
model = metadata.get("model") or perf.get("model_info", {}).get(
|
|
143
|
-
"model", "N/A"
|
|
144
|
-
)
|
|
145
|
-
is_local = metadata.get(
|
|
146
|
-
"use_local_llm", perf.get("model_info", {}).get("local_llm", "N/A")
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
perf_data = [
|
|
150
|
-
["Metric", "Value"],
|
|
151
|
-
["Model", str(model)],
|
|
152
|
-
["Local LLM", str(is_local)],
|
|
153
|
-
["Total Tokens", str(perf.get("total_tokens", "N/A"))],
|
|
154
|
-
[
|
|
155
|
-
"Prompt Tokens",
|
|
156
|
-
str(perf.get("prompt_tokens", perf.get("input_tokens", "N/A"))),
|
|
157
|
-
],
|
|
158
|
-
[
|
|
159
|
-
"Completion Tokens",
|
|
160
|
-
str(
|
|
161
|
-
perf.get("completion_tokens", perf.get("output_tokens", "N/A"))
|
|
162
|
-
),
|
|
163
|
-
],
|
|
164
|
-
["Time to First Token", f"{perf.get('time_to_first_token_ms', 0)}ms"],
|
|
165
|
-
["Tokens per Second", f"{perf.get('tokens_per_second', 0):.1f}"],
|
|
166
|
-
[
|
|
167
|
-
"Processing Time",
|
|
168
|
-
f"{perf.get('processing_time_ms', perf.get('total_processing_time_ms', 0))}ms",
|
|
169
|
-
],
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
t = Table(perf_data, colWidths=[3 * inch, 2 * inch])
|
|
173
|
-
t.setStyle(
|
|
174
|
-
TableStyle(
|
|
175
|
-
[
|
|
176
|
-
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
|
|
177
|
-
("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
|
|
178
|
-
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
179
|
-
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
180
|
-
("FONTSIZE", (0, 0), (-1, 0), 12),
|
|
181
|
-
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
|
|
182
|
-
("BACKGROUND", (0, 1), (-1, -1), colors.beige),
|
|
183
|
-
("GRID", (0, 0), (-1, -1), 1, colors.black),
|
|
184
|
-
]
|
|
185
|
-
)
|
|
186
|
-
)
|
|
187
|
-
story.append(t)
|
|
188
|
-
|
|
189
|
-
# Original content (if included)
|
|
190
|
-
if result.get("original_content"):
|
|
191
|
-
content = result["original_content"]
|
|
192
|
-
|
|
193
|
-
story.append(PageBreak())
|
|
194
|
-
story.append(Paragraph("Original Content", self.styles["SectionHeader"]))
|
|
195
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
196
|
-
|
|
197
|
-
# Split content into paragraphs
|
|
198
|
-
for para in content.split("\n\n"):
|
|
199
|
-
if para.strip():
|
|
200
|
-
story.append(Paragraph(para.strip(), self.styles["Normal"]))
|
|
201
|
-
story.append(Spacer(1, 0.1 * inch))
|
|
202
|
-
|
|
203
|
-
# Build PDF
|
|
204
|
-
doc.build(story)
|
|
205
|
-
|
|
206
|
-
def _add_text_with_newlines(self, story, text):
|
|
207
|
-
"""Add text to story, handling newlines by converting to HTML breaks"""
|
|
208
|
-
if not text:
|
|
209
|
-
return
|
|
210
|
-
|
|
211
|
-
# Simply replace newlines with HTML line breaks
|
|
212
|
-
formatted_text = text.replace("\n", "<br/>")
|
|
213
|
-
story.append(Paragraph(formatted_text, self.styles["Normal"]))
|
|
214
|
-
|
|
215
|
-
def _add_single_summary(self, story, summary_data, style_name):
|
|
216
|
-
"""Add a single summary section to the story"""
|
|
217
|
-
story.append(
|
|
218
|
-
Paragraph(
|
|
219
|
-
style_name.replace("_", " ").title(), self.styles["SectionHeader"]
|
|
220
|
-
)
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
if "text" in summary_data:
|
|
224
|
-
# Handle newlines by splitting into separate paragraphs
|
|
225
|
-
self._add_text_with_newlines(story, summary_data["text"])
|
|
226
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
227
|
-
|
|
228
|
-
if "items" in summary_data:
|
|
229
|
-
for item in summary_data["items"]:
|
|
230
|
-
story.append(Paragraph(f"• {item}", self.styles["Normal"]))
|
|
231
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
232
|
-
|
|
233
|
-
if "participants" in summary_data:
|
|
234
|
-
story.append(Paragraph("Participants:", self.styles["Normal"]))
|
|
235
|
-
for participant in summary_data["participants"]:
|
|
236
|
-
story.append(Paragraph(f"• {participant}", self.styles["Normal"]))
|
|
237
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
238
|
-
|
|
239
|
-
def _add_summary_section(self, story, style, content):
|
|
240
|
-
"""Add a summary section for a specific style"""
|
|
241
|
-
# Format style name
|
|
242
|
-
style_title = style.replace("_", " ").title()
|
|
243
|
-
story.append(Paragraph(style_title, self.styles["SectionHeader"]))
|
|
244
|
-
|
|
245
|
-
if isinstance(content, dict):
|
|
246
|
-
if "text" in content:
|
|
247
|
-
# Handle newlines by splitting into separate paragraphs
|
|
248
|
-
self._add_text_with_newlines(story, content["text"])
|
|
249
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
250
|
-
|
|
251
|
-
if "items" in content:
|
|
252
|
-
for item in content["items"]:
|
|
253
|
-
story.append(Paragraph(f"• {item}", self.styles["Normal"]))
|
|
254
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
255
|
-
|
|
256
|
-
if "participants" in content:
|
|
257
|
-
for participant in content["participants"]:
|
|
258
|
-
if isinstance(participant, dict):
|
|
259
|
-
p_text = f"• {participant.get('name', 'Unknown')}"
|
|
260
|
-
if participant.get("role"):
|
|
261
|
-
p_text += f" ({participant['role']})"
|
|
262
|
-
story.append(Paragraph(p_text, self.styles["Normal"]))
|
|
263
|
-
else:
|
|
264
|
-
story.append(
|
|
265
|
-
Paragraph(f"• {participant}", self.styles["Normal"])
|
|
266
|
-
)
|
|
267
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
268
|
-
|
|
269
|
-
# Email specific fields
|
|
270
|
-
if "sender" in content:
|
|
271
|
-
story.append(
|
|
272
|
-
Paragraph(f"From: {content['sender']}", self.styles["Normal"])
|
|
273
|
-
)
|
|
274
|
-
if "recipients" in content:
|
|
275
|
-
story.append(
|
|
276
|
-
Paragraph(
|
|
277
|
-
f"To: {', '.join(content['recipients'])}", self.styles["Normal"]
|
|
278
|
-
)
|
|
279
|
-
)
|
|
280
|
-
story.append(Spacer(1, 0.2 * inch))
|
|
281
|
-
else:
|
|
282
|
-
# Simple text content
|
|
283
|
-
self._add_text_with_newlines(story, str(content))
|
|
284
|
-
story.append(Spacer(1, 0.3 * inch))
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Copyright(C) 2024-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
PDF Formatter for summarizer output
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from reportlab.lib import colors
|
|
15
|
+
from reportlab.lib.enums import TA_CENTER
|
|
16
|
+
from reportlab.lib.pagesizes import letter
|
|
17
|
+
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
|
18
|
+
from reportlab.lib.units import inch
|
|
19
|
+
from reportlab.platypus import (
|
|
20
|
+
PageBreak,
|
|
21
|
+
Paragraph,
|
|
22
|
+
SimpleDocTemplate,
|
|
23
|
+
Spacer,
|
|
24
|
+
Table,
|
|
25
|
+
TableStyle,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
HAS_REPORTLAB = True
|
|
29
|
+
except ImportError:
|
|
30
|
+
HAS_REPORTLAB = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PDFFormatter:
|
|
34
|
+
"""Format summary results as PDF"""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
if not HAS_REPORTLAB:
|
|
38
|
+
raise ImportError(
|
|
39
|
+
"PDF output requires reportlab. Install with: uv pip install reportlab"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
self.styles = getSampleStyleSheet()
|
|
43
|
+
self._setup_custom_styles()
|
|
44
|
+
|
|
45
|
+
def _setup_custom_styles(self):
|
|
46
|
+
"""Setup custom paragraph styles"""
|
|
47
|
+
# Title style
|
|
48
|
+
self.styles.add(
|
|
49
|
+
ParagraphStyle(
|
|
50
|
+
name="CustomTitle",
|
|
51
|
+
parent=self.styles["Heading1"],
|
|
52
|
+
fontSize=24,
|
|
53
|
+
textColor=colors.HexColor("#1a1a1a"),
|
|
54
|
+
spaceAfter=30,
|
|
55
|
+
alignment=TA_CENTER,
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Section header style
|
|
60
|
+
self.styles.add(
|
|
61
|
+
ParagraphStyle(
|
|
62
|
+
name="SectionHeader",
|
|
63
|
+
parent=self.styles["Heading2"],
|
|
64
|
+
fontSize=16,
|
|
65
|
+
textColor=colors.HexColor("#2c3e50"),
|
|
66
|
+
spaceAfter=12,
|
|
67
|
+
spaceBefore=20,
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Metadata style
|
|
72
|
+
self.styles.add(
|
|
73
|
+
ParagraphStyle(
|
|
74
|
+
name="Metadata",
|
|
75
|
+
parent=self.styles["Normal"],
|
|
76
|
+
fontSize=10,
|
|
77
|
+
textColor=colors.HexColor("#7f8c8d"),
|
|
78
|
+
spaceAfter=6,
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def format_summary_as_pdf(self, result: Dict[str, Any], output_path: Path):
|
|
83
|
+
"""Generate PDF from summary result"""
|
|
84
|
+
doc = SimpleDocTemplate(
|
|
85
|
+
str(output_path),
|
|
86
|
+
pagesize=letter,
|
|
87
|
+
rightMargin=72,
|
|
88
|
+
leftMargin=72,
|
|
89
|
+
topMargin=72,
|
|
90
|
+
bottomMargin=18,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Build content
|
|
94
|
+
story = []
|
|
95
|
+
|
|
96
|
+
# Title
|
|
97
|
+
metadata = result.get("metadata", {})
|
|
98
|
+
input_file = Path(metadata.get("input_file", "Unknown")).name
|
|
99
|
+
story.append(
|
|
100
|
+
Paragraph(f"Summary Report: {input_file}", self.styles["CustomTitle"])
|
|
101
|
+
)
|
|
102
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
103
|
+
|
|
104
|
+
# Metadata section
|
|
105
|
+
story.append(Paragraph("Document Information", self.styles["SectionHeader"]))
|
|
106
|
+
meta_items = [
|
|
107
|
+
f"Type: {metadata.get('input_type', 'Unknown').title()}",
|
|
108
|
+
f"Generated: {metadata.get('timestamp', datetime.now().isoformat())}",
|
|
109
|
+
f"Model: {metadata.get('model', 'Unknown')}",
|
|
110
|
+
f"Processing Time: {metadata.get('processing_time_ms', 0)}ms",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
for item in meta_items:
|
|
114
|
+
story.append(Paragraph(item, self.styles["Metadata"]))
|
|
115
|
+
|
|
116
|
+
story.append(Spacer(1, 0.3 * inch))
|
|
117
|
+
|
|
118
|
+
# Summaries section
|
|
119
|
+
if "summary" in result:
|
|
120
|
+
# Single style output
|
|
121
|
+
self._add_single_summary(
|
|
122
|
+
story, result["summary"], metadata.get("summary_style", "Summary")
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
# Multiple styles output
|
|
126
|
+
summaries = result.get("summaries", {})
|
|
127
|
+
for style, content in summaries.items():
|
|
128
|
+
self._add_summary_section(story, style, content)
|
|
129
|
+
|
|
130
|
+
# Performance section (optional)
|
|
131
|
+
if result.get("performance") or result.get("aggregate_performance"):
|
|
132
|
+
story.append(PageBreak())
|
|
133
|
+
story.append(Paragraph("Performance Metrics", self.styles["SectionHeader"]))
|
|
134
|
+
|
|
135
|
+
# Use detailed performance stats from individual LLM calls first
|
|
136
|
+
perf = result.get("performance", {})
|
|
137
|
+
if not perf:
|
|
138
|
+
perf = result.get("aggregate_performance", {})
|
|
139
|
+
|
|
140
|
+
# Get model info from metadata or performance data
|
|
141
|
+
metadata = result.get("metadata", {})
|
|
142
|
+
model = metadata.get("model") or perf.get("model_info", {}).get(
|
|
143
|
+
"model", "N/A"
|
|
144
|
+
)
|
|
145
|
+
is_local = metadata.get(
|
|
146
|
+
"use_local_llm", perf.get("model_info", {}).get("local_llm", "N/A")
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
perf_data = [
|
|
150
|
+
["Metric", "Value"],
|
|
151
|
+
["Model", str(model)],
|
|
152
|
+
["Local LLM", str(is_local)],
|
|
153
|
+
["Total Tokens", str(perf.get("total_tokens", "N/A"))],
|
|
154
|
+
[
|
|
155
|
+
"Prompt Tokens",
|
|
156
|
+
str(perf.get("prompt_tokens", perf.get("input_tokens", "N/A"))),
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
"Completion Tokens",
|
|
160
|
+
str(
|
|
161
|
+
perf.get("completion_tokens", perf.get("output_tokens", "N/A"))
|
|
162
|
+
),
|
|
163
|
+
],
|
|
164
|
+
["Time to First Token", f"{perf.get('time_to_first_token_ms', 0)}ms"],
|
|
165
|
+
["Tokens per Second", f"{perf.get('tokens_per_second', 0):.1f}"],
|
|
166
|
+
[
|
|
167
|
+
"Processing Time",
|
|
168
|
+
f"{perf.get('processing_time_ms', perf.get('total_processing_time_ms', 0))}ms",
|
|
169
|
+
],
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
t = Table(perf_data, colWidths=[3 * inch, 2 * inch])
|
|
173
|
+
t.setStyle(
|
|
174
|
+
TableStyle(
|
|
175
|
+
[
|
|
176
|
+
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
|
|
177
|
+
("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
|
|
178
|
+
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
179
|
+
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
180
|
+
("FONTSIZE", (0, 0), (-1, 0), 12),
|
|
181
|
+
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
|
|
182
|
+
("BACKGROUND", (0, 1), (-1, -1), colors.beige),
|
|
183
|
+
("GRID", (0, 0), (-1, -1), 1, colors.black),
|
|
184
|
+
]
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
story.append(t)
|
|
188
|
+
|
|
189
|
+
# Original content (if included)
|
|
190
|
+
if result.get("original_content"):
|
|
191
|
+
content = result["original_content"]
|
|
192
|
+
|
|
193
|
+
story.append(PageBreak())
|
|
194
|
+
story.append(Paragraph("Original Content", self.styles["SectionHeader"]))
|
|
195
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
196
|
+
|
|
197
|
+
# Split content into paragraphs
|
|
198
|
+
for para in content.split("\n\n"):
|
|
199
|
+
if para.strip():
|
|
200
|
+
story.append(Paragraph(para.strip(), self.styles["Normal"]))
|
|
201
|
+
story.append(Spacer(1, 0.1 * inch))
|
|
202
|
+
|
|
203
|
+
# Build PDF
|
|
204
|
+
doc.build(story)
|
|
205
|
+
|
|
206
|
+
def _add_text_with_newlines(self, story, text):
|
|
207
|
+
"""Add text to story, handling newlines by converting to HTML breaks"""
|
|
208
|
+
if not text:
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
# Simply replace newlines with HTML line breaks
|
|
212
|
+
formatted_text = text.replace("\n", "<br/>")
|
|
213
|
+
story.append(Paragraph(formatted_text, self.styles["Normal"]))
|
|
214
|
+
|
|
215
|
+
def _add_single_summary(self, story, summary_data, style_name):
|
|
216
|
+
"""Add a single summary section to the story"""
|
|
217
|
+
story.append(
|
|
218
|
+
Paragraph(
|
|
219
|
+
style_name.replace("_", " ").title(), self.styles["SectionHeader"]
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
if "text" in summary_data:
|
|
224
|
+
# Handle newlines by splitting into separate paragraphs
|
|
225
|
+
self._add_text_with_newlines(story, summary_data["text"])
|
|
226
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
227
|
+
|
|
228
|
+
if "items" in summary_data:
|
|
229
|
+
for item in summary_data["items"]:
|
|
230
|
+
story.append(Paragraph(f"• {item}", self.styles["Normal"]))
|
|
231
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
232
|
+
|
|
233
|
+
if "participants" in summary_data:
|
|
234
|
+
story.append(Paragraph("Participants:", self.styles["Normal"]))
|
|
235
|
+
for participant in summary_data["participants"]:
|
|
236
|
+
story.append(Paragraph(f"• {participant}", self.styles["Normal"]))
|
|
237
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
238
|
+
|
|
239
|
+
def _add_summary_section(self, story, style, content):
|
|
240
|
+
"""Add a summary section for a specific style"""
|
|
241
|
+
# Format style name
|
|
242
|
+
style_title = style.replace("_", " ").title()
|
|
243
|
+
story.append(Paragraph(style_title, self.styles["SectionHeader"]))
|
|
244
|
+
|
|
245
|
+
if isinstance(content, dict):
|
|
246
|
+
if "text" in content:
|
|
247
|
+
# Handle newlines by splitting into separate paragraphs
|
|
248
|
+
self._add_text_with_newlines(story, content["text"])
|
|
249
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
250
|
+
|
|
251
|
+
if "items" in content:
|
|
252
|
+
for item in content["items"]:
|
|
253
|
+
story.append(Paragraph(f"• {item}", self.styles["Normal"]))
|
|
254
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
255
|
+
|
|
256
|
+
if "participants" in content:
|
|
257
|
+
for participant in content["participants"]:
|
|
258
|
+
if isinstance(participant, dict):
|
|
259
|
+
p_text = f"• {participant.get('name', 'Unknown')}"
|
|
260
|
+
if participant.get("role"):
|
|
261
|
+
p_text += f" ({participant['role']})"
|
|
262
|
+
story.append(Paragraph(p_text, self.styles["Normal"]))
|
|
263
|
+
else:
|
|
264
|
+
story.append(
|
|
265
|
+
Paragraph(f"• {participant}", self.styles["Normal"])
|
|
266
|
+
)
|
|
267
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
268
|
+
|
|
269
|
+
# Email specific fields
|
|
270
|
+
if "sender" in content:
|
|
271
|
+
story.append(
|
|
272
|
+
Paragraph(f"From: {content['sender']}", self.styles["Normal"])
|
|
273
|
+
)
|
|
274
|
+
if "recipients" in content:
|
|
275
|
+
story.append(
|
|
276
|
+
Paragraph(
|
|
277
|
+
f"To: {', '.join(content['recipients'])}", self.styles["Normal"]
|
|
278
|
+
)
|
|
279
|
+
)
|
|
280
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
281
|
+
else:
|
|
282
|
+
# Simple text content
|
|
283
|
+
self._add_text_with_newlines(story, str(content))
|
|
284
|
+
story.append(Spacer(1, 0.3 * inch))
|
gaia/audio/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
1
|
+
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|