Hhy / app.py
ffxbot's picture
Update app.py
0a905b7 verified
Raw
History Blame
12.5 kB
import gradio as gr
import numpy as np
import cv2
import os
import time
import requests
import sys
from PIL import Image
# ─── FIX FOR BASICSR & TORCHVISION ────────────────────────────────────────────
import torchvision.transforms.functional
sys.modules['torchvision.transforms.functional_tensor'] = torchvision.transforms.functional
# ──────────────────────────────────────────────────────────────────────────────
# ─── Model Download ───────────────────────────────────────────────────────────
MODEL_DIR = "weights"
MODEL_PATH = os.path.join(MODEL_DIR, "RealESRGAN_x4plus.pth")
MODEL_URL = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth"
def download_model():
os.makedirs(MODEL_DIR, exist_ok=True)
if not os.path.exists(MODEL_PATH):
print("📥 মডেল ডাউনলোড হচ্ছে...")
r = requests.get(MODEL_URL, stream=True)
with open(MODEL_PATH, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
print("✅ মডেল ডাউনলোড সম্পন্ন!")
download_model()
# ─── Real-ESRGAN Setup ────────────────────────────────────────────────────────
from basicsr.archs.rrdbnet_arch import RRDBNet
from realesrgan import RealESRGANer
def load_upsampler():
model = RRDBNet(
num_in_ch=3, num_out_ch=3,
num_feat=64, num_block=23, num_grow_ch=32, scale=4
)
upsampler = RealESRGANer(
scale=4,
model_path=MODEL_PATH,
model=model,
tile=128,
tile_pad=10,
pre_pad=0,
half=False
)
return upsampler
print("🔄 মডেল লোড হচ্ছে...")
upsampler = load_upsampler()
print("✅ মডেল রেডি!")
# ─── Image Analysis ───────────────────────────────────────────────────────────
def analyze_image(img: Image.Image) -> dict:
w, h = img.size
mp = (w * h) / 1_000_000
if w >= 3840 or h >= 2160:
quality_label = "4K বা তার বেশি (Ultra HD)"
quality_icon = "🟣"
elif w >= 1920 or h >= 1080:
quality_label = "1080p Full HD"
quality_icon = "🟢"
elif w >= 1280 or h >= 720:
quality_label = "720p HD"
quality_icon = "🟡"
elif w >= 854 or h >= 480:
quality_label = "480p SD"
quality_icon = "🟠"
else:
quality_label = "লো রেজোলিউশন"
quality_icon = "🔴"
mode_label = {"RGB": "রঙিন (RGB)", "RGBA": "রঙিন + Transparency", "L": "কালো-সাদা"}.get(img.mode, img.mode)
return {
"width": w, "height": h,
"megapixels": round(mp, 2),
"quality_label": quality_label,
"quality_icon": quality_icon,
"mode": mode_label,
"target_w": 3840, "target_h": 2160
}
# ─── Main Processing ──────────────────────────────────────────────────────────
def upscale_to_4k(pil_img):
if pil_img is None:
yield None, "❌ কোনো ছবি আপলোড করা হয়নি।", None, ""
return
t_start = time.time()
yield None, "🔍 **ছবি বিশ্লেষণ হচ্ছে...**", None, "⏳ প্রসেসিং শুরু হয়েছে"
time.sleep(0.3)
pil_img = pil_img.convert("RGB")
info = analyze_image(pil_img)
analysis_text = f"""
## 📊 ছবি বিশ্লেষণ ফলাফল
| তথ্য | মান |
| :--- | :--- |
| {info['quality_icon']} বর্তমান কোয়ালিটি | **{info['quality_label']}** |
| 📐 বর্তমান রেজোলিউশন | **{info['width']} × {info['height']} px** |
| 📷 মেগাপিক্সেল | **{info['megapixels']} MP** |
| 🎯 টার্গেট রেজোলিউশন | **3840 × 2160 (4K)** |
---
⚡ **AI Upscaling শুরু হচ্ছে (১-২ মিনিট সময় দিন)...**
"""
yield None, analysis_text, None, "🔄 AI প্রসেসিং চলছে..."
img_np = np.array(pil_img)
img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
try:
output_bgr, _ = upsampler.enhance(img_bgr, outscale=4)
except Exception as e:
yield None, f"❌ **এরর:** সার্ভার ওভারলোড হয়েছে, আবার চেষ্টা করুন।", None, "❌ ব্যর্থ হয়েছে"
return
output_rgb = cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB)
output_pil = Image.fromarray(output_rgb)
out_w, out_h = output_pil.size
if out_w != 3840 or out_h != 2160:
output_pil = output_pil.resize((3840, 2160), Image.LANCZOS)
t_end = time.time()
elapsed = t_end - t_start
mins = int(elapsed // 60)
secs = int(elapsed % 60)
time_str = f"{mins} মিনিট {secs} সেকেন্ড" if mins > 0 else f"{secs} সেকেন্ড"
out_path = "/tmp/4k_output.png"
output_pil.save(out_path, "PNG", optimize=False)
file_size_mb = os.path.getsize(out_path) / (1024 * 1024)
result_text = f"""
## ✅ 4K Upscaling সম্পন্ন!
| ফলাফল | মান |
| :--- | :--- |
| 🎯 আউটপুট রেজোলিউশন | **3840 × 2160 (4K Ultra HD)** |
| 📁 ফাইল সাইজ | **{file_size_mb:.1f} MB** |
| ⏱️ সময় লেগেছে | **{time_str}** |
| ✨ আপস্কেল রেশিও | **অটোম্যাটিক 4K এনালাইসিস** |
| 🧠 মডেল | **Real-ESRGAN x4plus** |
---
💾 নিচের ছবিতে রাইট ক্লিক করে **"Save Image"** দিয়ে ডাউনলোড করুন অথবা ডাউনলোড বাটনে চাপুন।
"""
time_display = f"✅ {time_str} এ সম্পন্ন | 3840×2160 (4K)"
yield output_pil, result_text, out_path, time_display
# ─── Custom CSS ───────────────────────────────────────────────────────────────
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&display=swap');
* { font-family: 'Inter', sans-serif; box-sizing: border-box; }
body, .gradio-container {
background: #0a0a0f !important;
color: #e8e8f0 !important;
}
.gradio-container {
max-width: 1100px !important;
margin: 0 auto !important;
padding: 20px !important;
}
#header {
text-align: center;
padding: 40px 20px 30px;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
border-radius: 20px;
margin-bottom: 24px;
border: 1px solid #2a2a4a;
}
#header h1 {
font-size: 2.8rem;
font-weight: 700;
background: linear-gradient(90deg, #00d4ff, #7b2ff7, #ff6b6b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin: 0 0 10px;
}
#header p {
color: #8888aa;
font-size: 1.05rem;
margin: 0;
}
.badge-row {
display: flex;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
margin-top: 16px;
}
.badge {
background: rgba(0,212,255,0.1);
border: 1px solid rgba(0,212,255,0.3);
color: #00d4ff;
padding: 5px 14px;
border-radius: 20px;
font-size: 0.82rem;
font-weight: 600;
}
#timer-box {
background: linear-gradient(135deg, #1a1a2e, #0f1923);
border: 1px solid #2a3a5a;
border-radius: 14px;
padding: 16px 24px;
text-align: center;
font-size: 1.1rem;
font-weight: 600;
color: #00d4ff;
margin-bottom: 16px;
min-height: 54px;
display: flex;
align-items: center;
justify-content: center;
}
.upload-zone label {
font-size: 1rem !important;
font-weight: 600 !important;
color: #aaaacc !important;
}
#upscale-btn {
background: linear-gradient(135deg, #7b2ff7, #00d4ff) !important;
border: none !important;
color: white !important;
font-size: 1.1rem !important;
font-weight: 700 !important;
padding: 14px 32px !important;
border-radius: 12px !important;
cursor: pointer !important;
transition: all 0.3s !important;
width: 100% !important;
letter-spacing: 0.5px !important;
}
#upscale-btn:hover {
transform: translateY(-2px) !important;
box-shadow: 0 8px 30px rgba(123,47,247,0.5) !important;
}
.panel {
background: #111122 !important;
border: 1px solid #2a2a4a !important;
border-radius: 16px !important;
padding: 20px !important;
}
.result-markdown {
background: #0d0d1f !important;
border-radius: 12px;
padding: 16px;
}
footer { display: none !important; }
"""
# ─── UI Layout ────────────────────────────────────────────────────────────────
with gr.Blocks(css=CSS, title="4K AI Upscaler") as demo:
gr.HTML("""
<div id="header">
<h1>🚀 4K AI Upscaler</h1>
<p>যেকোনো ছবি আপলোড করুন — AI স্বয়ংক্রিয়ভাবে বিশ্লেষণ করে ৪K Ultra HD তে রূপান্তর করবে</p>
<div class="badge-row">
<span class="badge">⚡ Real-ESRGAN</span>
<span class="badge">🎯 3840×2160 Output</span>
<span class="badge">🧠 AI Powered</span>
<span class="badge">🆓 সম্পূর্ণ বিনামূল্যে</span>
</div>
</div>
""")
timer_display = gr.HTML(
'<div id="timer-box">⏳ ছবি আপলোড করুন এবং বাটন চাপুন</div>',
elem_id="timer-container"
)
with gr.Row():
with gr.Column(scale=1, elem_classes="panel"):
input_img = gr.Image(
label="📤 ছবি আপলোড করুন",
type="pil",
sources=["upload", "clipboard"],
height=320,
elem_classes="upload-zone"
)
upscale_btn = gr.Button(
"✨ 4K তে রূপান্তর করুন",
elem_id="upscale-btn",
variant="primary"
)
with gr.Column(scale=1, elem_classes="panel"):
output_img = gr.Image(
label="📥 4K আউটপুট",
type="pil",
height=320,
interactive=False
)
with gr.Row():
with gr.Column():
result_md = gr.Markdown(
value="*এখানে বিশ্লেষণ ও ফলাফল দেখাবে...*",
elem_classes="result-markdown"
)
with gr.Column():
download_file = gr.File(
label="💾 4K ফাইল ডাউনলোড করুন",
interactive=False
)
gr.HTML("""
<div style="text-align:center; padding: 20px; color: #555577; font-size:0.85rem;">
Powered by Real-ESRGAN • Hosted on Hugging Face Spaces 🤗
</div>
""")
def run(img_pil):
last = None, "", None, ""
gen = upscale_to_4k(img_pil)
for out_img, md, path, timer in gen:
last = (out_img, md, path, timer)
timer_html = f'<div id="timer-box">{timer}</div>'
yield out_img, md, path, timer_html
return
upscale_btn.click(
fn=run,
inputs=[input_img],
outputs=[output_img, result_md, download_file, timer_display]
)
if __name__ == "__main__":
demo.queue().launch()