Den4ikAI's picture
Update app.py
c6714a7 verified
import gradio as gr
import pandas as pd
import json
# --- 1. Загрузка и подготовка данных ---
def load_data(json_path='data.json'):
"""Загружает данные из JSON и преобразует их в pandas DataFrame."""
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
df = pd.DataFrame(data)
# --- ИСПРАВЛЕНИЕ: Преобразуем колонку с датой в формат datetime ---
# dayfirst=True указывает pandas, что в формате ДД/ММ/ГГГГ день идет первым.
df['test_date'] = pd.to_datetime(df['test_date'], dayfirst=True)
return df
# --- 2. Логика фильтрации и обновления таблицы ---
def update_leaderboard(data_df, filter_type, search_query, show_outdated):
"""Фильтрует DataFrame на основе выбранного типа, поискового запроса и флага устаревших данных."""
# Шаг 1: Фильтрация по устаревшим данным
if not show_outdated:
# Скрываем модели с пометкой об устаревших данных
filtered_df = data_df[~data_df['notes'].str.contains('устаревших данных', na=False, case=False)].copy()
else:
filtered_df = data_df.copy()
# Шаг 2: Фильтрация по типу
if filter_type == "Только войсклонинг":
filtered_df = filtered_df[filtered_df['type'] == 'voice_cloning'].copy()
elif filter_type == "Без войсклонинга":
filtered_df = filtered_df[filtered_df['type'] == 'single_speaker'].copy()
# else: "Все модели" - оставляем как есть
# Шаг 3: Фильтрация по поисковому запросу
if search_query:
query = search_query.lower()
filtered_df = filtered_df[
filtered_df['engine'].str.lower().str.contains(query) |
filtered_df['voice'].str.lower().str.contains(query)
]
# Шаг 4: Подготовка DataFrame для отображения
# --- ИСПРАВЛЕНИЕ: Форматируем дату в 'ГГГГ-ММ-ДД' для корректной сортировки в UI ---
# Создаем копию, чтобы не изменять оригинальный DataFrame в gr.State
display_df = filtered_df.copy()
display_df['test_date'] = display_df['test_date'].dt.strftime('%Y-%m-%d')
column_mapping = {
"engine": "Движок", "voice": "Голос", "test_date": "Дата",
"hardware": "Железо", "utmos": "UTMOS (↑)", "cer": "CER (↓)",
"encodec_fad": "FAD (↓)", "similarity_avg": "Похожесть Avg (↑)",
"xrt_gpu": "xRT GPU (↓)", "xrt_cpu": "xRT CPU (↓)", "notes": "Примечания"
}
display_df = display_df[column_mapping.keys()].rename(columns=column_mapping)
return display_df
# --- 3. Создание интерфейса Gradio ---
# Загружаем данные один раз при старте приложения
original_df = load_data()
# Сортируем по-умолчанию по дате (самые новые вверху), скрывая устаревшие
initial_display_df = update_leaderboard(original_df, "Все модели", "", show_outdated=False)
initial_display_df = initial_display_df.sort_values(by="Дата", ascending=False)
with gr.Blocks(theme=gr.themes.Soft(), css="footer {visibility: hidden}") as demo:
gr.Markdown("# 🏆 Лидерборд TTS моделей для русского языка")
gr.Markdown(
"""
Этот лидерборд предназначен для сравнения различных Text-to-Speech моделей.
### Описание метрик:
- **UTMOS (↑)**: Оценка качества речи, основанная на мнении слушателей (Mean Opinion Score). **Больше — лучше.**
- **CER (↓)**: Character Error Rate (коэффициент ошибок по символам). Показывает, насколько часто синтез делает ошибки в произношении. **Меньше — лучше.**
- **FAD (↓)**: Fréchet Audio Distance. Объективная метрика, измеряющая расстояние между распределениями реального и синтезированного аудио. **Меньше — лучше.**
- **Похожесть Avg (↑)**: Средняя оценка схожести голоса с оригиналом при клонировании. **Больше — лучше.**
- **xRT GPU/CPU (↓)**: Real-Time Factor. Во сколько раз синтез быстрее (если < 1) или медленнее (если > 1) реального времени на GPU/CPU. **Меньше — лучше.**
- **Железо**: Тип оборудования, на котором производился тест (Cloud - облачный сервис, Local GPU/CPU - локальное железо, RTX 4090 - конкретная видеокарта).
*Кликните на заголовок колонки для сортировки. По умолчанию отсортировано по дате (сначала новые).*
"""
)
gr.Markdown("✉️ Чтобы добавить свою модель, а также вопросы и предложения пишите в Telegram [@bceloss](https://t.me/bceloss)")
gr.Markdown('✉️ Добавляйтесь в чат "Распознавание и синтез речи" [@speech_recognition_ru](https://t.me/speech_recognition_ru)')
gr.Markdown('👥 Авторы: Nikolay Shmyrev [@nshmyrev](https://t.me/nshmyrev), Denis Petrov [@bceloss](https://t.me/bceloss)')
with gr.Row():
with gr.Column(scale=3):
filter_radio = gr.Radio(
["Все модели", "Только войсклонинг", "Без войсклонинга"],
label="Тип модели",
value="Все модели"
)
with gr.Column(scale=3):
search_box = gr.Textbox(
label="Поиск по названию движка или голоса",
placeholder="Например, Silero, Vosk, Multi..."
)
with gr.Column(scale=2):
show_outdated_checkbox = gr.Checkbox(
label="Показать модели с устаревшими данными",
value=False,
info="⚠️ Данные этих моделей могут быть неточными"
)
# Информационное сообщение о скрытых моделях
outdated_info = gr.Markdown(visible=False)
leaderboard_df = gr.DataFrame(
value=initial_display_df,
interactive=True,
)
# Используем gr.State для передачи полного DataFrame с правильными типами данных
df_state = gr.State(original_df)
def on_change(filter_type, search_query, show_outdated, data_df):
"""Обновляет таблицу и показывает информацию о скрытых моделях."""
updated_df = update_leaderboard(data_df, filter_type, search_query, show_outdated)
# Подсчитываем количество скрытых моделей с устаревшими данными
if not show_outdated:
outdated_count = data_df[data_df['notes'].str.contains('устаревших данных', na=False, case=False)].shape[0]
if outdated_count > 0:
info_text = f"ℹ️ **Скрыто моделей с устаревшими данными: {outdated_count}**. Включите опцию выше, чтобы показать их."
return updated_df, gr.update(value=info_text, visible=True)
return updated_df, gr.update(visible=False)
# Связываем все элементы управления с функцией обновления
filter_radio.change(
fn=on_change,
inputs=[filter_radio, search_box, show_outdated_checkbox, df_state],
outputs=[leaderboard_df, outdated_info]
)
search_box.change(
fn=on_change,
inputs=[filter_radio, search_box, show_outdated_checkbox, df_state],
outputs=[leaderboard_df, outdated_info]
)
show_outdated_checkbox.change(
fn=on_change,
inputs=[filter_radio, search_box, show_outdated_checkbox, df_state],
outputs=[leaderboard_df, outdated_info]
)
# Показываем информацию о скрытых моделях при загрузке
demo.load(
fn=lambda: f"ℹ️ **Скрыто моделей с устаревшими данными: {original_df[original_df['notes'].str.contains('устаревших данных', na=False, case=False)].shape[0]}**. Включите опцию выше, чтобы показать их.",
outputs=outdated_info
)
# --- 4. Запуск приложения ---
if __name__ == "__main__":
demo.launch()