Изображение сгенерировано AI
Изображение сгенерировано AI

Всем привет! Меня зовут Александр Мешков, я автор бесплатной платформы TestGrow для тестировщиков. В последнее время я достаточно большое количество времени стал уделять генеративному искусственному интеллекту и возможностям его применения в различных аспектах обучения.

С появлением больших лингвистических моделей (LLM) сфера ИТ начала стремительно меняться. Уже сейчас многие ИТ специалисты и компании используют различные инструменты на базе ИИ для выполнения рутинных задач. Кроме того, постоянное развитие и обучение новых моделей большими игроками (Google-Gemini, Microsoft– OpenAI и Meta - Llama) приводит к тому, что генерация ответов на базе нейронных сетей становится все более и более качественной, поэтому, как бы это грубо ни звучало, в долгосрочной перспективе я ожидаю значительные изменения и интеграцию ИИ во многие рабочие аспекты.

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

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

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

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

  1. Получить список вопросов, который был бы полный и соответствовал той позиции, на которую человек хочет пройти интервью

  2. Дать обратную связь по каждому ответу на вопрос, получив ответ от человека.

В целом задача выглядит достаточно просто. Поэтому первым этапом необходимо было понять, какую модель лучше всего использовать для взаимодействия с ИИ на каждом этапе. Почему это важно? При работе с генеративным иску��ственным интеллектом стоит принимать во внимание 3 составляющих: скорость ответа, стоимость использования модели (в токенах) и качество ответа. Вам всегда необходимо найти некий баланс, который с минимальными затратами позволял бы получать достаточно быстро ответ, который был бы при этом еще и достаточно качественным. Наиболее популярные модели вы всегда можете посмотреть на HuggingFace. На момент написания статьи в категории качества ответов на русском языке (мы же живём в РФ все-таки) были следующие модели (честно, я пока не пробовал и не изучал модели от Яндекс YandexGPT и от Сбера Gigachat от Сбера, поэтому если у кого-то есть опыт использования, делитесь в комментариях):

A screenshot of a computer  Description automatically generated
A screenshot of a computer Description automatically generated

Из трех наиболее развитых LLM моделей я остановил свой выбор в пользу моделей OpenAI, потому, что:

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

  • Gemini – вполне хороший конкурент OpenAI по качеству генерации ответов, но платные google сервисы voice-to-text и text-to-voice, которые берут по 0.024 доллара за минуту обработки выглядит дороговато для бесплатного приложения, когда OpenAI предлагает стоимость в 4 раза ниже, 0.006 доллара за минуту обработки.

  • OpenAI - в целом уже достаточно давно работаю с данной моделью и мне нравиться как качество генерации ответов их моделей, а также доступность документации для разработчика, плюс удобный API и библиотеки для voice-to-text и text-to-voice. Не нужно изобретать велосипед заново, OpenAI уже обо всем за нас позаботился, что несомненно очень удобно.

Сравнение моделей gpt-4o, gpt-4o mini, o1 preview

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

С точки зрения стоимости и скорости ответа сразу отпала новая модель o1-preview, потому что используемая в ней технология chain of thoughts достаточно долго обрабатывает полученные запросы и время на получения ответа может доходить до 30-60 секунд. Плюс стоимость использования модели в 10 раз выше, чем модели 4o - $15.00 / 1M input tokens и $60.00 / 1M output  tokens.

Далее выбор встал между моделью gpt-4o и gpt-4o mini. Плюсы gpt-4o mini в том, что она в два раза дешевле обычной 4о модели, то есть $0.150 / 1M input tokens и $0.600 / 1M output tokens в gpt-4o mini против $2.50 / 1M input tokens и $10.00 / 1M output tokens в gpt-4o. 

Скрытый текст

Небольшой оффтоп.

Кстати из последних фишек от OpenAI буквально на прошлой неделе они объявили о том, что они внедряют возможности кэширования промптов, что позволяет еще в половину сократить стоимость использования их моделей. Подробности о кэшировании промптов можно посмотреть тут. https://platform.openai.com/docs/guides/prompt-caching

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

A screenshot of a cell phone  Description automatically generated
gpt-4o mini
A screenshot of a cell phone  Description automatically generated
gpt-4o

Какие можно сделать выводы. GPT-4o генерирует более последовательные вопросы, которые в том числе встраиваются по уровню сложности, а также включают в себя практические задачи, в отличии от gpt-4o mini, которая подготовила вопросы в основном только в части теории, но в целом при изменении промпта и добавления определенных условий, данная модель также способна вполне хорошо справляться с данной задачей.

Далее тест на разбор ответа от человека:

A screenshot of a cell phone  Description automatically generated
gpt-4o mini
A screenshot of a cell phone  Description automatically generated
gpt-4o

Тут уже разница появляется значительная разница в ответе. В своем запросе я специально не указал принцип ООП – Наследование, и как вы можете видеть из ответов моделей, gpt-4o сразу указала на это в своем разборе, а вот модель gpt-4o mini пропустила этот недочет. Также ответ gpt-4o явно указывает мне на то, что мне стоит подучить и как лучше ответить на вопрос именно для моей позиции JAVA junior разработчик, и эти подсказки фигурирует во всем ответе, тогда как gpt-4o mini ссылается на это только в конце своего сообщения. Ну и в целом, ответ gpt-4o выглядит более естественным для нас с вами.

Поэтому, когда планируете р��зработку решений на базе существующих генеративных ИИ моделей, всегда делайте такой первоначальный анализ, чтобы понять, насколько качественно модели будут обрабатывать ваши запросы. Что касается меня, то для генерации вопросов я пока отдал предпочтение gpt-4o mini, немного подкорректировав промпт и расширив его инструкциями, а вот анализ ответов отдал на откуп gpt-4o.

Технологии text-to-speech и speech-to-text

Теперь давайте перейдем к технической реализации приложения. 

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

Во-первых, они изначально используют модели, которые обучены OpenAI и явно будут значительно лучше обрабатывать или создавать аудио, а во-вторых, не нужно писать никакой логики, буквально 3-4 строчки кода на Python полностью решат все ваши проблемы.

Пример speech-to-text c использованием модели whisper (ссылка на документацию):

from openai import OpenAI

def speech_to_text(audio_file_path):

        with open(audio_file_path, "rb") as audio_file:

         # Используем OpenAI API для транскрипции речи

         transcription = client.audio.transcriptions.create(

                model="whisper-1",

                file=audio_file

            )

        recognized_text = transcription.text

        return recognized_text

Пример text-to-speech c использованием модели TTS (ссылка на документацию):

from openai import OpenAI

def text_to_speech(text_input, output_file_name="speech.mp3", voice="nova"):

        # Отправляем текст в OpenAI TTS API

        response = client.audio.speech.create(

            model="tts-1",

            voice=voice,

            input=text_input

        ) 

        # Сохраняем синтезированную речь в MP3 файл

        response.stream_to_file(speech_file_path)

        return str(speech_file_path) 

Из плюсов использования моделей Whisper еще заключается в том, что у нее достаточно хороший уровень поддержки русского языка. Измерение качества модели по показателям WERs (word error rates) or CER (character error rates) показывает достаточно низкий уровень количества ошибок. 

A screenshot of a graph  Description automatically generated
A screenshot of a graph Description automatically generated

Для сравнения я также пробовал использовать бесплатные библиотеки как для распознавания голосового ответа, так и в обратную сторону, но, к сожалению, качество бесплатных библиотек SpeechRecognition и pyttsx3 пока оставляет желать лучшего. 

Запись и обработка голосовых ответов

Наверное, если брать во внимание весь проект целиком, то данная часть была, наверное, максимально сложной. Почему? Ну во первых я выбрал JS, для реализации фронт-енд части приложения (к сожалению современных vue, node.js и прочего я не знаю) и оказывается, что в технологии записи голоса на js в браузер есть уйма нюансов, связанных с кроссбраузерностью и поддержкой тех или иных технологий записи голоса. Причем речь идет не только о Web браузерах, но и о мобильных также. 

Немного о том, как в общем происходит обработка голоса в браузере. Работа с записью голоса в браузере делится на 3 части:

  1.  Получение доступа к микрофону

  2. Запись и обработка голосового сообщения

  3. Сохранение его в медиафайл

Для работы с микрофонами в JS чаще всего используется API MediaDevices.

Данный API используется для получения доступа к микрофонам с помощью информационного объекта navigatorв Browser Object Model (BOM). 

Navigator – это объект, который используется для получения разной информации о браузере, сетевом соединении, операционной системе и так далее. Так как часто вы можете столкнуться с тем, что у пользователя могут быть подключены несколько микрофонов, то желательно в JS реализовывать отдельно возможность выбора микрофона.

async function getMicrophones() {

    const devices = await navigator.mediaDevices.enumerateDevices();

    const audioDevices = devices.filter(device => device.kind === 'audioinput');

    const microphoneSelect = document.getElementById('microphoneSelect');

 

    // Очищаем список перед его заполнением

    microphoneSelect.innerHTML = '';

 

    audioDevices.forEach(device => {

        const option = document.createElement('option');

        option.value = device.deviceId;

        option.text = device.label || `Микрофон ${audioDevices.length + 1}`;

        microphoneSelect.appendChild(option);

    });

 

    microphoneSelect.addEventListener('change', (event) => {

        selectedMicrophoneId = event.target.value;

    });

 

    if (audioDevices.length > 0) {

        selectedMicrophoneId = audioDevices[0].deviceId; // Устанавливаем микрофон по умолчанию

    }

}

Далее переходим в самой сложной части всего этого процесса – эта непосредственно запись и обработка голосового ответа.  Изначально в проекте я пробовал использовать просто MediaRecorder API.

navigator.mediaDevices.getUserMedia({ audio: true})
    .then(stream => {
        const mediaRecorder = new MediaRecorder(stream);
        let voice = [];
        document.querySelector('#start').addEventListener('click', function(){
            mediaRecorder.start();
        });

        mediaRecorder.addEventListener("dataavailable",function(event) {
            voice.push(event.data);
        });

        document.querySelector('#stop').addEventListener('click', function(){
            mediaRecorder.stop();
        });
    });

Но на первых же кроссбраузерных тестах оказалось, что есть проблемы, связанные с доступом к микрофону, например, Яндекс браузер доступ давать не хотел, а в Web Safary по умолчанию не выбирался микрофон. Плюс на мобильных браузерах результаты тестирования микрофона были очень нестабильными, несмотря на заявленные достаточно широкие возможности в части кроссбраузерности. В итоге пришлось искать другие, более стабильные варианты для записи голоса, и как выяснилось, на просторах интернета не там много практических кейсов работы с записью голоса в JS. Что меня спасло? Вот это видео, записанное уже почти 5 лет назад. 

Достаточно хорошим решением оказалось использование RecorderJS, который поддерживает в том числе и мобильные браузеры. Я не эксперт в JS, но мои результаты тестов показали в целом лучшую обработку записи на разных браузерах. 

Реализация всех рекордеров очень похожа, везде есть блок инициализации рекордера, начала и завершения записи.

navigator.mediaDevices.getUserMedia(constraints)
        .then(function (stream) {
            gumStream = stream;

            // Создаем источник для аудио потока
            const input = audioContext.createMediaStreamSource(stream);

            // Создаем объект Recorder.js с поддержкой одного канала
            recorder = new Recorder(input, { numChannels: 1 });

            // Начинаем запись
            recorder.record();

// Останавливаем запись
    recorder.stop();

    // Останавливаем поток микрофона
    gumStream.getAudioTracks()[0].stop();

    // Экспортируем записанные данные в формате WAV и отправляем на сервер
    recorder.exportWAV(function (blob) {
        console.log("Запись завершена");

        // Используем FileReader для отправки аудиофайла на сервер
        let reader = new FileReader();
        reader.readAsArrayBuffer(blob);
        reader.onloadend = function () {

            // Отправить аудио через API
            sendAudioAnswer(reader.result);
        };
    })

Каков итог?

На текущий момент приложение запущено  и доступно бесплатно каждому, кто хочет попробовать пройти интервью с AI и самое главное получить обратную связь. Это был мой первый опыт написания подобного рода приложения, поэтому я надеюсь, что бесплатная версия voice интервьюера может оказаться полезн��й, особенно для начинающий свою карьеру в ИТ специалистов. 

Какие есть возможности?

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

 Что важно знать. Не пытайтесь думать, что AI это человек, который будет вам отвечать очень естественно. Рассматривайте AI в контексте собеседований как помощника, который подскажет вам, как лучше ответить на тот или иной вопрос. И да, в моей промпте AI всегда даст вам замечания или предложения к ответу:)

Возможно сейчас собеседование с ИИ пока еще кажется чем-то необычным или противоречивым, но мне кажется, уже в ближайшем будущем большую часть технического интервью уже станет проводить AI, оставив нам оценку soft skills. 

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

Посмотрим, что нас будет ждать дальше!