В данной статье будет рассмотрена тема написания собственного frontend-приложения на основании React и некоторых других библиотек для использования чата (как посредством ручного ввода вопроса, так и посредством голоса).
Данная статья не создана для начинающих, так как многие вещи (такие, как правила использования хуков и тому подобное объяснены не будут).
Библиотеки, которые я использовал:
- axios (может быть заменена на ky, либо не использована вовсе);
- react;
- typescript;
- react-use-animation.
Начнем со структуры папок:
->components --->UI
->hooks
->server-api
->styles
Создадим пользовательский hook useMedia. В нем будут следующие строчки:
Далее создаём хук useEffect с пустым массивом зависимостей (т.е. срабатывает при инициализации приложения) и навесим в нем два события onresult и onspeechend на интерфейс взаимодействия с микрофоном:
И последнее в данном хуке (после чего просто ретурним все переменные и функции) это функция playback для воспроизведения текста:
Еще один хук, если вы хотите, чтобы запрос можно было не только говорить, но и писать ручками, это хук useDebounce. Там ничего замудренного, можете посмотреть примерную реализацию по этой ссылке.
Далее перейдем к server-api. Внутри я создал файл request-api. Создаем axios.instance, который будет содержать параметр авторизации: headers:{Authorization: `Bearer ${API_KEY || user_api_key}`} под API_KEY подразумевается, что вы либо создадите файл с переменной и экспортируете ее, либо просто вставите свой ключ с сайта OpenAI (чтобы его получить надо зайти во вкладку developers -> API-reference -> API-KEY (в тексте будет выделена бирюзовым) и там нажать create key.
Далее создаем метод запроса к чату:
Оборачиваем это все в try/catch для отлавливания простейших ошибок и вуаля. Осталось только немного побаловаться с React-компонентами, чтобы это все красиво выглядело. Да-да, согласен, что просто выводить в консоль ошибку - плохая практика: мог бы хотя бы попробовать сделать повторный запрос :)
Рассмотрим компоненту Main (думаю, раз речь идет о компоненте, то не стоит упоминать в какую папку я её положил).
Тут есть небольшой нюансик в виде того, что если вы хотите, чтобы ваш диалог с чатом был в контексте, а не в виде одиночных вопросов-ответов, то придется создать еще один useState для хранения всех вопросов/ответов (который удобно пригодиться, чтобы выводить их на экран, а не колупаться во всех хуках и выцеплять оттуда все данные).
К делу: создаем хук const [resp, setResp] = useState<messages>([]) (тип messages, который уже мелькал ранее это объект из двух свойств role: user/assistant и content - строка с ответом на ваш вопрос).
Далее берём useEffect, который реагирует только на изменение запроса query (он заполняется либо после окончания Debounce, либо когда человек закончил говорить в микрофон) и пишем туда следующее:
С большего это все, что я хотел рассказать. Стили показывать не вижу смысла - это дело вкуса. Могу только сказать, что есть классный сайт, который вместо дизайнера подберет вам цвета.
Реализацию компонент в виде jsx тоже наверное нету смысла показывать, тоже дело вкуса да и кто как сверстает. Единственное, что могу посоветовать это добавить какую-нибудь иконку включения/выключения чтения ответа от чата (за это у меня отвечает isPlaybackAllowed, setIsPlaybackAllowed) потому что браузер будет ругаться; Какое-нибудь обозначение, что ведётся запись вашего голоса (isRecording, setIsRecording) и, но тут уже на свой вкус и цвет, было бы неплохо добавить иконку Debounce для ввода текста. У меня стоит задержка в анимации на 0,2с (чтобы она не мелькала пока человек печатает) и сама анимация, по окончании которой отправляется запрос на сервер, 1.8 с.
Будет вопросы - пишите в комментарии/на почту. С умными людьми мне всегда интересно пообщаться :)
Конечный результат у меня получился примерно такой: