Spaces:
Running
Running
File size: 4,941 Bytes
5ed9749 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# 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
|