quantalogic 0.33.4__py3-none-any.whl → 0.40.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.
- quantalogic/__init__.py +0 -4
- quantalogic/agent.py +603 -362
- quantalogic/agent_config.py +260 -28
- quantalogic/agent_factory.py +43 -17
- quantalogic/coding_agent.py +20 -12
- quantalogic/config.py +7 -4
- quantalogic/console_print_events.py +4 -8
- quantalogic/console_print_token.py +2 -2
- quantalogic/docs_cli.py +15 -10
- quantalogic/event_emitter.py +258 -83
- quantalogic/flow/__init__.py +23 -0
- quantalogic/flow/flow.py +595 -0
- quantalogic/flow/flow_extractor.py +672 -0
- quantalogic/flow/flow_generator.py +89 -0
- quantalogic/flow/flow_manager.py +407 -0
- quantalogic/flow/flow_manager_schema.py +169 -0
- quantalogic/flow/flow_yaml.md +419 -0
- quantalogic/generative_model.py +109 -77
- quantalogic/get_model_info.py +6 -6
- quantalogic/interactive_text_editor.py +100 -73
- quantalogic/main.py +36 -23
- quantalogic/model_info_list.py +12 -0
- quantalogic/model_info_litellm.py +14 -14
- quantalogic/prompts.py +2 -1
- quantalogic/{llm.py → quantlitellm.py} +29 -39
- quantalogic/search_agent.py +4 -4
- quantalogic/server/models.py +4 -1
- quantalogic/task_file_reader.py +5 -5
- quantalogic/task_runner.py +21 -20
- quantalogic/tool_manager.py +10 -21
- quantalogic/tools/__init__.py +98 -68
- quantalogic/tools/composio/composio.py +416 -0
- quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
- quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
- quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
- quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
- quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
- quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
- quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
- quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
- quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
- quantalogic/tools/duckduckgo_search_tool.py +2 -4
- quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
- quantalogic/tools/finance/ccxt_tool.py +373 -0
- quantalogic/tools/finance/finance_llm_tool.py +387 -0
- quantalogic/tools/finance/google_finance.py +192 -0
- quantalogic/tools/finance/market_intelligence_tool.py +520 -0
- quantalogic/tools/finance/technical_analysis_tool.py +491 -0
- quantalogic/tools/finance/tradingview_tool.py +336 -0
- quantalogic/tools/finance/yahoo_finance.py +236 -0
- quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
- quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
- quantalogic/tools/git/clone_repo_tool.py +189 -0
- quantalogic/tools/git/git_operations_tool.py +532 -0
- quantalogic/tools/google_packages/google_news_tool.py +480 -0
- quantalogic/tools/grep_app_tool.py +123 -186
- quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
- quantalogic/tools/jinja_tool.py +6 -10
- quantalogic/tools/language_handlers/__init__.py +22 -9
- quantalogic/tools/list_directory_tool.py +131 -42
- quantalogic/tools/llm_tool.py +45 -15
- quantalogic/tools/llm_vision_tool.py +59 -7
- quantalogic/tools/markitdown_tool.py +17 -5
- quantalogic/tools/nasa_packages/models.py +47 -0
- quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
- quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
- quantalogic/tools/nasa_packages/services.py +82 -0
- quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
- quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
- quantalogic/tools/product_hunt/services.py +63 -0
- quantalogic/tools/rag_tool/__init__.py +48 -0
- quantalogic/tools/rag_tool/document_metadata.py +15 -0
- quantalogic/tools/rag_tool/query_response.py +20 -0
- quantalogic/tools/rag_tool/rag_tool.py +566 -0
- quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
- quantalogic/tools/read_html_tool.py +24 -38
- quantalogic/tools/replace_in_file_tool.py +10 -10
- quantalogic/tools/safe_python_interpreter_tool.py +10 -24
- quantalogic/tools/search_definition_names.py +2 -2
- quantalogic/tools/sequence_tool.py +14 -23
- quantalogic/tools/sql_query_tool.py +17 -19
- quantalogic/tools/tool.py +39 -15
- quantalogic/tools/unified_diff_tool.py +1 -1
- quantalogic/tools/utilities/csv_processor_tool.py +234 -0
- quantalogic/tools/utilities/download_file_tool.py +179 -0
- quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
- quantalogic/tools/utils/__init__.py +1 -4
- quantalogic/tools/utils/create_sample_database.py +24 -38
- quantalogic/tools/utils/generate_database_report.py +74 -82
- quantalogic/tools/wikipedia_search_tool.py +17 -21
- quantalogic/utils/ask_user_validation.py +1 -1
- quantalogic/utils/async_utils.py +35 -0
- quantalogic/utils/check_version.py +3 -5
- quantalogic/utils/get_all_models.py +2 -1
- quantalogic/utils/git_ls.py +21 -7
- quantalogic/utils/lm_studio_model_info.py +9 -7
- quantalogic/utils/python_interpreter.py +113 -43
- quantalogic/utils/xml_utility.py +178 -0
- quantalogic/version_check.py +1 -1
- quantalogic/welcome_message.py +7 -7
- quantalogic/xml_parser.py +0 -1
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/METADATA +44 -1
- quantalogic-0.40.0.dist-info/RECORD +148 -0
- quantalogic-0.33.4.dist-info/RECORD +0 -102
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
- {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,319 @@
|
|
1
|
+
"""Tool for converting markdown content to well-structured PowerPoint presentations.
|
2
|
+
|
3
|
+
Why this tool:
|
4
|
+
- Provides a standardized way to convert markdown to professional PPTX presentations
|
5
|
+
- Maintains consistent styling and formatting across slides
|
6
|
+
- Handles complex elements like diagrams, code blocks, and images
|
7
|
+
- Supports customization through templates and style configurations
|
8
|
+
"""
|
9
|
+
|
10
|
+
import json
|
11
|
+
import os
|
12
|
+
from pathlib import Path
|
13
|
+
from typing import Any, Dict, List, Optional, Union
|
14
|
+
|
15
|
+
import markdown
|
16
|
+
from bs4 import BeautifulSoup
|
17
|
+
from loguru import logger
|
18
|
+
from pptx import Presentation
|
19
|
+
from pptx.dml.color import RGBColor
|
20
|
+
from pptx.util import Inches, Pt
|
21
|
+
|
22
|
+
from quantalogic.tools.tool import Tool, ToolArgument
|
23
|
+
|
24
|
+
|
25
|
+
class MarkdownToPptxTool(Tool):
|
26
|
+
"""Converts markdown to professional PowerPoint presentations with advanced formatting."""
|
27
|
+
|
28
|
+
model_config = {
|
29
|
+
"arbitrary_types_allowed": True
|
30
|
+
}
|
31
|
+
|
32
|
+
name: str = "markdown_to_pptx_tool"
|
33
|
+
description: str = (
|
34
|
+
"Converts markdown to PPTX with support for images, Mermaid diagrams, "
|
35
|
+
"code blocks, and advanced slide formatting."
|
36
|
+
)
|
37
|
+
need_validation: bool = False
|
38
|
+
|
39
|
+
arguments: List[ToolArgument] = [
|
40
|
+
ToolArgument(
|
41
|
+
name="markdown_content",
|
42
|
+
arg_type="string",
|
43
|
+
description="Markdown content where slides are separated by '---'. Supports headers, bullet points, numbered lists, bold/italic text, code blocks, and Mermaid diagrams.",
|
44
|
+
required=True,
|
45
|
+
example='''# Project Overview
|
46
|
+
Quarterly Update Q1 2024
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
# Key Achievements
|
51
|
+
- **Revenue Growth**: 25% YoY increase
|
52
|
+
- **New Features**:
|
53
|
+
- AI-powered recommendations
|
54
|
+
- Real-time analytics
|
55
|
+
- **Customer Satisfaction**: 4.8/5
|
56
|
+
|
57
|
+
---
|
58
|
+
|
59
|
+
# Technical Architecture
|
60
|
+
```mermaid
|
61
|
+
graph TD
|
62
|
+
A[Frontend] --> B[API Gateway]
|
63
|
+
B --> C[Microservices]
|
64
|
+
C --> D[Database]
|
65
|
+
```
|
66
|
+
|
67
|
+
---
|
68
|
+
|
69
|
+
# Next Steps
|
70
|
+
1. Launch mobile app
|
71
|
+
2. Expand to new markets
|
72
|
+
3. Enhance AI capabilities
|
73
|
+
|
74
|
+
---
|
75
|
+
|
76
|
+
# Questions?
|
77
|
+
Thank you for your attention!
|
78
|
+
''',
|
79
|
+
),
|
80
|
+
ToolArgument(
|
81
|
+
name="output_path",
|
82
|
+
arg_type="string",
|
83
|
+
description="Path for saving the PPTX file",
|
84
|
+
required=True,
|
85
|
+
example="/path/to/output.pptx",
|
86
|
+
),
|
87
|
+
ToolArgument(
|
88
|
+
name="template_path",
|
89
|
+
arg_type="string",
|
90
|
+
description="Optional PPTX template path",
|
91
|
+
required=False,
|
92
|
+
example="/path/to/template.pptx",
|
93
|
+
),
|
94
|
+
ToolArgument(
|
95
|
+
name="style_config",
|
96
|
+
arg_type="string",
|
97
|
+
description="JSON string with style settings (fonts, colors, sizes)",
|
98
|
+
required=False,
|
99
|
+
example='{"font_name": "Calibri", "title_size": 44, "body_size": 24}',
|
100
|
+
),
|
101
|
+
]
|
102
|
+
|
103
|
+
# Default style configuration
|
104
|
+
DEFAULT_STYLES: Dict[str, Union[str, int, List[int]]] = {
|
105
|
+
"font_name": "Calibri",
|
106
|
+
"title_size": 44,
|
107
|
+
"body_size": 24,
|
108
|
+
"code_size": 18,
|
109
|
+
"code_font": "Consolas",
|
110
|
+
"primary_color": [0, 112, 192],
|
111
|
+
"secondary_color": [68, 114, 196],
|
112
|
+
"text_color": [0, 0, 0],
|
113
|
+
}
|
114
|
+
|
115
|
+
def _normalize_path(self, path: str) -> Path:
|
116
|
+
"""Convert path string to normalized Path object."""
|
117
|
+
if path.startswith("~"):
|
118
|
+
path = os.path.expanduser(path)
|
119
|
+
return Path(path).resolve()
|
120
|
+
|
121
|
+
def _parse_style_config(self, style_config: Optional[str]) -> Dict:
|
122
|
+
"""Parse and validate style configuration."""
|
123
|
+
try:
|
124
|
+
if not style_config:
|
125
|
+
return self.DEFAULT_STYLES.copy()
|
126
|
+
|
127
|
+
custom_styles = json.loads(style_config)
|
128
|
+
styles = self.DEFAULT_STYLES.copy()
|
129
|
+
styles.update(custom_styles)
|
130
|
+
return styles
|
131
|
+
except json.JSONDecodeError as e:
|
132
|
+
logger.error(f"Invalid style configuration JSON: {e}")
|
133
|
+
return self.DEFAULT_STYLES.copy()
|
134
|
+
|
135
|
+
def _create_presentation(self, template_path: Optional[str] = None) -> Presentation:
|
136
|
+
"""Create a new presentation, optionally from a template."""
|
137
|
+
if template_path:
|
138
|
+
template_path = self._normalize_path(template_path)
|
139
|
+
if not template_path.exists():
|
140
|
+
logger.warning(f"Template not found: {template_path}. Using default template.")
|
141
|
+
return Presentation()
|
142
|
+
return Presentation(template_path)
|
143
|
+
return Presentation()
|
144
|
+
|
145
|
+
def _apply_text_style(self, paragraph, font_name: str, font_size: int, color: List[int]):
|
146
|
+
"""Apply text styling to a paragraph."""
|
147
|
+
run = paragraph.runs[0] if paragraph.runs else paragraph.add_run()
|
148
|
+
font = run.font
|
149
|
+
font.name = font_name
|
150
|
+
font.size = Pt(font_size)
|
151
|
+
font.color.rgb = RGBColor(*color)
|
152
|
+
|
153
|
+
def _add_title_slide(self, prs: Presentation, title: str, subtitle: Optional[str] = None):
|
154
|
+
"""Add a title slide to the presentation."""
|
155
|
+
layout = prs.slide_layouts[0] # Title slide layout
|
156
|
+
slide = prs.slides.add_slide(layout)
|
157
|
+
|
158
|
+
# Add title
|
159
|
+
if slide.shapes.title:
|
160
|
+
title_shape = slide.shapes.title
|
161
|
+
title_shape.text = title
|
162
|
+
|
163
|
+
# Add subtitle if it exists and there's a subtitle placeholder
|
164
|
+
if subtitle:
|
165
|
+
try:
|
166
|
+
subtitle_shape = slide.placeholders[1] # Index 1 is typically the subtitle placeholder
|
167
|
+
subtitle_shape.text = subtitle
|
168
|
+
except (KeyError, IndexError):
|
169
|
+
logger.warning("No subtitle placeholder found in the slide layout")
|
170
|
+
|
171
|
+
def _add_content_slide(self, prs: Presentation, title: str, content: str, styles: Dict):
|
172
|
+
"""Add a content slide with formatted text and elements."""
|
173
|
+
layout = prs.slide_layouts[1] # Content slide layout
|
174
|
+
slide = prs.slides.add_slide(layout)
|
175
|
+
|
176
|
+
# Add title if title placeholder exists
|
177
|
+
if slide.shapes.title:
|
178
|
+
title_shape = slide.shapes.title
|
179
|
+
title_shape.text = title
|
180
|
+
self._apply_text_style(
|
181
|
+
title_shape.text_frame.paragraphs[0],
|
182
|
+
styles["font_name"],
|
183
|
+
styles["title_size"],
|
184
|
+
styles["primary_color"]
|
185
|
+
)
|
186
|
+
|
187
|
+
try:
|
188
|
+
# Get content placeholder
|
189
|
+
content_shape = slide.placeholders[1]
|
190
|
+
tf = content_shape.text_frame
|
191
|
+
tf.clear() # Clear existing content
|
192
|
+
|
193
|
+
# Convert markdown to HTML for better parsing
|
194
|
+
html_content = markdown.markdown(content)
|
195
|
+
soup = BeautifulSoup(html_content, 'html.parser')
|
196
|
+
|
197
|
+
# Process content
|
198
|
+
for element in soup.children:
|
199
|
+
if isinstance(element, str):
|
200
|
+
continue
|
201
|
+
|
202
|
+
if element.name == 'ul':
|
203
|
+
# Handle bullet points
|
204
|
+
for li in element.find_all('li'):
|
205
|
+
p = tf.add_paragraph()
|
206
|
+
p.level = 0
|
207
|
+
p.text = li.get_text().strip()
|
208
|
+
self._apply_text_style(p, styles["font_name"], styles["body_size"], styles["text_color"])
|
209
|
+
elif element.name == 'p':
|
210
|
+
# Handle paragraphs
|
211
|
+
p = tf.add_paragraph()
|
212
|
+
p.text = element.get_text().strip()
|
213
|
+
self._apply_text_style(p, styles["font_name"], styles["body_size"], styles["text_color"])
|
214
|
+
|
215
|
+
except (KeyError, IndexError) as e:
|
216
|
+
logger.warning(f"Error adding content to slide: {str(e)}")
|
217
|
+
# Fallback to basic text box if no content placeholder
|
218
|
+
left = Inches(1)
|
219
|
+
top = Inches(2)
|
220
|
+
width = Inches(8)
|
221
|
+
height = Inches(5)
|
222
|
+
txBox = slide.shapes.add_textbox(left, top, width, height)
|
223
|
+
tf = txBox.text_frame
|
224
|
+
p = tf.add_paragraph()
|
225
|
+
p.text = content
|
226
|
+
self._apply_text_style(p, styles["font_name"], styles["body_size"], styles["text_color"])
|
227
|
+
|
228
|
+
def execute(self, **kwargs) -> Dict:
|
229
|
+
"""Convert markdown content to a PowerPoint presentation."""
|
230
|
+
try:
|
231
|
+
markdown_content = kwargs.get("markdown_content")
|
232
|
+
output_path = kwargs.get("output_path")
|
233
|
+
template_path = kwargs.get("template_path")
|
234
|
+
style_config = kwargs.get("style_config")
|
235
|
+
|
236
|
+
if not markdown_content or not output_path:
|
237
|
+
raise ValueError("markdown_content and output_path are required")
|
238
|
+
|
239
|
+
# Parse style configuration
|
240
|
+
styles = self._parse_style_config(style_config)
|
241
|
+
|
242
|
+
# Create presentation
|
243
|
+
prs = self._create_presentation(template_path)
|
244
|
+
|
245
|
+
# Split content into slides
|
246
|
+
slides = markdown_content.split("---")
|
247
|
+
|
248
|
+
# Process each slide
|
249
|
+
for i, slide_content in enumerate(slides):
|
250
|
+
if not slide_content.strip():
|
251
|
+
continue
|
252
|
+
|
253
|
+
# Parse slide content
|
254
|
+
lines = slide_content.strip().split("\n")
|
255
|
+
title = lines[0].lstrip("#").strip() if lines else "Untitled Slide"
|
256
|
+
content = "\n".join(lines[1:]).strip()
|
257
|
+
|
258
|
+
if i == 0:
|
259
|
+
# First slide is title slide
|
260
|
+
subtitle = content if content else None
|
261
|
+
self._add_title_slide(prs, title, subtitle)
|
262
|
+
else:
|
263
|
+
self._add_content_slide(prs, title, content, styles)
|
264
|
+
|
265
|
+
# Save presentation
|
266
|
+
output_path = self._normalize_path(output_path)
|
267
|
+
prs.save(str(output_path))
|
268
|
+
|
269
|
+
return {
|
270
|
+
"status": "success",
|
271
|
+
"message": f"Presentation saved to {output_path}",
|
272
|
+
"output_path": str(output_path)
|
273
|
+
}
|
274
|
+
|
275
|
+
except Exception as e:
|
276
|
+
logger.error(f"Error creating presentation: {str(e)}")
|
277
|
+
return {
|
278
|
+
"status": "error",
|
279
|
+
"message": str(e)
|
280
|
+
}
|
281
|
+
|
282
|
+
|
283
|
+
if __name__ == "__main__":
|
284
|
+
# Example usage with error handling
|
285
|
+
try:
|
286
|
+
tool = MarkdownToPptxTool()
|
287
|
+
|
288
|
+
# Example markdown content
|
289
|
+
markdown_content = """
|
290
|
+
# Project Overview
|
291
|
+
Quarterly Update Q1 2024
|
292
|
+
|
293
|
+
---
|
294
|
+
|
295
|
+
# Key Achievements
|
296
|
+
|
297
|
+
- Launched new product features
|
298
|
+
- Increased user engagement by 25%
|
299
|
+
- Improved system performance
|
300
|
+
|
301
|
+
---
|
302
|
+
|
303
|
+
# Next Steps
|
304
|
+
|
305
|
+
1. Scale infrastructure
|
306
|
+
2. Release mobile app
|
307
|
+
3. Expand market reach
|
308
|
+
"""
|
309
|
+
|
310
|
+
result = tool.execute(
|
311
|
+
markdown_content=markdown_content,
|
312
|
+
output_path="presentation.pptx",
|
313
|
+
style_config='{"primary_color": [44, 85, 169]}'
|
314
|
+
)
|
315
|
+
|
316
|
+
print(result)
|
317
|
+
|
318
|
+
except Exception as e:
|
319
|
+
logger.error(f"Example usage failed: {e}")
|
@@ -33,10 +33,7 @@ class DuckDuckGoSearchTool(Tool):
|
|
33
33
|
"""
|
34
34
|
|
35
35
|
name: str = "duckduckgo_tool"
|
36
|
-
description: str =
|
37
|
-
"Retrieves search results from DuckDuckGo. "
|
38
|
-
"Provides structured output of search results."
|
39
|
-
)
|
36
|
+
description: str = "Retrieves search results from DuckDuckGo. " "Provides structured output of search results."
|
40
37
|
arguments: list = [
|
41
38
|
ToolArgument(
|
42
39
|
name="query",
|
@@ -183,6 +180,7 @@ class DuckDuckGoSearchTool(Tool):
|
|
183
180
|
|
184
181
|
# Return pretty-printed JSON
|
185
182
|
import json
|
183
|
+
|
186
184
|
return json.dumps(results, indent=4, ensure_ascii=False)
|
187
185
|
|
188
186
|
except Exception as e:
|