deepagents-printshop 0.1.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.
- agents/content_editor/__init__.py +1 -0
- agents/content_editor/agent.py +279 -0
- agents/content_editor/content_reviewer.py +327 -0
- agents/content_editor/versioned_agent.py +455 -0
- agents/latex_specialist/__init__.py +1 -0
- agents/latex_specialist/agent.py +531 -0
- agents/latex_specialist/latex_analyzer.py +510 -0
- agents/latex_specialist/latex_optimizer.py +1192 -0
- agents/qa_orchestrator/__init__.py +1 -0
- agents/qa_orchestrator/agent.py +603 -0
- agents/qa_orchestrator/langgraph_workflow.py +733 -0
- agents/qa_orchestrator/pipeline_types.py +72 -0
- agents/qa_orchestrator/quality_gates.py +495 -0
- agents/qa_orchestrator/workflow_coordinator.py +139 -0
- agents/research_agent/__init__.py +1 -0
- agents/research_agent/agent.py +258 -0
- agents/research_agent/llm_report_generator.py +1023 -0
- agents/research_agent/report_generator.py +536 -0
- agents/visual_qa/__init__.py +1 -0
- agents/visual_qa/agent.py +410 -0
- deepagents_printshop-0.1.0.dist-info/METADATA +744 -0
- deepagents_printshop-0.1.0.dist-info/RECORD +37 -0
- deepagents_printshop-0.1.0.dist-info/WHEEL +4 -0
- deepagents_printshop-0.1.0.dist-info/entry_points.txt +2 -0
- deepagents_printshop-0.1.0.dist-info/licenses/LICENSE +86 -0
- tools/__init__.py +1 -0
- tools/change_tracker.py +419 -0
- tools/content_type_loader.py +171 -0
- tools/graph_generator.py +281 -0
- tools/latex_generator.py +374 -0
- tools/llm_latex_generator.py +678 -0
- tools/magazine_layout.py +462 -0
- tools/pattern_injector.py +250 -0
- tools/pattern_learner.py +477 -0
- tools/pdf_compiler.py +386 -0
- tools/version_manager.py +346 -0
- tools/visual_qa.py +799 -0
tools/latex_generator.py
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"""LaTeX document generator with comprehensive formatting support."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import List, Dict, Optional
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class DocumentConfig:
|
|
10
|
+
"""Configuration for LaTeX document generation."""
|
|
11
|
+
doc_class: str = "article" # article, book, report, etc.
|
|
12
|
+
font_size: str = "12pt"
|
|
13
|
+
paper_size: str = "letterpaper"
|
|
14
|
+
title: str = ""
|
|
15
|
+
author: str = ""
|
|
16
|
+
date: str = r"\today"
|
|
17
|
+
|
|
18
|
+
# Document options
|
|
19
|
+
include_toc: bool = True
|
|
20
|
+
include_bibliography: bool = True
|
|
21
|
+
two_column: bool = False
|
|
22
|
+
|
|
23
|
+
# Header/Footer
|
|
24
|
+
header_left: str = ""
|
|
25
|
+
header_center: str = ""
|
|
26
|
+
header_right: str = ""
|
|
27
|
+
footer_left: str = ""
|
|
28
|
+
footer_center: str = r"\thepage"
|
|
29
|
+
footer_right: str = ""
|
|
30
|
+
|
|
31
|
+
# Packages to include
|
|
32
|
+
extra_packages: List[str] = field(default_factory=list)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class LaTeXGenerator:
|
|
36
|
+
"""Generate LaTeX documents with advanced formatting."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, config: DocumentConfig):
|
|
39
|
+
self.config = config
|
|
40
|
+
self.content_sections = []
|
|
41
|
+
self.bibliography_entries = []
|
|
42
|
+
|
|
43
|
+
def generate_preamble(self) -> str:
|
|
44
|
+
"""Generate the document preamble with packages and settings."""
|
|
45
|
+
options = [self.config.font_size, self.config.paper_size]
|
|
46
|
+
if self.config.two_column:
|
|
47
|
+
options.append("twocolumn")
|
|
48
|
+
|
|
49
|
+
preamble = [
|
|
50
|
+
f"\\documentclass[{','.join(options)}]{{{self.config.doc_class}}}",
|
|
51
|
+
"",
|
|
52
|
+
"% Packages",
|
|
53
|
+
"\\usepackage[utf8]{inputenc}",
|
|
54
|
+
"\\usepackage[T1]{fontenc}",
|
|
55
|
+
"\\usepackage{lmodern}",
|
|
56
|
+
"\\usepackage{graphicx}",
|
|
57
|
+
"\\usepackage{hyperref}",
|
|
58
|
+
"\\usepackage{cite}",
|
|
59
|
+
"\\usepackage{amsmath}",
|
|
60
|
+
"\\usepackage{booktabs}",
|
|
61
|
+
"\\usepackage{array}",
|
|
62
|
+
"\\usepackage{float}",
|
|
63
|
+
"\\usepackage{wrapfig}",
|
|
64
|
+
"\\usepackage{caption}",
|
|
65
|
+
"\\usepackage{subcaption}",
|
|
66
|
+
"\\usepackage{geometry}",
|
|
67
|
+
"\\usepackage{fancyhdr}",
|
|
68
|
+
"\\usepackage{csvsimple}",
|
|
69
|
+
"\\usepackage{longtable}",
|
|
70
|
+
"\\usepackage{tikz}",
|
|
71
|
+
"\\usepackage{xcolor}",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
# Add extra packages
|
|
75
|
+
for pkg in self.config.extra_packages:
|
|
76
|
+
preamble.append(f"\\usepackage{{{pkg}}}")
|
|
77
|
+
|
|
78
|
+
# Geometry settings
|
|
79
|
+
preamble.extend([
|
|
80
|
+
"",
|
|
81
|
+
"% Page geometry",
|
|
82
|
+
"\\geometry{margin=1in}",
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
# Header/Footer setup
|
|
86
|
+
if any([self.config.header_left, self.config.header_center, self.config.header_right,
|
|
87
|
+
self.config.footer_left, self.config.footer_center, self.config.footer_right]):
|
|
88
|
+
preamble.extend([
|
|
89
|
+
"",
|
|
90
|
+
"% Header and Footer",
|
|
91
|
+
"\\pagestyle{fancy}",
|
|
92
|
+
"\\fancyhf{}",
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
if self.config.header_left:
|
|
96
|
+
preamble.append(f"\\fancyhead[L]{{{self.config.header_left}}}")
|
|
97
|
+
if self.config.header_center:
|
|
98
|
+
preamble.append(f"\\fancyhead[C]{{{self.config.header_center}}}")
|
|
99
|
+
if self.config.header_right:
|
|
100
|
+
preamble.append(f"\\fancyhead[R]{{{self.config.header_right}}}")
|
|
101
|
+
if self.config.footer_left:
|
|
102
|
+
preamble.append(f"\\fancyfoot[L]{{{self.config.footer_left}}}")
|
|
103
|
+
if self.config.footer_center:
|
|
104
|
+
preamble.append(f"\\fancyfoot[C]{{{self.config.footer_center}}}")
|
|
105
|
+
if self.config.footer_right:
|
|
106
|
+
preamble.append(f"\\fancyfoot[R]{{{self.config.footer_right}}}")
|
|
107
|
+
|
|
108
|
+
# Hyperref settings
|
|
109
|
+
preamble.extend([
|
|
110
|
+
"",
|
|
111
|
+
"% Hyperref settings",
|
|
112
|
+
"\\hypersetup{",
|
|
113
|
+
" colorlinks=true,",
|
|
114
|
+
" linkcolor=blue,",
|
|
115
|
+
" filecolor=magenta,",
|
|
116
|
+
" urlcolor=cyan,",
|
|
117
|
+
" citecolor=blue,",
|
|
118
|
+
"}",
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
# Title information
|
|
122
|
+
if self.config.title:
|
|
123
|
+
preamble.extend([
|
|
124
|
+
"",
|
|
125
|
+
f"\\title{{{self.config.title}}}",
|
|
126
|
+
f"\\author{{{self.config.author}}}",
|
|
127
|
+
f"\\date{{{self.config.date}}}",
|
|
128
|
+
])
|
|
129
|
+
|
|
130
|
+
return "\n".join(preamble)
|
|
131
|
+
|
|
132
|
+
def add_section(self, title: str, content: str, level: int = 1):
|
|
133
|
+
"""Add a section to the document."""
|
|
134
|
+
section_cmd = {
|
|
135
|
+
0: "chapter",
|
|
136
|
+
1: "section",
|
|
137
|
+
2: "subsection",
|
|
138
|
+
3: "subsubsection",
|
|
139
|
+
}.get(level, "section")
|
|
140
|
+
|
|
141
|
+
self.content_sections.append({
|
|
142
|
+
"type": "section",
|
|
143
|
+
"command": section_cmd,
|
|
144
|
+
"title": title,
|
|
145
|
+
"content": content
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
def add_table(self, caption: str, headers: List[str], rows: List[List[str]],
|
|
149
|
+
label: Optional[str] = None):
|
|
150
|
+
"""Add a formatted table to the document."""
|
|
151
|
+
col_format = "l" * len(headers)
|
|
152
|
+
|
|
153
|
+
table_content = [
|
|
154
|
+
"\\begin{table}[H]",
|
|
155
|
+
"\\centering",
|
|
156
|
+
f"\\begin{{tabular}}{{{col_format}}}",
|
|
157
|
+
"\\toprule",
|
|
158
|
+
" & ".join(headers) + " \\\\",
|
|
159
|
+
"\\midrule",
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
for row in rows:
|
|
163
|
+
table_content.append(" & ".join(row) + " \\\\")
|
|
164
|
+
|
|
165
|
+
table_content.extend([
|
|
166
|
+
"\\bottomrule",
|
|
167
|
+
"\\end{tabular}",
|
|
168
|
+
f"\\caption{{{caption}}}",
|
|
169
|
+
])
|
|
170
|
+
|
|
171
|
+
if label:
|
|
172
|
+
table_content.append(f"\\label{{{label}}}")
|
|
173
|
+
|
|
174
|
+
table_content.append("\\end{table}")
|
|
175
|
+
|
|
176
|
+
self.content_sections.append({
|
|
177
|
+
"type": "table",
|
|
178
|
+
"content": "\n".join(table_content)
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
def add_csv_table(self, caption: str, csv_file: str, label: Optional[str] = None):
|
|
182
|
+
"""Add a table from a CSV file."""
|
|
183
|
+
table_content = [
|
|
184
|
+
"\\begin{table}[H]",
|
|
185
|
+
"\\centering",
|
|
186
|
+
"\\csvautotabular{" + csv_file + "}",
|
|
187
|
+
f"\\caption{{{caption}}}",
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
if label:
|
|
191
|
+
table_content.append(f"\\label{{{label}}}")
|
|
192
|
+
|
|
193
|
+
table_content.append("\\end{table}")
|
|
194
|
+
|
|
195
|
+
self.content_sections.append({
|
|
196
|
+
"type": "csv_table",
|
|
197
|
+
"content": "\n".join(table_content)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
def add_figure(self, image_path: str, caption: str, width: str = "0.8\\textwidth",
|
|
201
|
+
label: Optional[str] = None):
|
|
202
|
+
"""Add a figure to the document."""
|
|
203
|
+
figure_content = [
|
|
204
|
+
"\\begin{figure}[H]",
|
|
205
|
+
"\\centering",
|
|
206
|
+
f"\\includegraphics[width={width}]{{{image_path}}}",
|
|
207
|
+
f"\\caption{{{caption}}}",
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
if label:
|
|
211
|
+
figure_content.append(f"\\label{{{label}}}")
|
|
212
|
+
|
|
213
|
+
figure_content.append("\\end{figure}")
|
|
214
|
+
|
|
215
|
+
self.content_sections.append({
|
|
216
|
+
"type": "figure",
|
|
217
|
+
"content": "\n".join(figure_content)
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
def add_wrapped_figure(self, image_path: str, caption: str, width: str = "0.4\\textwidth",
|
|
221
|
+
position: str = "r", label: Optional[str] = None):
|
|
222
|
+
"""Add a figure with text wrapping."""
|
|
223
|
+
figure_content = [
|
|
224
|
+
f"\\begin{{wrapfigure}}{{{position}}}{{{width}}}",
|
|
225
|
+
"\\centering",
|
|
226
|
+
f"\\includegraphics[width={width}]{{{image_path}}}",
|
|
227
|
+
f"\\caption{{{caption}}}",
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
if label:
|
|
231
|
+
figure_content.append(f"\\label{{{label}}}")
|
|
232
|
+
|
|
233
|
+
figure_content.append("\\end{wrapfigure}")
|
|
234
|
+
|
|
235
|
+
self.content_sections.append({
|
|
236
|
+
"type": "wrapfigure",
|
|
237
|
+
"content": "\n".join(figure_content)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
def add_tikz_diagram(self, tikz_code: str, caption: str, label: Optional[str] = None):
|
|
241
|
+
"""Add a TikZ vector diagram."""
|
|
242
|
+
figure_content = [
|
|
243
|
+
"\\begin{figure}[H]",
|
|
244
|
+
"\\centering",
|
|
245
|
+
"\\begin{tikzpicture}",
|
|
246
|
+
tikz_code,
|
|
247
|
+
"\\end{tikzpicture}",
|
|
248
|
+
f"\\caption{{{caption}}}",
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
if label:
|
|
252
|
+
figure_content.append(f"\\label{{{label}}}")
|
|
253
|
+
|
|
254
|
+
figure_content.append("\\end{figure}")
|
|
255
|
+
|
|
256
|
+
self.content_sections.append({
|
|
257
|
+
"type": "tikz",
|
|
258
|
+
"content": "\n".join(figure_content)
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
def add_citation(self, cite_key: str) -> str:
|
|
262
|
+
"""Add an inline citation reference."""
|
|
263
|
+
return f"\\cite{{{cite_key}}}"
|
|
264
|
+
|
|
265
|
+
def add_bib_entry(self, entry: str):
|
|
266
|
+
"""Add a bibliography entry."""
|
|
267
|
+
self.bibliography_entries.append(entry)
|
|
268
|
+
|
|
269
|
+
def add_itemize_list(self, items: List[str]):
|
|
270
|
+
"""Add a bulleted list."""
|
|
271
|
+
list_content = ["\\begin{itemize}"]
|
|
272
|
+
for item in items:
|
|
273
|
+
list_content.append(f" \\item {item}")
|
|
274
|
+
list_content.append("\\end{itemize}")
|
|
275
|
+
|
|
276
|
+
self.content_sections.append({
|
|
277
|
+
"type": "list",
|
|
278
|
+
"content": "\n".join(list_content)
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
def add_enumerate_list(self, items: List[str]):
|
|
282
|
+
"""Add a numbered list."""
|
|
283
|
+
list_content = ["\\begin{enumerate}"]
|
|
284
|
+
for item in items:
|
|
285
|
+
list_content.append(f" \\item {item}")
|
|
286
|
+
list_content.append("\\end{enumerate}")
|
|
287
|
+
|
|
288
|
+
self.content_sections.append({
|
|
289
|
+
"type": "list",
|
|
290
|
+
"content": "\n".join(list_content)
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
def add_hyperlink(self, url: str, text: Optional[str] = None) -> str:
|
|
294
|
+
"""Create a hyperlink."""
|
|
295
|
+
if text:
|
|
296
|
+
return f"\\href{{{url}}}{{{text}}}"
|
|
297
|
+
else:
|
|
298
|
+
return f"\\url{{{url}}}"
|
|
299
|
+
|
|
300
|
+
def add_raw_latex(self, latex_code: str):
|
|
301
|
+
"""Add raw LaTeX code."""
|
|
302
|
+
self.content_sections.append({
|
|
303
|
+
"type": "raw",
|
|
304
|
+
"content": latex_code
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
def generate_document(self) -> str:
|
|
308
|
+
"""Generate the complete LaTeX document."""
|
|
309
|
+
doc = [self.generate_preamble(), "", "\\begin{document}"]
|
|
310
|
+
|
|
311
|
+
# Title page
|
|
312
|
+
if self.config.title:
|
|
313
|
+
doc.extend(["", "\\maketitle"])
|
|
314
|
+
|
|
315
|
+
# Table of contents
|
|
316
|
+
if self.config.include_toc:
|
|
317
|
+
doc.extend(["", "\\tableofcontents", "\\newpage"])
|
|
318
|
+
|
|
319
|
+
# Content sections
|
|
320
|
+
for section in self.content_sections:
|
|
321
|
+
doc.append("")
|
|
322
|
+
if section["type"] == "section":
|
|
323
|
+
doc.append(f"\\{section['command']}{{{section['title']}}}")
|
|
324
|
+
doc.append(section["content"])
|
|
325
|
+
else:
|
|
326
|
+
doc.append(section["content"])
|
|
327
|
+
|
|
328
|
+
# Bibliography
|
|
329
|
+
if self.config.include_bibliography and self.bibliography_entries:
|
|
330
|
+
doc.extend([
|
|
331
|
+
"",
|
|
332
|
+
"\\begin{thebibliography}{99}",
|
|
333
|
+
])
|
|
334
|
+
for entry in self.bibliography_entries:
|
|
335
|
+
doc.append(entry)
|
|
336
|
+
doc.append("\\end{thebibliography}")
|
|
337
|
+
|
|
338
|
+
doc.extend(["", "\\end{document}"])
|
|
339
|
+
|
|
340
|
+
return "\n".join(doc)
|
|
341
|
+
|
|
342
|
+
def save(self, output_path: str):
|
|
343
|
+
"""Save the LaTeX document to a file."""
|
|
344
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
345
|
+
f.write(self.generate_document())
|
|
346
|
+
return output_path
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def markdown_to_latex(markdown_text: str) -> str:
|
|
350
|
+
"""Convert basic markdown to LaTeX."""
|
|
351
|
+
latex = markdown_text
|
|
352
|
+
|
|
353
|
+
# Bold
|
|
354
|
+
import re
|
|
355
|
+
latex = re.sub(r'\*\*(.+?)\*\*', r'\\textbf{\1}', latex)
|
|
356
|
+
latex = re.sub(r'__(.+?)__', r'\\textbf{\1}', latex)
|
|
357
|
+
|
|
358
|
+
# Italic
|
|
359
|
+
latex = re.sub(r'\*(.+?)\*', r'\\textit{\1}', latex)
|
|
360
|
+
latex = re.sub(r'_(.+?)_', r'\\textit{\1}', latex)
|
|
361
|
+
|
|
362
|
+
# Code
|
|
363
|
+
latex = re.sub(r'`(.+?)`', r'\\texttt{\1}', latex)
|
|
364
|
+
|
|
365
|
+
# Special characters
|
|
366
|
+
latex = latex.replace('&', '\\&')
|
|
367
|
+
latex = latex.replace('%', '\\%')
|
|
368
|
+
latex = latex.replace('$', '\\$')
|
|
369
|
+
latex = latex.replace('#', '\\#')
|
|
370
|
+
latex = latex.replace('_', '\\_')
|
|
371
|
+
latex = latex.replace('{', '\\{')
|
|
372
|
+
latex = latex.replace('}', '\\}')
|
|
373
|
+
|
|
374
|
+
return latex
|