import speech_recognition as sr from pydub import AudioSegment import os import gradio as gr import types import typing import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') def convert_wav_to_text(audio_file_path: str) -> str: """ Эта функция получает на вход файл, который который представляет собой аудио. Если формат .wav, то такой файл сразу распознаётся. А если формат отличается от .wav, то такой аудиофайл сначала конвертируется во временное представление .wav, распознаётся и удаляется. Args: audio_file_path (Str): Путь к файлу-голосовому сообщению. Returns: text_from_audio (Str): Текст, полученный из голосового сообщения. error (Str): Сообщение об ошибке. """ file_extension = audio_file_path.split('.')[-1].lower() #получаем формат файла try: #блок для отлова возможных ошибок if file_extension != 'wav': #если формат не .wav audio = AudioSegment.from_file(audio_file_path, format=file_extension) #загружаем аудиофайл с указанием его формата audio = audio.set_channels(1).set_frame_rate(16000) #преобразуем аудио в моно (1 канал) и устанавливаем частоту дискретизации 16000 герц (необходимо для улучшения качества распознавания речи) temp_wav_path = 'temp.wav' #определяем временный путь для сохранения преорбазованногоаудиофайла в формате .wav audio.export(temp_wav_path, format='wav') #экспортируем преобразованное аудио в формат .wav и сохраняем по временному пути else: #иначе temp_wav_path = audio_file_path #просто сохраняем аудиофайл recognizer = sr.Recognizer() #создаём объект-распознаватель речи with sr.AudioFile(temp_wav_path) as source: #открываем аудиофайл audio_data = recognizer.record(source) #и записываем его содержимое try: #блок для отлова возможных ошибок text_from_audio = recognizer.recognize_google(audio_data, language='ru-RU') #пробуем преобразовать данные аудиофайла с помощью сервисов Google return text_from_audio #возвращаем полученный текст except sr.UnknownValueError: #если ошибка связана с речью или шумом error_str = 'Не удалось распознать аудио! Возможно, в данных слишком много шума.' #то создаём сообщение-ошибку return error_str #и печатаем его except sr.RequestError as e: #если ошибка при запросе error_str = f'Возникла неожиданная ошибка: {e}' #то создаём сообщение-ошибку return error_str #и печатаем его finally: #этот блок выполняется независимо от наличия ошибок if file_extension != 'wav' and os.path.exists('temp.wav'): #если есть воеменный файл temp.wav (который создаётся для перезаписывания аудиофайла) os.remove('temp.wav') #то удаляем этот файл def recognize_speech_from_microphone(audio: typing.Union[str, types.NoneType, AudioSegment]) -> str: """ Функция, которая записывает аудио. Args: audio (Str): Путь к аудиофайлу (загруженный файл). audio (types.NoneType): Появляется при смене типа входных данных. audio (AudioSegment): При записи звука микрофоном. Return: text_from_audio (Str): Результат выполнения функции convert_wav_to_text(). warning_str (Str): Предупреждение при смене типа входных данных. """ if isinstance(audio, str): #если входящие данные - путь к файлу (а не записанный звук с микрофона) audio_file_path = audio #то сразу передаём путь без экспорта elif isinstance(audio, types.NoneType): #если входящие данные без типа (пользователь кликнул по смене типа входящих данных) warning_str = 'Вы изменили источник входных данных. Запишите звук или загрузите файл.' #то создаём сообщение-предупреждение return warning_str #и печатаем его else: #иначе (пользователь записывает звук микрофоном) audio_file_path = 'temp_input.wav' #задаём имя файлу audio.export(audio_file_path, format='wav') #конвертируем в .wav-формат return convert_wav_to_text(audio_file_path) #передаём в функцию-распознаватель gui = gr.Interface( #создаём пользовательский интерфейс gradio fn=recognize_speech_from_microphone, #функция, которая вызывается при записи аудио inputs=gr.Audio(type='filepath'), #входной компонент для записи аудио с микрофона устройства outputs='text', #выходной компонент для отображения текста live=True #позволяет запускаться и работать в реальном времени ) if __name__ == '__main__': gui.launch(share=True) #запускаем страницу и локально, и публично