prodimg / app.py
iu69's picture
changed the free AI model for background gen
8ea4751 verified
Raw
History Blame Contribute Delete
6.05 kB
import os
import io
import zipfile
import sys
import traceback
import time
import tempfile
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
# --- DEBUG SETUP ---
sys.stdout.flush()
print("=== APP STARTING UP ===")
print(f"Current Working Directory: {os.getcwd()}")
print(f"Python Version: {sys.version}")
# CRITICAL FIX: Catch import errors
try:
import cv2
import numpy as np
from PIL import Image
from rembg import remove, new_session
from huggingface_hub import InferenceClient
import gradio as gr
print("All libraries imported successfully.")
except Exception as e:
print("CRITICAL IMPORT ERROR:", e)
print(traceback.format_exc())
sys.exit(1)
# Get your HF Token
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
print("WARNING: HF_TOKEN environment variable is NOT SET. AI Backgrounds will fail.")
else:
print("HF_TOKEN found.")
client = InferenceClient(token=HF_TOKEN)
# Preload the rembg model
print("Loading rembg model... (this takes ~20 seconds)")
try:
session = new_session()
print("rembg model loaded successfully!")
except Exception as e:
print("ERROR loading rembg model:", e)
print(traceback.format_exc())
session = None
def enhance_lighting(pil_img):
try:
cv_img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
lab = cv2.cvtColor(cv_img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
l = clahe.apply(l)
lab = cv2.merge([l, a, b])
cv_img = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
return Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))
except Exception as e:
print(f"Lighting fix failed: {e}")
return pil_img
def fix_aspect_ratio(pil_img, ratio_str):
w, h = pil_img.size
ratio_map = {"1:1": 1.0, "4:5": 0.8, "16:9": 1.777}
target_r = ratio_map[ratio_str]
current_r = w / h
if current_r > target_r:
new_w = int(h * target_r)
pil_img = pil_img.crop(((w - new_w)//2, 0, (w + new_w)//2, h))
else:
new_h = int(w / target_r)
pil_img = pil_img.crop((0, (h - new_h)//2, w, (h + new_h)//2))
return pil_img
def process_batch(files, ratio, rm_bg, prompt):
processed = []
# Check if files is None or empty
if not files:
return "❌ Error: No files uploaded. Please upload at least one image."
# Loop through all uploaded files
for idx, file in enumerate(files):
try:
print(f"--- Processing image {idx+1} of {len(files)} ---")
start_time = time.time()
# 1. Open the image
img = Image.open(file).convert("RGB")
print(f"Image opened. Size: {img.size}")
# 2. Fix Lighting
img = enhance_lighting(img)
# 3. Fix Aspect Ratio
img = fix_aspect_ratio(img, ratio)
# 4. Remove Background
if rm_bg:
if session is None:
raise Exception("rembg model failed to load during startup. Check Space Logs.")
print("Running rembg...")
img = remove(img, session=session)
print("rembg completed.")
# 5. Generate AI Background
if prompt and rm_bg:
print(f"Generating AI background for prompt: {prompt}")
# --- FIXED MODEL HERE ---
bg_img = client.text_to_image(
f"Product photography background of {prompt}, elegant, soft studio light, photorealistic, 8k",
model="black-forest-labs/FLUX.1-dev" # Updated model
)
bg_img = bg_img.resize(img.size).convert("RGBA")
final = bg_img.copy()
final.paste(img, (0, 0), img)
img = final
print("AI background composited.")
processed.append(img)
print(f"Image {idx+1} finished in {time.time() - start_time:.2f} seconds.")
except Exception as e:
# --- FIXED ERROR HANDLER ---
error_msg = f"❌ ERROR on image {idx+1} ('{file.name}'):\n{str(e)}"
print(error_msg)
print(traceback.format_exc())
# Return the error as a string directly to the UI
return error_msg
# --- FINAL RETURN LOGIC ---
if not processed:
return None
# Create a temporary directory
temp_dir = tempfile.mkdtemp()
zip_path = os.path.join(temp_dir, "jewelry_processed.zip")
# Write the ZIP file to disk with PNG compression
with zipfile.ZipFile(zip_path, "w") as zf:
for i, img in enumerate(processed):
buff = io.BytesIO()
# PNG compression
if img.width > 3000 or img.height > 3000:
img.thumbnail((3000, 3000), Image.LANCZOS)
img.save(buff, format="PNG", compress_level=9)
buff.seek(0)
zf.writestr(f"jewelry_processed_{i+1}.png", buff.getvalue())
# Return the absolute file path string
return zip_path
# Gradio UI
with gr.Blocks(title="Jewelry Batch Processor") as demo:
gr.Markdown("## ✨ Free Jewelry Batch Processor")
with gr.Row():
files = gr.Files(label="Upload Jewelry Images", file_count="multiple")
ratio = gr.Dropdown(choices=["1:1", "4:5", "16:9"], value="1:1", label="Aspect Ratio")
with gr.Row():
rm_bg = gr.Checkbox(label="Remove Background", value=True)
prompt = gr.Textbox(label="AI Background Prompt (leave empty to skip)")
btn = gr.Button("🚀 Process Batch", variant="primary")
output = gr.File(label="Download Processed ZIP")
btn.click(process_batch, inputs=[files, ratio, rm_bg, prompt], outputs=output)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)