Программисты не понаслышке знают, как важно периодически давать отдых уставшим запястьям. И в этом случае возможность диктовки текста – будь то во время длительных сессий программирования или в стремлении к более эргономичной организации работы – может стать настоящим спасением. В данном туториале я вместе с вами подробно рассмотрю процесс создания современного инструмента для транскрибации речи в текст на языке Python, отличающегося высокой скоростью и точностью благодаря использованию ИИ, а именно API Whisper от Groq.

Наша цель – разработать скрипт, работающий в фоновом режиме и позволяющий активировать голосовой ввод в любом приложении простым нажатием кнопки. После отпускания кнопки скрипт мгновенно преобразует речь в текст и автоматически вставит его в активное поле ввода. Таким образом, мы получаем возможность голосового ввода практически в любом вашем приложении.

Приятного прочтения!

Предварительные требования

Прежде чем мы приступим к реализации проекта, необходимо убедиться в наличии определенных инструментов. В первую очередь, в нашей системе должен быть установлен Python, а также потребуется установка следующих библиотек:

      pip install keyboard pyautogui pyperclip groq pyaudio

Каждая из этих библиотек играет важную роль в нашем проекте:

  • PyAudio, который беспечивает обработку аудиосигнала, поступающего с микрофона;

  • Keyboard, который позволяет отслеживать события клавиатуры и реагировать на нажатие клавиш;

  • PyAutoGUI, который имитирует ввод с клавиатуры для автоматической вставки транскрибированного текста;

  • Pyperclip, который взаимодействует с буфером обмена операционной системы;

  • И, наконец, Groq, а именно клиент API Groq, обеспечивающий доступ к реализации Whisper.

Также нам с вами понадобится ключ API Groq. Если у вас его еще нет, вы можете получить его бесплатно, зарегистрировавшись на сайте.

Код

Если захотите ознакомиться с готовым проектом, то полный код вы сможете найти в моем репозитории на GitHub. В статье же мы сфокусируемся на ключевых компонентах скрипта и проанализируем их взаимодействие, обеспечивающее функционирование инструмента для транскрибации речи в текст.

Важно отметить, что в этой реализации мы не используем библиотеку Atomic Agents.

Настройка окружения

Первым шагом в реализации нашего проекта будет импорт необходимых библиотек и настройка клиента Groq. Для инициализации клиента Groq мы будем использовать ключ API, хранящийся в переменной окружения. Такой подход является общепринятой практикой для работы с конфиденциальной информацией, в частности, с ключами API, поскольку он позволяет избежать хранения ключей непосредственно в исходном коде. Поэтому, прежде чем продолжить, убедитесь, что вы создали файл .env, содержащий ваш ключ API.

import os
import tempfile
import wave
import pyaudio
import keyboard
import pyautogui
import pyperclip
from groq import Groq

client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
    

Запись аудио

Функция record_audio, как следует из ее названия, предназначена для захвата аудио с микрофона:

def record_audio(sample_rate=16000, channels=1, chunk=1024):
    p = pyaudio.PyAudio()
    stream = p.open(
        format=pyaudio.paInt16,
        channels=channels,
        rate=sample_rate,
        input=True,
        frames_per_buffer=chunk,
    )

    print("Нажмите и удерживайте кнопку PAUSE, чтобы начать запись...")
    frames = []
    keyboard.wait("pause")  # Ожидание нажатия кнопки PAUSE
    print("Запись... (Отпустите PAUSE, чтобы остановить)")
    while keyboard.is_pressed("pause"):
        data = stream.read(chunk)
        frames.append(data)
    print("Запись завершена.")
    stream.stop_stream()
    stream.close()
    p.terminate()
    return frames, sample_rate
    

В данном случае мы используем частоту дискретизации 16000 Гц, которая является оптимальной для работы с Whisper. Поскольку Whisper самостоятельно понижает частоту дискретизации до 16000 Гц, использование более высокого значения приведет лишь к увеличению размера файла и, как следствие, к сокращению длительности записи, доступной для транскрибации.

Функция инициализирует поток PyAudio и ожидает нажатия клавиши PAUSE. После нажатия начинается запись аудио, которая продолжается до тех пор, пока клавиша удерживается. Выбор клавиши PAUSE обусловлен ее редким использованием в современных приложениях, однако вы можете легко изменить этот параметр и использовать любую другую клавишу на свое усмотрение.

Сохранение аудио во временный файл

После завершения записи аудио, следующий шаг заключается в их сохранении во временный файл для последующей обработки. Для этой цели используем функцию save_audio:

def save_audio(frames, sample_rate):
    with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_audio:
        wf = wave.open(temp_audio.name, "wb")
        wf.setnchannels(1)
        wf.setsampwidth(pyaudio.PyAudio().get_sample_size(pyaudio.paInt16))
        wf.setframerate(sample_rate)
        wf.writeframes(b"".join(frames))
        wf.close()
        return temp_audio.name
    

Данная функция создает временный WAV-файл с помощью tempfile. Использование временных файлов в данном случае обусловлено тем, что аудиоданные необходимы нам лишь на короткий промежуток времени для проведения транскрибации. После этого файл будет удален, к чему мы вернемся позднее.

Транскрибация аудио с помощью Groq

Сердцевиной нашего скрипта является процесс транскрибации, который реализован в функции transcribe_audio:

def transcribe_audio(audio_file_path):
    try:
        with open(audio_file_path, "rb") as file:
            transcription = client.audio.transcriptions.create(
                file=(os.path.basename(audio_file_path), file.read()),
                model="whisper-large-v3",
                prompt="""Аудиозапись программиста, обсуждающего проблемы программирования. Программист в основном использует Python и может упоминать библиотеки Python или ссылаться на код в своей речи.""",
                response_format="text",
                language="en",
            )
        return transcription
    except Exception as e:
        print(f"Произошла ошибка: {str(e)}")
        return None
    

Функция transcribe_audio осуществляет транскрибацию аудиофайла посредством API Groq. Для достижения высокой точности распознавания речи мы выбираем модель "whisper-large-v3", которая, благодаря оптимизации API Groq, работает с впечатляющей скоростью. Параметр prompt позволяет задать контекст для модели, что способствует более точному пониманию содержания аудиозаписи. В нашем случае мы указали, что речь идет о программировании, что позволяет модели более эффективно распознавать специфические термины, такие как названия библиотек.

Обработка результатов транскрипции

После того, как транскрибация завершена и текст получен, необходимо вставить его в активное приложение. Эта задача выполняется функцией copy_transcription_to_clipboard:

def copy_transcription_to_clipboard(text):
    pyperclip.copy(text)
    pyautogui.hotkey("ctrl", "v")
    

Функция использует библиотеку pyperclip для копирования транскрибированного текста в буфер обмена, а затем, с помощью библиотеки pyautogui, имитирует нажатие клавиш "Ctrl+V", что приводит к вставке текста в активное приложение. Такой подход обеспечивает универсальность нашего инструмента и позволяет ему корректно работать с любым полем ввода текста, независимо от используемого приложения.

Главный цикл

И последним элементом нашего скрипта является функция main(), которая объединяет все компоненты в единый рабочий процесс:

def main():
    while True:
        # Запись аудио
        frames, sample_rate = record_audio()

        # Сохранение аудио во временный файл
        temp_audio_file = save_audio(frames, sample_rate)

        # Транскрибация аудио
        print("Транскрибация...")
        transcription = transcribe_audio(temp_audio_file)

        # Копирование транскрипции в буфер обмена
        if transcription:
            print("\nТранскрипция:")
            print(transcription)
            print("Копирование транскрипции в буфер обмена...")
            copy_transcription_to_clipboard(transcription)
            print("Транскрипция скопирована в буфер обмена и вставлена в приложение.")
        else:
            print("Транскрибация не удалась.")

        # Удаление временного файла
        os.unlink(temp_audio_file)
        print("\nГотов к следующей записи. Нажмите PAUSE для начала.")
    

Функция main() организована в виде бесконечного цикла, позволяя пользователю выполнять несколько записей без необходимости перезапуска скрипта. Каждая итерация цикла включает в себя следующие этапы:

  1. При нажатии и удержании клавиши PAUSE производится запись аудио;

  2. Записанные аудиоданные сохраняются во временный файл;

  3. С помощью API Whisper от Groq производится транскрибация аудиозаписи в текст;

  4. В случае успешной транскрибации, текст копируется в буфер обмена и вставляется в активное приложение;

  5. Временный файл с аудиоданными удаляется для освобождения ресурсов.

Спасибо за прочтение!

Комментарии (6)


  1. vagon333
    27.08.2024 04:52

    Забрал код, протестировал.
    Приемлемо: ошибок нет, но разметку нужно добавлять самому.
    Порадовала скорость - текст пришел меньше чем за секунду.

    Приемлемо: ошибок нет, но разметку нужно добавлять самому.

    Начитал из: https://www.home-assistant.io/integrations/image_processing/
    В вордовый документ.


  1. ajhebwk
    27.08.2024 04:52

    Почему бы просто не использовать клавишу виндовс + H, с помощью которой я и отправил этот комментарий?


    1. nbaranov
      27.08.2024 04:52
      +1

      Ну например в Linux не работает )


    1. Ratenti
      27.08.2024 04:52

      Запятые он сам расставляет?


  1. Cognac
    27.08.2024 04:52

    Не работает в linux из-за "You must be root to use this library on linux", чего требует input. Вот здесь описано решение, которое работает для многих, но не для меня: https://github.com/boppreh/keyboard/issues/312#issuecomment-1189734564


  1. goroldioa
    27.08.2024 04:52

    .