@@ -223,19 +223,65 @@ def _on_error(error_msg):
223223 )
224224
225225 def _send_deep_research_telegram (self , report_path : str ):
226- """Send deep research completion notification and full report file to Telegram ."""
226+ """Send deep research report as PDF to Telegram (with md fallback) ."""
227227 if not self .telegram .is_configured :
228228 return
229229 try :
230230 self .telegram .send ("Deep Research completed!" )
231- ok = self .telegram .send_document (report_path , caption = "📄 Full Deep Research report" )
231+ # Convert markdown to PDF for better readability
232+ pdf_path = self ._convert_md_to_pdf (report_path )
233+ if pdf_path :
234+ ok = self .telegram .send_document (pdf_path , caption = "📄 Deep Research Report (PDF)" )
235+ if ok :
236+ return
237+ # Fallback: send the .md file
238+ ok = self .telegram .send_document (report_path , caption = "📄 Deep Research report (Markdown)" )
232239 if not ok :
233- # Fallback: send as text if document upload fails
234240 content = Path (report_path ).read_text ()
235241 self .telegram .send_raw (content [:4000 ])
236242 except Exception as e :
237243 self .log (f"Failed to send deep research to Telegram: { e } " , "WARN" )
238244
245+ def _convert_md_to_pdf (self , md_path : str ) -> str :
246+ """Convert a markdown file to PDF. Returns PDF path or empty string on failure."""
247+ try :
248+ import markdown
249+ from weasyprint import HTML
250+
251+ md_content = Path (md_path ).read_text ()
252+ html_body = markdown .markdown (
253+ md_content ,
254+ extensions = ["tables" , "fenced_code" , "codehilite" , "toc" ],
255+ )
256+
257+ # Wrap in styled HTML
258+ html_full = f"""<!DOCTYPE html>
259+ <html><head><meta charset="utf-8">
260+ <style>
261+ body {{ font-family: 'Helvetica Neue', Arial, sans-serif; font-size: 11pt;
262+ line-height: 1.6; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #333; }}
263+ h1 {{ font-size: 20pt; color: #1a1a2e; border-bottom: 2px solid #0d9488; padding-bottom: 8px; }}
264+ h2 {{ font-size: 15pt; color: #1a1a2e; margin-top: 24px; }}
265+ h3 {{ font-size: 12pt; color: #374151; }}
266+ code {{ background: #f3f4f6; padding: 2px 6px; border-radius: 4px; font-size: 10pt; }}
267+ pre {{ background: #f3f4f6; padding: 12px; border-radius: 8px; overflow-x: auto; font-size: 9pt; }}
268+ table {{ border-collapse: collapse; width: 100%; margin: 12px 0; }}
269+ th, td {{ border: 1px solid #d1d5db; padding: 8px 12px; text-align: left; font-size: 10pt; }}
270+ th {{ background: #f0fdfa; font-weight: 600; }}
271+ blockquote {{ border-left: 4px solid #0d9488; margin: 12px 0; padding: 8px 16px; color: #555; background: #f0fdfa; }}
272+ a {{ color: #0d9488; }}
273+ </style></head><body>{ html_body } </body></html>"""
274+
275+ pdf_path = str (Path (md_path ).with_suffix (".pdf" ))
276+ HTML (string = html_full ).write_pdf (pdf_path )
277+ self .log (f"Converted deep research to PDF: { pdf_path } " , "INFO" )
278+ return pdf_path
279+ except ImportError :
280+ self .log ("markdown/weasyprint not installed, skipping PDF conversion" , "WARN" )
281+ except Exception as e :
282+ self .log (f"PDF conversion failed: { e } " , "WARN" )
283+ return ""
284+
239285 # ========== Telegram ==========
240286
241287 def _tg_history_append (self , role : str , text : str ):
0 commit comments