BeatDebate / src /main.py
SulmanK's picture
Enhance README.md and main.py for HuggingFace Spaces deployment - Updated README to include live demo links, deployment checklist, and detailed instructions for setting up HuggingFace Spaces. Improved main.py with enhanced environment detection for Spaces and optimized backend configuration, ensuring a smoother deployment experience. This update aims to provide clearer guidance for users and streamline the deployment process for the BeatDebate application.
4923cf4
Raw
History Blame Contribute Delete
8.25 kB
"""
BeatDebate Main Application
This module provides the main entry point for the BeatDebate application,
integrating the FastAPI backend with the Gradio frontend for a complete
Phase 3 implementation.
"""
import asyncio
import os
import threading
import time
from typing import Optional
import gradio as gr
import uvicorn
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Setup comprehensive logging FIRST - before importing modules that use it
from .utils.logging_config import setup_logging, get_logger
log_level = os.getenv("LOG_LEVEL", "INFO")
enable_console = os.getenv("ENABLE_CONSOLE_LOGGING", "true").lower() == "true"
setup_logging(
log_dir="logs",
log_level=log_level,
enable_console=enable_console
)
logger = get_logger(__name__)
# Now import modules that may use logging
from .api.backend import app as fastapi_app
from .ui.chat_interface import create_chat_interface
class BeatDebateApp:
"""
Main BeatDebate application that runs both FastAPI backend and Gradio frontend.
Features:
- FastAPI backend for 4-agent recommendation system
- Gradio frontend for ChatGPT-style interface
- Integrated deployment for HuggingFace Spaces
"""
def __init__(
self,
backend_port: int = 8000,
frontend_port: int = 7860,
backend_host: str = "127.0.0.1",
frontend_host: str = "0.0.0.0"
):
"""
Initialize the BeatDebate application.
Args:
backend_port: Port for FastAPI backend
frontend_port: Port for Gradio frontend
backend_host: Host for FastAPI backend
frontend_host: Host for Gradio frontend
"""
self.backend_port = backend_port
self.frontend_port = frontend_port
self.backend_host = backend_host
self.frontend_host = frontend_host
self.backend_url = f"http://{backend_host}:{backend_port}"
# Application components
self.fastapi_app = fastapi_app
self.gradio_interface: Optional[gr.Blocks] = None
self.backend_server: Optional[uvicorn.Server] = None
logger.info(f"BeatDebate app initialized - Backend: {self.backend_url}")
def create_gradio_interface(self) -> gr.Blocks:
"""Create the Gradio interface."""
if not self.gradio_interface:
self.gradio_interface = create_chat_interface(self.backend_url)
return self.gradio_interface
def start_backend(self) -> None:
"""Start the FastAPI backend server in a separate thread."""
def run_backend():
config = uvicorn.Config(
app=self.fastapi_app,
host=self.backend_host,
port=self.backend_port,
log_level="info"
)
server = uvicorn.Server(config)
self.backend_server = server
logger.info(f"Starting FastAPI backend on {self.backend_url}")
asyncio.run(server.serve())
backend_thread = threading.Thread(target=run_backend, daemon=True)
backend_thread.start()
# Wait for backend to start
self._wait_for_backend()
def _wait_for_backend(self, timeout: int = 30) -> None:
"""Wait for the backend to be ready."""
import requests
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(f"{self.backend_url}/health", timeout=5)
if response.status_code == 200:
logger.info("Backend is ready!")
return
except requests.exceptions.RequestException:
pass
time.sleep(1)
logger.warning("Backend may not be ready - continuing anyway")
def launch_frontend(
self,
share: bool = False,
debug: bool = False,
**kwargs
) -> None:
"""
Launch the Gradio frontend.
Args:
share: Whether to create a public link
debug: Whether to enable debug mode
**kwargs: Additional arguments for Gradio launch
"""
interface = self.create_gradio_interface()
logger.info(f"Launching Gradio frontend on port {self.frontend_port}")
interface.launch(
server_name=self.frontend_host,
server_port=self.frontend_port,
share=share,
debug=debug,
**kwargs
)
def launch(
self,
share: bool = False,
debug: bool = False,
**kwargs
) -> None:
"""
Launch the complete BeatDebate application.
Args:
share: Whether to create a public link
debug: Whether to enable debug mode
**kwargs: Additional arguments for Gradio launch
"""
logger.info("🎡 Starting BeatDebate - AI Music Discovery System")
# Start backend
self.start_backend()
# Launch frontend
self.launch_frontend(share=share, debug=debug, **kwargs)
def create_app() -> BeatDebateApp:
"""
Factory function to create a BeatDebate application instance.
Returns:
Configured BeatDebate application
"""
# Get configuration from environment variables
backend_port = int(os.getenv("BACKEND_PORT", "8000"))
frontend_port = int(os.getenv("FRONTEND_PORT", "7860"))
backend_host = os.getenv("BACKEND_HOST", "127.0.0.1")
frontend_host = os.getenv("FRONTEND_HOST", "0.0.0.0")
return BeatDebateApp(
backend_port=backend_port,
frontend_port=frontend_port,
backend_host=backend_host,
frontend_host=frontend_host
)
def main():
"""Main entry point for the application."""
try:
# Create and launch the application
app = create_app()
# Check if running in HuggingFace Spaces
is_spaces = is_running_in_spaces()
app.launch(
share=not is_spaces, # Don't create public links in Spaces
debug=os.getenv("DEBUG", "false").lower() == "true"
)
except KeyboardInterrupt:
logger.info("Application stopped by user")
except Exception as e:
logger.error(f"Application failed to start: {e}")
raise
def is_running_in_spaces() -> bool:
"""Check if running in HuggingFace Spaces environment."""
return os.getenv("SPACE_ID") is not None or os.getenv("HF_SPACE_NAME") is not None
# HuggingFace Spaces compatibility
def create_gradio_app() -> gr.Blocks:
"""
Create a Gradio app for HuggingFace Spaces deployment.
This function is used when deploying to HuggingFace Spaces where
we need to return a Gradio interface directly.
Returns:
Gradio Blocks interface
"""
logger.info("πŸš€ Creating BeatDebate for HuggingFace Spaces")
# Enhanced Spaces environment detection
if is_running_in_spaces():
space_id = os.getenv("SPACE_ID", os.getenv("HF_SPACE_NAME", "Unknown"))
logger.info(f"🌟 Running in HuggingFace Spaces: {space_id}")
# Backend configuration for Spaces
backend_url = "http://127.0.0.1:8000"
# Start backend with Spaces-optimized settings
def start_backend_for_spaces():
config = uvicorn.Config(
app=fastapi_app,
host="127.0.0.1",
port=8000,
log_level="info",
access_log=False # Reduce log noise in Spaces
)
server = uvicorn.Server(config)
asyncio.run(server.serve())
backend_thread = threading.Thread(target=start_backend_for_spaces, daemon=True)
backend_thread.start()
# Wait for backend to be ready (slightly longer for Spaces)
time.sleep(3)
# Create Gradio interface with Spaces-specific configurations
interface = create_chat_interface(backend_url)
logger.info("βœ… BeatDebate ready for HuggingFace Spaces deployment")
return interface
if __name__ == "__main__":
main()