Spaces:
Sleeping
Sleeping
import os | |
import smtplib | |
import tempfile | |
from email.mime.multipart import MIMEMultipart | |
from email.mime.text import MIMEText | |
from email.mime.application import MIMEApplication | |
from dotenv import load_dotenv | |
from markdown_it import MarkdownIt | |
from datetime import datetime | |
import weasyprint | |
# Tải biến môi trường | |
load_dotenv() | |
# Thông tin email từ biến môi trường | |
SENDER_EMAIL = os.getenv("SENDER_EMAIL") | |
SENDER_APP_PASSWORD = os.getenv("SENDER_APP_PASSWORD") | |
def _markdown_to_html(markdown_string): | |
"""Convert Markdown to HTML""" | |
md = MarkdownIt() | |
html_content = md.render(markdown_string) | |
# Format current date | |
current_date = datetime.now().strftime("%d/%m/%Y") | |
# Create complete HTML with CSS for nice formatting | |
full_html = f""" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Daily Market Report - {current_date}</title> | |
<style> | |
@page {{ | |
size: A4; | |
margin: 2cm; | |
}} | |
body {{ | |
font-family: Arial, Helvetica, sans-serif; | |
line-height: 1.5; | |
color: #333; | |
max-width: 800px; | |
margin: 0 auto; | |
}} | |
.report-header {{ | |
text-align: center; | |
margin-bottom: 30px; | |
}} | |
.report-date {{ | |
font-style: italic; | |
color: #666; | |
margin-bottom: 10px; | |
}} | |
.report-title {{ | |
font-size: 24pt; | |
margin-bottom: 5px; | |
color: #2c3e50; | |
}} | |
.report-subtitle {{ | |
font-size: 14pt; | |
color: #7f8c8d; | |
margin-top: 0; | |
}} | |
.report-body {{ | |
text-align: justify; | |
}} | |
h1, h2, h3, h4, h5, h6 {{ | |
color: #2c3e50; | |
margin-top: 20px; | |
}} | |
h1 {{ font-size: 20pt; }} | |
h2 {{ font-size: 18pt; }} | |
h3 {{ font-size: 16pt; }} | |
h4 {{ font-size: 14pt; }} | |
h5 {{ font-size: 12pt; }} | |
h6 {{ font-size: 10pt; }} | |
p {{ | |
margin-bottom: 10px; | |
}} | |
a {{ | |
color: #3498db; | |
text-decoration: none; | |
}} | |
a:hover {{ | |
text-decoration: underline; | |
}} | |
ul, ol {{ | |
margin: 10px 0 10px 20px; | |
}} | |
li {{ | |
margin-bottom: 5px; | |
}} | |
blockquote {{ | |
border-left: 4px solid #eee; | |
padding-left: 10px; | |
margin-left: 0; | |
color: #777; | |
}} | |
.section {{ | |
margin-bottom: 30px; | |
}} | |
.footer {{ | |
text-align: center; | |
margin-top: 40px; | |
padding-top: 20px; | |
font-size: 12px; | |
color: #777; | |
border-top: 1px solid #eee; | |
}} | |
/* Custom styling for bullet points */ | |
ul {{ | |
list-style-type: disc; | |
}} | |
ul ul {{ | |
list-style-type: circle; | |
}} | |
ul ul ul {{ | |
list-style-type: square; | |
}} | |
</style> | |
</head> | |
<body> | |
<div class="report-header"> | |
<div class="report-date">Date: {current_date}</div> | |
<h1 class="report-title">Daily Market Report</h1> | |
<h2 class="report-subtitle">AI Financial Dashboard</h2> | |
</div> | |
<div class="report-body"> | |
{html_content} | |
</div> | |
<div class="footer"> | |
This report was automatically generated by AI Financial Dashboard. Information is for reference only. | |
</div> | |
</body> | |
</html> | |
""" | |
return full_html | |
def _generate_pdf_from_markdown(markdown_string): | |
"""Generate PDF from Markdown using WeasyPrint""" | |
# Convert markdown to HTML | |
html_content = _markdown_to_html(markdown_string) | |
# Create temporary HTML file | |
with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as temp_html: | |
temp_html_path = temp_html.name | |
temp_html.write(html_content.encode('utf-8')) | |
# Create PDF from HTML | |
try: | |
# Create temporary PDF filename | |
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as temp_pdf: | |
temp_pdf_path = temp_pdf.name | |
# Generate PDF | |
weasyprint.HTML(filename=temp_html_path).write_pdf(temp_pdf_path) | |
# Read PDF content | |
with open(temp_pdf_path, 'rb') as f: | |
pdf_data = f.read() | |
# Delete temporary files | |
os.unlink(temp_html_path) | |
os.unlink(temp_pdf_path) | |
return pdf_data | |
except Exception as e: | |
# Handle errors and ensure temporary files are deleted | |
if os.path.exists(temp_html_path): | |
os.unlink(temp_html_path) | |
raise e | |
def send_report_via_email(report_markdown, recipient_email): | |
"""Send market report via email""" | |
try: | |
# Generate PDF from markdown | |
pdf_data = _generate_pdf_from_markdown(report_markdown) | |
# Create message | |
message = MIMEMultipart() | |
message["From"] = SENDER_EMAIL | |
message["To"] = recipient_email | |
message["Subject"] = f"AI Financial Dashboard - Daily Market Report {datetime.now().strftime('%d/%m/%Y')}" | |
# Add content with UTF-8 encoding | |
body = """ | |
Dear User, | |
Attached is today's financial market report, automatically generated by AI Financial Dashboard. | |
Best regards, | |
AI Financial Dashboard Team | |
""" | |
message.attach(MIMEText(body, "plain", "utf-8")) | |
# Attach PDF file | |
attachment = MIMEApplication(pdf_data, _subtype="pdf") | |
attachment.add_header( | |
"Content-Disposition", "attachment", | |
filename=f"Market_Report_{datetime.now().strftime('%Y%m%d')}.pdf" | |
) | |
message.attach(attachment) | |
# Connect to SMTP server and send email | |
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server: | |
server.login(SENDER_EMAIL, SENDER_APP_PASSWORD) | |
server.send_message(message) | |
return True, "Email sent successfully!" | |
except Exception as e: | |
return False, f"Error sending email: {str(e)}" |