| import os |
| import time |
| import base64 |
| import json |
| import httpx |
| import uuid |
| import hmac |
| import hashlib |
| from fastapi import APIRouter, Form, File, UploadFile |
| from fastapi.responses import HTMLResponse, JSONResponse |
|
|
| router = APIRouter() |
|
|
| |
| BALE_BOT_TOKEN = os.environ.get("BALE_BOT_TOKEN", "2030030646:atvybsEWn6HNfx7ciG_sM6MY-majP0hEQgE").strip() |
|
|
| |
| SHARED_SECRET = "AI_ALPHA_SECURE_TOKEN_2026" |
|
|
| CONTEXT_TRANSLATIONS = { |
| "edit_image": "ویرایش عکس 🪄", |
| "voice_change": "تغییر صدا 🎙️", |
| "voice_clone": "کلون کردن صدا 👤", |
| "animate_image": "متحرکسازی تصویر 🎞️", |
| "video_image": "ساخت ویدیو با عکس 🖼️", |
| "image_analysis": "تحلیل تصویر 🔍", |
| "stt": "تبدیل صدا به متن 📝", |
| "chat_file": "چت با فایل/عکس 🤖" |
| } |
|
|
| |
| EXPIRED_HTML = """ |
| <!DOCTYPE html> |
| <html lang="fa" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>لینک منقضی شده است | هوش مصنوعی آلفا</title> |
| <style> |
| body { font-family: Tahoma, sans-serif; background-color: #1a1a2e; color: #fff; text-align: center; padding: 20px; margin: 0; } |
| .container { background: #16213e; max-width: 400px; margin: 80px auto; padding: 45px 30px; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); border: 2.5px solid #e94560; } |
| h2 { color: #e94560; font-size: 24px; margin-bottom: 20px; font-weight: bold; } |
| p { color: #a2a2bd; font-size: 15px; line-height: 1.8; margin-bottom: 30px; } |
| .btn { display: inline-block; background: #e94560; color: #fff; text-decoration: none; padding: 12px 25px; border-radius: 8px; font-size: 16px; font-weight: bold; transition: 0.3s; } |
| .btn:hover { background: #ff5e7e; } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h2>⚠️ لینک منقضی شده است!</h2> |
| <p>متأسفانه این لینک منقضی شده است.<br><br>لطفاً از طریق ربات مجدداً روی دکمه مورد نظر کلیک کنید تا لینک جدید و فعال دریافت کنید.</p> |
| <a href="https://rubika.ir/aialpha" class="btn">برگشت به روبیکا 🤖</a> |
| </div> |
| </body> |
| </html> |
| """ |
|
|
| BRIDGE_HTML = """ |
| <!DOCTYPE html> |
| <html lang="fa" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>آپلود فایل | هوش مصنوعی آلفا</title> |
| <style> |
| body { font-family: Tahoma, sans-serif; background-color: #1a1a2e; color: #fff; text-align: center; padding: 20px; margin: 0; } |
| .container { background: #16213e; max-width: 400px; margin: 50px auto; padding: 30px; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); } |
| h2 { color: #e94560; font-size: 22px; margin-bottom: 5px; } |
| .context-badge { display: inline-block; background: #0f3460; color: #43dde6; padding: 5px 15px; border-radius: 20px; font-size: 13px; font-weight: bold; margin-bottom: 20px; } |
| p { color: #a2a2bd; font-size: 14px; margin-bottom: 30px; line-height: 1.6; } |
| .upload-area { border: 2px dashed #e94560; padding: 40px 20px; border-radius: 10px; cursor: pointer; transition: 0.3s; display: block;} |
| .upload-area:hover { background: rgba(233, 69, 96, 0.1); } |
| .upload-area input { display: none; } |
| .btn { background: #e94560; color: #fff; border: none; padding: 12px 25px; border-radius: 8px; font-size: 16px; font-weight: bold; cursor: pointer; margin-top: 20px; width: 100%; transition: 0.2s;} |
| .btn:active { transform: scale(0.95); } |
| .loader { border: 4px solid #16213e; border-top: 4px solid #e94560; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 10px auto; display: none; } |
| @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } |
| #success-msg { display: none; color: #4caf50; margin-top: 20px; font-weight: bold; font-size: 18px; line-height: 1.5; } |
| .warning { color: #ffeb3b; font-size: 12px; margin-top: 15px; } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h2>آپلود سنتر آلفا 🚀</h2> |
| <div class="context-badge">بخش: {CONTEXT_NAME}</div> |
| |
| <p>فایل خود را اینجا انتخاب کنید تا مستقیماً و پرسرعت به ربات متصل شود.</p> |
| |
| <form id="uploadForm"> |
| <input type="hidden" id="file_id" name="file_id" value="{FILE_ID}"> |
| <input type="hidden" id="bot_b64" name="bot_b64" value="{BOT_B64}"> |
| <input type="hidden" id="t" name="t" value="{TIMESTAMP}"> |
| <label class="upload-area" id="drop-area"> |
| <input type="file" id="fileInput" name="file" required> |
| <div id="fileName" style="font-size:16px;">📂 برای انتخاب فایل کلیک کنید</div> |
| </label> |
| <button type="submit" class="btn" id="submitBtn">آپلود و ارسال</button> |
| <div class="loader" id="loader"></div> |
| <div class="warning">⏳ این لینک یکبار مصرف است و تا ۲ دقیقه اعتبار دارد.</div> |
| </form> |
| |
| <div id="success-msg"> |
| ✅ فایل با موفقیت به ربات ارسال شد!<br><br> |
| <span style="font-size:14px; color:#a2a2bd;">لطفاً این صفحه را ببندید و به روبیکا برگردید. ربات در حال پردازش است.</span> |
| </div> |
| </div> |
| |
| <script> |
| const fileInput = document.getElementById('fileInput'); |
| const fileNameDiv = document.getElementById('fileName'); |
| const form = document.getElementById('uploadForm'); |
| const loader = document.getElementById('loader'); |
| const submitBtn = document.getElementById('submitBtn'); |
| const successMsg = document.getElementById('success-msg'); |
| |
| fileInput.addEventListener('change', function() { |
| if(this.files.length > 0) { |
| fileNameDiv.innerHTML = "📄 " + this.files[0].name; |
| } |
| }); |
| |
| form.addEventListener('submit', function(e) { |
| e.preventDefault(); |
| if(fileInput.files.length === 0) return alert("لطفا یک فایل انتخاب کنید."); |
| |
| submitBtn.style.display = "none"; |
| loader.style.display = "block"; |
| |
| let formData = new FormData(form); |
| fetch('/api/bridge/upload', { |
| method: 'POST', |
| body: formData |
| }) |
| .then(response => response.json()) |
| .then(data => { |
| loader.style.display = "none"; |
| if(data.status === "success") { |
| form.style.display = "none"; |
| successMsg.style.display = "block"; |
| } else { |
| alert("خطا در آپلود: " + data.message); |
| submitBtn.style.display = "block"; |
| } |
| }) |
| .catch(error => { |
| loader.style.display = "none"; |
| submitBtn.style.display = "block"; |
| alert("ارتباط با سرور قطع شد!"); |
| }); |
| }); |
| </script> |
| </body> |
| </html> |
| """ |
|
|
| VIEWER_HTML = """ |
| <!DOCTYPE html> |
| <html lang="fa" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>{FILE_NAME} | دانلود سنتر آلفا</title> |
| <style> |
| body { font-family: Tahoma, sans-serif; background-color: #1a1a2e; color: #fff; text-align: center; padding: 20px; margin: 0; display: flex; flex-direction: column; min-height: 100vh; justify-content: center; align-items: center; } |
| .container { background: #16213e; max-width: 500px; width: 90%; padding: 30px; border-radius: 15px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); border: 1px solid rgba(233, 69, 96, 0.2); } |
| h2 { color: #e94560; font-size: 18px; margin-bottom: 20px; word-wrap: break-word; line-height: 1.6; } |
| .media-box { background: #0f3460; padding: 20px; border-radius: 10px; margin-bottom: 25px; display: flex; justify-content: center; align-items: center; min-height: 150px; } |
| img, video { max-width: 100%; max-height: 350px; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.3); } |
| audio { width: 100%; } |
| .file-icon { font-size: 70px; margin-bottom: 10px; display: block; animation: float 3s ease-in-out infinite; } |
| @keyframes float { 0% { transform: translateY(0px); } 50% { transform: translateY(-10px); } 100% { transform: translateY(0px); } } |
| .btn-dl { display: block; background: #e94560; color: #fff; text-decoration: none; padding: 14px 20px; border-radius: 8px; font-size: 17px; font-weight: bold; transition: 0.3s; box-shadow: 0 4px 10px rgba(233, 69, 96, 0.3); } |
| .btn-dl:hover { background: #ff5e7e; box-shadow: 0 6px 15px rgba(233, 69, 96, 0.5); } |
| .btn-dl:active { transform: scale(0.98); } |
| .footer { margin-top: 20px; font-size: 12px; color: #a2a2bd; } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h2>{FILE_NAME}</h2> |
| <div class="media-box"> |
| {MEDIA_CONTENT} |
| </div> |
| <a href="{BALE_URL}" download="{FILE_NAME}" class="btn-dl">دانلود مستقیم فایل 📥</a> |
| <div class="footer">قدرت گرفته از هسته هوش مصنوعی آلفا 🚀</div> |
| </div> |
| </body> |
| </html> |
| """ |
|
|
| def verify_signature(user_code: str, unique_token: str, ctx: str, t: int, p: str, sig: str) -> bool: |
| """بررسی و راستیآزمایی امضای دیجیتال برای جلوگیری از دستکاری دستی پارامترها""" |
| message = f"{user_code}:{unique_token}:{ctx}:{t}:{p}" |
| expected_sig = hmac.new(SHARED_SECRET.encode(), message.encode(), hashlib.sha256).hexdigest() |
| return hmac.compare_digest(expected_sig, sig) |
|
|
| @router.get("/view/{encoded}") |
| async def view_file_page(encoded: str): |
| """رمزگشایی ریاضیاتی آدرس بله در رم و نمایش صفحه لودر بدون مصرف هارد رانفلر""" |
| try: |
| missing_padding = len(encoded) % 4 |
| if missing_padding: |
| encoded += '=' * (4 - missing_padding) |
| |
| data_bytes = base64.urlsafe_b64decode(encoded) |
| data = json.loads(data_bytes.decode('utf-8')) |
| |
| bale_url = data.get("u") |
| file_name = data.get("n", "file") |
| file_type = data.get("t", "File") |
| |
| media_content = "" |
| ft_lower = file_type.lower() |
| if ft_lower in ["photo", "image"]: |
| media_content = f'<img src="{bale_url}" alt="{file_name}">' |
| elif ft_lower in ["video"]: |
| media_content = f'<video src="{bale_url}" controls></video>' |
| elif ft_lower in ["voice", "music", "audio"]: |
| media_content = f'<audio src="{bale_url}" controls></audio>' |
| else: |
| media_content = '<div style="text-align:center;"><span class="file-icon">📄</span><span style="color:#a2a2bd; font-size:14px;">نمایش پیشنمایش برای این نوع سند در دسترس نیست.</span></div>' |
| |
| final_html = VIEWER_HTML.replace("{FILE_NAME}", file_name).replace("{MEDIA_CONTENT}", media_content).replace("{BALE_URL}", bale_url) |
| return HTMLResponse(content=final_html, status_code=200) |
| except: |
| return HTMLResponse("<h1>❌ فایل معتبر نیست یا لینک مخدوش شده است.</h1>", status_code=400) |
|
|
|
|
| @router.get("/v") |
| @router.get("/v/") |
| async def view_file_short(t: str = "File", id: str = ""): |
| """🟢 لودر اختصاصی بسیار کوتاه بدون مصرف هارد و دیسک رانفلر""" |
| try: |
| bale_url = f"https://tapi.bale.ai/file/bot{BALE_BOT_TOKEN}/{id}" |
| |
| titles = { |
| "photo": "تصویر هوش مصنوعی 🎨", |
| "image": "تصویر هوش مصنوعی 🎨", |
| "video": "ویدیوی ساخته شده 🎬", |
| "voice": "صدای تولید شده 🎙️", |
| "music": "موسیقی ساخته شده 🎵", |
| "audio": "فایل صوتی 🎧", |
| "file": "سند متنی آلفا 📄" |
| } |
| display_name = titles.get(t.lower(), "فایل خروجی آلفا 📁") |
| |
| media_content = "" |
| ft_lower = t.lower() |
| if ft_lower in ["photo", "image"]: |
| media_content = f'<img src="{bale_url}" alt="{display_name}">' |
| elif ft_lower in ["video"]: |
| media_content = f'<video src="{bale_url}" controls></video>' |
| elif ft_lower in ["voice", "music", "audio"]: |
| media_content = f'<audio src="{bale_url}" controls></audio>' |
| else: |
| media_content = '<div style="text-align:center;"><span class="file-icon">📄</span><span style="color:#a2a2bd; font-size:14px;">فرمت فایل عمومی</span></div>' |
| |
| final_html = VIEWER_HTML.replace("{FILE_NAME}", display_name).replace("{MEDIA_CONTENT}", media_content).replace("{BALE_URL}", bale_url) |
| return HTMLResponse(content=final_html, status_code=200) |
| except: |
| return HTMLResponse("<h1>❌ ارتباط با سرور برقرار نشد.</h1>", status_code=400) |
|
|
|
|
| @router.get("/upload/{user_code}/{unique_token}") |
| async def upload_web_page(user_code: str, unique_token: str, ctx: str = "unknown", b: str = "", t: int = 0, p: str = "0", sig: str = ""): |
| """صفحهای که کاربر باز میکند (همراه با بررسی اعتبار زمانی لینک و لود پویای ادیتور روبیکا)""" |
| current_time = int(time.time()) |
| if t == 0 or (current_time - t) > 120: |
| return HTMLResponse(content=EXPIRED_HTML, status_code=200) |
|
|
| is_premium_verified = False |
| if sig and verify_signature(user_code, unique_token, ctx, t, p, sig): |
| if p == "1": |
| is_premium_verified = True |
|
|
| premium_status_val = "paid" if is_premium_verified else "free" |
| file_id = f"{user_code}_{ctx}_{unique_token}" |
| |
| |
| if ctx == "edit_image" and os.path.exists("boteditor.html"): |
| with open("boteditor.html", "r", encoding="utf-8") as f: |
| boteditor_content = f.read() |
| final_html = boteditor_content.replace("{FILE_ID}", file_id).replace("{BOT_B64}", b).replace("{TIMESTAMP}", str(t)).replace("{PREMIUM_STATUS}", premium_status_val) |
| return HTMLResponse(content=final_html, status_code=200) |
|
|
| |
| if ctx == "voice_clone" and os.path.exists("botclone.html"): |
| with open("botclone.html", "r", encoding="utf-8") as f: |
| botclone_content = f.read() |
| final_html = botclone_content.replace("{FILE_ID}", file_id).replace("{BOT_B64}", b).replace("{TIMESTAMP}", str(t)).replace("{PREMIUM_STATUS}", premium_status_val) |
| return HTMLResponse(content=final_html, status_code=200) |
|
|
| context_name = CONTEXT_TRANSLATIONS.get(ctx, "فایل عمومی 📁") |
| html_content = BRIDGE_HTML.replace("{FILE_ID}", file_id).replace("{CONTEXT_NAME}", context_name).replace("{BOT_B64}", b).replace("{TIMESTAMP}", str(t)) |
| return HTMLResponse(content=html_content, status_code=200) |
|
|
| @router.post("/api/bridge/upload") |
| async def bridge_upload( |
| file_id: str = Form(...), |
| bot_b64: str = Form(...), |
| t: int = Form(...), |
| prompt: str = Form(""), |
| file: UploadFile = File(...) |
| ): |
| """دریافت فایل و پرامپت از کاربر و ارسال مستقیم به سرور هاگینگ فیس""" |
| current_time = int(time.time()) |
| if (current_time - t) > 120: |
| return JSONResponse({"status": "error", "message": "این لینک منقضی شده است. مجدداً از ربات لینک بگیرید."}) |
|
|
| try: |
| bot_url = base64.b64decode(bot_b64).decode('utf-8').strip() |
| file_content = await file.read() |
| target_url = f"{bot_url}/api/bridge/webhook" |
| |
| async with httpx.AsyncClient(verify=False, timeout=90.0) as client: |
| resp = await client.post( |
| target_url, |
| files={"file": (file.filename, file_content, file.content_type)}, |
| data={ |
| "file_id": file_id, |
| "prompt": prompt |
| } |
| ) |
| |
| if resp.status_code == 200: |
| return JSONResponse({"status": "success"}) |
| else: |
| return JSONResponse({"status": "error", "message": f"خطای ارتباط با هاگینگ فیس: {resp.text[:120]}"}) |
| |
| except Exception as e: |
| return JSONResponse({"status": "error", "message": f"خطای داخلی رانفلر: {str(e)}"}) |
|
|
| @router.post("/api/bridge/upload_clone") |
| async def bridge_upload_clone( |
| file_id: str = Form(...), |
| bot_b64: str = Form(...), |
| t: int = Form(...), |
| file1: UploadFile = File(...), |
| file2: UploadFile = File(...) |
| ): |
| """🟢 مسیر جدید: دریافتِ همزمان دو فایل صوتی برای کلون صدا و ارسال مستقیم به هاگینگ فیس""" |
| current_time = int(time.time()) |
| if (current_time - t) > 120: |
| return JSONResponse({"status": "error", "message": "این لینک منقضی شده است. مجدداً از ربات لینک بگیرید."}) |
|
|
| try: |
| bot_url = base64.b64decode(bot_b64).decode('utf-8').strip() |
| |
| |
| file1_content = await file1.read() |
| file2_content = await file2.read() |
| |
| target_url = f"{bot_url}/api/bridge/webhook_clone" |
| |
| async with httpx.AsyncClient(verify=False, timeout=120.0) as client: |
| resp = await client.post( |
| target_url, |
| files={ |
| "file1": (file1.filename, file1_content, file1.content_type), |
| "file2": (file2.filename, file2_content, file2.content_type) |
| }, |
| data={"file_id": file_id} |
| ) |
| |
| if resp.status_code == 200: |
| return JSONResponse({"status": "success"}) |
| else: |
| return JSONResponse({"status": "error", "message": f"خطای ارتباط با هاگینگ فیس: {resp.text[:120]}"}) |
| |
| except Exception as e: |
| return JSONResponse({"status": "error", "message": f"خطای داخلی رانفلر: {str(e)}"}) |