import gradio as gr import base64 import io from PIL import Image as PILImage from models.data_manager import DataManager from models.image_processor import ( image_search_performers, ) class WebInterface: def __init__(self, data_manager: DataManager, default_threshold: float = 0.5): """ Initialize the web interface. Parameters: data_manager: DataManager instance default_threshold: Default confidence threshold """ self.data_manager = data_manager self.default_threshold = default_threshold def multiple_image_search(self, img): """Wrapper for the multiple image search function""" try: # Use default values: threshold=0.5, results=4 return image_search_performers(img, self.data_manager, 0.5, 4) except ValueError as e: if "No faces found" in str(e): return {"error": "No faces detected in the uploaded image. Please try uploading an image with visible faces."} else: raise e def format_results_for_visual_display(self, json_results): """ Convert JSON results to visual components for better UX Parameters: json_results: List of face detection results from image_search_performers Returns: tuple: (gallery_images, html_content) """ if not json_results: return [], "

No faces detected or no matches found.

" # Handle error case if isinstance(json_results, dict) and "error" in json_results: error_html = f"""

Error

{json_results['error']}

""" return [], error_html gallery_images = [] html_parts = [] html_parts.append(""" """) for i, face_result in enumerate(json_results): # Convert base64 face image to PIL for gallery try: face_image_data = base64.b64decode(face_result['image']) face_pil = PILImage.open(io.BytesIO(face_image_data)) gallery_images.append(face_pil) except Exception as e: print(f"Error decoding face image: {e}") continue # Create HTML for this face face_confidence = face_result['confidence'] performers = face_result['performers'] # Create base64 data URL for the detected face image face_image_b64 = f"data:image/jpeg;base64,{face_result['image']}" html_parts.append(f"""
Detected Face {i+1}

Face {i+1}

Detection Confidence: {face_confidence:.1%}

Matches Found: {len(performers)}

""") if performers: html_parts.append('
') for performer in performers: confidence_class = "high-confidence" if performer['confidence'] >= 70 else "medium-confidence" if performer['confidence'] >= 50 else "low-confidence" # Create performer name with link if URL exists performer_name = performer['name'] if performer.get('url'): performer_name = f'{performer["name"]}' html_parts.append(f"""
{performer['name']}

{performer_name}

{performer['confidence']}%
""") html_parts.append('
') else: html_parts.append('

No performer matches found for this face.

') html_parts.append('
') return gallery_images, ''.join(html_parts) def multiple_image_search_with_visual(self, img): """ Enhanced search function that returns both JSON and visual components Returns: tuple: (json_results, gallery_images, html_content) """ try: json_results = self.multiple_image_search(img) gallery_images, html_content = self.format_results_for_visual_display(json_results) return json_results, gallery_images, html_content except Exception as e: error_msg = f"

Error

{str(e)}

" return [], [], error_msg def _create_visual_search_interface(self): """Create the visual search interface""" with gr.Blocks() as interface: gr.Markdown("# Who is in the photo?") gr.Markdown("Upload an image of a person(s) and we'll show you who it is with photos and details.") with gr.Row(): with gr.Column(): img_input = gr.Image(type="pil") search_btn = gr.Button("Search") with gr.Column(): performer_info = gr.HTML( label="Performer Information", value="

Upload an image and click search to see results.

" ) def visual_search_wrapper(img): """Wrapper that returns only visual components""" json_results, gallery_images, html_content = self.multiple_image_search_with_visual(img) return html_content search_btn.click( fn=visual_search_wrapper, inputs=[img_input], outputs=[performer_info], api_name="multiple_image_search_with_visual" ) return interface def launch(self, server_name="0.0.0.0", server_port=7860, share=True): """Launch the web interface""" with gr.Blocks( css=""" .gradio-container { background-color: #1e1e1e !important; color: #d4d4d4 !important; } .dark { --background-fill-primary: #2d2d2d; --background-fill-secondary: #3c3c3c; --border-color-primary: #404040; --block-title-text-color: #ffffff; --body-text-color: #d4d4d4; } """ ) as demo: with gr.Tabs(): with gr.TabItem("Visual Search"): self._create_visual_search_interface() demo.queue().launch(server_name=server_name, server_port=server_port, share=share, ssr_mode=False)