Spaces:
Running
Running
| # Standard Library Imports | |
| from typing import Tuple, Union | |
| # Third-Party Library Imports | |
| import gradio as gr | |
| # Local Application Imports | |
| from src.common import Config, logger | |
| from src.core import TTSService, VotingService | |
| from src.database import AsyncDBSessionMaker | |
| from .components import Arena, Leaderboard | |
| class Frontend: | |
| """ | |
| Main frontend class orchestrating the Gradio UI application. | |
| Initializes and manages the Arena and Leaderboard components, builds the overall UI structure (Tabs, HTML), | |
| and handles top-level events like tab selection. | |
| """ | |
| def __init__(self, config: Config, db_session_maker: AsyncDBSessionMaker): | |
| """ | |
| Initializes the Frontend application controller. | |
| Args: | |
| config: The application configuration object. | |
| db_session_maker: An asynchronous database session factory. | |
| """ | |
| self.config = config | |
| # Instantiate services | |
| self.tts_service: TTSService = TTSService(config) | |
| self.voting_service: VotingService = VotingService(db_session_maker) | |
| logger.debug("Frontend initialized with TTSService and VotingService.") | |
| # Initialize components with dependencies | |
| self.arena = Arena(config, self.tts_service, self.voting_service) | |
| self.leaderboard = Leaderboard(self.voting_service) | |
| logger.debug("Frontend initialized with Arena and Leaderboard components.") | |
| async def _handle_tab_select(self, evt: gr.SelectData) -> Tuple[ | |
| Union[dict, gr.skip], | |
| Union[dict, gr.skip], | |
| Union[dict, gr.skip], | |
| ]: | |
| """ | |
| Handles tab selection events. Refreshes leaderboard if its tab is selected. | |
| Args: | |
| evt: Gradio SelectData event, containing the selected tab's value (label). | |
| Returns: | |
| A tuple of Gradio update dictionaries for the leaderboard tables if the Leaderboard tab was selected | |
| and data needed refreshing, otherwise a tuple of gr.skip() objects. | |
| """ | |
| selected_tab = evt.value | |
| if selected_tab == "Leaderboard": | |
| # Refresh leaderboard, but don't force it (allow cache/throttle) | |
| return await self.leaderboard.refresh_leaderboard(force=False) | |
| # Return skip updates for other tabs | |
| return gr.skip(), gr.skip(), gr.skip() | |
| async def build_gradio_interface(self) -> gr.Blocks: | |
| """ | |
| Builds and configures the complete Gradio Blocks UI. | |
| Pre-loads initial leaderboard data, defines layout (HTML, Tabs), integrates Arena and Leaderboard sections, | |
| and sets up tab selection handler. | |
| Returns: | |
| The fully constructed Gradio Blocks application instance. | |
| """ | |
| logger.info("Building Gradio interface...") | |
| with gr.Blocks(title="Expressive TTS Arena", css_paths="static/css/styles.css") as demo: | |
| # --- Header HTML --- | |
| gr.HTML( | |
| value=""" | |
| <div class="title-container"> | |
| <h1>Expressive TTS Arena</h1> | |
| <div class="social-links"> | |
| <a | |
| href="https://discord.com/invite/humeai" | |
| target="_blank" | |
| id="discord-link" | |
| title="Join our Discord" | |
| aria-label="Join our Discord server" | |
| ></a> | |
| <a | |
| href="https://github.com/HumeAI/expressive-tts-arena" | |
| target="_blank" | |
| id="github-link" | |
| title="View on GitHub" | |
| aria-label="View project on GitHub" | |
| ></a> | |
| </div> | |
| </div> | |
| <div class="excerpt-container"> | |
| <p> | |
| Join the community in evaluating text-to-speech models, and vote for the AI voice that best | |
| captures the emotion, nuance, and expressiveness of human speech. | |
| </p> | |
| </div> | |
| """ | |
| ) | |
| # --- Tabs --- | |
| with gr.Tabs() as tabs: | |
| with gr.TabItem("Arena"): | |
| self.arena.build_arena_section() | |
| with gr.TabItem("Leaderboard"): | |
| ( | |
| leaderboard_table, | |
| battle_counts_table, | |
| win_rates_table | |
| ) = await self.leaderboard.build_leaderboard_section() | |
| # --- Top-level Event Handlers --- | |
| tabs.select( | |
| fn=self._handle_tab_select, | |
| inputs=[], | |
| outputs=[leaderboard_table, battle_counts_table, win_rates_table], | |
| ) | |
| logger.debug("Gradio interface built successfully") | |
| return demo | |