import gradio as gr from src.search.service import SearchService from src.utils.constants import Constants from src.utils.logging import get_logger class UIComponents: """ Class to handle the Gradio UI components for the application. """ def __init__(self): """ Initialize the UI components. """ self.logger = get_logger() self.logger.info("Initializing UI components") try: self.search_service = SearchService() self.logger.info("UI components initialized successfully") except Exception as e: self.logger.error(f"Failed to initialize UI components: {str(e)}") raise def create_customer_tab(self): """ Create the customer search tab. Returns: gradio.Tab: The customer search tab. """ with gr.Tab(Constants.UI_CUSTOMER_TAB) as tab: gr.Markdown(f"## {Constants.UI_CUSTOMER_DESCRIPTION}") with gr.Row(): text_input = gr.Textbox( label=Constants.UI_TEXT_INPUT_LABEL, placeholder="Ex: Une grille décorative pour mon jardin avec des motifs floraux", lines=3 ) with gr.Row(): image_input = gr.Image( label=Constants.UI_IMAGE_INPUT_LABEL, type="pil" ) with gr.Row(): search_button = gr.Button(Constants.UI_SEARCH_BUTTON, variant="primary") with gr.Row(visible=False) as loading_indicator: gr.Markdown(f"### {Constants.UI_LOADING_TEXT}") results_container = gr.HTML(visible=False) def search(text, image): self.logger.info("Customer UI search initiated") self.logger.debug(f"Search parameters - Text: '{text}', Image provided: {image is not None}") if not text and image is None: self.logger.info("No search parameters provided, returning empty results") return None, gr.update(visible=False), gr.update(visible=False) try: self.logger.info("Calling customer search service") results = self.search_service.customer_search(text, image) if not results: self.logger.info("No results found for customer search") return None, gr.update(visible=False), gr.HTML( f"
{Constants.UI_NO_RESULTS}
", visible=True) # Prepare gallery images self.logger.debug(f"Preparing gallery with {len(results)} images") gallery_images = [] for result in results: gallery_images.append((result["thumbnail"], result["title"])) # Prepare HTML for results self.logger.debug("Creating HTML for search results") html = self._create_results_html(results) self.logger.info(f"Customer search completed successfully with {len(results)} results") return gr.HTML(html, visible=True) except Exception as e: self.logger.error(f"Error during customer UI search: {str(e)}") # Return a user-friendly error message error_html = f"
Une erreur s'est produite lors de la recherche. Veuillez réessayer.
" return None, gr.update(visible=False), gr.HTML(error_html, visible=True) search_button.click( fn=search, inputs=[text_input, image_input], outputs=[results_container], # js=""" # function(text, image) { # // Disable search button and show loading indicator # document.querySelector("button[variant='primary']").disabled = true; # return [text, image]; # } # """, preprocess=True ).then( # js=""" # function() { # // Re-enable search button and hide loading indicator # document.querySelector("button[variant='primary']").disabled = false; # return []; # } # """ ) # Show/hide loading indicator search_button.click( fn=lambda: gr.update(visible=True), inputs=None, outputs=loading_indicator ).then( fn=lambda: gr.update(visible=False), inputs=None, outputs=loading_indicator ) return tab def create_staff_tab(self): """ Create the staff search tab. Returns: gradio.Tab: The staff search tab. """ with gr.Tab(Constants.UI_STAFF_TAB) as tab: gr.Markdown(f"## {Constants.UI_STAFF_DESCRIPTION}") with gr.Row(): image_input = gr.Image( label=Constants.UI_IMAGE_INPUT_LABEL, type="pil" ) with gr.Row(): search_button = gr.Button(Constants.UI_SEARCH_BUTTON, variant="primary") with gr.Row(visible=False) as loading_indicator: gr.Markdown(f"### {Constants.UI_LOADING_TEXT}") result_container = gr.HTML(visible=False) def search(image): self.logger.info("Staff UI search initiated") self.logger.debug(f"Search parameters - Image provided: {image is not None}") if image is None: self.logger.info("No image provided for staff search, returning empty results") return gr.update(visible=False) try: self.logger.info("Calling staff search service") result = self.search_service.staff_search(image) if not result: self.logger.info("No results found for staff search") return gr.HTML(f"
{Constants.UI_NO_RESULTS}
", visible=True) # Prepare HTML for result self.logger.debug("Creating HTML for search result") html = self._create_results_html([result]) self.logger.info("Staff search completed successfully with a match") return gr.HTML(html, visible=True) except Exception as e: self.logger.error(f"Error during staff UI search: {str(e)}") # Return a user-friendly error message error_html = f"
Une erreur s'est produite lors de la recherche. Veuillez réessayer.
" return gr.HTML(error_html, visible=True) search_button.click( fn=search, inputs=[image_input], outputs=[result_container], # js=""" # function(image) { # // Disable search button and show loading indicator # document.querySelector("button[variant='primary']").disabled = true; # return [image]; # } # """, preprocess=True ).then( # js=""" # function() { # // Re-enable search button and hide loading indicator # document.querySelector("button[variant='primary']").disabled = false; # return []; # } # """ ) # Show/hide loading indicator search_button.click( fn=lambda: gr.update(visible=True), inputs=None, outputs=loading_indicator ).then( fn=lambda: gr.update(visible=False), inputs=None, outputs=loading_indicator ) return tab def _create_results_html(self, results): """ Create HTML for displaying search results. Args: results (list): List of search results. Returns: str: HTML string for displaying results. """ self.logger.debug(f"Creating HTML for {len(results)} results") try: html = "
" for i, result in enumerate(results): self.logger.debug(f"Adding result {i + 1}: {result['title']}") html += f"""
{result["title"]}

{result["title"]}

{result["description"]}

{Constants.UI_PRICE_LABEL} {result["price"]}

{Constants.UI_PRODUCT_BUTTON}
""" html += "
" self.logger.debug("HTML for results created successfully") except Exception as e: self.logger.error(f"Error creating HTML for results: {str(e)}") # Create a simple fallback HTML in case of error html = "

Résultats disponibles mais impossible de les afficher correctement.

" # Add CSS for styling html += """ """ return html def create_interface(self): """ Create the complete Gradio interface. Returns: gradio.Blocks: The Gradio interface. """ with gr.Blocks(title=Constants.UI_TITLE, theme=gr.themes.Soft()) as interface: gr.Markdown(f"# {Constants.UI_TITLE}") with gr.Tabs(): self.create_customer_tab() self.create_staff_tab() # Add CSS for responsive design gr.HTML(""" """) return interface def close(self): """ Close connections and resources. """ self.logger.info("Closing UI components resources") try: self.search_service.close() self.logger.info("UI components resources closed successfully") except Exception as e: self.logger.error(f"Error closing UI components resources: {str(e)}") # We don't re-raise the exception here to ensure cleanup continues even if there's an error