quantalogic 0.35.0__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.
Files changed (107) hide show
  1. quantalogic/__init__.py +0 -4
  2. quantalogic/agent.py +603 -363
  3. quantalogic/agent_config.py +233 -46
  4. quantalogic/agent_factory.py +34 -22
  5. quantalogic/coding_agent.py +16 -14
  6. quantalogic/config.py +2 -1
  7. quantalogic/console_print_events.py +4 -8
  8. quantalogic/console_print_token.py +2 -2
  9. quantalogic/docs_cli.py +15 -10
  10. quantalogic/event_emitter.py +258 -83
  11. quantalogic/flow/__init__.py +23 -0
  12. quantalogic/flow/flow.py +595 -0
  13. quantalogic/flow/flow_extractor.py +672 -0
  14. quantalogic/flow/flow_generator.py +89 -0
  15. quantalogic/flow/flow_manager.py +407 -0
  16. quantalogic/flow/flow_manager_schema.py +169 -0
  17. quantalogic/flow/flow_yaml.md +419 -0
  18. quantalogic/generative_model.py +109 -77
  19. quantalogic/get_model_info.py +5 -5
  20. quantalogic/interactive_text_editor.py +100 -73
  21. quantalogic/main.py +17 -21
  22. quantalogic/model_info_list.py +3 -3
  23. quantalogic/model_info_litellm.py +14 -14
  24. quantalogic/prompts.py +2 -1
  25. quantalogic/{llm.py → quantlitellm.py} +29 -39
  26. quantalogic/search_agent.py +4 -4
  27. quantalogic/server/models.py +4 -1
  28. quantalogic/task_file_reader.py +5 -5
  29. quantalogic/task_runner.py +20 -20
  30. quantalogic/tool_manager.py +10 -21
  31. quantalogic/tools/__init__.py +98 -68
  32. quantalogic/tools/composio/composio.py +416 -0
  33. quantalogic/tools/{generate_database_report_tool.py → database/generate_database_report_tool.py} +4 -9
  34. quantalogic/tools/database/sql_query_tool_advanced.py +261 -0
  35. quantalogic/tools/document_tools/markdown_to_docx_tool.py +620 -0
  36. quantalogic/tools/document_tools/markdown_to_epub_tool.py +438 -0
  37. quantalogic/tools/document_tools/markdown_to_html_tool.py +362 -0
  38. quantalogic/tools/document_tools/markdown_to_ipynb_tool.py +319 -0
  39. quantalogic/tools/document_tools/markdown_to_latex_tool.py +420 -0
  40. quantalogic/tools/document_tools/markdown_to_pdf_tool.py +623 -0
  41. quantalogic/tools/document_tools/markdown_to_pptx_tool.py +319 -0
  42. quantalogic/tools/duckduckgo_search_tool.py +2 -4
  43. quantalogic/tools/finance/alpha_vantage_tool.py +440 -0
  44. quantalogic/tools/finance/ccxt_tool.py +373 -0
  45. quantalogic/tools/finance/finance_llm_tool.py +387 -0
  46. quantalogic/tools/finance/google_finance.py +192 -0
  47. quantalogic/tools/finance/market_intelligence_tool.py +520 -0
  48. quantalogic/tools/finance/technical_analysis_tool.py +491 -0
  49. quantalogic/tools/finance/tradingview_tool.py +336 -0
  50. quantalogic/tools/finance/yahoo_finance.py +236 -0
  51. quantalogic/tools/git/bitbucket_clone_repo_tool.py +181 -0
  52. quantalogic/tools/git/bitbucket_operations_tool.py +326 -0
  53. quantalogic/tools/git/clone_repo_tool.py +189 -0
  54. quantalogic/tools/git/git_operations_tool.py +532 -0
  55. quantalogic/tools/google_packages/google_news_tool.py +480 -0
  56. quantalogic/tools/grep_app_tool.py +123 -186
  57. quantalogic/tools/{dalle_e.py → image_generation/dalle_e.py} +37 -27
  58. quantalogic/tools/jinja_tool.py +6 -10
  59. quantalogic/tools/language_handlers/__init__.py +22 -9
  60. quantalogic/tools/list_directory_tool.py +131 -42
  61. quantalogic/tools/llm_tool.py +45 -15
  62. quantalogic/tools/llm_vision_tool.py +59 -7
  63. quantalogic/tools/markitdown_tool.py +17 -5
  64. quantalogic/tools/nasa_packages/models.py +47 -0
  65. quantalogic/tools/nasa_packages/nasa_apod_tool.py +232 -0
  66. quantalogic/tools/nasa_packages/nasa_neows_tool.py +147 -0
  67. quantalogic/tools/nasa_packages/services.py +82 -0
  68. quantalogic/tools/presentation_tools/presentation_llm_tool.py +396 -0
  69. quantalogic/tools/product_hunt/product_hunt_tool.py +258 -0
  70. quantalogic/tools/product_hunt/services.py +63 -0
  71. quantalogic/tools/rag_tool/__init__.py +48 -0
  72. quantalogic/tools/rag_tool/document_metadata.py +15 -0
  73. quantalogic/tools/rag_tool/query_response.py +20 -0
  74. quantalogic/tools/rag_tool/rag_tool.py +566 -0
  75. quantalogic/tools/rag_tool/rag_tool_beta.py +264 -0
  76. quantalogic/tools/read_html_tool.py +24 -38
  77. quantalogic/tools/replace_in_file_tool.py +10 -10
  78. quantalogic/tools/safe_python_interpreter_tool.py +10 -24
  79. quantalogic/tools/search_definition_names.py +2 -2
  80. quantalogic/tools/sequence_tool.py +14 -23
  81. quantalogic/tools/sql_query_tool.py +17 -19
  82. quantalogic/tools/tool.py +39 -15
  83. quantalogic/tools/unified_diff_tool.py +1 -1
  84. quantalogic/tools/utilities/csv_processor_tool.py +234 -0
  85. quantalogic/tools/utilities/download_file_tool.py +179 -0
  86. quantalogic/tools/utilities/mermaid_validator_tool.py +661 -0
  87. quantalogic/tools/utils/__init__.py +1 -4
  88. quantalogic/tools/utils/create_sample_database.py +24 -38
  89. quantalogic/tools/utils/generate_database_report.py +74 -82
  90. quantalogic/tools/wikipedia_search_tool.py +17 -21
  91. quantalogic/utils/ask_user_validation.py +1 -1
  92. quantalogic/utils/async_utils.py +35 -0
  93. quantalogic/utils/check_version.py +3 -5
  94. quantalogic/utils/get_all_models.py +2 -1
  95. quantalogic/utils/git_ls.py +21 -7
  96. quantalogic/utils/lm_studio_model_info.py +9 -7
  97. quantalogic/utils/python_interpreter.py +113 -43
  98. quantalogic/utils/xml_utility.py +178 -0
  99. quantalogic/version_check.py +1 -1
  100. quantalogic/welcome_message.py +7 -7
  101. quantalogic/xml_parser.py +0 -1
  102. {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/METADATA +41 -1
  103. quantalogic-0.40.0.dist-info/RECORD +148 -0
  104. quantalogic-0.35.0.dist-info/RECORD +0 -102
  105. {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
  106. {quantalogic-0.35.0.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
  107. {quantalogic-0.35.0.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: