aaron-official's picture
Update app.py
2d6593a verified
import os
from config.settings import (
OPENAI_API_KEY, ANTHROPIC_API_KEY, REMOVE_BG_API_KEY, DEEPSEEK_API_KEY,
GRADIO_SERVER_NAME, GRADIO_SERVER_PORT
)
from config.logging_config import setup_logging
from src.image_processing import ImageProcessor
from src.ai_image_generator import AIImageGenerator
from src.background_removal import BackgroundRemover
from src.image_analysis import ImageAnalysis
from src.custom_filters import apply_custom_filter
from src.resize_crop import resize_crop_image
import logging
import io
import zipfile
import tempfile
from PIL import Image
setup_logging()
logger = logging.getLogger(__name__)
import gradio as gr
SUPPORTED_FORMATS = [
"JPEG", "JPG", "PNG", "BMP", "TIFF", "TIF", "WEBP", "GIF",
"ICO", "EPS", "PDF", "PSD", "SVG", "HEIC", "AVIF", "JXL"
]
ENHANCEMENT_OPTIONS = [
"AI Super Resolution", "Noise Reduction", "Color Enhancement", "Brightness/Contrast", "Sharpening", "HDR Effect", "Vintage Filter", "Black & White", "Sepia", "Vignette", "Blur Background"
]
processor = ImageProcessor()
ai_generator = AIImageGenerator(openai_key=OPENAI_API_KEY, anthropic_key=ANTHROPIC_API_KEY)
bg_remover = BackgroundRemover()
# Restore AI_MODELS and BG_REMOVAL_SERVICES constants
AI_MODELS = {
"OpenAI DALL-E 3": "dall-e-3",
"OpenAI DALL-E 2": "dall-e-2",
"Anthropic Claude (via API)": "claude-3-5-sonnet-20241022",
"DeepSeek": "deepseek-chat"
}
BG_REMOVAL_SERVICES = {
"Remove.bg": "removebg",
"Removal.ai": "removelai",
"Local rembg": "local",
"Clipdrop": "clipdrop"
}
# Android icon sizes (density: size in px)
ANDROID_ICON_SIZES = {
"mdpi": 48,
"hdpi": 72,
"xhdpi": 96,
"xxhdpi": 144,
"xxxhdpi": 192,
}
def make_android_icons_zip(image: Image.Image) -> str:
import tempfile
with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as tmp:
with zipfile.ZipFile(tmp, mode="w") as zf:
for density, size in ANDROID_ICON_SIZES.items():
icon = image.resize((size, size), Image.LANCZOS)
icon_bytes = io.BytesIO()
icon.save(icon_bytes, format="PNG")
icon_bytes.seek(0)
zf.writestr(f"ic_launcher_{density}.png", icon_bytes.read())
return tmp.name # Return the file path for gr.File
# Main Gradio Interface
with gr.Blocks(title="Advanced Image Processing Suite") as demo:
gr.Markdown("# Advanced Image Processing Suite")
gr.Markdown("Professional-grade image processing, AI generation, and enhancement tools")
with gr.Tabs() as tabs:
# Tab 1: Format
with gr.Tab("Format"):
gr.Markdown("### Convert images between multiple formats with advanced options")
with gr.Row():
with gr.Column():
conv_input = gr.Image(label="Upload Image", type="filepath")
conv_format = gr.Dropdown(
choices=SUPPORTED_FORMATS,
value="PNG",
label="Target Format"
)
conv_quality = gr.Slider(
minimum=10, maximum=100, value=95,
label="Quality (for JPEG/WebP)", step=5
)
conv_btn = gr.Button("Convert Image", variant="primary")
with gr.Column():
conv_output = gr.File(label="Download Converted Image")
conv_status = gr.Textbox(label="Status", interactive=False)
conv_btn.click(
fn=lambda img, fmt, qual: processor.convert_image(img, fmt, qual) if img else (None, "Please upload an image"),
inputs=[conv_input, conv_format, conv_quality],
outputs=[conv_output, conv_status]
)
# Tab 2: AI Gen
with gr.Tab("AI Gen"):
gr.Markdown("### Generate stunning images using state-of-the-art AI models")
with gr.Row():
with gr.Column():
gr.Markdown("#### API Configuration")
openai_key = gr.Textbox(
label="OpenAI API Key",
type="password",
placeholder="sk-..."
)
anthropic_key = gr.Textbox(
label="Anthropic API Key",
type="password",
placeholder="sk-ant-..."
)
deepseek_key = gr.Textbox(
label="DeepSeek API Key",
type="password",
placeholder="sk-..."
)
save_keys_btn = gr.Button("Save API Keys")
key_status = gr.Textbox(label="Key Status", interactive=False)
with gr.Row():
with gr.Column():
ai_prompt = gr.Textbox(
label="Image Prompt",
placeholder="A serene landscape with mountains and a lake at sunset...",
lines=3
)
ai_model = gr.Dropdown(
choices=list(AI_MODELS.keys()),
value="OpenAI DALL-E 3",
label="AI Model"
)
ai_size = gr.Dropdown(
choices=["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"],
value="1024x1024",
label="Image Size"
)
generate_btn = gr.Button("Generate Image", variant="primary")
with gr.Column():
ai_output = gr.Image(label="Generated Image")
ai_status = gr.Textbox(label="Generation Status", interactive=False)
# API key saving (refactored)
def save_api_keys(openai, anthropic, deepseek):
ai_generator.openai_key = openai
ai_generator.anthropic_key = anthropic
# DeepSeek can be added to ai_generator if implemented
saved_keys = []
if openai:
saved_keys.append("OpenAI")
if anthropic:
saved_keys.append("Anthropic")
if deepseek:
saved_keys.append("DeepSeek")
if saved_keys:
return f"Saved keys for: {', '.join(saved_keys)}"
return "No keys provided"
save_keys_btn.click(
fn=save_api_keys,
inputs=[openai_key, anthropic_key, deepseek_key],
outputs=key_status
)
# Image generation (fixed: pass API keys directly)
def generate_image(prompt, model, size, openai, anthropic):
if not prompt:
return None, "Please enter a prompt"
if "OpenAI" in model:
model_name = AI_MODELS[model]
temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
return temp_gen.generate_image_openai(prompt, model_name, size)
elif "Anthropic" in model:
temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
return temp_gen.generate_image_anthropic(prompt)
else:
return None, f"{model} not yet implemented"
generate_btn.click(
fn=generate_image,
inputs=[ai_prompt, ai_model, ai_size, openai_key, anthropic_key],
outputs=[ai_output, ai_status]
)
# Tab 3: Enhance
with gr.Tab("Enhance"):
gr.Markdown("### Enhance your images with professional-grade filters and AI")
with gr.Row():
with gr.Column():
enhance_input = gr.Image(label="Upload Image to Enhance", type="filepath")
enhance_type = gr.Dropdown(
choices=ENHANCEMENT_OPTIONS,
value="Color Enhancement",
label="Enhancement Type"
)
enhance_intensity = gr.Slider(
minimum=0.1, maximum=2.0, value=1.0, step=0.1,
label="Enhancement Intensity"
)
enhance_btn = gr.Button("Enhance Image", variant="primary")
with gr.Column():
enhance_output = gr.Image(label="Enhanced Image")
enhance_status = gr.Textbox(label="Enhancement Status", interactive=False)
enhance_btn.click(
fn=lambda img, enh_type, intensity: processor.enhance_image(img, enh_type, intensity) if img else (None, "Please upload an image"),
inputs=[enhance_input, enhance_type, enhance_intensity],
outputs=[enhance_output, enhance_status]
)
# Tab 4: BG Remove
with gr.Tab("BG Remove"):
gr.Markdown("### Remove backgrounds instantly with AI-powered tools")
with gr.Row():
with gr.Column():
gr.Markdown("#### API Keys for Premium Services")
removebg_key = gr.Textbox(
label="Remove.bg API Key",
type="password",
placeholder="Your Remove.bg API key"
)
save_bg_key_btn = gr.Button("Save Remove.bg Key")
bg_key_status = gr.Textbox(label="API Status", interactive=False)
with gr.Row():
with gr.Column():
bg_input = gr.Image(label="Upload Image", type="filepath")
bg_service = gr.Dropdown(
choices=list(BG_REMOVAL_SERVICES.keys()),
value="Local rembg",
label="Background Removal Service"
)
bg_btn = gr.Button("Remove Background", variant="primary")
with gr.Column():
bg_output = gr.Image(label="Result (Transparent Background)")
bg_status = gr.Textbox(label="Processing Status", interactive=False)
# Save background removal API key (refactored)
def save_bg_api_key(key):
bg_remover.removebg_key = key
if key:
return "Remove.bg API key saved"
return "No key provided"
save_bg_key_btn.click(
fn=save_bg_api_key,
inputs=removebg_key,
outputs=bg_key_status
)
# Background removal (fixed: pass Remove.bg key directly)
def remove_bg(img, service, removebg):
if not img:
return None, "Please upload an image"
service_key = BG_REMOVAL_SERVICES.get(service, "local")
if service_key == "local":
return bg_remover.remove_local(img)
elif service_key == "removebg":
temp_remover = BackgroundRemover(removebg_key=removebg)
return temp_remover.remove_with_removebg(img)
else:
return None, f"{service} not implemented"
bg_btn.click(
fn=remove_bg,
inputs=[bg_input, bg_service, removebg_key],
outputs=[bg_output, bg_status]
)
# Tab 5: Batch
with gr.Tab("Batch"):
gr.Markdown("### Process multiple images simultaneously")
with gr.Row():
with gr.Column():
batch_files = gr.Files(label="Upload Multiple Images", file_types=["image"])
batch_operation = gr.Dropdown(
choices=["Format Conversion", "Enhancement", "Background Removal"],
value="Format Conversion",
label="Batch Operation"
)
batch_btn = gr.Button("Process Batch", variant="primary")
with gr.Column():
batch_output = gr.Files(label="Download Processed Images")
batch_status = gr.Textbox(label="Batch Status", interactive=False, lines=5)
# Batch processing (refactored)
def process_batch(files, operation):
if not files:
return None, "Please upload images for batch processing"
results = []
status_messages = []
for i, file in enumerate(files):
try:
if operation == "Format Conversion":
result, msg = processor.convert_image(file.name, "PNG")
elif operation == "Enhancement":
result, msg = processor.enhance_image(file.name, "Color Enhancement")
elif operation == "Background Removal":
result, msg = bg_remover.remove_local(file.name)
if result:
results.append(result)
status_messages.append(f"File {i+1}: {msg}")
except Exception as e:
status_messages.append(f"File {i+1}: Error - {str(e)}")
return results if results else None, "\n".join(status_messages)
batch_btn.click(
fn=process_batch,
inputs=[batch_files, batch_operation],
outputs=[batch_output, batch_status]
)
# Tab 6: Tools
with gr.Tab("Tools"):
gr.Markdown("### Professional image analysis and specialized processing")
with gr.Tabs():
with gr.Tab("Image Analysis"):
with gr.Row():
with gr.Column():
analysis_input = gr.Image(label="Upload Image for Analysis", type="filepath")
analysis_btn = gr.Button("Analyze Image", variant="primary")
with gr.Column():
analysis_output = gr.JSON(label="Image Analysis Results")
# Advanced Tools: Image Analysis (refactored)
def analyze_image(img_path):
return ImageAnalysis.analyze_image(img_path)
analysis_btn.click(
fn=analyze_image,
inputs=analysis_input,
outputs=analysis_output
)
with gr.Tab("Custom Filters"):
with gr.Row():
with gr.Column():
filter_input = gr.Image(label="Upload Image", type="filepath")
# Custom filter controls
brightness = gr.Slider(-100, 100, 0, label="Brightness")
contrast = gr.Slider(-100, 100, 0, label="Contrast")
saturation = gr.Slider(-100, 100, 0, label="Saturation")
hue_shift = gr.Slider(-180, 180, 0, label="Hue Shift")
apply_filter_btn = gr.Button("Apply Custom Filter", variant="primary")
with gr.Column():
filter_output = gr.Image(label="Filtered Image")
filter_status = gr.Textbox(label="Filter Status", interactive=False)
# Advanced Tools: Custom Filters (refactored)
apply_filter_btn.click(
fn=apply_custom_filter,
inputs=[filter_input, brightness, contrast, saturation, hue_shift],
outputs=[filter_output, filter_status]
)
with gr.Tab("Resize & Crop"):
with gr.Row():
with gr.Column():
resize_input = gr.Image(label="Upload Image", type="filepath")
resize_mode = gr.Radio(
choices=["Resize", "Crop", "Smart Crop", "Canvas Resize"],
value="Resize",
label="Operation Mode"
)
new_width = gr.Number(label="Width", value=800)
new_height = gr.Number(label="Height", value=600)
maintain_ratio = gr.Checkbox(label="Maintain Aspect Ratio", value=True)
resize_quality = gr.Dropdown(
choices=["NEAREST", "LANCZOS", "BILINEAR", "BICUBIC"],
value="LANCZOS",
label="Resize Quality"
)
resize_btn = gr.Button("Process Image", variant="primary")
with gr.Column():
resize_output = gr.Image(label="Processed Image")
resize_status = gr.Textbox(label="Processing Status", interactive=False)
# Advanced Tools: Resize & Crop (refactored)
resize_btn.click(
fn=resize_crop_image,
inputs=[resize_input, resize_mode, new_width, new_height, maintain_ratio, resize_quality],
outputs=[resize_output, resize_status]
)
# Tab 7: Android Icons
with gr.Tab("Android Icons"):
gr.Markdown("### Generate all Android app icon sizes and download as a ZIP")
with gr.Row():
with gr.Column():
android_icon_input = gr.Image(type="pil", label="Upload Icon Source Image")
android_icon_btn = gr.Button("Generate Android Icons", variant="primary")
with gr.Column():
android_icon_zip = gr.File(label="Download Icons ZIP")
android_status = gr.Textbox(label="Generation Status", interactive=False)
def handle_android_icon(image):
if image is None:
return None, "Please upload an image"
try:
zip_path = make_android_icons_zip(image)
return zip_path, "Android icons generated successfully!"
except Exception as e:
return None, f"Error generating icons: {str(e)}"
android_icon_btn.click(
fn=handle_android_icon,
inputs=android_icon_input,
outputs=[android_icon_zip, android_status]
)
# Launch configuration
if __name__ == "__main__":
# For Hugging Face Spaces, do not set server_name or server_port
# Use environment variables or defaults for other options
launch_kwargs = {}
# Optionally allow share, favicon_path, ssl_verify, show_api to be set via env
if os.environ.get("GRADIO_SHARE", "false").lower() == "true":
launch_kwargs["share"] = True
if os.environ.get("GRADIO_FAVICON_PATH"):
launch_kwargs["favicon_path"] = os.environ["GRADIO_FAVICON_PATH"]
if os.environ.get("GRADIO_SSL_VERIFY", "false").lower() == "true":
launch_kwargs["ssl_verify"] = True
if os.environ.get("GRADIO_SHOW_API", "false").lower() == "true":
launch_kwargs["show_api"] = True
demo.launch(**launch_kwargs)