Пошаговое руководство с использованием AssemblyAI и Streamlit

Научить ИИ разговаривать шёпотом — непростая задача даже сегодня. Но мы покажем, насколько простыми стали распознавание и транскрипция речи, по крайней мере, на поверхности. Интересно? Тогда добро пожаловать под кат.
Материал подготовлен к старту курса по Fullstack-разработке на Python.
Введение
Приложение расшифровки речи в режиме реального времени автоматически преобразует текст в речь. Этот текст почти мгновенно отображается на экране, а использовать подобные приложения можно для самых разных целей, включая расшифровку лекций, конференций и встреч. Здесь есть ряд преимуществ:
-
можно сразу записывать идеи и беседы. Это очень полезная функция для людей, которые работают в быстро меняющейся среде, и для людей с большим количеством идей;
-
развивать навыки общения, ведь теперь вы увидите, как говорите вы сами и как говорят другие.
-
Такими приложениями могут пользоваться люди с нарушением слуха или те, кто учит английский. Приложение расшифровывает аудио в реальном времени, а пользователь видит текст на экране параллельно произношению слов. К тексту можно применить обработку естественного языка.
Мы научимся создавать приложение для динамического преобразования речи в текст и сделаем это с помощью API AssemblyAI (серверная часть) и Streamlit (клиентская часть).
Вот видеоверсия статьи:
Обзор приложения
Для приложения понадобятся следующие библиотеки для Python:
-
streamlit — веб-фреймворком воспользуемся для размещения всех виджетов ввода и вывода;
-
websocket — позволяет приложению взаимодействовать с API AssemblyAI;
-
asyncio — позволяет выполнять всевозможный речевой ввод и вывод асинхронно;
-
base64 — кодирует и декодирует аудиосигнал перед его отправкой в API AssemblyAI;
-
json — считывает речевой вывод, сгенерированный через API AssemblyAI (например, расшифрованный текст);
-
pyaudio — обрабатывает речевой ввод через библиотеку PortAudio;
-
os и pathlib — используются для перехода по различным папкам проекта и работы с файлами.
Настройка рабочей среды
Чтобы воссоздать приложение для динамической расшифровки речи на вашем компьютере, мы создадим среду conda под названием transcription:
conda create -n transcription python=3.9
Возможно, высветится запрос на установку зависимостей Python-библиотеки. Если так, нажмите клавишу Y, чтобы подтвердить действие и продолжить.

После создания среды conda активировать её можно так:
conda activate transcription
Делать это нужно каждый раз в начале написания кода, а по завершении работы с кодом из среды нужно выйти:
conda deactivate
Загрузка GitHub-репозитория
Загрузим с GitHub весь репозиторий приложения динамической расшифровки речи:
git clone https://github.com/dataprofessor/realtime-transcription
Переходим в папку realtime-transcription:
cd realtime-transcription
Можно установить обязательные библиотеки, которыми пользуется приложение:
pip install -r requirements.txt
Получение ключа от API AssemblyAI
Получить доступ к API в AssemblyAI крайне просто. Для начала зарегистрируйтесь на AssemblyAI, это бесплатно. Зайдите в учётную запись. На панели справа вы увидите API-ключ:

Теперь, когда вы скопировали API-ключ в память, необходимо добавить его в файл secrets.toml из папки.streamlit. Путь к файлу выглядит так: .streamlit/secrets.toml. Его содержание должно быть таким:
api_key = 'xxxxx'
Вместо xxxxx вставьте свой ключ от API. Получить этот ключ мы сможем с помощью строки кода st.secrets[‘api_key’].
Запуск приложения
Прежде чем запускать приложение, давайте рассмотрим содержимое рабочей директории (то, что открывается по команде tree в Bash):

Содержимое папки realtime-transcription
Теперь мы готовы запустить своё приложение:
streamlit run streamlit_app.py
Этот код позволит открыть приложение в новом окне браузера:

Посмотрим, как работает приложение:

Объяснение кода
Ниже объясняется базовый код приложения.
-
Строки 1–8 — импорт обязательных библиотек веб-приложения.
-
Строки 10-13 — начальное состоянии сессии приложения.
-
Строки 15-22 — ввод для приём пользовательского ввода параметров аудио представлены виджетом text_input.
-
Строки 24-31 — для открытия потока аудиоданных через pyaudio используются входные параметры аудио из блока кода выше.
-
Строки 33-46 — определяют 3 пользовательские функции (например, start_listening, stop_listening и download_transcription), которые будут вызываться в коде (см. ниже).
-
Строка 49 — отображает название приложения через строку st.title.
-
Строки 51–62 — отображает информацию о приложении (раздел About) с помощью строки st.expander.
-
Строки 64–67 — создают 2 столбца строкой st.columns для размещения кнопок «Пуск» (Start) и «Стоп» (Stop). То есть они используют start_listening и stop_listening через параметр on_click виджета кнопки.
-
Строки 69–139 — здесь выполняется обработка речевого входа и выхода: аудиосигнал передаётся в API AssemblyAI, где расшифрованный текст выдаётся в формате JSON. Эта часть была изменена и адаптирована из блока кода, написанного Мисрой Турп и Джорджиосом Мириантусом.
-
Строки 141–144 — отображают кнопку загрузки расшифровки, а затем удаляют файл.
Весь код
import streamlit as st import websockets import asyncio import base64 import json import pyaudio import os from pathlib import Path # Состояние сессии if 'text' not in st.session_state: st.session_state['text'] = 'Listening...' st.session_state['run'] = False # Параметры аудио st.sidebar.header('Audio Parameters') FRAMES_PER_BUFFER = int(st.sidebar.text_input('Frames per buffer', 3200)) FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = int(st.sidebar.text_input('Rate', 16000)) p = pyaudio.PyAudio() # Открываем аудиопоток с указанными выше параметрами stream = p.open( format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=FRAMES_PER_BUFFER ) # Запуск и остановка прослушивания def start_listening(): st.session_state['run'] = True def download_transcription(): read_txt = open('transcription.txt', 'r') st.download_button( label="Download transcription", data=read_txt, file_name='transcription_output.txt', mime='text/plain') def stop_listening(): st.session_state['run'] = False # Веб-интерфейс (фронтенд) st.title('?️ Real-Time Transcription App') with st.expander('About this App'): st.markdown(''' This Streamlit app uses the AssemblyAI API to perform real-time transcription. Libraries used: - `streamlit` - web framework - `pyaudio` - a Python library providing bindings to [PortAudio](http://www.portaudio.com/) (cross-platform audio processing library) - `websockets` - allows interaction with the API - `asyncio` - allows concurrent input/output processing - `base64` - encode/decode audio data - `json` - allows reading of AssemblyAI audio output in JSON format ''') col1, col2 = st.columns(2) col1.button('Start', on_click=start_listening) col2.button('Stop', on_click=stop_listening) # Отправляем аудио (ввод) async def send_receive(): URL = f"wss://api.assemblyai.com/v2/realtime/ws?sample_rate={RATE}" print(f'Connecting websocket to url ${URL}') async with websockets.connect( URL, extra_headers=(("Authorization", st.secrets['api_key']),), ping_interval=5, ping_timeout=20 ) as _ws: r = await asyncio.sleep(0.1) print("Receiving messages ...") session_begins = await _ws.recv() print(session_begins) print("Sending messages ...") async def send(): while st.session_state['run']: try: data = stream.read(FRAMES_PER_BUFFER) data = base64.b64encode(data).decode("utf-8") json_data = json.dumps({"audio_data":str(data)}) r = await _ws.send(json_data) except websockets.exceptions.ConnectionClosedError as e: print(e) assert e.code == 4008 break except Exception as e: print(e) assert False, "Not a websocket 4008 error" r = await asyncio.sleep(0.01) # Принимаем транскрипцию (вывод) async def receive(): while st.session_state['run']: try: result_str = await _ws.recv() result = json.loads(result_str)['text'] if json.loads(result_str)['message_type']=='FinalTranscript': print(result) st.session_state['text'] = result st.write(st.session_state['text']) transcription_txt = open('transcription.txt', 'a') transcription_txt.write(st.session_state['text']) transcription_txt.write(' ') transcription_txt.close() except websockets.exceptions.ConnectionClosedError as e: print(e) assert e.code == 4008 break except Exception as e: print(e) assert False, "Not a websocket 4008 error" send_result, receive_result = await asyncio.gather(send(), receive()) asyncio.run(send_receive()) if Path('transcription.txt').is_file(): st.markdown('### Download') download_transcription() os.remove('transcription.txt') # Ссылки (этот код — адаптация кода по ссылкам ниже) # 1. https://github.com/misraturp/Real-time-transcription-from-microphone # 2. https://medium.com/towards-data-science/real-time-speech-recognition-python-assemblyai-13d35eeed226
Заключение
Поздравляем, вы создали приложение для динамического преобразования речи на Python с помощью API AssemblyAI. Как уже говорилось, у таких приложений есть несколько вариантов использования (диктовка статьи/сочинения или письма, развитие навыков общения преобразование речи для людей с нарушением слуха и т. д.).
Вы можете поступить как автор, то есть снова адаптировать код, уже для российских голосовых API. А мы поможем прокачать ваши навыки или с самого начала освоить профессию, актуальную в любое время:
Выбрать другую востребованную профессию.

ссылка на оригинал статьи https://habr.com/ru/company/skillfactory/blog/669126/
Добавить комментарий