Spaces:
Paused
Paused
| import os | |
| import threading | |
| import time | |
| import telebot | |
| from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton | |
| import fitz # PyMuPDF | |
| import subprocess | |
| import shutil | |
| import gradio as gr | |
| from concurrent.futures import ThreadPoolExecutor | |
| TOKEN = os.environ.get("BOT_TOKEN") | |
| GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY") | |
| if not TOKEN: | |
| raise ValueError("لطفاً BOT_TOKEN را در بخش Secrets تنظیم کنید.") | |
| bot = telebot.TeleBot(TOKEN) | |
| user_target_langs = {} | |
| # استفاده از ThreadPool برای اینکه بات بتواند همزمان پاسخگوی چند کاربر باشد | |
| executor = ThreadPoolExecutor(max_workers=3) | |
| LANGUAGES = { | |
| "فارسی 🇮🇷": "fa", | |
| "انگلیسی 🇬🇧": "eng", | |
| "اسپانیایی 🇪🇸": "spa", | |
| "عربی 🇸🇦": "ara", | |
| "فرانسوی 🇫🇷": "fra", | |
| "روسی 🇷🇺": "rus" | |
| } | |
| def process_manga_page(image_bytes, page_num, target_lang, chat_id): | |
| input_filename = f"temp_in_{chat_id}_{page_num}.png" | |
| output_dir = f"temp_out_{chat_id}_{page_num}" | |
| with open(input_filename, "wb") as f: | |
| f.write(image_bytes) | |
| try: | |
| custom_env = os.environ.copy() | |
| command = [ | |
| "manga_translator", | |
| "--mode", "batch", | |
| "--use-cpu", | |
| "-i", input_filename, | |
| "-d", output_dir, | |
| "--target-lang", target_lang | |
| ] | |
| if GEMINI_API_KEY: | |
| custom_env["OPENAI_API_KEY"] = GEMINI_API_KEY | |
| custom_env["OPENAI_API_BASE"] = "https://generativelanguage.googleapis.com/v1beta/openai/" | |
| command.extend(["--translator", "chatgpt"]) | |
| else: | |
| command.extend(["--translator", "google"]) | |
| subprocess.run(command, env=custom_env, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | |
| translated_file_path = os.path.join(output_dir, input_filename) | |
| with open(translated_file_path, "rb") as f: | |
| translated_bytes = f.read() | |
| return translated_bytes | |
| except Exception as e: | |
| print(f"Error on page {page_num}: {e}") | |
| return image_bytes # در صورت خطا عکس اورجینال را حفظ کن | |
| finally: | |
| if os.path.exists(input_filename): | |
| os.remove(input_filename) | |
| if os.path.exists(output_dir): | |
| shutil.rmtree(output_dir) | |
| def translate_task(input_path, output_path, chat_id, target_lang, message_id_to_edit): | |
| try: | |
| doc = fitz.open(input_path) | |
| new_doc = fitz.open() | |
| total_pages = len(doc) | |
| for page_num in range(total_pages): | |
| # آپدیت کردن پیام وضعیت به جای ارسال پیام جدید | |
| bot.edit_message_text( | |
| chat_id=chat_id, | |
| message_id=message_id_to_edit, | |
| text=f"🔄 **در حال پردازش مانگا...**\n\n" | |
| f"📄 صفحه: {page_num + 1} از {total_pages}\n" | |
| f"⚙️ عملیات: تشخیص زبان، ترجمه مفهومی با AI و جایگذاری متن...", | |
| parse_mode="Markdown" | |
| ) | |
| page = doc[page_num] | |
| image_list = page.get_images(full=True) | |
| if image_list: | |
| xref = image_list[0][0] | |
| base_image = doc.extract_image(xref) | |
| image_bytes = base_image["image"] | |
| processed_bytes = process_manga_page(image_bytes, page_num, target_lang, chat_id) | |
| rect = page.rect | |
| new_page = new_doc.new_page(width=rect.width, height=rect.height) | |
| new_page.insert_image(rect, stream=processed_bytes) | |
| else: | |
| new_page = new_doc.new_page(width=page.rect.width, height=page.rect.height) | |
| new_page.show_pdf_page(new_page.rect, doc, page_num) | |
| # بهینهسازی و فشردهسازی PDF نهایی | |
| new_doc.save(output_path, garbage=4, deflate=True) | |
| new_doc.close() | |
| doc.close() | |
| bot.edit_message_text( | |
| chat_id=chat_id, | |
| message_id=message_id_to_edit, | |
| text="✅ **پردازش تمام شد! در حال آپلود فایل...**", | |
| parse_mode="Markdown" | |
| ) | |
| with open(output_path, 'rb') as final_doc: | |
| bot.send_document(chat_id, final_doc, caption="🎉 این هم از مانگای ترجمهشده شما!\nامیدوارم از خواندنش لذت ببرید.") | |
| except Exception as e: | |
| bot.send_message(chat_id, f"❌ متأسفانه در حین پردازش خطایی رخ داد: {str(e)}") | |
| finally: | |
| if os.path.exists(input_path): | |
| os.remove(input_path) | |
| if os.path.exists(output_path): | |
| os.remove(output_path) | |
| def language_keyboard(): | |
| markup = InlineKeyboardMarkup() | |
| markup.row_width = 2 | |
| buttons = [InlineKeyboardButton(text, callback_data=f"lang_{code}") for text, code in LANGUAGES.items()] | |
| markup.add(*buttons) | |
| return markup | |
| def send_welcome(message): | |
| user_target_langs[message.chat.id] = "fa" | |
| bot.reply_to( | |
| message, | |
| "به ربات فوقپیشرفته مترجم مانگا خوش آمدید! 📚✨\n\n" | |
| "فرقی نمیکند یک داستان عاشقانه لطیف باشد یا یک ایسکای تاریک و روانشناختی با اصطلاحات پیچیده؛ من زبان اصلی را کاملاً خودکار تشخیص داده و با هوش مصنوعی (Gemini/ChatGPT) به بهترین شکل ترجمه و تایپ میکنم.\n\n" | |
| "👇 ابتدا از منوی زیر زبان مقصد را انتخاب کنید و سپس فایل PDF را بفرستید:", | |
| reply_markup=language_keyboard() | |
| ) | |
| def handle_language_selection(call): | |
| lang_code = call.data.split('_')[1] | |
| user_target_langs[call.message.chat.id] = lang_code | |
| bot.answer_callback_query(call.id, "زبان با موفقیت تغییر کرد!") | |
| bot.edit_message_text( | |
| chat_id=call.message.chat.id, | |
| message_id=call.message.message_id, | |
| text=f"✅ زبان مقصد روی **{lang_code}** تنظیم شد.\n\nاکنون منتظر دریافت فایل PDF شما هستم.", | |
| parse_mode="Markdown" | |
| ) | |
| def handle_docs(message): | |
| chat_id = message.chat.id | |
| target_lang = user_target_langs.get(chat_id, "fa") | |
| if message.document.mime_type != 'application/pdf': | |
| bot.reply_to(message, "لطفاً فقط فایل با فرمت PDF ارسال کنید. 🚫") | |
| return | |
| # بررسی حجم فایل (تلگرام محدودیت ۲۰ مگابایتی برای رباتها دارد) | |
| if message.document.file_size > 20 * 1024 * 1024: | |
| bot.reply_to(message, "⚠️ حجم فایل شما بیشتر از ۲۰ مگابایت است. رباتهای تلگرام به صورت پیشفرض نمیتوانند فایلهای بزرگتر را دانلود کنند. لطفاً فایل را به بخشهای کوچکتر تقسیم کنید.") | |
| return | |
| status_message = bot.reply_to(message, "📥 در حال دانلود فایل از سرورهای تلگرام...") | |
| try: | |
| file_info = bot.get_file(message.document.file_id) | |
| downloaded_file = bot.download_file(file_info.file_path) | |
| input_pdf = f"input_{chat_id}_{message.message_id}.pdf" | |
| output_pdf = f"output_{chat_id}_{message.message_id}.pdf" | |
| with open(input_pdf, 'wb') as new_file: | |
| new_file.write(downloaded_file) | |
| bot.edit_message_text( | |
| chat_id=chat_id, | |
| message_id=status_message.message_id, | |
| text="✅ فایل دریافت شد. فایل به صف پردازش اضافه شد..." | |
| ) | |
| # ارسال کار به پسزمینه تا ربات هنگ نکند | |
| executor.submit(translate_task, input_pdf, output_pdf, chat_id, target_lang, status_message.message_id) | |
| except Exception as e: | |
| bot.edit_message_text( | |
| chat_id=chat_id, | |
| message_id=status_message.message_id, | |
| text=f"❌ خطایی در دریافت فایل رخ داد: {str(e)}" | |
| ) | |
| def run_bot(): | |
| bot.infinity_polling(timeout=60, long_polling_timeout=60) | |
| thread = threading.Thread(target=run_bot) | |
| thread.start() | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# 🚀 نسخه نهایی و بهینهشده مترجم مانگا در حال اجراست!") | |
| gr.Markdown("این نسخه مجهز به **Threading**، **فشردهسازی PDF** و **سیستم ویرایش پیام زنده** است.") | |
| if GEMINI_API_KEY: | |
| gr.Markdown("✅ موتور هوش مصنوعی Gemini به عنوان مترجم مفهومی **متصل است**.") | |
| demo.launch() |