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 |