AI доступный каждому разработчику

в 11:14, , рубрики: AI, asr, chatgpt, TTS, искусственный интеллект, машинное обучение, Программирование

Долгое время я прекрасно обходился без использования технологий искусственного интеллекта. Одни задачи можно было реализовать без всякого ИИ, а для других или готовых моделей не было или это были какие-то коммерческие облачные API.

В последнее время всё сильно изменилось и волна популярности искусственного интеллекта принесла множество крутейших моделей, позволяющих реализовать новые идеи или переосмыслить старые.

Казалось бы, есть и локально запускаемые аналоги ChatGPT или сервисов генерации изображений. Есть библиотеки типа llama.cpp - бери и используй! Но если бы было всё так просто, то не было бы этой статьи.

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

Всё началось с идеи создания своего локального голосового помощника, который можно встроить в умный дом. Да, я в курсе, что есть множество готовых проектов, но меня в них всегда что-то не устраивало, а главное мне было интересно самому разработать софт, напечатать на 3D-принтере корпуса и собрать свои устройства для взаимодействия с виртуальным ассистентом.

Дальше я расскажу, с какими проблемами я столкнулся.

Сложность интеграции

Какие-то решения написаны на C++, какие-то на python или даже C# и JavaScript. Что-то придётся собирать руками, а для чего-то есть готовые пакеты под популярные дистрибутивы linux. У каких-то решений есть готовое API, а для других придётся писать C-биндинги и реализовывать API самому. Какие-то приложения собираются просто, а с другими приходится повозиться.

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

AI доступный каждому разработчику - 1

Было бы хорошо, если бы все компоненты можно было запустить в Docker и не возиться с этим всем.

Непригодность для запуска на конечных устройствах

Я встречал много комментариев, где люди успешно запускали llama.cpp и whisper на mac mini и использовали это как готовое решение. Кто-то даже на Raspberry Pi умудряется запускать 7b модели.

Мне это решение категорически не подходило.

Представьте, что у вас умный дом. В нём несколько комнат: спальня, гостиная, кухня. Как-то очень накладно в каждую комнату ставить железки, способные потянуть такие тяжелые задачи.

AI доступный каждому разработчику - 2

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

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

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

Низкая производительность и ограниченность

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

Для серьёзных моделей нужны устройства с большим количеством CPU, оперативной памяти и видеокартой способной вместить модель целиком в память (например, Nvidia 3090 или 4090). С хорошим оборудованием можно будет получать более качественные результаты и быстрее.

AI доступный каждому разработчику - 3

Это ещё один аргумент для использования центрального сервера.

Отсутствие стандартизированного API

Продукты в области ИИ очень активно развиваются и постоянно появляется что-то новое, решающее задачу более качественно. Кому-то для распознавания голоса (ASR) нравится whisper, потому что он поддерживает около 100 языков и умеет автоматически определять язык, а кому-то Vosk, потому что он это делает качественнее и быстрее, хоть и для меньшего числа языков. Все эти решения имеют разные API и переход с одного на другое неизбежно будет приводить к переписыванию клиентского кода приложения. При этом вам повезло, если вы используете только распознавание текста, а если у вас ещё и отдельные интеграции для синтеза речи, шумоподавления, генерации текста и изображений — это будет сложнее.

AI доступный каждому разработчику - 4

Хотелось бы по принципу облачных сервисов реализовать один раз API и париться только подменяя реализации.

Итоги:

Для себя я отметил следующие пожелания к системам на базе ИИ:

  • Возможность запуска в Docker

  • Стандартизированное API, позволяющее без переписывания клиентского кода подменять реализации

  • Модульность

  • Простота использования

Так появился проект VoiceDock, призванный сделать ИИ доступнее для разработчиков конечных приложений.

VoiceDock API

В качестве протокола был выбран gRPC из-за его производительности, поддержки стриминга, простоты описания спецификации и большему числу генераторов клиентского кода для разных языков программирования.

В данный момент API решает следующие задачи:

SttAPI
// Speech-to-text service.
service SttAPI {
  // Converts speech to text.
  rpc SpeechToText(stream SpeechToTextRequest) returns (stream SpeechToTextResponse);
  // Returns available language packs.
  rpc GetLanguagePacks(GetLanguagePacksRequest) returns (GetLanguagePacksResponse);
  // Downloads selected language pack.
  rpc DownloadLanguagePack(DownloadLanguagePackRequest) returns (DownloadLanguagePackResponse);
}

AichatAPI
// Speech-to-text service.
service AichatAPI {
  // Generate response text by prompt.
  rpc Generate(GenerateRequest) returns (stream GenerateResponse);
  // Returns available ai chat models.
  rpc GetModels(GetModelsRequest) returns (GetModelsResponse);
  // Downloads selected ai model.
  rpc DownloadModel(DownloadModelRequest) returns (DownloadModelResponse);
}

TtsAPI
// Text-to-speech service.
service TtsAPI {
  // Converts text to speech.
  rpc TextToSpeech(TextToSpeechRequest) returns (stream TextToSpeechResponse);
  // Returns available voices.
  rpc GetVoices(GetVoicesRequest) returns (GetVoicesResponse);
  // Downloads selected voice.
  rpc DownloadVoice(DownloadVoiceRequest) returns (DownloadVoiceResponse);
}

Помимо методов, непосредственно решающих задачу, везде присутствуют следующие методы:

  • для получения списка моделей;

  • определение, какие из них уже загружены, какие из них можно загрузить по сети;

  • для запуска скачивания выбранной модели.

Пример описания модели AI Chat
// AI Chat model info.
message Model {
  // Model name
  string name = 1;
  // Is downloaded
  bool downloaded = 2;
  // Can be downloaded
  bool downloadable = 3;
  // License text to accept
  string license = 4;
}

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

Методы распознавания и синтеза речи работают с потоком аудиоданных. Метод распознавания принимает стрим аудиоданных. А метод синтеза возвращает стрим аудиоданных.

Я долго думал, как представить этот поток аудиоданных, чтобы реализация на клиентской стороне оставалась максимально простой, и остановился на следующей структуре, где данные представлены в виде сырого PCM (int16 little endian):

// Container for raw PCM audio.
message AudioContainer {
  // 16 bit raw PCM (is the format of 16 bits integers little endian)
  bytes data = 1;
  // Sample rate of audio data
  int32 sample_rate = 2;
  // Audio channels
  int32 channels = 3;
}

API - это хорошо, но толку от него мало, если нет реализации. Об этом далее.

VoiceDock Apps

На данный момент есть 3 готовых для использования реализации:

  • STT Whisper – реализует API распознавания речи

  • AI Chat llama – позволяет запускать llama подобные модели в ggml-формате

  • TTS Piper – реализует API синтеза речи

STT Whisper

Построен на базе whisper.cpp (Быстрая С++ реализации проекта Whisper от Open AI). Распознаёт текст на ~99 языках, может автоматически определять язык.

Запускается как на CPU:

docker run --rm 
  -v "$(pwd)/config:/data/config" 
  -v "$(pwd)/dataset:/data/dataset" 
  -p 9999:9999 
  ghcr.io/voicedock/sttwhisper:latest sttwhisper

Так и на GPU:

docker run --rm 
  -v "$(pwd)/config:/data/config" 
  -v "$(pwd)/dataset:/data/dataset" 
  -p 9999:9999 
  ghcr.io/voicedock/sttwhisper:gpu sttwhisper

Перед запуском нужно создать директории под конфигурацию и модели:

mkdir dataset
mkdir config

А также создать файл конфигурации «config/sttwhisper.json».

Либо скачать пример:

curl -o config/sttwhisper.json https://raw.githubusercontent.com/voicedock/sttwhisper/main/config/sttwhisper.json

Либо настроить самому:

[
  {
    "name": "model_name",
    "languages": ["ru", "en"],
    "download_url": "download_url",
    "license": "license text to accept"
  }
]

Если «download_url» не пустой, то модель можно будет скачивать по API. Остальное, думаю, понятно.

Модель можно загрузить предварительно и положить по пути «dataset/{model_name}/model.bin».

Модели принимает в формате ggml (скачать можно тут).

После запуска можно делать gRPC запросы по порту 9999.

AI chat llama

Сделана на базе популярного проекта llama.cpp от того же автора, что и whisper.cpp. На Hugging Face вы можете найти множество моделей уже сконвертированных в ggml формат. Рейтинг самых лучших моделей можно посмотреть тут и потом найти их ggml-версии. Ggml формат поддерживает разные методы квантования и обычно в описании репозитория написано, чем они отличаются. Вариант квантования «q4_1», вероятно, подойдёт всем.

Запустить можно как на CPU:

docker run --rm 
  -v "$(pwd)/config:/data/config" 
  -v "$(pwd)/dataset:/data/dataset" 
  -p 9999:9999 
  ghcr.io/voicedock/aichatllama:latest aichatllama

Так и на GPU:

docker run --rm 
  -v "$(pwd)/config:/data/config" 
  -v "$(pwd)/dataset:/data/dataset" 
  -e LLAMA_GPU_LAYERS=2 
  --runtime=nvidia --gpus all 
  -p 9999:9999 
  ghcr.io/voicedock/aichatllama:gpu aichatllama

Обратите внимание на параметр LLAMA_GPU_LAYERS, который говорит сколько слоёв модели нужно загрузить в память GPU. Чем больше, тем быстрее, но и требует больше памяти видеокарты.

Перед запуском также нужно создать директории под конфигурацию и модели:

mkdir dataset
mkdir config

И создать файл конфигурации «config/aichatllama.json».

Либо скачать пример:

curl -o config/aichatllama.json https://raw.githubusercontent.com/voicedock/aichatllama/main/config/aichatllama.json

Либо настроить самому:

[
  {
    "name": "model_name",
    "download_url": "download_url",
    "license": "license text to accept"
  }
]

Модель можно загрузить предварительно и положить по пути «dataset/{model_name}/model.bin».

После запуска можно делать gRPC запросы по порту 9999.

TTS Piper

Решение основано на проекте Piper и позволяет достаточно качественно и быстро синтезировать голос (демки можно послушать тут). К сожалению, на момент создания Piper не предоставлял shared library (сейчас, насколько мне известно, предоставляет), поэтому пришлось поработать напильником, но, думаю, скоро переделаю по-нормальному.

TTS Piper поддерживает 26 языков. В принципе, можно и самостоятельно добавить поддержку нового языка.

Запускается только на CPU, но работает оно быстро и без GPU:

docker run --rm 
  -v "$(pwd)/config:/data/config" 
  -v "$(pwd)/dataset:/data/dataset" 
  -p 9999:9999 
  ghcr.io/voicedock/ttspiper:latest ttspiper

Как обычно перед запуском нужно создать директории под конфигурацию и модели:

mkdir dataset
mkdir config

И создать файл конфигурации «config/ttspiper.json».

Либо скачать пример:

curl -o config/ttspiper.json https://raw.githubusercontent.com/voicedock/ttspiper/main/config/ttspiper.json

Либо настроить самому:

[
  {
    "lang": "lang_code",
    "speaker": "speaker_name",
    "download_url": "download_url",
    "license": "license text to accept"
  }
]

Модель можно загрузить предварительно и распаковать по пути «dataset/{lang}/{speaker}/».

После запуска можно делать gRPC запросы по порту 9999.

Заключение

Пройдя этот путь, уже не так сложно начать стоить свой проект голосового ассистента. Наверняка, и у вас есть куча своих идей, которыми вы горите: может это будет web-сервис для сокращения текста, а может telegram-бот для расшифровки лекций или аудио сообщений. И я буду рад, если кому-то, кроме меня, пригодятся наработки проекта VoiceDock.

Всю информацию я буду собирать на сайте VoiceDock.app. Вы можете использовать как готовые приложения, так и делать собственные, реализуя gRPC спецификацию API.

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

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

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

Автор: Константин Осипов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js