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,420 @@
|
|
1
|
+
"""Tool for converting markdown content to well-structured LaTeX documents.
|
2
|
+
|
3
|
+
Why this tool:
|
4
|
+
- Provides a standardized way to convert markdown to professional LaTeX documents
|
5
|
+
- Supports mathematical equations and scientific content
|
6
|
+
- Handles citations, references, and bibliographies
|
7
|
+
- Maintains consistent academic formatting
|
8
|
+
- Supports custom document classes and packages
|
9
|
+
"""
|
10
|
+
|
11
|
+
import json
|
12
|
+
import os
|
13
|
+
import re
|
14
|
+
from pathlib import Path
|
15
|
+
from typing import Any, ClassVar, Dict, List, Optional, Union
|
16
|
+
|
17
|
+
import mermaid
|
18
|
+
from loguru import logger
|
19
|
+
|
20
|
+
from quantalogic.tools.tool import Tool, ToolArgument
|
21
|
+
|
22
|
+
|
23
|
+
class MarkdownToLatexTool(Tool):
|
24
|
+
"""Converts markdown to professional LaTeX documents with advanced formatting."""
|
25
|
+
|
26
|
+
model_config = {
|
27
|
+
"arbitrary_types_allowed": True
|
28
|
+
}
|
29
|
+
|
30
|
+
name: str = "markdown_to_latex_tool"
|
31
|
+
description: str = (
|
32
|
+
"Converts markdown to LaTeX with support for images, Mermaid diagrams, "
|
33
|
+
"code blocks, tables, and advanced formatting."
|
34
|
+
)
|
35
|
+
need_validation: bool = False
|
36
|
+
|
37
|
+
arguments: List[ToolArgument] = [
|
38
|
+
ToolArgument(
|
39
|
+
name="markdown_content",
|
40
|
+
arg_type="string",
|
41
|
+
description="Markdown content with support for LaTeX equations, citations, and academic formatting",
|
42
|
+
required=True,
|
43
|
+
example="# Title\n\nEquation: $E=mc^2$\n\nCite: [@einstein1905]",
|
44
|
+
),
|
45
|
+
ToolArgument(
|
46
|
+
name="output_path",
|
47
|
+
arg_type="string",
|
48
|
+
description="Path for saving the LaTeX file",
|
49
|
+
required=True,
|
50
|
+
example="/path/to/output.tex",
|
51
|
+
),
|
52
|
+
ToolArgument(
|
53
|
+
name="document_class",
|
54
|
+
arg_type="string",
|
55
|
+
description="LaTeX document class (article, report, book)",
|
56
|
+
required=False,
|
57
|
+
default="article",
|
58
|
+
),
|
59
|
+
ToolArgument(
|
60
|
+
name="bibliography_file",
|
61
|
+
arg_type="string",
|
62
|
+
description="Optional path to BibTeX file",
|
63
|
+
required=False,
|
64
|
+
example="path/to/references.bib",
|
65
|
+
),
|
66
|
+
ToolArgument(
|
67
|
+
name="style_config",
|
68
|
+
arg_type="string",
|
69
|
+
description="JSON string with style settings and packages",
|
70
|
+
required=False,
|
71
|
+
example='{"font_size": "12pt", "packages": ["amsmath", "graphicx"]}',
|
72
|
+
),
|
73
|
+
]
|
74
|
+
|
75
|
+
DOCUMENT_TEMPLATE: ClassVar[str] = r"""\documentclass[{font_size},{paper_size}]{article}
|
76
|
+
|
77
|
+
% Packages
|
78
|
+
{packages}
|
79
|
+
|
80
|
+
% Document settings
|
81
|
+
\usepackage[{margin}]{geometry}
|
82
|
+
\usepackage{{font_package}}
|
83
|
+
\usepackage[utf8]{inputenc}
|
84
|
+
\usepackage[T1]{fontenc}
|
85
|
+
|
86
|
+
% Hyperref settings
|
87
|
+
\hypersetup{
|
88
|
+
colorlinks=true,
|
89
|
+
linkcolor=blue,
|
90
|
+
filecolor=magenta,
|
91
|
+
urlcolor=cyan,
|
92
|
+
pdftitle={{title}}
|
93
|
+
}
|
94
|
+
|
95
|
+
\setlength{\parskip}{1em}
|
96
|
+
\renewcommand{\baselinestretch}{line_spacing}
|
97
|
+
|
98
|
+
{extra_preamble}
|
99
|
+
|
100
|
+
\begin{document}
|
101
|
+
|
102
|
+
{content}
|
103
|
+
|
104
|
+
{bibliography}
|
105
|
+
|
106
|
+
\end{document}
|
107
|
+
"""
|
108
|
+
|
109
|
+
DEFAULT_PACKAGES: ClassVar[List[str]] = [
|
110
|
+
"graphicx",
|
111
|
+
"hyperref",
|
112
|
+
"listings",
|
113
|
+
"xcolor",
|
114
|
+
"amsmath",
|
115
|
+
"amssymb",
|
116
|
+
"booktabs",
|
117
|
+
"float",
|
118
|
+
"caption",
|
119
|
+
"subcaption",
|
120
|
+
"fancyhdr",
|
121
|
+
"titlesec",
|
122
|
+
"enumitem",
|
123
|
+
"microtype",
|
124
|
+
]
|
125
|
+
|
126
|
+
DEFAULT_STYLES: ClassVar[Dict[str, Union[str, float, List[str]]]] = {
|
127
|
+
"font_size": "12pt",
|
128
|
+
"paper_size": "a4paper",
|
129
|
+
"margin": "margin=1in",
|
130
|
+
"font_package": "lmodern",
|
131
|
+
"line_spacing": 1.15,
|
132
|
+
"code_style": {
|
133
|
+
"basicstyle": r"\ttfamily\small",
|
134
|
+
"breaklines": "true",
|
135
|
+
"commentstyle": r"\color{gray}",
|
136
|
+
"keywordstyle": r"\color{blue}",
|
137
|
+
"stringstyle": r"\color{green!50!black}",
|
138
|
+
"numberstyle": r"\tiny\color{gray}",
|
139
|
+
"frame": "single",
|
140
|
+
"rulecolor": r"\color{black!30}",
|
141
|
+
"backgroundcolor": r"\color{gray!5}",
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
def _normalize_path(self, path: str) -> Path:
|
146
|
+
"""Convert path string to normalized Path object."""
|
147
|
+
if path.startswith("~"):
|
148
|
+
path = os.path.expanduser(path)
|
149
|
+
return Path(path).resolve()
|
150
|
+
|
151
|
+
def _parse_style_config(self, style_config: Optional[str]) -> Dict[str, Any]:
|
152
|
+
"""Parse and validate style configuration."""
|
153
|
+
try:
|
154
|
+
if not style_config:
|
155
|
+
return self.DEFAULT_STYLES.copy()
|
156
|
+
|
157
|
+
custom_styles = json.loads(style_config)
|
158
|
+
styles = self.DEFAULT_STYLES.copy()
|
159
|
+
styles.update(custom_styles)
|
160
|
+
return styles
|
161
|
+
except json.JSONDecodeError as e:
|
162
|
+
logger.error(f"Invalid style configuration JSON: {e}")
|
163
|
+
return self.DEFAULT_STYLES.copy()
|
164
|
+
|
165
|
+
def _escape_latex(self, text: str) -> str:
|
166
|
+
"""Escape special LaTeX characters."""
|
167
|
+
chars = {
|
168
|
+
'&': '\\&',
|
169
|
+
'%': '\\%',
|
170
|
+
'$': '\\$',
|
171
|
+
'#': '\\#',
|
172
|
+
'_': '\\_',
|
173
|
+
'{': '\\{',
|
174
|
+
'}': '\\}',
|
175
|
+
'~': '\\textasciitilde{}',
|
176
|
+
'^': '\\textasciicircum{}',
|
177
|
+
'\\': '\\textbackslash{}',
|
178
|
+
}
|
179
|
+
pattern = '|'.join(map(re.escape, chars.keys()))
|
180
|
+
return re.sub(pattern, lambda m: chars[m.group()], text)
|
181
|
+
|
182
|
+
def _convert_math(self, text: str) -> str:
|
183
|
+
"""Convert markdown math to LaTeX math."""
|
184
|
+
# Inline math
|
185
|
+
text = re.sub(r'\$([^$]+)\$', r'$\1$', text)
|
186
|
+
# Display math
|
187
|
+
text = re.sub(r'\$\$([^$]+)\$\$', r'\\[\1\\]', text)
|
188
|
+
return text
|
189
|
+
|
190
|
+
def _convert_code_blocks(self, text: str) -> str:
|
191
|
+
"""Convert markdown code blocks to LaTeX listings."""
|
192
|
+
def replace_code(match):
|
193
|
+
code = match.group(2)
|
194
|
+
lang = match.group(1) if match.group(1) else ''
|
195
|
+
return (
|
196
|
+
f"\\begin{{lstlisting}}[language={lang}, "
|
197
|
+
"basicstyle=\\ttfamily\\small, "
|
198
|
+
"breaklines=true, "
|
199
|
+
"commentstyle=\\color{gray}, "
|
200
|
+
"keywordstyle=\\color{blue}, "
|
201
|
+
"stringstyle=\\color{green}, "
|
202
|
+
"numbers=left, "
|
203
|
+
"frame=single]\n"
|
204
|
+
f"{code}\n"
|
205
|
+
"\\end{lstlisting}\n"
|
206
|
+
)
|
207
|
+
|
208
|
+
return re.sub(
|
209
|
+
r'```(\w+)?\n(.*?)\n```',
|
210
|
+
replace_code,
|
211
|
+
text,
|
212
|
+
flags=re.DOTALL
|
213
|
+
)
|
214
|
+
|
215
|
+
def _convert_tables(self, text: str) -> str:
|
216
|
+
"""Convert markdown tables to LaTeX tables."""
|
217
|
+
def convert_table(match):
|
218
|
+
lines = match.group(0).split('\n')
|
219
|
+
header = lines[0].strip('|').split('|')
|
220
|
+
alignment = lines[1].strip('|').split('|')
|
221
|
+
data = [line.strip('|').split('|') for line in lines[2:] if line.strip()]
|
222
|
+
|
223
|
+
# Determine column alignment
|
224
|
+
col_align = []
|
225
|
+
for col in alignment:
|
226
|
+
col = col.strip()
|
227
|
+
if col.startswith(':') and col.endswith(':'):
|
228
|
+
col_align.append('c')
|
229
|
+
elif col.endswith(':'):
|
230
|
+
col_align.append('r')
|
231
|
+
else:
|
232
|
+
col_align.append('l')
|
233
|
+
|
234
|
+
# Build LaTeX table
|
235
|
+
latex = "\\begin{table}[H]\n\\centering\n\\begin{tabular}"
|
236
|
+
latex += "{" + "".join(col_align) + "}\n"
|
237
|
+
latex += "\\toprule\n"
|
238
|
+
latex += " & ".join(h.strip() for h in header) + " \\\\\n"
|
239
|
+
latex += "\\midrule\n"
|
240
|
+
for row in data:
|
241
|
+
latex += " & ".join(cell.strip() for cell in row) + " \\\\\n"
|
242
|
+
latex += "\\bottomrule\n"
|
243
|
+
latex += "\\end{tabular}\n\\end{table}\n"
|
244
|
+
|
245
|
+
return latex
|
246
|
+
|
247
|
+
pattern = r'\|.+\|\n\|[-:| ]+\|\n(?:\|.+\|\n?)+'
|
248
|
+
return re.sub(pattern, convert_table, text)
|
249
|
+
|
250
|
+
def _process_citations(self, text: str, bib_file: Optional[Path]) -> tuple[str, bool]:
|
251
|
+
"""Process markdown citations and return updated text and citation flag."""
|
252
|
+
has_citations = False
|
253
|
+
|
254
|
+
if bib_file and bib_file.exists():
|
255
|
+
# Convert [@citation] to \cite{citation}
|
256
|
+
text = re.sub(r'\[@([^\]]+)\]', r'\\cite{\1}', text)
|
257
|
+
has_citations = bool(re.search(r'\\cite{', text))
|
258
|
+
|
259
|
+
return text, has_citations
|
260
|
+
|
261
|
+
def _process_mermaid_diagrams(self, text: str, output_dir: Path) -> str:
|
262
|
+
"""Convert Mermaid diagrams to TikZ or image figures."""
|
263
|
+
def replace_mermaid(match):
|
264
|
+
try:
|
265
|
+
diagram = mermaid.generate_diagram(match.group(1))
|
266
|
+
img_path = output_dir / f"diagram_{hash(match.group(1))}.pdf"
|
267
|
+
|
268
|
+
# Save diagram as PDF
|
269
|
+
with open(img_path, 'wb') as f:
|
270
|
+
f.write(diagram)
|
271
|
+
|
272
|
+
return (
|
273
|
+
"\\begin{figure}[H]\n"
|
274
|
+
"\\centering\n"
|
275
|
+
f"\\includegraphics[width=0.8\\textwidth]{{{img_path}}}\n"
|
276
|
+
"\\caption{Generated diagram}\n"
|
277
|
+
"\\end{figure}\n"
|
278
|
+
)
|
279
|
+
except Exception as e:
|
280
|
+
logger.error(f"Error processing Mermaid diagram: {e}")
|
281
|
+
return "% Error processing diagram\n"
|
282
|
+
|
283
|
+
return re.sub(
|
284
|
+
r'```mermaid\n(.*?)\n```',
|
285
|
+
replace_mermaid,
|
286
|
+
text,
|
287
|
+
flags=re.DOTALL
|
288
|
+
)
|
289
|
+
|
290
|
+
def execute(self, **kwargs) -> str:
|
291
|
+
"""Execute the markdown to LaTeX conversion.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
**kwargs: Tool arguments including markdown_content, output_path,
|
295
|
+
document_class, bibliography_file, and style_config
|
296
|
+
|
297
|
+
Returns:
|
298
|
+
Success message with output path
|
299
|
+
"""
|
300
|
+
try:
|
301
|
+
markdown_content = kwargs['markdown_content']
|
302
|
+
output_path = self._normalize_path(kwargs['output_path'])
|
303
|
+
document_class = kwargs.get('document_class', 'article')
|
304
|
+
bib_file = kwargs.get('bibliography_file')
|
305
|
+
style_config = kwargs.get('style_config')
|
306
|
+
|
307
|
+
# Create output directory
|
308
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
309
|
+
|
310
|
+
# Parse style configuration
|
311
|
+
styles = self._parse_style_config(style_config)
|
312
|
+
|
313
|
+
# Process content
|
314
|
+
content = markdown_content
|
315
|
+
|
316
|
+
# Convert math expressions
|
317
|
+
content = self._convert_math(content)
|
318
|
+
|
319
|
+
# Process citations
|
320
|
+
bib_path = self._normalize_path(bib_file) if bib_file else None
|
321
|
+
content, has_citations = self._process_citations(content, bib_path)
|
322
|
+
|
323
|
+
# Convert code blocks
|
324
|
+
content = self._convert_code_blocks(content)
|
325
|
+
|
326
|
+
# Convert tables
|
327
|
+
content = self._convert_tables(content)
|
328
|
+
|
329
|
+
# Process Mermaid diagrams
|
330
|
+
content = self._process_mermaid_diagrams(content, output_path.parent)
|
331
|
+
|
332
|
+
# Extract title
|
333
|
+
title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
|
334
|
+
title = title_match.group(1) if title_match else 'Document'
|
335
|
+
content = re.sub(r'^#\s+(.+)$', r'\\title{\1}\n\\maketitle', content, flags=re.MULTILINE)
|
336
|
+
|
337
|
+
# Convert headers
|
338
|
+
content = re.sub(r'^#{6}\s+(.+)$', r'\\paragraph{\1}', content, flags=re.MULTILINE)
|
339
|
+
content = re.sub(r'^#{5}\s+(.+)$', r'\\subsubsection{\1}', content, flags=re.MULTILINE)
|
340
|
+
content = re.sub(r'^#{4}\s+(.+)$', r'\\subsection{\1}', content, flags=re.MULTILINE)
|
341
|
+
content = re.sub(r'^#{3}\s+(.+)$', r'\\section{\1}', content, flags=re.MULTILINE)
|
342
|
+
content = re.sub(r'^#{2}\s+(.+)$', r'\\section{\1}', content, flags=re.MULTILINE)
|
343
|
+
|
344
|
+
# Convert emphasis
|
345
|
+
content = re.sub(r'\*\*(.+?)\*\*', r'\\textbf{\1}', content)
|
346
|
+
content = re.sub(r'\*(.+?)\*', r'\\textit{\1}', content)
|
347
|
+
|
348
|
+
# Convert links
|
349
|
+
content = re.sub(r'\[([^\]]+)\]\(([^\)]+)\)', r'\\href{\2}{\1}', content)
|
350
|
+
|
351
|
+
# Generate package includes
|
352
|
+
packages = '\n'.join(f"\\usepackage{{{pkg}}}" for pkg in self.DEFAULT_PACKAGES)
|
353
|
+
|
354
|
+
# Generate bibliography settings
|
355
|
+
bibliography = ""
|
356
|
+
if has_citations and bib_path and bib_path.exists():
|
357
|
+
bibliography = (
|
358
|
+
f"\\bibliographystyle{{{styles['bibliography_style']}}}\n"
|
359
|
+
f"\\bibliography{{{bib_path.stem}}}"
|
360
|
+
)
|
361
|
+
|
362
|
+
# Generate final LaTeX
|
363
|
+
latex_content = self.DOCUMENT_TEMPLATE.format(
|
364
|
+
font_size=styles['font_size'],
|
365
|
+
paper_size=styles['paper_size'],
|
366
|
+
margin=styles['margin'],
|
367
|
+
font_package=styles['font_package'],
|
368
|
+
packages=packages,
|
369
|
+
title=title,
|
370
|
+
line_spacing=styles['line_spacing'],
|
371
|
+
extra_preamble="",
|
372
|
+
content=content,
|
373
|
+
bibliography=bibliography
|
374
|
+
)
|
375
|
+
|
376
|
+
# Write output file
|
377
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
378
|
+
f.write(latex_content)
|
379
|
+
|
380
|
+
return f"Successfully created LaTeX document at: {output_path}"
|
381
|
+
|
382
|
+
except Exception as e:
|
383
|
+
error_msg = f"Error converting markdown to LaTeX: {str(e)}"
|
384
|
+
logger.error(error_msg)
|
385
|
+
raise RuntimeError(error_msg)
|
386
|
+
|
387
|
+
|
388
|
+
if __name__ == "__main__":
|
389
|
+
# Example usage with error handling
|
390
|
+
try:
|
391
|
+
tool = MarkdownToLatexTool()
|
392
|
+
result = tool.execute(
|
393
|
+
markdown_content="""
|
394
|
+
# Sample Academic Document
|
395
|
+
|
396
|
+
## Introduction
|
397
|
+
|
398
|
+
This is a sample document with an equation:
|
399
|
+
|
400
|
+
$$E = mc^2$$
|
401
|
+
|
402
|
+
And a citation [@einstein1905].
|
403
|
+
|
404
|
+
```python
|
405
|
+
def calculate_energy(mass):
|
406
|
+
c = 299792458 # speed of light
|
407
|
+
return mass * (c ** 2)
|
408
|
+
```
|
409
|
+
|
410
|
+
| Column 1 | Column 2 |
|
411
|
+
|:---------|----------:|
|
412
|
+
| Data 1 | Value 1 |
|
413
|
+
| Data 2 | Value 2 |
|
414
|
+
""",
|
415
|
+
output_path="sample.tex",
|
416
|
+
bibliography_file="references.bib"
|
417
|
+
)
|
418
|
+
print(result)
|
419
|
+
except Exception as e:
|
420
|
+
print(f"Error: {e}")
|