File size: 8,814 Bytes
66bb2ef
e69631b
 
 
 
 
66bb2ef
e69631b
 
f35e5f5
e69631b
779f9f6
09bd3ae
e69631b
66bb2ef
779f9f6
66bb2ef
e69631b
779f9f6
66bb2ef
 
 
 
 
 
 
 
 
 
e69631b
66bb2ef
e69631b
66bb2ef
 
 
 
e69631b
66bb2ef
 
 
 
 
 
 
 
 
 
 
 
e69631b
 
66bb2ef
 
 
 
e69631b
66bb2ef
 
 
e69631b
66bb2ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93b15c3
954a2f1
93b15c3
954a2f1
 
 
93b15c3
 
 
954a2f1
 
93b15c3
954a2f1
 
93b15c3
 
954a2f1
 
 
93b15c3
954a2f1
93b15c3
 
 
 
 
954a2f1
874b150
 
93b15c3
 
 
954a2f1
 
 
 
 
 
 
 
 
 
 
 
93b15c3
954a2f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66bb2ef
 
 
 
779f9f6
5467c51
66bb2ef
 
 
 
 
 
 
779f9f6
66bb2ef
 
779f9f6
66bb2ef
 
 
 
 
 
 
 
 
 
 
 
e69631b
b2b0b4b
 
 
 
 
 
 
 
66bb2ef
 
779f9f6
 
66bb2ef
779f9f6
 
 
66bb2ef
 
 
 
 
 
 
 
 
b2b0b4b
 
 
 
 
 
 
66bb2ef
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# -*- coding: utf-8 -*-
import torch
import gradio as gr
import yt_dlp as youtube_dl
from transformers import pipeline
from transformers.pipelines.audio_utils import ffmpeg_read
from huggingface_hub import login

import tempfile
import uuid
import os
import time
import yt_dlp

# --- Конфигурация ---
HF_TOKEN = os.getenv("HF_ACCESS_TOKEN")
MODEL_NAME = "artyomboyko/whisper-small-ru-v4"
BATCH_SIZE = 8
# FILE_LIMIT_MB = 1000

# --- Инициализация ---
try:
    if HF_TOKEN:
        login(token=HF_TOKEN)
        print("Успешный вход в Hugging Face Hub.")
    else:
        print("HF_ACCESS_TOKEN не найден. Запуск в оффлайн-режиме или с публичными моделями.")
except Exception as e:
    print(f"Не удалось войти в Hugging Face Hub: {e}")

# Определение устройства для вычислений (GPU или CPU)
device = 0 if torch.cuda.is_available() else "cpu"
if device == 0:
    print("GPU доступен, вычисления будут производиться на GPU.")
else:
    print("GPU не доступен, вычисления будут производиться на CPU.")

# Загрузка модели распознавания речи
try:
    pipe = pipeline(
        task="automatic-speech-recognition",
        model=MODEL_NAME,
        chunk_length_s=30,
        device=device,
    )
    print(f"Модель {MODEL_NAME} успешно загружена.")
except Exception as e:
    print(f"Ошибка при загрузке модели {MODEL_NAME}: {e}")
    exit()


# --- Функции ---
def transcribe(filepath, task):
    """
    Транскрибирует аудиофайл с помощью загруженной модели Whisper.

    Args:
        filepath (str): Путь к аудиофайлу.
        task (str): Задача для модели ("transcribe" или "translate").

    Returns:
        str: Распознанный текст.
    """
    if filepath is None:
        # Используем gr.Warning вместо gr.Error для неблокирующего уведомления
        gr.Warning("Аудиофайл не предоставлен! Пожалуйста, загрузите или запишите аудио перед отправкой запроса.")
        return "Ошибка: Аудиофайл не предоставлен." # Возвращаем строку ошибки

    print(f"Начало транскрибации файла: {filepath}, Задача: {task}")
    try:
        result = pipe(filepath, batch_size=BATCH_SIZE, generate_kwargs={"task": task}, return_timestamps=True)
        text = result["text"]
        print("Транскрибация завершена успешно.")
        return text
    except Exception as e:
        print(f"Ошибка во время транскрибации: {e}")
        # Используем gr.Error для вывода серьезной ошибки
        raise gr.Error(f"Произошла ошибка при обработке аудио: {e}")


def download_audio(video_url: str, download_folder: str) -> str:

    if not video_url:
        gr.Warning("URL YouTube видео не предоставлен.")
        return None

    unique_filename = f"{uuid.uuid4()}.mp3"
    audio_filepath = os.path.join(download_folder, unique_filename)
    
    ydl_opts = {
        'format': 'bestaudio/best',
        'outtmpl': audio_filepath,
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '192',
        }],
        'quiet': True,
    }

    try:
        os.makedirs(download_folder, exist_ok=True)
    
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            ydl.download([video_url])

    except Exception as e:
        print(f"Не удалось скачать аудио с YouTube: {e}")
        gr.Error(f"Не удалось скачать аудио с YouTube: {e}", duration=5)
        audio_filepath = None
    
    return audio_filepath

def transcribe_youtube(youtube_url, task):
    """
    Скачивает аудио с YouTube и транскрибирует его.

    Args:
        youtube_url (str): URL YouTube видео.
        task (str): Задача для модели ("transcribe" или "translate").

    Returns:
        str: Распознанный текст или сообщение об ошибке.
    """
    audio_filepath = download_audio(youtube_url, "./downloded_audio")
    if audio_filepath:
        try:
            transcription = transcribe(audio_filepath, task)
            # Удаляем временный файл и директорию после транскрибации
            os.remove(audio_filepath)
            os.rmdir(os.path.dirname(audio_filepath))
            return transcription
        except Exception as e:
            # Удаляем временный файл и директорию даже если транскрибация не удалась
            if os.path.exists(audio_filepath):
                 os.remove(audio_filepath)
                 os.rmdir(os.path.dirname(audio_filepath))
            raise e # Перебрасываем ошибку для обработки Gradio
    else:
        return "Не удалось скачать аудио."

# --- Создание интерфейса Gradio ---
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="neutral")) as demo:
    gr.Markdown(
        f"""
        # Whisper: Транскрибация аудио
        Транскрибируйте длинные аудиозаписи (с микрофона или из файла) одним нажатием кнопки!
        Демо использует модель OpenAI Whisper [{MODEL_NAME}](https://huggingface.co/{MODEL_NAME})
        через библиотеку 🤗 Transformers для распознавания речи.
        """
    )

    # Создание вкладок
    with gr.Tabs():
        
        # Вкладка 1: Транскрибация с микрофона
        with gr.TabItem("Микрофон"):
            with gr.Row():
                mic_input = gr.Audio(sources=["microphone"], type="filepath", label="Запись с микрофона")
                task_mic = gr.Radio(["transcribe", "translate"], label="Задача", value="transcribe")
            output_mic = gr.Textbox(label="Результат", lines=7) # Увеличили количество строк для текста
            mic_button = gr.Button("Транскрибировать с микрофона")

        # Вкладка 2: Транскрибация из файла
        with gr.TabItem("Аудиофайл"):
            with gr.Row():
                file_input = gr.Audio(sources=["upload"], type="filepath", label="Загрузить аудиофайл")
                task_file = gr.Radio(["transcribe", "translate"], label="Задача", value="transcribe")
            output_file = gr.Textbox(label="Результат", lines=7)
            file_button = gr.Button("Транскрибировать файл")

        # Вкладка 3: Транскрибация с YouTube URL
        with gr.TabItem("YouTube URL"):
            with gr.Row():
                url_input = gr.Textbox(label="Введите URL YouTube видео")
                task_youtube = gr.Radio(["transcribe", "translate"], label="Задача", value="transcribe")
            output_youtube = gr.Textbox(label="Результат", lines=7)
            youtube_button = gr.Button("Транскрибировать с YouTube")


    # --- Привязка функций к кнопкам ---
    
    # Связываем кнопку "Транскрибировать с микрофона" с функцией transcrib
    mic_button.click(
        fn=transcribe,                     
        inputs=[mic_input, task_mic],      
        outputs=output_mic                 
    )

    # Связываем кнопку "Транскрибировать файл" с функцией transcribe
    file_button.click(
        fn=transcribe,
        inputs=[file_input, task_file],
        outputs=output_file
    )

    # Связываем кнопку "Транскрибировать с YouTube" с функцией transcribe_youtube
    youtube_button.click(
        fn=transcribe_youtube,
        inputs=[url_input, task_youtube],
        outputs=output_youtube
    )

# --- Запуск приложения ---
print("Запуск интерфейса Gradio...")
demo.queue().launch(debug=True, share=False)