Add FastMCP tool for web scrapping.
Add logging info for tools calling
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import markdown
|
||||
from weasyprint import HTML
|
||||
|
||||
# ==========================================
|
||||
# REUSABLE HTML & CSS LAYOUT TEMPLATE
|
||||
# ==========================================
|
||||
PDF_REPORT_TEMPLATE = """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
@page {{
|
||||
size: A4;
|
||||
margin: 20mm;
|
||||
@bottom-right {{
|
||||
content: counter(page);
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 9pt;
|
||||
}}
|
||||
}}
|
||||
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
color: #333333;
|
||||
line-height: 1.6;
|
||||
font-size: 11pt;
|
||||
}}
|
||||
|
||||
h1 {{ font-size: 18pt; margin-top: 24pt; border-bottom: 1px solid #ddd; padding-bottom: 6px; }}
|
||||
h2 {{ font-size: 14pt; margin-top: 18pt; color: #2c3e50; }}
|
||||
h3 {{ font-size: 12pt; margin-top: 14pt; color: #7f8c8d; }}
|
||||
|
||||
/* --- Layout Tables --- */
|
||||
table {{
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 15pt 0;
|
||||
}}
|
||||
th, td {{
|
||||
border: 1px solid #dddddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}}
|
||||
th {{ background-color: #f8f9fa; font-weight: bold; }}
|
||||
tr:nth-child(even) {{ background-color: #fdfdfd; }}
|
||||
|
||||
/* --- Links --- */
|
||||
a {{ color: #3498db; text-decoration: none; }}
|
||||
a:hover {{ text-decoration: underline; }}
|
||||
|
||||
/* ==========================================
|
||||
DYNAMIC PAGED MEDIA TOC LAYOUT
|
||||
========================================== */
|
||||
.toc-wrapper {{
|
||||
margin: 20pt 0;
|
||||
padding: 15pt;
|
||||
background: #fdfdfd;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 5px;
|
||||
page-break-after: always;
|
||||
}}
|
||||
|
||||
/* Clear default markdown padding/bullets on root list element */
|
||||
.toc-wrapper > ul {{
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}}
|
||||
|
||||
/* Main Level 1 entries (bolded for contrast) */
|
||||
.toc-wrapper > ul > li {{
|
||||
font-weight: bold;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
}}
|
||||
|
||||
/* Indent Subsections (Level 2 nested lists) */
|
||||
.toc-wrapper li ul {{
|
||||
list-style-type: none;
|
||||
padding-left: 25px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}}
|
||||
|
||||
/* Ensure subsection text lines are regular weight */
|
||||
.toc-wrapper li ul li {{
|
||||
font-weight: normal;
|
||||
margin-bottom: 6px;
|
||||
}}
|
||||
|
||||
.toc-wrapper li {{
|
||||
position: relative;
|
||||
display: block;
|
||||
}}
|
||||
|
||||
/* Pulls the target page number of the markdown heading reference link */
|
||||
.toc-wrapper a::after {{
|
||||
content: target-counter(attr(href), page);
|
||||
float: right;
|
||||
color: #7f8c8d;
|
||||
font-weight: normal;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
{html_body}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
def export_to_pdf(llm_response: str, output_filename: str = "output.pdf") -> None:
|
||||
"""Converts structured LLM response with a fully clickable, indented manual TOC into a clean PDF."""
|
||||
|
||||
# 1. Standard markdown conversion with 'toc' extension enabled.
|
||||
# This automatically adds unique ID anchors to your <h1> and <h2> elements
|
||||
# so that clicking the TOC links will correctly jump down to that section.
|
||||
html_body = markdown.markdown(
|
||||
llm_response,
|
||||
extensions=['fenced_code', 'tables', 'toc']
|
||||
)
|
||||
|
||||
# 2. Inject a styling hook class wrapper around your Table of Contents list block
|
||||
html_body = html_body.replace('<h3>Table of Contents</h3>', '<h3>Table of Contents</h3><div class="toc-wrapper">')
|
||||
|
||||
# Close the div wrapper cleanly right before the next main topic heading begins
|
||||
html_body = html_body.replace('<h1>1.', '</div><h1>1.')
|
||||
|
||||
# 3. Format the final output document string structure
|
||||
final_html_content = PDF_REPORT_TEMPLATE.format(html_body=html_body)
|
||||
|
||||
# 4. Generate the clickable PDF file
|
||||
HTML(string=final_html_content).write_pdf(output_filename)
|
||||
Reference in New Issue
Block a user