Книга: Анализ данных с LLM. Текст, таблицы, изображения и аудио
Назад: 6. Анализ изображений и видеороликов
Дальше: Часть III. Углубленное изучение

7. Анализ аудиоданных

В этой главе

• Транскрибация аудиозаписей.

• Перевод аудиоданных.

• Генерация речи.

Посмотрите любой качественный научно-фантастический телесериал или фильм, и вы нигде не увидите, чтобы люди при взаимодействии с компьютерами набирали команды на клавиатуре. Будь то «Звездный путь» или «Космическая одиссея 2001 года» (оба выпущены в 1960-х), люди разговаривают со своими компьютерами (а не набирают текст). И на то есть веские причины! Для большинства пользователей голос — самая естественная форма общения (потому что первая). Неудивительно, что люди представляли себе разговор с компьютерами задолго до того, как он стал технически возможен.

Теперь реальность догнала научную фантастику, и голосовые помощники, такие как Alexa от Amazon, Assistant от Google и Cortana от Microsoft (а также многие другие), распространены повсеместно. Новейшее поколение моделей распознавания (и генерации) речи достигло уровня, близкого к человеческому. И конечно, голосовое взаимодействие с компьютерами — лишь один из вариантов использования этой удивительной технологии.

В этой главе мы будем использовать новейшие модели OpenAI для транскрибации речи, ее перевода и генерации — и все это в нескольких мини-проектах. Сначала мы выясним, что для транскрибации голосовых записей в текст требуется всего несколько строк кода на Python. После этого мы рассмотрим более сложные приложения, начиная с голосовой версии нашего интерфейса запросов на естественном языке к базе данных, с которым мы работали в главе 5. И если раньше текст вопросов приходилось набирать, то теперь их можно просто произнести, и система выдаст ответ. Наконец, вы увидите, как создать систему синхронного перевода, которая превратит ваш голосовой ввод в голосовой вывод на другом языке.

7.1. Подготовка

Прежде чем приступить к этим увлекательным проектам, необходимо выполнить несколько подготовительных действий. Вы будете записывать голосовой ввод со своего компьютера. Для этого нужен микрофон. В большинстве современных ноутбуков есть встроенный микрофон. Он не обязательно должен быть профессиональным; подойдет любой способ записи звука на вашем компьютере. Помимо микрофона, вам потребуется программное обеспечение для преобразования аудиозаписей в файлы, которое можно активизировать из кода Python. Для этого можно использовать библиотеку Python sounddevice. Чтобы установить нужную версию, выполните в терминале следующую команду:

pip install sounddevice==0.4

Эта библиотека взаимодействует с библиотекой Python scipy, которую тоже нужно установить. Выполните в терминале команду:

pip install scipy==1.11

Вместе библиотеки позволят вам записывать голосовой ввод (который затем можно будет транскрибировать, перевести или кратко пересказать с помощью моделей OpenAI).

Мы рассмотрели вопросы ввода данных, а как насчет вывода? В некоторых проектах нам потребуется не только слушать аудиозаписи, но и генерировать их! Для генерации речи мы снова воспользуемся моделями генеративного ИИ от компании OpenAI. Однако после того, как речь будет сгенерирована и сохранена в аудиофайле, потребуются библиотеки для воспроизведения ее на компьютере из кода Python. Мы будем использовать библиотеку playsound. Чтобы установить нужную версию, запустите в терминале эту команду:

pip install playsound==1.3

В некоторых операционных системах (в частности, macOS) дополнительно потребуется установить библиотеку PyObjC:

pip install PyObjC==10.0

Если вы еще не сделали этого, работая над прошлой главой, то установите библиотеку requests (позволяющую отправлять запросы напрямую к API OpenAI):

pip install requests==2.31.0

Отлично! Если при выполнении этих команд не появились сообщения об ошибках, значит, система подготовлена для обработки аудиоданных с помощью моделей-трансформеров OpenAI. В следующем разделе мы приступим к первому проекту.

7.2. Транскрибация аудиофайлов

Начав работать в компании Banana, вы поразились количеству совещаний. Их слишком много, быть на всех не получается, но пропустить что-то важное не хочется! К счастью, в Banana разумно подошли к вопросу и ввели общее правило: делать аудиозаписи всех рабочих встреч (с согласия участников). Однако прослушивание всех этих записей по-прежнему отнимает слишком много времени.

Было бы хорошо получать расшифровки записей, позволяющие быстро находить всю информацию, касающуюся вашего отдела, с помощью обычного текстового поиска. К сожалению, в Banana такие расшифровки не предусмотрены, а никто из коллег не хочет вести протоколы совещаний. Можно ли создавать такие расшифровки автоматически? В этом разделе вы увидите, что это не только возможно, но и несложно.

7.2.1. Транскрибация речи

Для преобразования речи в текст мы воспользуемся моделью Whisper от OpenAI. В отличие от моделей, с которыми мы работали до этого (в частности, моделей GPT), Whisper предназначена именно для транскрибации аудиозаписей.

Что такое модель Whisper

Whisper — это модель-трансформер, обученная на большом количестве аудиозаписей (более 680 000 часов записей, если быть точным!). Whisper обучалась на многоязычном корпусе аудиофайлов и поэтому поддерживает множество языков ввода, которые она преобразует в русский (то есть вы получаете одновременно расшифровку и перевод речи).

Как и в случае с моделями GPT, мы получим доступ к Whisper, используя библио­теку OpenAI для Python. А значит, не нужно ничего дополнительно настраивать на компьютере (при условии, что вы установили библиотеку OpenAI для Python, как описано в главе 3).

В этом разделе мы будем использовать модель Whisper для транскрибации аудиофайла с компьютера. Предположим, что аудиофайл изначально хранится на диске. Whisper поддерживает широкий спектр форматов файлов: MP3, MP4, MPEG, MPGA, M4A, WAV и WEBM. На момент написания книги размер файла был ограничен 25 Мбайт. Представим, что нужный файл есть и что путь к нему хранится в переменной audio_path. Теперь для преобразования его содержимого в текст нужно лишь ввести следующие строки кода на Python:

Сначала необходимо открыть аудиофайл. Для этого можно выполнить команду open в Python. Обратите внимание, что в качестве параметра команды open используется параметр rb. Он указывает Python, что мы хотим прочитать файл (r) и что открываем двоичный файл (b). Двоичным является файл, который не содержит читаемых символов. Звуковые файлы, наподобие того, который мы пытаемся открыть, обычно квалифицируются как двоичные. После обработки первой строки содержимое файла доступно через переменную audio_file.

На втором этапе выполняется фактическая транскрибация. Теперь мы используем другой эндпоинт, предназначенный для обработки аудиоданных. Из него мы вызываем сервис транскрибации (transcrip­tions.create), используя два параметра:

file — ссылка на файл для транскрибации;

model — имя модели для транскрибации.

Мы ссылаемся на ранее открытый файл (audio_file) и выбираем whisper-1 в качестве модели для транскрибации. Результатом является объект, содержащий расшифрованный текст и метаданные о процессе транскрибации. Доступ к тексту можно получить через поле text (то есть через transcription.text). После распаковки в полученной папке должны находиться три каталога.

Как видите, для транскрибации текста требуется всего несколько строк кода на Python! В следующем подразделе мы используем этот код для создания простого сервиса транскрибации.

7.2.2. Полный рабочий код

В листинге 7.1 содержится код простой программы транскрибации. Фактически транскрибация происходит в функции transcribe . По сути, мы обсуждали этот код в предыдущем подразделе. Получив в качестве входных данных аудиофайл, функция возвращает расшифрованный текст.

Листинг 7.1. Транскрибация аудиофайлов в текст

import argparse

import openai

 

client = openai.OpenAI()

 

def transcribe(audio_path):    

    """Транскрибировать аудиофайл в текст.

 

    Аргументы:

        audio_path: путь к аудиофайлу.

 

    Выводит:

        транскрибированный текст.

    """

    with open(audio_path, 'rb') as audio_file:

    transcription = client.audio.transcriptions.create(

        file=audio_file, model='whisper-1')

    return transcription.text

 

if __name__ == '__main__':     

 

    parser = argparse.ArgumentParser()

    parser.add_argument('audiopath', type=str, help='Путь к аудиофайлу')

    args = parser.parse_args()

 

    transcript = transcribe(args.audiopath)

    print(transcript)

Функция main в качестве входных данных считывает путь к аудиофайлу (который должен содержать речь). После вызова функции transcriptions.create она выводит расшифрованный текст на экран.

7.2.3. Проверка в работе

Для тестирования необходимо сначала получить аудиофайл с записанной речью. Можно использовать любой такой файл (в том числе запись ваших рабочих совещаний, если она есть) при условии, что он соответствует ограничениям по формату и размеру, описанным в подразделе 7.2.1. Однако помните, что вы платите за каждую минуту обработанных аудиоданных! На момент написания книги использование модели Whisper через библиотеку OpenAI стоило 0,006 доллара за минуту (более актуальную информацию о ценах можно найти на сайте https://openai.com/pricing). Следовательно, обработка длинных записей может оказаться дорогостоящей.

Если вам не хочется использовать собственную запись, то можете взять другую — из дополнительных материалов к этой главе. Запись доступна по ссылке Audio. По умолчанию файл должен называться QuoteFromTheAlchemist.mp3.

Там же, в дополнительных материалах к главе, вы можете найти ссылку на файл с кодом из листинга 7.1 (Listing 1). Скачав файл, перейдите в соответствующий репозиторий в терминале. Предположим, вы загрузили аудиофайл в текущий каталог, теперь выполните в терминале следующую команду для создания расшифровки файла примера:

python listing1.py QuoteFromTheAlchemist.mp3

Если все получится, то в терминале должен отобразиться такой вывод (для файла примера с сайта):

На том самом месте, где ты сейчас стоишь, я сам два года назад несколько раз видел один и тот же сон.

Нажмите на файл примера, прослушайте его и убедитесь, что расшифровка точна!

Далее мы интегрируем расшифровку речи в более сложные приложения.

7.3. Голосовые запросы к реляционным базам данных

Анализировать табличные данные — интересное занятие! Значительная часть вашей работы в компании Banana состоит в том, чтобы изучать таблицы данных, извлекать ценную информацию, а затем готовить соответствующие отчеты и визуализации. Вы используете интерфейс преобразования текста в SQL (см. главу 5) для автоматического перевода текстовых вопросов в формальные запросы (на языке SQL), их выполнения и представления результатов запроса. Это упрощает анализ данных и выполняется быстрее, чем написание сложных SQL-запросов с нуля.

Однако есть проблема: во время анализа данных вам лучше думается, когда вы расхаживаете по кабинету. Вот только, чтобы ввести запрос, каждый раз приходится возвращаться к столу. Нельзя ли изменить интерфейс запросов так, чтобы он поддерживал голосовой ввод вместо текстового?

Оказывается, действительно можно! В этом разделе вы узнаете, как использовать модели OpenAI для создания простого голосового интерфейса запросов к табличным данным.

7.3.1. Подготовка

Мы создадим интерфейс голосовых запросов, который будет обрабатывать устные вопросы о табличных данных. Он представляет собой расширение интерфейса запросов, который мы обсуждали в главе 5. Предположим, что устные вопросы касаются данных, хранящихся в SQLite — популярной системе для обработки запросов к реляционным базам данным. Краткое введение в SQLite и инструкции по установке изложены в главе 5. Чтобы протестировать приведенный ниже код, сначала необходимо установить систему баз данных SQLite.

Система SQLite обрабатывает запросы, сформулированные на SQL (языке структурированных запросов). К счастью, вам не потребуется самостоятельно писать SQL-запросы (их напишет языковая модель). Однако модели неидеальны и иногда могут выдавать некорректные запросы. Чтобы выявлять такие случаи, полезно иметь опыт работы с SQL. Краткое введение в SQL представлено в главе 5. Более подробную информацию можно найти на сайте www.databaselecture.com.

Наш интерфейс голосовых запросов обрабатывает устные вопросы, поэтому необходимо убедиться, что микрофон работает. Кроме того, перед выполнением приведенного ниже кода удостоверьтесь, что у интерфейса голосовых запросов есть все необходимые разрешения для доступа к микрофону.

7.3.2. Обзор

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

• «Сколько игр компания Activision продала в 2023 году?»;

• «Сколько экшен-игр было выпущено в период с 2019 по 2021 год?».

Получив устный вопрос, интерфейс голосовых запросов выполняет следующие действия.

1. Транскрибирует устный вопрос в текст.

2. Переводит текстовый вопрос в SQL-запрос.

3. Обрабатывает SQL-запрос к данным с помощью SQLite.

4. Отображает результат запроса пользователю.

На рис. 7.1 более подробно показаны разные этапы обработки. Процесс выполняется для каждого устного вопроса.

Рис. 7.1. Интерфейс голосовых запросов транскрибирует устные вопросы в текст, переводит текстовые вопросы в SQL-запросы, наконец, обрабатывает эти запросы и выводит результат

7.3.3. Запись аудио

Работая с приложением расшифровки аудиозаписей, мы предполагали, что аудиозапись уже доступна. В этом проекте мы будем отправлять голосовые запросы многократно. Следовательно, нам придется записывать их. Как это сделать в Python? Начнем с того, что для этой цели потребуется импортировать две библиотеки:

Библиотека sounddevice содержит множество полезных функций для записи аудиоввода с микрофона. Что мы будем делать с записями? Хранить их на диске в формате .wav. В предыдущем разделе описывалось, как выполнить расшифровку аудиоданных, сохраненных в этом формате. Здесь используется вторая библиотека, scipy : она позволяет сохранять записи в формате .wav на диск.

При записи необходимо определить два важных момента:

• с какой частотой дискретизации следует считывать ввод с микрофона;

• сколько секунд речи записывать.

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

Что касается частоты дискретизации — то есть количества точек аудиоданных, сохраняемых в секунду, — мы выберем 44 100 Герц. Это стандарт для записей качества компакт-диска. Общее количество фреймов — количество точек аудиоданных, полученных в сумме, — будет равно 44 100, умноженным на количество секунд записи (в нашем случае это 5 секунд). Сохраним количество фреймов и частоту дискретизации во вспомогательных переменных:

sample_rate = 44100

nr_frames = 5 * sample_rate

Теперь мы готовы записывать с помощью функции rec библиотеки sounddevice:

Первая команда начинает запись через микрофон, передавая в качестве входных данных общее количество кадров для записи, а также частоту дискретизации. Количество каналов (третий параметр в вызове функции) зависит от микрофона, используемого для записи. Если у микрофона более одного канала, то попробуйте указать в нем большее значение. После начала записи необходимо подождать, пока пройдет заданное время. Мы добьемся этого с помощью команды wait .

В результате выполнения приведенного выше кода в переменной recording оказываются записанные аудиоданные. Как обсуждалось ранее, запись необходимо сохранить на диск как файл с расширением .wav. Для этого достаточно одной команды из библиотеки scipy:

scipy.io.wavfile.write(output_path, sample_rate, recording)

Вот и все! Мы записали несколько секунд звука и сохранили их в файле на диске.

7.3.4. Полный рабочий код

В листинге 7.2 приведен код интерфейса голосовых запросов. Помимо стандартных библиотек openai и argparse, мы импортируем библиотеки для обработки аудио (sounddevice и scipy), а также библиотеку sqlite3 (для обработки SQL-запросов) и библиотеку time (для ожидания заданного количества времени (для голосового ввода)).

Листинг 7.2. Отправка запросов к базе данных SQLite с помощью голосовых команд

import argparse                               

import openai

import re

import scipy.io.wavfile

import sounddevice

import sqlite3

import time

 

client = openai.OpenAI()

 

def get_structure(data_path):                 

    """Извлечь структуру из базы данных SQLite.

 

    Аргументы:

        data_path: путь к файлу данных SQLite.

 

    Выводит:

        текстовое описание структуры базы данных.

    """

    with sqlite3.connect(data_path) as connection:

        cursor = connection.cursor()

        cursor.execute("select sql from sqlite_master where type = 'table';")

        table_rows = cursor.fetchall()

        table_ddls = [r[0] for r in table_rows]

        return '\n'.join(table_ddls)

 

def record(output_path):                      

    """Записать аудио и сохранить в файле .wav.

 

    Аргументы:

        output_path: сохранить аудиозапись здесь.

    """

    sample_rate = 44100

    nr_frames = 5 * sample_rate

    recording = sounddevice.rec(

        nr_frames, samplerate=sample_rate, channels=1)

    sounddevice.wait()

    scipy.io.wavfile.write(output_path, sample_rate, recording)

 

def transcribe(audio_path):                   

    """ Транскрибировать аудиофайл в текст.

 

    Аргументы:

        audio_path: путь к аудиофайлу.

 

    Выводит:

        транскрибированный текст.

    """

    with open(audio_path, 'rb') as audio_file:

        transcription = client.audio.transcriptions.create(

            file=audio_file, model='whisper-1')

        return transcription.text

 

def create_prompt(description, question):

Создает запрос для преобразования текста в формат SQL

    """ Сгенерировать промпт для перевода вопроса в SQL-запрос.

 

    Аргументы:

        description: текстовое описание структуры базы данных.

        question: вопрос о данных на естественном языке.

 

    Выводит:

        Промпт для перевода вопроса.

    """

    parts = []

    parts += ['База данных:']

    parts += [description]

    parts += ['Переведи этот вопрос в SQL-запрос:']

    parts += [question]

    parts += ['SQL-запрос:']

    return '\n'.join(parts)

 

def call_llm(prompt):                         

    """ Отправить запрос большой языковой модели и вывести ответ.

 

    Аргументы:

        prompt: ввести запрос к языковой модели.

 

    Выводит:

        Ответ языковой модели.

    """

    for nr_retries in range(1, 4):

        try:

            response = client.chat.completions.create(

                model='gpt-4o',

                messages=[

                    {'role':'user', 'content':prompt}

                    ]

                )

            return response.choices[0].message.content

        except:

            time.sleep(nr_retries * 2)

    raise Exception('Не удается выполнить запрос к модели OpenAI!')

 

def process_query(data_path, query):          

    """ Обрабатывает SQL-запрос и возвращает результат.

 

    Аргументы:

        data_path: путь к файлу данных SQLite.

        query: обработать этот запрос к базе данных.

 

    Выводит:

        результат запроса.

    """

    with sqlite3.connect(data_path) as connection:

        cursor = connection.cursor()

        cursor.execute(query)

        table_rows = cursor.fetchall()

        table_strings = [str(r) for r in table_rows]

        return '\n'.join(table_strings)

 

if __name__ == '__main__':                    

 

    parser = argparse.ArgumentParser()

    parser.add_argument('dbpath', type=str, help='Путь к данным SQLite')

    args = parser.parse_args()

 

    data_structure = get_structure(args.dbpath)

 

    while True:                               

 

        user_input = input('Нажмите Enter, чтобы начать запись (введите quit,

                            чтобы выйти из приложения).')

        if user_input == 'quit':

            break

 

        audio_path = 'question.wav'           

        record(audio_path)

        question = transcribe(audio_path)

        print(f'Вопрос: {question}')

 

        prompt = create_prompt(data_structure, question)  

        answer = call_llm(prompt)

        query = re.findall('```sql(.*)```', answer, re.DOTALL)[0]

        print(f'SQL: {query}')

 

        try:                                  

            answer = process_query(args.dbpath, query)

            print(f'Ответ: {answer}')

        except:

            print('Ошибка обработки запроса! Попробуйте переформулировать.')

Теперь обсудим функции, представленные в этом листинге 7.2.

Мы обрабатываем голосовые запросы, которые адресованы данным, хранящимся в реляционной базе данных. Чтобы переводить голосовые команды в формальные запросы, сформулированные на языке SQL, необходимо иметь определенные сведения о структуре базы данных. В частности, нужно знать имена таблиц данных и их столбцов (то есть схему базы). Функция get_structure извлекает команды, примененные для создания схемы. Эти команды содержат имена таблиц и столбцов, а также типы данных, связанные со столбцами таблиц. Мы используем эти команды как часть промпта, дав языковой модели указание переводить вопросы в SQL-запросы.

Прежде чем вопросы можно будет переводить, их сначала необходимо записать через микрофон. Для этого предназначена функция record . Она использует библиотеку sounddevice для записи 5 последовательных секунд ввода аудиоданных через микрофон. Полученная аудиозапись сохраняется на диске как файл в формате .wav по пути, который указан как входной параметр функции (output_path). Строго говоря, сохранять вводимые аудиоданные в виде файла не обязательно (можно обрабатывать их непосредственно в памяти). Но сохраненная на диск аудиозапись может пригодиться при отладке. Если системе не удастся преобразовать голосовой ввод в соответствующие запросы, то вы сможете сами прослушать аудиофайл, чтобы оценить уровень фонового шума и общее качество звука. Если микрофон настроен неправильно (распространенная проблема), то аудиозаписи будут содержать только тишину.

После записи входных данных через микрофон их нужно сначала преобразовать в текст. Для этого используется функция transcribe . Получив путь к аудиофайлу (в данном случае — к записи с микрофона), она возвращает расшифровку, сгенерированную с помощью модели Whisper от OpenAI (той же, что мы использовали ранее).

Далее необходимо перевести вопросы в формальные SQL-запросы. Разумеется, для этой задачи используются языковые модели. Функция create_prompt генерирует подходящий промпт. Он содержит ранее извлеченное описание базы данных, транскрибированный вопрос и описание задачи. Функция call_llm вызывает для перевода вопросов языковую модель GPT-4o, используя в качестве входных данных упомянутый ранее промпт. Наконец, функция process_query обрабатывает получившиеся запросы в базе данных и возвращает результат запроса.

Пора собрать все вместе! Наш интерфейс голосовых запросов принимает в качестве входных данных путь к файлу базы данных SQLite . После извлечения схемы базы мы входим в главный цикл . Каждая итерация обрабатывает один голосовой запрос (если только пользователь не введет команду quit; в этом случае программа завершится). Для простоты мы ждем, пока пользователь нажмет клавишу Enter, прежде чем записывать голосовой ввод (более сложная версия записывала бы непрерывно). После этого записываем голосовой ввод с микрофона. Мы выводим транскрибированный вопрос и сохраняем саму запись на диске в файле question.wav . Затем переводим транскрибированный текст в запрос , выполняем его (здесь потребуется обработка исключений на случай некорректных запросов!) и показываем результат пользователям.

7.3.5. Проверка в работе

Файл с кодом из листинга 7.2 доступен по ссылке Listing 2, которую можно найти на сайте книги в разделе дополнительных материалов к этой главе. Скачайте код и перейдите в содержащую его папку в терминале.

Помимо кода, для тестирования интерфейса голосовых запросов нам потребуется база данных SQLite. В главе 5 мы обсуждали, как настроить демонстрационную базу, содержащую информацию о продажах компьютерных игр. Предположим, что она хранится в одной папке с кодом и называется games.db (конечно, для проверки голосового интерфейса вы можете использовать любую другую базу данных SQLite). Теперь введите в терминале следующую команду:

python listing2.py games.db

Обновите путь к файлу базы, указав тот, к которому хотите получить доступ. В зависимости от операционной системы и настроек безопасности, возможно, вам придется разрешить приложению доступ к микрофону. После этого нажмите Enter и задайте вопрос. Например, если вы работаете с базой данных игр, то можете спросить: «Сколько игр было продано в 2007 году?» или «Сколько игр каждого жанра было выпущено?». Должен отобразиться примерно такой вывод:

Нажмите Enter, чтобы начать запись (введите quit, чтобы выйти из приложения).

Вопрос: Сколько игр каждого жанра было выпущено?

SQL: SELECT genre, COUNT(*) as num_games

FROM games

GROUP BY genre

Ответ: ('Экшен', 3316)

('Приключения', 1286)

('Файтинг', 848)

('Жанр', 1)

('Прочее', 1739)

('Платформенная игра', 886)

('Головоломка', 582)

('Гонки', 1249)

('Ролевая игра', 1488)

('Шутер', 1310)

('Симулятор', 867)

('Спортивные игры', 2346)

('Стратегия', 681)

В этом выводе содержится транскрибированный вопрос, преобразованный в SQL-запрос, и результат запроса (или сообщение об ошибке, если запрос не может быть выполнен). Очевидно, что путь от голосового вопроса до результата запроса долог! Ошибка в записи, транскрибации или переводе приведет к неверным результатам. Прежде чем доверять результату запроса, обязательно проверьте дополнительный вывод, чтобы убедиться, что система не ошиблась.

СОВЕТ Если голосовой интерфейс выдает только бессмыслицу, то проверьте записи в файле question.wav. Если вы ничего не слышите, то убедитесь, что у вашего приложения есть доступ к микрофону. По умолчанию приложения обычно не имеют такого доступа (чтобы злоумышленникам было сложнее использовать их для слежки за вами с помощью вредоносного ПО). Для предоставления доступа необходимо обновить настройки безопасности.

7.4. Перевод речи в речь

Филиал компании Banana в Париже начал изучать языковые модели и потенциальные приложения для задач анализа данных. Вы заслужили репутацию эксперта в этой теме, и менеджер просит вас проконсультировать французскую команду о том, с чего начать. Есть лишь одна маленькая проблема: вы не говорите по-французски. Услышав, что в парижском филиале компании большинство собраний персонала проводится на французском языке, вы собираетесь отказаться от задания. Но, поразмыслив, понимаете, что все может быть не так уж и страшно. Да, вы не говорите по-французски, но модель GPT-4o точно говорит! Можно ли использовать языковые модели для перевода с одного языка на другой?

Оказывается, можно. В этом разделе мы создадим инструмент перевода, который будет получать входные данные в речевой форме на одном языке и предоставлять голосовой вывод на другом языке. Поскольку инструмент предоставляет вывод в голосовой форме, вам даже не придется отрабатывать французское произношение. Просто говорите на своем языке и ждите, пока инструмент выполнит устный перевод. Таким образом, вы сможете сотрудничать с французскими коллегами и одновременно демонстрировать возможности современных языковых моделей!

7.4.1. Обзор

Наш инструмент перевода обрабатывает голосовой ввод. Как и прежде, мы будем использовать модель Whisper от OpenAI для транскрибации речи в текст. Затем с помощью модели GPT-4o будем переводить текст на другой язык. В наших примерах в качестве целевого языка будет использоваться французский. Однако благодаря удивительным возможностям таких моделей, как GPT-4o, инструмент не ограничится именно этим языком! Он позволит пользователям указывать целевой язык в качестве входных данных, и эта информация добавится в промпт для модели — как инструкция, на какой язык переводить.

После того как текстовый перевод будет сгенерирован, нам потребуется его голосовая версия. Оказывается, можно использовать еще одну модель OpenAI для преобразования текста в голосовой вывод на различных языках. На рис. 7.2 показан полный конвейер обработки, начиная с голосового ввода на первом языке и заканчивая голосовым выводом на втором.

Рис. 7.2. Наш инструмент перевода записывает голосовой ввод на первом языке, транскрибирует ввод в текст, переводит этот текст на второй язык и, наконец, генерирует голосовой вывод

7.4.2. Генерация речи

Конвейер на рис. 7.2 требует выполнения нескольких преобразований. В разделе 7.2 мы выяснили, как данные из голосового ввода можно преобразовать в текст. Переводить текст с помощью языковых моделей относительно легко (попросите модель GPT-4o перевести с одного языка на другой, и она это сделает). Однако мы пока не можем преобразовывать письменный текст (например, на французском языке) в голосовой вывод. Далее мы обсудим, как это сделать.

OpenAI (как и другие провайдеры) предлагает несколько моделей преобразования текста в речь (text-to-speech, TTS). Такие модели принимают в качестве входных данных письменный текст, а в выводе выдают голосовую версию. Этот фрагмент кода превращает в речь содержимое текстовой строки (хранящейся в переменной speech_text):

import openai

client = openai.OpenAI()

 

response = client.audio.speech.create(

    model='tts-1', voice='alloy',

    input=speech_text)

В этом примере мы используем новый эндпоинт (audio.speech) и настраиваем метод create с помощью трех параметров:

model — имя модели, используемой для генерации голосового вывода. Мы используем модель преобразования текста в речь tts-1 компании OpenAI;

• input — мы генерируем устный вывод для этого текста. Отправьте текст на любом из языков, поддерживаемых моделью (https://github.com/openai/whisper);

voice — для озвучивания речи можно выбирать разные голоса. Здесь мы используем вариант alloy.

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

А какова цена?

На момент написания книги компания OpenAI брала плату 1,5 цента за 1000 токенов при генерации текста с помощью модели TTS и вдвое больше за версию высокого качества (TTS HD). Скорее всего, стоимость со временем изменится, поэтому обязательно посетите сайт с ценами OpenAI (https://openai.com/pricing), чтобы получить актуальную информацию.

7.4.3. Полный рабочий код

В листинге 7.3 представлен полный рабочий код нашего инструмента перевода. Начнем с обсуждения импортируемых библиотек . Помимо библиотеки openai и модуля argparse, использовавшихся во всех предыдущих проектах, мы импортируем библиотеки sounddevice и scipy для записи и сохранения аудиофайлов, а также модуль time для ограничения времени записи.

Листинг 7.3. Перевод голосового ввода на другой язык

import argparse                 

import openai

import playsound

import requests

import scipy.io.wavfile

import sounddevice

import time

 

client = openai.OpenAI()

 

def record(output_path):        

    """Записать аудио и сохранить в файле .wav.

 

    Аргументы:

        output_path: сохранить аудиозапись здесь.

    """

    sample_rate = 44100

    nr_frames = 5 * sample_rate

    recording = sounddevice.rec(

        nr_frames, samplerate=sample_rate, channels=1)

    sounddevice.wait()

    scipy.io.wavfile.write(output_path, sample_rate, recording)

 

def transcribe(audio_path):                    

    """Транскрибировать аудиофайл в текст.

 

    Аргументы:

        audio_path: путь к аудиофайлу.

 

    Выводит:

        транскрибированный текст.

    """

    with open(audio_path, 'rb') as audio_file:

        transcription = client.audio.transcriptions.create(

            file=audio_file, model='whisper-1')

        return transcription.text

 

def create_prompt(to_translate, to_language):

    """Сгенерировать промпт для перевода текста на целевой язык.

 

    Аргументы:

        to_translate: перевести этот текст.

        to_language: перевести текст на этот язык.

 

    Выводит:

        Переведенный текст.

    """

    parts = []

    parts += [f'Перевести этот текст на {to_language}:']

    parts += [to_translate]

    parts += ['Переведенный текст:']

    return '\n'.join(parts)

 

def call_llm(prompt):                          

    """ Отправить запрос большой языковой модели и вывести ответ.

 

    Аргументы:

        prompt: введите запрос к языковой модели.

 

    Выводит:

        Ответ языковой модели.

    """

    for nr_retries in range(1, 4):

        try:

            response = client.chat.completions.create(

                model='gpt-4o',

                messages=[

                    {'role':'user', 'content':prompt}

                    ]

                )

            return response.choices[0].message.content

        except:

            time.sleep(nr_retries * 2)

    raise Exception('Не удается выполнить запрос к модели OpenAI!')

 

def generate_speech(speech_text):              

    """ Генерирует речь из конкретного текста.

 

    Аргументы:

        speech_text: сгенерировать речь из этого текста.

 

    Выводит:

        результат запроса.

    """

    response = client.audio.speech.create(

        model='tts-1', voice='alloy',

        input=speech_text)

    return response.content

 

if __name__ == '__main__':                     

 

    parser = argparse.ArgumentParser()

    parser.add_argument('tolanguage', type=str, help='Целевой язык')

    args = parser.parse_args()

 

    while True:                                

 

        user_input = input('Нажмите Enter, чтобы начать запись (введите quit,

                            чтобы выйти из приложения.')

        if user_input == 'quit':

            break

 

        audio_path = 'to_translate.wav'        

        record(audio_path)

        to_translate = transcribe(audio_path)

        print(f'Оригинальный текст: {to_translate}')

 

        

        prompt = create_prompt(to_translate, args.tolanguage)

        translated = call_llm(prompt)

        print(f'Текст перевода: {translated}')

 

        speech = generate_speech(translated)   

        with open('translation.mp3', 'wb') as file:

            file.write(speech)

 

        playsound.playsound('translation.mp3')

Библиотека playsound используется для воспроизведения аудиофайлов, сгенерированных моделями OpenAI. Поскольку мы генерируем речь через HTTP-интерфейс OpenAI, то импортируем библиотеку requests для создания HTTP-запросов. А теперь обсудим функции, используемые в листинге 7.3.

Как и в предыдущем проекте, аудиоданные записываются с микрофона. Функция record записывает 5 секунд аудиоввода и сохраняет их на диске в файле формата .wav. Функция transcribe транскрибирует этот аудиоввод в текст. Обе функции мы подробно рассмотрели при работе с предыдущими проектами этой главы.

Функция create_prompt генерирует промпт для перевода. Как и в предыдущих проектах, промпт содержит описание задачи и все релевантные входные данные. В данном случае мы хотим перевести с исходного языка (английского) на целевой язык (французский). Обратите внимание, что целевой язык указан как входной параметр (to_language). Этот параметр соответствует текстовому фрагменту, описывающему желаемый язык вывода. В простейшем случае это может быть название языка (например, французский). Кроме того, пользователи могут даже попросить озвучить текст на определенном диалекте (скажем, швабский диалект немецкого языка) или в определенном стиле (например, шекспировский английский). Целевой язык интегрируется в описание задачи, которое появляется в промпте вместе с текстом для перевода.

Обратите внимание, что исходный язык указывать не требуется. Предполагается, что языковая модель способна распознать язык входного текста (иначе бессмысленно надеяться, что она его переведет).

После вызова функции call_llm с передачей ей промпта мы должны получить переведенный текст. Функция generate_speech генерирует соответствующую речь, используя подход, который мы рассмотрели в предыдущем подразделе.

Приложение-переводчик ожидает в качестве входных данных текст, описываю­щий целевой язык. Этот параметр представляет собой строку, которая может содержать произвольный текст. Она просто ставится вместо метки-заполнителя в промпте, используемом для перевода. В главном цикле пользователи нажимают клавишу Enter и после этого начинают говорить или вводят команду quit, чтобы завершить работу приложения.

При записи пользовательского ввода мы сначала сохраняем пятисекундную аудиозапись в файле с именем to_translate.wav, а затем транскрибируем ввод с помощью функции transcribe . После этого мы используем языковую модель GPT-4o для перевода входных данных на целевой язык , а затем генерируем речь из перевода . Мы сохраняем сгенерированную речь на диске в файле формата .mp3 (это означает, что последний вывод можно будет легко прослушать еще раз) и, наконец, с помощью библиотеки playsound, как вы уже догадались, воспроизводим сгенерированный звуковой файл.

7.4.4. Проверка в работе

Самое время протестировать наш переводчик! Его код доступен по ссылке Listing 3, размещенной на сайте книги, в разделе дополнительных материалов к этой главе. Скачайте код и в терминале перейдите в папку с ним. Можно выбрать целевой язык для перевода. Конечно, качество перевода и звукового вывода может варьироваться в зависимости от вашего выбора. В частности, и модель, используемая для расшифровки речи, и модель, выполняющая генерацию речи, поддерживают набор примерно из 60 распространенных языков. Транскрибация аудиоввода или генерация голосового вывода на менее распространенных языках может не сработать. Найдите в Интернете актуальный список поддерживаемых языков для расшифровки (https://help.openai.com/en/articles/7031512-whisper-api-faq) и генерации речи (https://platform.openai.com/docs/guides/text-to-speech). Пока что в соответствии со сценарием, описанным в начале раздела, мы выберем в качестве целевого языка французский. Чтобы запустить переводчик, введите в терминале команду:

python listing3.py "French"

Строго говоря, кавычки вокруг слова French не нужны. Но описание желаемого целевого языка может состоять из нескольких слов, поэтому в следующих примерах мы используем кавычки, чтобы избежать ошибок, если консоль неверно интерпретирует наш ввод как значения для нескольких параметров.

Как и в предыдущем проекте, приложению необходимо предоставить доступ к микрофону. Нажмите Yes (Да), если появится запрос на доступ к микрофону; в противном случае убедитесь, что настройки безопасности разрешают такой доступ. Вот отрывок диалога с инструментом перевода:

Нажмите Enter, чтобы начать запись (введите quit, чтобы выйти из приложения).

Исходный текст: Добрый день, мои парижские коллеги.

Переведенный текст: Bonjour mes collègues à Paris.

Нажмите Enter, чтобы начать запись (введите quit, чтобы выйти из приложения).

Исходный текст: Позвольте, я расскажу вам кое-что о языковых моделях.

Переведенный текст: Laisse-moi t'apprendre quelque chose à propos des modèles de langage.

Вы увидите расшифровку ввода и сгенерированный перевод. Кроме того, вы должны услышать голосовую версию перевода (если нет, то проверьте настройки аудиовыхода). Неплохо для нескольких строк кода на Python!

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

python listing3.py "Английский язык, стиль Шекспира"

Вот что получится, если придать обычному приветствию гораздо более утонченную форму (это задание может стать хорошим введением в курс по языковым моделям для коллег из американского филиала Banana):

Нажмите Enter, чтобы начать запись (введите quit, чтобы выйти из приложения).

Исходный текст: Добрый день, мои парижские коллеги.

Переведенный текст: Внемлите, мои добрые соратники, приветствую вас!

Нажмите Enter, чтобы начать запись (введите quit, чтобы выйти из приложения).

Исходный текст: Позвольте, я расскажу вам кое-что о языковых моделях.

Переведенный текст: Внемлите, о благородные слушатели, дабы я поведал вам о таинствах языковых моделей.

Протестируйте его еще с несколькими целевыми языками! Возможности (почти) безграничны.

Резюме

• Модель Whisper от OpenAI транскрибирует голосовой ввод в текст.

• Доступ к тексту расшифровки можно получить через эндпоинт API-метода для транскрибации аудио.

• Стоимость расшифровки зависит от количества минут.

• Компания OpenAI предлагает несколько моделей, способных преобразовать текст в речь.

• Можно выбрать голос и качество генерируемой речи.

• Стоимость генерации речи зависит от количества токенов.

Назад: 6. Анализ изображений и видеороликов
Дальше: Часть III. Углубленное изучение