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()