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.
Files changed (107) hide show
  1. quantalogic/__init__.py +0 -4
  2. quantalogic/agent.py +603 -362
  3. quantalogic/agent_config.py +260 -28
  4. quantalogic/agent_factory.py +43 -17
  5. quantalogic/coding_agent.py +20 -12
  6. quantalogic/config.py +7 -4
  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 +6 -6
  20. quantalogic/interactive_text_editor.py +100 -73
  21. quantalogic/main.py +36 -23
  22. quantalogic/model_info_list.py +12 -0
  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 +21 -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.33.4.dist-info → quantalogic-0.40.0.dist-info}/METADATA +44 -1
  103. quantalogic-0.40.0.dist-info/RECORD +148 -0
  104. quantalogic-0.33.4.dist-info/RECORD +0 -102
  105. {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/LICENSE +0 -0
  106. {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/WHEEL +0 -0
  107. {quantalogic-0.33.4.dist-info → quantalogic-0.40.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,438 @@
1
+ """Tool for converting markdown content to well-structured ePub documents.
2
+
3
+ Why this tool:
4
+ - Provides a standardized way to convert markdown to professional ePub books
5
+ - Supports rich formatting and interactive elements
6
+ - Creates responsive e-books that work on all devices
7
+ - Handles chapters, table of contents, and metadata
8
+ - Includes support for custom styling and themes
9
+ """
10
+
11
+ import json
12
+ import os
13
+ import tempfile
14
+ import uuid
15
+ from pathlib import Path
16
+ from typing import ClassVar, Dict, List, Optional
17
+
18
+ import markdown
19
+ import mermaid
20
+ from bs4 import BeautifulSoup
21
+ from ebooklib import epub
22
+ from loguru import logger
23
+
24
+ from quantalogic.tools.tool import Tool, ToolArgument
25
+
26
+
27
+ class MarkdownToEpubTool(Tool):
28
+ """Converts markdown to professional EPUB documents with advanced formatting."""
29
+
30
+ model_config = {
31
+ "arbitrary_types_allowed": True
32
+ }
33
+
34
+ name: str = "markdown_to_epub_tool"
35
+ description: str = (
36
+ "Converts markdown to EPUB with support for images, Mermaid diagrams, "
37
+ "code blocks, tables, and advanced styling."
38
+ )
39
+ need_validation: bool = False
40
+
41
+ arguments: List[ToolArgument] = [
42
+ ToolArgument(
43
+ name="markdown_content",
44
+ arg_type="string",
45
+ description="Markdown content with optional chapter separators (---)",
46
+ required=True,
47
+ example="# Book Title\n\n## Chapter 1\n\nContent...\n\n---\n\n## Chapter 2\n\nMore content...",
48
+ ),
49
+ ToolArgument(
50
+ name="output_path",
51
+ arg_type="string",
52
+ description="Path for saving the EPUB file",
53
+ required=True,
54
+ example="/path/to/output.epub",
55
+ ),
56
+ ToolArgument(
57
+ name="metadata",
58
+ arg_type="string",
59
+ description="JSON string with book metadata",
60
+ required=False,
61
+ example='{"title": "My Book", "author": "John Doe", "language": "en"}',
62
+ ),
63
+ ToolArgument(
64
+ name="cover_image",
65
+ arg_type="string",
66
+ description="Path to cover image file",
67
+ required=False,
68
+ example="path/to/cover.jpg",
69
+ ),
70
+ ToolArgument(
71
+ name="style_config",
72
+ arg_type="string",
73
+ description="JSON string with style settings",
74
+ required=False,
75
+ example='{"theme": "light", "font_family": "Literata"}',
76
+ ),
77
+ ]
78
+
79
+ # Default style configuration
80
+ DEFAULT_CSS: ClassVar[str] = """
81
+ @import url('https://fonts.googleapis.com/css2?family=Literata:ital,wght@0,400;0,600;1,400&family=Source+Code+Pro&display=swap');
82
+
83
+ :root {
84
+ color-scheme: %(theme)s;
85
+ }
86
+
87
+ body {
88
+ font-family: %(font_family)s;
89
+ line-height: %(line_height)s;
90
+ color: %(text_color)s;
91
+ background-color: %(background_color)s;
92
+ margin: 0 auto;
93
+ max-width: %(max_width)s;
94
+ padding: 1em;
95
+ }
96
+
97
+ h1, h2, h3, h4, h5, h6 {
98
+ font-family: %(heading_font)s;
99
+ color: %(heading_color)s;
100
+ margin-top: 1.5em;
101
+ margin-bottom: 0.5em;
102
+ }
103
+
104
+ a {
105
+ color: %(link_color)s;
106
+ text-decoration: none;
107
+ }
108
+
109
+ pre, code {
110
+ font-family: %(code_font)s;
111
+ background-color: #f6f8fa;
112
+ border-radius: 3px;
113
+ font-size: 0.9em;
114
+ }
115
+
116
+ pre {
117
+ padding: 1em;
118
+ overflow-x: auto;
119
+ line-height: 1.45;
120
+ }
121
+
122
+ code {
123
+ padding: 0.2em 0.4em;
124
+ }
125
+
126
+ img {
127
+ max-width: 100%%;
128
+ height: auto;
129
+ display: block;
130
+ margin: 1em auto;
131
+ }
132
+
133
+ blockquote {
134
+ margin: 1em 0;
135
+ padding-left: 1em;
136
+ border-left: 4px solid %(link_color)s;
137
+ color: #666666;
138
+ }
139
+
140
+ table {
141
+ width: 100%%;
142
+ border-collapse: collapse;
143
+ margin: 1em 0;
144
+ }
145
+
146
+ th, td {
147
+ border: 1px solid #ddd;
148
+ padding: 8px;
149
+ text-align: left;
150
+ }
151
+
152
+ th {
153
+ background-color: #f6f8fa;
154
+ }
155
+
156
+ .chapter-title {
157
+ text-align: center;
158
+ margin-top: 3em;
159
+ margin-bottom: 2em;
160
+ }
161
+
162
+ .chapter {
163
+ break-before: page;
164
+ }
165
+
166
+ @media (prefers-color-scheme: dark) {
167
+ body {
168
+ background-color: #1a1a1a;
169
+ color: #e6e6e6;
170
+ }
171
+
172
+ pre, code {
173
+ background-color: #2d2d2d;
174
+ }
175
+
176
+ th {
177
+ background-color: #2d2d2d;
178
+ }
179
+
180
+ blockquote {
181
+ color: #b3b3b3;
182
+ }
183
+ }
184
+ """
185
+
186
+ DEFAULT_STYLES: ClassVar[Dict[str, str]] = {
187
+ "theme": "light",
188
+ "font_family": "'Literata', Georgia, serif",
189
+ "heading_font": "'Literata', Georgia, serif",
190
+ "code_font": "'Source Code Pro', monospace",
191
+ "line_height": "1.6",
192
+ "max_width": "45em",
193
+ "text_color": "#333333",
194
+ "heading_color": "#222222",
195
+ "link_color": "#0366d6",
196
+ "background_color": "#ffffff"
197
+ }
198
+
199
+ def _normalize_path(self, path: str) -> Path:
200
+ """Convert path string to normalized Path object."""
201
+ if path.startswith("~"):
202
+ path = os.path.expanduser(path)
203
+ return Path(path).resolve()
204
+
205
+ def _parse_style_config(self, style_config: Optional[str]) -> Dict[str, str]:
206
+ """Parse and validate style configuration."""
207
+ try:
208
+ if not style_config:
209
+ return self.DEFAULT_STYLES.copy()
210
+
211
+ custom_styles = json.loads(style_config)
212
+ styles = self.DEFAULT_STYLES.copy()
213
+ styles.update(custom_styles)
214
+ return styles
215
+ except json.JSONDecodeError as e:
216
+ logger.error(f"Invalid style configuration JSON: {e}")
217
+ return self.DEFAULT_STYLES.copy()
218
+
219
+ def _process_mermaid_diagrams(self, html_content: str, temp_dir: Path) -> str:
220
+ """Convert Mermaid diagram code blocks to SVG images."""
221
+ soup = BeautifulSoup(html_content, 'html.parser')
222
+ mermaid_blocks = soup.find_all('code', class_='language-mermaid')
223
+
224
+ for block in mermaid_blocks:
225
+ try:
226
+ diagram = mermaid.generate_diagram(block.text)
227
+ img_name = f"diagram_{hash(block.text)}.svg"
228
+ img_path = temp_dir / img_name
229
+
230
+ with open(img_path, 'wb') as f:
231
+ f.write(diagram)
232
+
233
+ img_tag = soup.new_tag('img')
234
+ img_tag['src'] = img_name
235
+ img_tag['alt'] = 'Diagram'
236
+ block.parent.replace_with(img_tag)
237
+ except Exception as e:
238
+ logger.error(f"Error processing Mermaid diagram: {e}")
239
+
240
+ return str(soup)
241
+
242
+ def _split_chapters(self, content: str) -> List[Dict[str, str]]:
243
+ """Split markdown content into chapters."""
244
+ chapters = []
245
+ current_chapter = []
246
+ current_title = "Untitled Chapter"
247
+
248
+ for line in content.split('\n'):
249
+ if line.strip() == '---':
250
+ if current_chapter:
251
+ chapters.append({
252
+ 'title': current_title,
253
+ 'content': '\n'.join(current_chapter)
254
+ })
255
+ current_chapter = []
256
+ current_title = "Untitled Chapter"
257
+ else:
258
+ if line.startswith('# '):
259
+ current_title = line[2:].strip()
260
+ current_chapter.append(line)
261
+
262
+ if current_chapter:
263
+ chapters.append({
264
+ 'title': current_title,
265
+ 'content': '\n'.join(current_chapter)
266
+ })
267
+
268
+ return chapters
269
+
270
+ def _create_nav_page(self, chapters: List[Dict[str, str]]) -> epub.EpubHtml:
271
+ """Create table of contents navigation page."""
272
+ content = """
273
+ <h1>Table of Contents</h1>
274
+ <nav epub:type="toc">
275
+ <ol>
276
+ """
277
+
278
+ for i, chapter in enumerate(chapters, 1):
279
+ content += f'<li><a href="chapter_{i}.xhtml">{chapter["title"]}</a></li>'
280
+
281
+ content += """
282
+ </ol>
283
+ </nav>
284
+ """
285
+
286
+ nav = epub.EpubHtml(
287
+ title='Table of Contents',
288
+ file_name='nav.xhtml',
289
+ content=content
290
+ )
291
+ return nav
292
+
293
+ def execute(self, **kwargs) -> str:
294
+ """Execute the markdown to EPUB conversion.
295
+
296
+ Args:
297
+ **kwargs: Tool arguments including markdown_content, output_path,
298
+ metadata, cover_image, and style_config
299
+
300
+ Returns:
301
+ Success message with output path
302
+ """
303
+ try:
304
+ markdown_content = kwargs['markdown_content']
305
+ output_path = self._normalize_path(kwargs['output_path'])
306
+ metadata = json.loads(kwargs.get('metadata', '{}'))
307
+ cover_image = kwargs.get('cover_image')
308
+ style_config = kwargs.get('style_config')
309
+
310
+ # Create output directory
311
+ output_path.parent.mkdir(parents=True, exist_ok=True)
312
+
313
+ # Create temporary directory for assets
314
+ with tempfile.TemporaryDirectory() as temp_dir:
315
+ temp_path = Path(temp_dir)
316
+
317
+ # Initialize EPUB book
318
+ book = epub.EpubBook()
319
+
320
+ # Set metadata
321
+ book.set_identifier(str(uuid.uuid4()))
322
+ book.set_title(metadata.get('title', 'Untitled'))
323
+ book.set_language(metadata.get('language', 'en'))
324
+ book.add_author(metadata.get('author', 'Unknown'))
325
+ book.set_cover('cover.jpg', open(cover_image, 'rb').read()) if cover_image else None
326
+
327
+ # Parse style configuration
328
+ styles = self._parse_style_config(style_config)
329
+ css_content = self.DEFAULT_CSS % styles
330
+
331
+ # Add CSS
332
+ style = epub.EpubItem(
333
+ uid="style",
334
+ file_name="style.css",
335
+ media_type="text/css",
336
+ content=css_content
337
+ )
338
+ book.add_item(style)
339
+
340
+ # Split content into chapters
341
+ chapters = self._split_chapters(markdown_content)
342
+ epub_chapters = []
343
+
344
+ # Process chapters
345
+ for i, chapter in enumerate(chapters, 1):
346
+ # Convert markdown to HTML
347
+ html_content = markdown.markdown(
348
+ chapter['content'],
349
+ extensions=['extra', 'codehilite', 'tables', 'fenced_code']
350
+ )
351
+
352
+ # Process Mermaid diagrams
353
+ html_content = self._process_mermaid_diagrams(html_content, temp_path)
354
+
355
+ # Create chapter
356
+ epub_chapter = epub.EpubHtml(
357
+ title=chapter['title'],
358
+ file_name=f'chapter_{i}.xhtml',
359
+ content=f'''
360
+ <h1 class="chapter-title">{chapter['title']}</h1>
361
+ <div class="chapter">
362
+ {html_content}
363
+ </div>
364
+ '''
365
+ )
366
+ epub_chapter.add_item(style)
367
+ book.add_item(epub_chapter)
368
+ epub_chapters.append(epub_chapter)
369
+
370
+ # Add navigation
371
+ book.toc = [(epub.Section(chapter['title']), [c])
372
+ for chapter, c in zip(chapters, epub_chapters)]
373
+
374
+ # Add navigation page
375
+ nav = self._create_nav_page(chapters)
376
+ book.add_item(nav)
377
+
378
+ # Basic spine
379
+ book.spine = ['nav'] + epub_chapters
380
+
381
+ # Add any images from temp directory
382
+ for img_path in temp_path.glob('*.svg'):
383
+ with open(img_path, 'rb') as f:
384
+ epub_image = epub.EpubItem(
385
+ uid=f"image_{img_path.stem}",
386
+ file_name=img_path.name,
387
+ media_type="image/svg+xml",
388
+ content=f.read()
389
+ )
390
+ book.add_item(epub_image)
391
+
392
+ # Write EPUB file
393
+ epub.write_epub(str(output_path), book, {})
394
+
395
+ return f"Successfully created EPUB at: {output_path}"
396
+
397
+ except Exception as e:
398
+ error_msg = f"Error converting markdown to EPUB: {str(e)}"
399
+ logger.error(error_msg)
400
+ raise RuntimeError(error_msg)
401
+
402
+
403
+ if __name__ == "__main__":
404
+ # Example usage with error handling
405
+ try:
406
+ tool = MarkdownToEpubTool()
407
+ result = tool.execute(
408
+ markdown_content="""
409
+ # My Book
410
+
411
+ ## Chapter 1: Introduction
412
+
413
+ This is the first chapter with some **bold** text and a diagram:
414
+
415
+ ```mermaid
416
+ graph TD
417
+ A[Start] --> B[Process]
418
+ B --> C[End]
419
+ ```
420
+
421
+ ---
422
+
423
+ ## Chapter 2: Development
424
+
425
+ This is the second chapter with a code block:
426
+
427
+ ```python
428
+ def hello():
429
+ print("Hello, World!")
430
+ ```
431
+ """,
432
+ output_path="my_book.epub",
433
+ metadata='{"title": "My Book", "author": "John Doe"}',
434
+ style_config='{"theme": "light", "font_family": "Literata"}'
435
+ )
436
+ print(result)
437
+ except Exception as e:
438
+ print(f"Error: {e}")