import os import io import traceback import re from flask import Flask, request, send_file, render_template from flask_cors import CORS from docx import Document from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.shared import Pt from weasyprint import HTML, CSS import arabic_reshaper from bidi.algorithm import get_display # برای راست‌چین و ترکیب حروف فارسی import markdown from htmldocx import HtmlToDocx app = Flask(__name__) CORS(app) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) FONT_FILE_NAME = "Vazirmatn-Regular.ttf" FOOTER_TEXT = "هوش مصنوعی آلفا دانلود از گوگل پلی" def get_line_direction(line): if not line or line.isspace(): return 'ltr' rtl_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F]') return 'rtl' if rtl_pattern.search(line) else 'ltr' def reshape_rtl_text(text): # ترکیب reshaper و bidi برای خروجی بی‌نقص در فایل‌ها reshaped_text = arabic_reshaper.reshape(text) return get_display(reshaped_text) def get_base_html_for_conversion(text_content): raw_html = markdown.markdown( text_content, extensions=['extra', 'tables', 'nl2br', 'sane_lists'] ) reshaped_html = arabic_reshaper.reshape(raw_html) tags_to_rtl =['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'table', 'th', 'td'] for tag in tags_to_rtl: pattern = re.compile(rf'<{tag}(?P\s[^>]*)?>', re.IGNORECASE) def replacer(match): attrs = match.group('attrs') or '' if 'dir="ltr"' in attrs.lower() or 'style="text-align: left' in attrs.lower(): return match.group(0) return f'<{tag}{attrs} style="text-align: right; direction: rtl; font-family: Vazir, sans-serif;">' reshaped_html = pattern.sub(replacer, reshaped_html) return reshaped_html def create_docx(text_content): try: document = Document() parser = HtmlToDocx() html_content = get_base_html_for_conversion(text_content) parser.add_html_to_document(html_content, document) document.add_paragraph("") footer_p = document.add_paragraph(FOOTER_TEXT) footer_p.alignment = WD_ALIGN_PARAGRAPH.CENTER for run in footer_p.runs: run.bold = True buffer = io.BytesIO() document.save(buffer) buffer.seek(0) return buffer except Exception as e: print(f"⚠️ HTML to DOCX Failed: {e}") # سیستم Fallback: اگر مارک‌داون هوش مصنوعی خراب بود، فایل Word ساده می‌سازد document = Document() document.styles['Normal'].font.name = 'Arial' for line in text_content.split('\n'): if line.strip(): p = document.add_paragraph(reshape_rtl_text(line)) p.alignment = WD_ALIGN_PARAGRAPH.RIGHT document.add_paragraph("\n") footer_p = document.add_paragraph(FOOTER_TEXT) footer_p.alignment = WD_ALIGN_PARAGRAPH.CENTER for run in footer_p.runs: run.bold = True buffer = io.BytesIO() document.save(buffer) buffer.seek(0) return buffer def create_pdf_with_weasyprint(text_content): html_body = get_base_html_for_conversion(text_content) reshaped_footer = FOOTER_TEXT full_html = f""" Exported PDF {html_body} """ try: html = HTML(string=full_html, base_url=BASE_DIR) return io.BytesIO(html.write_pdf()) except Exception as e: print(f"🔥🔥🔥 WEASYPRINT FAILED! 🔥🔥🔥\n{e}") # در صورت شکست، به جای ارور دادن، یک خروجی ساده برمی‌گرداند return create_txt("خطا در ساخت PDF به دلیل پیچیدگی متن. لطفا از فایل DOCX استفاده کنید.\n\n" + text_content) def create_txt(text_content): full_content = f"{text_content}\n\n\n---\n{FOOTER_TEXT}" return io.BytesIO(full_content.encode('utf-8')) def create_html(text_content): html_body = get_base_html_for_conversion(text_content) reshaped_footer = FOOTER_TEXT full_html = f""" Exported File {html_body} """ return io.BytesIO(full_html.encode('utf-8')) def process_request(content, file_format): actions = {'pdf': create_pdf_with_weasyprint, 'docx': create_docx, 'html': create_html, 'txt': create_txt} buffer_func = actions.get(file_format, create_txt) buffer = buffer_func(content) mimetypes = {'pdf': 'application/pdf', 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'html': 'text/html', 'txt': 'text/plain'} mimetype = mimetypes.get(file_format, 'text/plain') filename = f'export.{file_format}' return send_file(buffer, as_attachment=True, download_name=filename, mimetype=mimetype) @app.route('/', methods=['GET', 'POST', 'HEAD']) def index(): if request.method == 'HEAD': return '', 200 if request.method == 'POST': content = request.form.get('content') file_format = request.form.get('format', 'txt').lower() if not content: return "لطفا متنی برای تبدیل وارد کنید.", 400 return process_request(content, file_format) return render_template('index.html') if __name__ == '__main__': app.run(debug=False, host='0.0.0.0', port=7860)