Spaces:
Sleeping
Sleeping
| # app.py | |
| import gradio as gr | |
| import asyncio | |
| import sys | |
| import os | |
| import traceback # Import traceback for detailed error logging if needed | |
| # --- Attempt to import necessary components for the actual app --- | |
| try: | |
| from src.chimera.core.orchestrator import run_analysis | |
| from src.chimera.utils.logging_config import setup_logging, logger | |
| from src.chimera.config import GEMINI_API_KEY, SERPAPI_API_KEY # Import API keys to check configuration | |
| # --- Perform initial setup --- | |
| setup_logging() # Initialize logging system | |
| logger.info("Logging initialized.") | |
| # --- Configuration Checks --- | |
| CONFIG_ERRORS = [] | |
| if not GEMINI_API_KEY: | |
| CONFIG_ERRORS.append("GEMINI_API_KEY is not set.") | |
| logger.error("CRITICAL CONFIG ERROR: GEMINI_API_KEY is not set.") | |
| if not SERPAPI_API_KEY: | |
| # Assuming SERP is essential, make it critical too | |
| CONFIG_ERRORS.append("SERPAPI_API_KEY is not set.") | |
| logger.error("CRITICAL CONFIG ERROR: SERPAPI_API_KEY is not set.") | |
| # Add checks for other essential API keys here | |
| # --- Set flag based on configuration status --- | |
| IS_CONFIGURED_PROPERLY = not CONFIG_ERRORS | |
| except ImportError as e: | |
| # Handle case where core modules cannot be imported - app cannot function | |
| print(f"FATAL IMPORT ERROR: {e}") | |
| print("Could not import necessary Chimera components. Ensure structure is correct and __init__.py files exist.") | |
| traceback.print_exc() | |
| # Define dummy elements to allow the script to potentially reach the end | |
| # but indicate a non-functional state | |
| run_analysis = None | |
| setup_logging = lambda: print("!!! Logging setup skipped due to import error !!!") | |
| logger = type('DummyLogger', (object,), {'info': print, 'warning': print, 'error': print, 'exception': print})() | |
| logger.error("!!! Logging is not properly configured due to import errors !!!") | |
| IS_CONFIGURED_PROPERLY = False | |
| CONFIG_ERRORS = ["Core application modules failed to import."] | |
| print("!!! Application will not function correctly due to import errors !!!") | |
| # --- Define the core Gradio interface function --- | |
| async def chimera_interface(query: str): | |
| """ | |
| Wrapper function for Gradio to call the async orchestrator. | |
| Handles input validation, configuration checks, and calls the backend. | |
| """ | |
| # 1. Check if the application backend is fundamentally broken (import errors) | |
| if run_analysis is None: | |
| logger.error("Attempted analysis but run_analysis function failed to import during startup.") | |
| # Provide a clear error message in the UI | |
| return "## Error: Application Backend Failed\n\nThe core analysis function could not be loaded. Please check the application logs." | |
| # 2. Check if essential configuration (API Keys) is missing | |
| if not IS_CONFIGURED_PROPERLY: | |
| logger.error(f"Attempted analysis with missing configuration: {', '.join(CONFIG_ERRORS)}") | |
| error_list = "\n".join([f"- {err}" for err in CONFIG_ERRORS]) | |
| # Provide a clear error message in the UI | |
| return f"## Error: Application Not Configured\n\nThe following essential configurations are missing:\n{error_list}\nPlease check the application secrets/environment variables." | |
| # 3. Check for empty user input | |
| if not query or not query.strip(): | |
| logger.warning("Received empty query.") | |
| # Provide guidance in the UI | |
| return "Please enter a query in the text box above." | |
| # 4. If all checks pass, proceed with the analysis | |
| logger.info(f"Gradio interface received query: '{query[:100]}...'") # Log snippet | |
| try: | |
| # Gradio handles running the async function correctly | |
| result = await run_analysis(query) | |
| logger.info("Gradio interface processing complete.") | |
| # Return the result (expecting markdown formatted string from backend) | |
| return result | |
| except Exception as e: | |
| # Log the full error details for debugging | |
| logger.exception(f"Unexpected error during run_analysis for query: '{query[:100]}...'") | |
| # Provide a user-friendly error message in the UI | |
| # Avoid exposing raw exception details directly unless intended for debugging UI | |
| return f"## Error: Analysis Failed\n\nAn unexpected error occurred while processing your request.\nDetails have been logged by the application administrator.\n\n*(Error type: {type(e).__name__})*" | |
| # --- Gradio UI Definition --- | |
| # Use a try-except block to catch errors during UI construction | |
| demo = None # Initialize demo to None | |
| try: | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Project Chimera") as demo: | |
| # Display configuration errors prominently if they exist | |
| if not IS_CONFIGURED_PROPERLY: | |
| config_error_msg = "\n".join([f"- {err}" for err in CONFIG_ERRORS]) | |
| gr.Markdown( | |
| f""" | |
| ## ⚠️ Application Configuration Error | |
| The application cannot function correctly because the following configurations are missing: | |
| {config_error_msg} | |
| Please contact the administrator or check the environment secrets. | |
| """, | |
| elem_id="config_error_banner" | |
| ) | |
| # Main UI components | |
| gr.Markdown( | |
| """ | |
| # Project Chimera : Real-Time Global Analysis Engine | |
| Enter your query to analyze real-time data from SERP and other sources using Gemini. | |
| *(Example: "Analyze recent news about renewable energy investments in the US")* | |
| """ | |
| ) | |
| with gr.Row(): | |
| query_input = gr.Textbox( | |
| label="Your Query:", | |
| placeholder="Type your complex question or analysis request here...", | |
| lines=3, | |
| elem_id="query_input_box" | |
| ) | |
| submit_button = gr.Button("Analyze", variant="primary", elem_id="submit_button") | |
| with gr.Row(): | |
| # Using Markdown for output allows richer formatting (like headers from error messages) | |
| output_display = gr.Markdown(label="Chimera Analysis:", elem_id="output_display_markdown") | |
| # Link the button click to the interface function | |
| submit_button.click( | |
| fn=chimera_interface, | |
| inputs=[query_input], | |
| outputs=[output_display], | |
| # Add API name for potential tracking/analytics if needed by Gradio | |
| # api_name="chimera_analysis" | |
| ) | |
| # Example usage display | |
| gr.Examples( | |
| examples=[ | |
| "Search recent news about AI impact on healthcare.", | |
| "What are the latest developments in fusion energy according to recent searches?", | |
| "Summarize the latest discussion around supply chain disruptions.", | |
| "What are recent news headlines mentioning 'geopolitical tensions'?" | |
| ], | |
| inputs=[query_input], | |
| outputs=[output_display], | |
| fn=chimera_interface, # Make examples clickable | |
| cache_examples=False, # Avoid caching as results depend on real-time data | |
| elem_id="examples_section" | |
| ) | |
| except Exception as e: | |
| logger.exception("FATAL: Failed to build Gradio interface.") | |
| # demo remains None if gr.Blocks fails | |
| print(f"Error creating Gradio Blocks: {e}") | |
| traceback.print_exc() | |
| # --- Launching the App --- | |
| if __name__ == "__main__": | |
| if demo and IS_CONFIGURED_PROPERLY and run_analysis is not None: | |
| # Only launch if Gradio Blocks were created AND config is okay AND core function loaded | |
| logger.info("Starting Gradio application...") | |
| # Standard launch for Hugging Face Spaces | |
| # queue() can be added for better handling of concurrent users if needed: demo.queue().launch() | |
| demo.launch() | |
| elif not demo: | |
| logger.error("Gradio application blocks failed to initialize. Cannot launch.") | |
| print("Application launch aborted due to UI build errors.") | |
| else: | |
| # Handles cases where config failed or run_analysis didn't import | |
| logger.error("Application launch aborted due to configuration errors or failed imports.") | |
| print("Application launch aborted. Please check configuration and import logs.") | |
| # Keep the container running but without the app interface (or exit) | |
| # Depending on HF Spaces behavior, it might restart or just show logs |