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
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"""Dynamic Visual QA Agent that processes findings and applies improvements."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import re
|
|
6
|
+
import shutil
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Dict, List, Tuple, Optional
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
import os
|
|
13
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
14
|
+
|
|
15
|
+
from tools.visual_qa import VisualQAAgent, DocumentVisualQA
|
|
16
|
+
from tools.latex_generator import LaTeXGenerator, DocumentConfig
|
|
17
|
+
from tools.llm_latex_generator import LLMLaTeXGenerator
|
|
18
|
+
from tools.pdf_compiler import PDFCompiler
|
|
19
|
+
from tools.version_manager import VersionManager
|
|
20
|
+
from tools.change_tracker import ChangeTracker
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ImprovementAction:
|
|
25
|
+
"""Represents a specific improvement action to take."""
|
|
26
|
+
issue_type: str
|
|
27
|
+
description: str
|
|
28
|
+
latex_fix: str
|
|
29
|
+
priority: int # 1-10, higher is more important
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class VisualQAFeedbackAgent:
|
|
33
|
+
"""Agent that processes Visual QA results and applies dynamic improvements."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, content_source: str = ""):
|
|
36
|
+
self.content_source = content_source
|
|
37
|
+
self.visual_qa = VisualQAAgent(content_source=content_source)
|
|
38
|
+
self.pdf_compiler = PDFCompiler()
|
|
39
|
+
self.llm_latex_generator = LLMLaTeXGenerator()
|
|
40
|
+
self.improvement_patterns = self._load_improvement_patterns()
|
|
41
|
+
self.version_manager = VersionManager()
|
|
42
|
+
self.change_tracker = ChangeTracker()
|
|
43
|
+
|
|
44
|
+
def _load_improvement_patterns(self) -> Dict[str, Dict]:
|
|
45
|
+
"""Load patterns for mapping Visual QA issues to LaTeX improvements."""
|
|
46
|
+
return {
|
|
47
|
+
"line_spacing": {
|
|
48
|
+
"keywords": ["line spacing", "linespacing", "spacing between lines"],
|
|
49
|
+
"latex_fixes": [
|
|
50
|
+
"\\linespread{0.9}",
|
|
51
|
+
"\\linespread{1.1}",
|
|
52
|
+
"\\setlength{\\baselineskip}{1.2\\baselineskip}"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"paragraph_spacing": {
|
|
56
|
+
"keywords": ["paragraph spacing", "parskip", "spacing between paragraphs"],
|
|
57
|
+
"latex_fixes": [
|
|
58
|
+
"\\setlength{\\parskip}{0.5em plus 0.1em minus 0.05em}",
|
|
59
|
+
"\\setlength{\\parskip}{1em plus 0.2em minus 0.1em}",
|
|
60
|
+
"\\setlength{\\parskip}{1.2em plus 0.3em minus 0.1em}"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"section_spacing": {
|
|
64
|
+
"keywords": ["section spacing", "uneven spacing", "spacing between sections"],
|
|
65
|
+
"latex_fixes": [
|
|
66
|
+
"\\titlespacing\\section{0pt}{1.5em plus 0.2em minus 0.1em}{0.8em plus 0.1em minus 0.05em}",
|
|
67
|
+
"\\titlespacing\\subsection{0pt}{1.2em plus 0.15em minus 0.08em}{0.6em plus 0.08em minus 0.04em}"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"typography": {
|
|
71
|
+
"keywords": ["font size", "typography", "readability", "text flow"],
|
|
72
|
+
"latex_fixes": [
|
|
73
|
+
"\\usepackage[11pt]{extsizes}",
|
|
74
|
+
"\\usepackage{microtype}",
|
|
75
|
+
"\\setlength{\\textwidth}{0.9\\textwidth}"
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"table_formatting": {
|
|
79
|
+
"keywords": ["table", "tabular", "formatting", "alignment"],
|
|
80
|
+
"latex_fixes": [
|
|
81
|
+
"\\renewcommand{\\arraystretch}{1.2}",
|
|
82
|
+
"\\setlength{\\tabcolsep}{6pt}",
|
|
83
|
+
"\\usepackage{longtabu}"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
"header_footer": {
|
|
87
|
+
"keywords": ["header", "footer", "page numbers", "headheight"],
|
|
88
|
+
"latex_fixes": [
|
|
89
|
+
"\\setlength{\\headheight}{14.5pt}",
|
|
90
|
+
"\\addtolength{\\topmargin}{-2.5pt}"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
def analyze_and_improve(self, pdf_path: str, max_iterations: int = 3) -> Tuple[str, List[str], Optional[str]]:
|
|
96
|
+
"""
|
|
97
|
+
Analyze PDF with Visual QA and iteratively improve it.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Tuple of (final_pdf_path, improvements_made, final_version_name)
|
|
101
|
+
"""
|
|
102
|
+
current_pdf = pdf_path
|
|
103
|
+
improvements_made = []
|
|
104
|
+
final_version = None
|
|
105
|
+
|
|
106
|
+
for iteration in range(max_iterations):
|
|
107
|
+
print(f"\nš Visual QA Iteration {iteration + 1}/{max_iterations}")
|
|
108
|
+
print("=" * 50)
|
|
109
|
+
|
|
110
|
+
# Run Visual QA analysis
|
|
111
|
+
qa_results = self.visual_qa.validate_pdf_visual_quality(current_pdf)
|
|
112
|
+
|
|
113
|
+
print(f"š Current Score: {qa_results.overall_score:.1f}/100")
|
|
114
|
+
|
|
115
|
+
# Stop if score is good enough
|
|
116
|
+
if qa_results.overall_score >= 90:
|
|
117
|
+
print("ā
Quality target achieved!")
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
# Extract improvement actions from QA results
|
|
121
|
+
actions = self._extract_improvement_actions(qa_results)
|
|
122
|
+
|
|
123
|
+
if not actions:
|
|
124
|
+
print("ā¹ļø No more actionable improvements found")
|
|
125
|
+
break
|
|
126
|
+
|
|
127
|
+
print(f"š§ Found {len(actions)} potential improvements:")
|
|
128
|
+
for action in actions:
|
|
129
|
+
print(f" - {action.description} (Priority: {action.priority})")
|
|
130
|
+
|
|
131
|
+
# Apply improvements
|
|
132
|
+
tex_path = pdf_path.replace('.pdf', '.tex')
|
|
133
|
+
improved_tex = self._apply_improvements(tex_path, actions)
|
|
134
|
+
|
|
135
|
+
# Track version before compilation
|
|
136
|
+
version_name = f"v3_visual_qa_iter{iteration + 1}"
|
|
137
|
+
parent_version = "v2_latex_optimized" if iteration == 0 else f"v3_visual_qa_iter{iteration}"
|
|
138
|
+
|
|
139
|
+
# Read old and new LaTeX content for version tracking
|
|
140
|
+
with open(tex_path, 'r', encoding='utf-8') as f:
|
|
141
|
+
old_latex_content = f.read()
|
|
142
|
+
with open(improved_tex, 'r', encoding='utf-8') as f:
|
|
143
|
+
new_latex_content = f.read()
|
|
144
|
+
|
|
145
|
+
# Recompile PDF to iterations folder
|
|
146
|
+
iterations_dir = Path("artifacts/reviewed_content/v3_visual_qa/iterations")
|
|
147
|
+
iterations_dir.mkdir(parents=True, exist_ok=True)
|
|
148
|
+
new_pdf_path = str(iterations_dir / f"iteration_{iteration + 1}.pdf")
|
|
149
|
+
|
|
150
|
+
if self._compile_improved_tex(improved_tex, new_pdf_path):
|
|
151
|
+
# Save version to reviewed_content
|
|
152
|
+
version_dir = Path(f"artifacts/reviewed_content/{version_name}")
|
|
153
|
+
version_dir.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
|
|
155
|
+
# Save improved .tex file to version directory
|
|
156
|
+
tex_filename = f"{self.content_source}.tex" if self.content_source else "research_report.tex"
|
|
157
|
+
pdf_filename = f"{self.content_source}.pdf" if self.content_source else "research_report.pdf"
|
|
158
|
+
version_tex_path = version_dir / tex_filename
|
|
159
|
+
with open(version_tex_path, 'w', encoding='utf-8') as f:
|
|
160
|
+
f.write(new_latex_content)
|
|
161
|
+
|
|
162
|
+
# Copy PDF to version directory
|
|
163
|
+
version_pdf_path = version_dir / pdf_filename
|
|
164
|
+
shutil.copy(new_pdf_path, version_pdf_path)
|
|
165
|
+
|
|
166
|
+
# Track version in version manager
|
|
167
|
+
content_dict = {tex_filename: new_latex_content}
|
|
168
|
+
self.version_manager.create_version(
|
|
169
|
+
content_dict=content_dict,
|
|
170
|
+
version_name=version_name,
|
|
171
|
+
agent_name="visual_qa_feedback",
|
|
172
|
+
parent_version=parent_version,
|
|
173
|
+
metadata={
|
|
174
|
+
"iteration": iteration + 1,
|
|
175
|
+
"improvements": [action.description for action in actions],
|
|
176
|
+
"qa_score": qa_results.overall_score
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Track changes in version history
|
|
181
|
+
old_content_dict = {tex_filename: old_latex_content}
|
|
182
|
+
new_content_dict = {tex_filename: new_latex_content}
|
|
183
|
+
self.change_tracker.create_change_report(
|
|
184
|
+
old_version=parent_version,
|
|
185
|
+
new_version=version_name,
|
|
186
|
+
old_content=old_content_dict,
|
|
187
|
+
new_content=new_content_dict
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
print(f"ā
Version {version_name} tracked in version_history")
|
|
191
|
+
print(f"ā
Generated improved PDF: {new_pdf_path}")
|
|
192
|
+
|
|
193
|
+
# Update current PDF for next iteration
|
|
194
|
+
current_pdf = new_pdf_path
|
|
195
|
+
improvements_made.extend([action.description for action in actions])
|
|
196
|
+
final_version = version_name # Track the final version created
|
|
197
|
+
else:
|
|
198
|
+
print("ā Compilation failed, reverting changes")
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
return current_pdf, improvements_made, final_version
|
|
202
|
+
|
|
203
|
+
def _extract_improvement_actions(self, qa_results: DocumentVisualQA) -> List[ImprovementAction]:
|
|
204
|
+
"""Extract actionable improvements from Visual QA results."""
|
|
205
|
+
actions = []
|
|
206
|
+
|
|
207
|
+
# Analyze all page issues
|
|
208
|
+
all_issues = []
|
|
209
|
+
for page_result in qa_results.page_results:
|
|
210
|
+
all_issues.extend(page_result.issues_found)
|
|
211
|
+
|
|
212
|
+
# Map issues to improvement actions using AI analysis
|
|
213
|
+
for issue in all_issues:
|
|
214
|
+
action = self._map_issue_to_action(issue, qa_results.overall_score)
|
|
215
|
+
if action:
|
|
216
|
+
actions.append(action)
|
|
217
|
+
|
|
218
|
+
# Sort by priority
|
|
219
|
+
actions.sort(key=lambda x: x.priority, reverse=True)
|
|
220
|
+
|
|
221
|
+
return actions[:3] # Limit to top 3 actions per iteration
|
|
222
|
+
|
|
223
|
+
def _map_issue_to_action(self, issue: str, current_score: float) -> Optional[ImprovementAction]:
|
|
224
|
+
"""Map a specific issue to an improvement action."""
|
|
225
|
+
issue_lower = issue.lower()
|
|
226
|
+
|
|
227
|
+
# Priority based on current score (lower score = higher priority fixes)
|
|
228
|
+
base_priority = max(1, 10 - int(current_score / 10))
|
|
229
|
+
|
|
230
|
+
for pattern_name, pattern_info in self.improvement_patterns.items():
|
|
231
|
+
for keyword in pattern_info["keywords"]:
|
|
232
|
+
if keyword in issue_lower:
|
|
233
|
+
# Select appropriate fix based on issue context
|
|
234
|
+
latex_fix = self._select_best_fix(issue, pattern_info["latex_fixes"])
|
|
235
|
+
|
|
236
|
+
return ImprovementAction(
|
|
237
|
+
issue_type=pattern_name,
|
|
238
|
+
description=f"Fix {pattern_name}: {issue}",
|
|
239
|
+
latex_fix=latex_fix,
|
|
240
|
+
priority=base_priority + self._calculate_issue_priority(issue)
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
def _select_best_fix(self, issue: str, available_fixes: List[str]) -> str:
|
|
246
|
+
"""Select the most appropriate fix for the specific issue."""
|
|
247
|
+
issue_lower = issue.lower()
|
|
248
|
+
|
|
249
|
+
# Simple heuristics for fix selection
|
|
250
|
+
if "reduce" in issue_lower or "decrease" in issue_lower:
|
|
251
|
+
return available_fixes[0] # Usually the "smaller" option
|
|
252
|
+
elif "increase" in issue_lower or "improve" in issue_lower:
|
|
253
|
+
return available_fixes[-1] # Usually the "larger" option
|
|
254
|
+
else:
|
|
255
|
+
return available_fixes[len(available_fixes) // 2] # Middle option
|
|
256
|
+
|
|
257
|
+
def _calculate_issue_priority(self, issue: str) -> int:
|
|
258
|
+
"""Calculate additional priority based on issue severity."""
|
|
259
|
+
issue_lower = issue.lower()
|
|
260
|
+
|
|
261
|
+
# High priority keywords
|
|
262
|
+
if any(word in issue_lower for word in ["unreadable", "poor", "bad", "error"]):
|
|
263
|
+
return 3
|
|
264
|
+
elif any(word in issue_lower for word in ["improve", "enhance", "better"]):
|
|
265
|
+
return 2
|
|
266
|
+
elif any(word in issue_lower for word in ["slightly", "minor", "small"]):
|
|
267
|
+
return 1
|
|
268
|
+
else:
|
|
269
|
+
return 2
|
|
270
|
+
|
|
271
|
+
def _apply_improvements(self, tex_path: str, actions: List[ImprovementAction]) -> str:
|
|
272
|
+
"""Apply improvement actions to LaTeX document using LLM reasoning."""
|
|
273
|
+
# Read current LaTeX content
|
|
274
|
+
with open(tex_path, 'r') as f:
|
|
275
|
+
content = f.read()
|
|
276
|
+
|
|
277
|
+
# Extract issue descriptions from actions
|
|
278
|
+
issues = [action.description for action in actions]
|
|
279
|
+
|
|
280
|
+
# Use LLM-based LaTeX generator to apply fixes intelligently
|
|
281
|
+
print(f"š¤ Using LLM to apply {len(issues)} improvements...")
|
|
282
|
+
fixed_latex, success, fixes_applied = self.llm_latex_generator.apply_visual_qa_fixes(
|
|
283
|
+
content, issues
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if not success:
|
|
287
|
+
print("ā ļø LLM fixes failed, falling back to manual approach")
|
|
288
|
+
# Fallback to simple approach
|
|
289
|
+
for action in actions:
|
|
290
|
+
fixed_latex = self._apply_latex_fix_simple(fixed_latex, action)
|
|
291
|
+
|
|
292
|
+
# Write improved version
|
|
293
|
+
improved_path = tex_path.replace('.tex', '_improved.tex')
|
|
294
|
+
with open(improved_path, 'w', encoding='utf-8') as f:
|
|
295
|
+
f.write(fixed_latex)
|
|
296
|
+
|
|
297
|
+
return improved_path
|
|
298
|
+
|
|
299
|
+
def _apply_latex_fix_simple(self, content: str, action: ImprovementAction) -> str:
|
|
300
|
+
"""Apply a specific LaTeX fix to the content (simple fallback method)."""
|
|
301
|
+
# This is the old simple method, kept as fallback
|
|
302
|
+
# Insert fix in preamble before \begin{document}
|
|
303
|
+
begin_doc_pos = content.find('\\begin{document}')
|
|
304
|
+
if begin_doc_pos == -1:
|
|
305
|
+
return content
|
|
306
|
+
|
|
307
|
+
# Add improvement comment and fix
|
|
308
|
+
improvement_block = f"""
|
|
309
|
+
% Visual QA Improvement: {action.description}
|
|
310
|
+
{action.latex_fix}
|
|
311
|
+
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
# Insert before \begin{document}
|
|
315
|
+
improved_content = (
|
|
316
|
+
content[:begin_doc_pos] +
|
|
317
|
+
improvement_block +
|
|
318
|
+
content[begin_doc_pos:]
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
return improved_content
|
|
322
|
+
|
|
323
|
+
def _compile_improved_tex(self, tex_path: str, output_pdf: str, max_corrections: int = 3) -> bool:
|
|
324
|
+
"""
|
|
325
|
+
Compile improved LaTeX to PDF with LLM self-correction on errors.
|
|
326
|
+
|
|
327
|
+
If compilation fails, uses LLM to analyze the error and fix it,
|
|
328
|
+
then tries again. Repeats up to max_corrections times.
|
|
329
|
+
"""
|
|
330
|
+
try:
|
|
331
|
+
# First compilation attempt
|
|
332
|
+
success, message = self.pdf_compiler.compile(tex_path)
|
|
333
|
+
if success:
|
|
334
|
+
# Move generated PDF to desired location
|
|
335
|
+
generated_pdf = tex_path.replace('.tex', '.pdf')
|
|
336
|
+
if os.path.exists(generated_pdf) and generated_pdf != output_pdf:
|
|
337
|
+
# Remove existing file first (Windows compatibility)
|
|
338
|
+
if os.path.exists(output_pdf):
|
|
339
|
+
os.remove(output_pdf)
|
|
340
|
+
shutil.move(generated_pdf, output_pdf)
|
|
341
|
+
return True
|
|
342
|
+
|
|
343
|
+
# Compilation failed - enter self-correction loop
|
|
344
|
+
print(f"ā ļø Initial compilation failed. Starting LLM self-correction...")
|
|
345
|
+
|
|
346
|
+
# Read the failed LaTeX
|
|
347
|
+
with open(tex_path, 'r', encoding='utf-8') as f:
|
|
348
|
+
failed_latex = f.read()
|
|
349
|
+
|
|
350
|
+
# Use LLM to self-correct based on compilation error
|
|
351
|
+
corrected_latex, correction_success, corrections = \
|
|
352
|
+
self.llm_latex_generator.self_correct_compilation_errors(
|
|
353
|
+
failed_latex, message, max_attempts=max_corrections
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
if not correction_success:
|
|
357
|
+
print(f"ā LLM self-correction failed after {max_corrections} attempts")
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
# Write the corrected LaTeX
|
|
361
|
+
with open(tex_path, 'w', encoding='utf-8') as f:
|
|
362
|
+
f.write(corrected_latex)
|
|
363
|
+
|
|
364
|
+
# Try compiling the corrected version
|
|
365
|
+
print("š Compiling LLM-corrected LaTeX...")
|
|
366
|
+
success, message = self.pdf_compiler.compile(tex_path)
|
|
367
|
+
|
|
368
|
+
if success:
|
|
369
|
+
generated_pdf = tex_path.replace('.tex', '.pdf')
|
|
370
|
+
if os.path.exists(generated_pdf) and generated_pdf != output_pdf:
|
|
371
|
+
# Remove existing file first (Windows compatibility)
|
|
372
|
+
if os.path.exists(output_pdf):
|
|
373
|
+
os.remove(output_pdf)
|
|
374
|
+
shutil.move(generated_pdf, output_pdf)
|
|
375
|
+
print(f"ā
LLM self-correction successful! PDF generated.")
|
|
376
|
+
return True
|
|
377
|
+
else:
|
|
378
|
+
print(f"ā Compilation still failed after LLM correction: {message}")
|
|
379
|
+
return False
|
|
380
|
+
|
|
381
|
+
except Exception as e:
|
|
382
|
+
print(f"ā Compilation error: {e}")
|
|
383
|
+
return False
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def main():
|
|
387
|
+
"""Test the dynamic Visual QA feedback system."""
|
|
388
|
+
if len(os.sys.argv) != 2:
|
|
389
|
+
print("Usage: python visual_qa_agent.py <pdf_path>")
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
pdf_path = os.sys.argv[1]
|
|
393
|
+
agent = VisualQAFeedbackAgent()
|
|
394
|
+
|
|
395
|
+
print("šÆ Starting Dynamic Visual QA Improvement Process")
|
|
396
|
+
print("=" * 60)
|
|
397
|
+
|
|
398
|
+
final_pdf, improvements, final_version = agent.analyze_and_improve(pdf_path)
|
|
399
|
+
|
|
400
|
+
print(f"\nš Process Complete!")
|
|
401
|
+
print(f"š Final PDF: {final_pdf}")
|
|
402
|
+
if final_version:
|
|
403
|
+
print(f"š¦ Final Version: {final_version}")
|
|
404
|
+
print(f"š§ Improvements Made: {len(improvements)}")
|
|
405
|
+
for i, improvement in enumerate(improvements, 1):
|
|
406
|
+
print(f" {i}. {improvement}")
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
if __name__ == "__main__":
|
|
410
|
+
main()
|