amd-gaia 0.14.3__py3-none-any.whl → 0.15.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {amd_gaia-0.14.3.dist-info → amd_gaia-0.15.1.dist-info}/METADATA +223 -223
- amd_gaia-0.15.1.dist-info/RECORD +178 -0
- {amd_gaia-0.14.3.dist-info → amd_gaia-0.15.1.dist-info}/entry_points.txt +1 -0
- {amd_gaia-0.14.3.dist-info → amd_gaia-0.15.1.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 +2177 -2177
- gaia/agents/base/api_agent.py +120 -120
- gaia/agents/base/console.py +1841 -1841
- gaia/agents/base/errors.py +237 -237
- gaia/agents/base/mcp_agent.py +86 -86
- gaia/agents/base/tools.py +83 -83
- gaia/agents/blender/agent.py +556 -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 +835 -835
- gaia/agents/chat/app.py +1058 -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 +1729 -1729
- gaia/agents/chat/tools/shell_tools.py +436 -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 +2036 -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 +642 -642
- gaia/agents/emr/__init__.py +8 -8
- gaia/agents/emr/agent.py +1506 -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 +1974 -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 +173 -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 +430 -430
- gaia/chat/prompts.py +522 -522
- gaia/chat/sdk.py +1228 -1225
- gaia/cli.py +5481 -5621
- 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/llm/__init__.py +9 -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 +3236 -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 +120 -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 +163 -163
- gaia/talk/app.py +289 -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.14.3.dist-info/RECORD +0 -168
- gaia/agents/code/app.py +0 -266
- gaia/llm/llm_client.py +0 -729
- {amd_gaia-0.14.3.dist-info → amd_gaia-0.15.1.dist-info}/WHEEL +0 -0
- {amd_gaia-0.14.3.dist-info → amd_gaia-0.15.1.dist-info}/top_level.txt +0 -0
gaia/apps/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
"""Gaia Applications"""
|
|
1
|
+
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""Gaia Applications"""
|
gaia/apps/llm/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
LLM agent module for simple LLM queries.
|
|
6
|
-
"""
|
|
1
|
+
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
LLM agent module for simple LLM queries.
|
|
6
|
+
"""
|
gaia/apps/llm/app.py
CHANGED
|
@@ -1,169 +1,173 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
# Copyright(C)
|
|
4
|
-
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
"""
|
|
7
|
-
Simple LLM App using the existing LLMClient wrapper to call Lemonade localhost backend.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import argparse
|
|
11
|
-
import sys
|
|
12
|
-
from typing import Iterator, Optional, Union
|
|
13
|
-
|
|
14
|
-
from gaia.llm
|
|
15
|
-
from gaia.logger import get_logger
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class LlmApp:
|
|
19
|
-
"""Simple LLM application wrapper using LLMClient."""
|
|
20
|
-
|
|
21
|
-
def __init__(
|
|
22
|
-
self, system_prompt: Optional[str] = None, base_url: Optional[str] = None
|
|
23
|
-
):
|
|
24
|
-
"""Initialize the LLM app.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
system_prompt: Optional system prompt for the LLM
|
|
28
|
-
base_url: Base URL for local LLM server (defaults to LEMONADE_BASE_URL env var)
|
|
29
|
-
"""
|
|
30
|
-
self.log = get_logger(__name__)
|
|
31
|
-
self.client =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
parser.
|
|
108
|
-
|
|
109
|
-
)
|
|
110
|
-
parser.add_argument("--
|
|
111
|
-
parser.add_argument(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
parser.add_argument(
|
|
118
|
-
"--
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
print("=
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
print("
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Simple LLM App using the existing LLMClient wrapper to call Lemonade localhost backend.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import sys
|
|
12
|
+
from typing import Iterator, Optional, Union
|
|
13
|
+
|
|
14
|
+
from gaia.llm import create_client
|
|
15
|
+
from gaia.logger import get_logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LlmApp:
|
|
19
|
+
"""Simple LLM application wrapper using LLMClient."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self, system_prompt: Optional[str] = None, base_url: Optional[str] = None
|
|
23
|
+
):
|
|
24
|
+
"""Initialize the LLM app.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
system_prompt: Optional system prompt for the LLM
|
|
28
|
+
base_url: Base URL for local LLM server (defaults to LEMONADE_BASE_URL env var)
|
|
29
|
+
"""
|
|
30
|
+
self.log = get_logger(__name__)
|
|
31
|
+
self.client = create_client(
|
|
32
|
+
"lemonade",
|
|
33
|
+
base_url=base_url,
|
|
34
|
+
system_prompt=system_prompt,
|
|
35
|
+
)
|
|
36
|
+
self.log.debug("LLM app initialized")
|
|
37
|
+
|
|
38
|
+
def query(
|
|
39
|
+
self,
|
|
40
|
+
prompt: str,
|
|
41
|
+
model: Optional[str] = None,
|
|
42
|
+
max_tokens: int = 512,
|
|
43
|
+
stream: bool = False,
|
|
44
|
+
**kwargs,
|
|
45
|
+
) -> Union[str, Iterator[str]]:
|
|
46
|
+
"""Send a query to the LLM and get a response."""
|
|
47
|
+
if not prompt.strip():
|
|
48
|
+
raise ValueError("Prompt cannot be empty")
|
|
49
|
+
|
|
50
|
+
self.log.debug(f"Processing query with model: {model or 'default'}")
|
|
51
|
+
|
|
52
|
+
# Prepare arguments
|
|
53
|
+
generate_kwargs = dict(kwargs)
|
|
54
|
+
if max_tokens:
|
|
55
|
+
generate_kwargs["max_tokens"] = max_tokens
|
|
56
|
+
|
|
57
|
+
# Generate response
|
|
58
|
+
return self.client.generate(
|
|
59
|
+
prompt=prompt.strip(), model=model, stream=stream, **generate_kwargs
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def get_stats(self):
|
|
63
|
+
"""Get performance statistics."""
|
|
64
|
+
return self.client.get_performance_stats() or {}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main(
|
|
68
|
+
query: Optional[str] = None,
|
|
69
|
+
model: Optional[str] = None,
|
|
70
|
+
max_tokens: int = 512,
|
|
71
|
+
system_prompt: Optional[str] = None,
|
|
72
|
+
stream: bool = True,
|
|
73
|
+
base_url: Optional[str] = None,
|
|
74
|
+
) -> str:
|
|
75
|
+
"""Main function to run the LLM app.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
query: Query to send to the LLM
|
|
79
|
+
model: Model name to use
|
|
80
|
+
max_tokens: Maximum tokens to generate
|
|
81
|
+
system_prompt: Optional system prompt
|
|
82
|
+
stream: Whether to stream the response
|
|
83
|
+
base_url: Base URL for local LLM server (defaults to LEMONADE_BASE_URL env var)
|
|
84
|
+
"""
|
|
85
|
+
if not query:
|
|
86
|
+
raise ValueError("Query is required")
|
|
87
|
+
|
|
88
|
+
app = LlmApp(system_prompt=system_prompt, base_url=base_url)
|
|
89
|
+
response = app.query(
|
|
90
|
+
prompt=query, model=model, max_tokens=max_tokens, stream=stream
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
if stream:
|
|
94
|
+
# Handle streaming response
|
|
95
|
+
full_response = ""
|
|
96
|
+
for chunk in response:
|
|
97
|
+
print(chunk, end="", flush=True)
|
|
98
|
+
full_response += chunk
|
|
99
|
+
print() # Add newline
|
|
100
|
+
return full_response
|
|
101
|
+
else:
|
|
102
|
+
return response
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def cli_main():
|
|
106
|
+
"""Command line interface."""
|
|
107
|
+
parser = argparse.ArgumentParser(description="Simple LLM App")
|
|
108
|
+
|
|
109
|
+
parser.add_argument("query", help="Query to send to the LLM")
|
|
110
|
+
parser.add_argument("--model", help="Model name to use")
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"--max-tokens", type=int, default=512, help="Max tokens (default: 512)"
|
|
113
|
+
)
|
|
114
|
+
parser.add_argument("--system-prompt", help="System prompt")
|
|
115
|
+
parser.add_argument("--stream", action="store_true", help="Stream response")
|
|
116
|
+
parser.add_argument("--stats", action="store_true", help="Show stats")
|
|
117
|
+
parser.add_argument(
|
|
118
|
+
"--base-url",
|
|
119
|
+
help="Base URL for local LLM server (defaults to LEMONADE_BASE_URL env var)",
|
|
120
|
+
)
|
|
121
|
+
parser.add_argument(
|
|
122
|
+
"--logging-level",
|
|
123
|
+
default="INFO",
|
|
124
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
125
|
+
help="Logging level",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
args = parser.parse_args()
|
|
129
|
+
|
|
130
|
+
# Setup logging
|
|
131
|
+
import logging
|
|
132
|
+
|
|
133
|
+
from gaia.logger import log_manager
|
|
134
|
+
|
|
135
|
+
log_manager.set_level("gaia", getattr(logging, args.logging_level))
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
app = LlmApp(system_prompt=args.system_prompt, base_url=args.base_url)
|
|
139
|
+
|
|
140
|
+
response = app.query(
|
|
141
|
+
prompt=args.query,
|
|
142
|
+
model=args.model,
|
|
143
|
+
max_tokens=args.max_tokens,
|
|
144
|
+
stream=args.stream,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if args.stream:
|
|
148
|
+
# Already printed during streaming
|
|
149
|
+
pass
|
|
150
|
+
else:
|
|
151
|
+
print(f"\n{'='*50}")
|
|
152
|
+
print("LLM Response:")
|
|
153
|
+
print("=" * 50)
|
|
154
|
+
print(response)
|
|
155
|
+
print("=" * 50)
|
|
156
|
+
|
|
157
|
+
if args.stats:
|
|
158
|
+
stats = app.get_stats()
|
|
159
|
+
if stats:
|
|
160
|
+
print(f"\n{'='*50}")
|
|
161
|
+
print("Performance Statistics:")
|
|
162
|
+
print("=" * 50)
|
|
163
|
+
for key, value in stats.items():
|
|
164
|
+
print(f"{key}: {value}")
|
|
165
|
+
print("=" * 50)
|
|
166
|
+
|
|
167
|
+
except Exception as e:
|
|
168
|
+
print(f"Error: {e}")
|
|
169
|
+
sys.exit(1)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
cli_main()
|