Может ли нейро-сотрудник на базе ChatGPT звонить по обычной телефонной линии?

require(Modules.ASR); require(Modules.CallList); require(Modules.AI); // OpenAI API URL const openaiURL = 'https://api.openai.com/v1/chat/completions' // Your OpenAI API KEY const openaiApiKey = 'sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' var messages = []; // Массив всех сообщений в диалоге var ai_busy = false; var ai_say = false; var speech = ""; // В этой переменной будем накапливать распознаваемый текст от абонента. var voice = ""; var model = "gpt-3.5-turbo"; (// Модель по умолчанию, у каждого нейро-сотрудника может быть установлена своя модель. timeouts = { silence: null, pause: null, duration: null } var hello_text = ""; // Первая фраза сотрудника, приходит с платформы. messages.push({ "role": "system", "content": "" }) // Массив сообщений. Первый элемент это системная роль. Текст роли придет с платформы. var call, player, asr; // Send request to the API async function requestCompletion() { Logger.write(`--->>> requestCompletion ${messages}`); return Net.httpRequestAsync(openaiURL, { headers: [ "Content-Type: application/json", "Authorization: Bearer " + openaiApiKey ], method: 'POST', postData: JSON.stringify({ "model": model, // gpt-4-1106-preview gpt-3.5-turbo "messages": messages, "openai_api_key": openaiApiKey, "temperature": 0, }) }) } function speechAnalysis() { // останавливаем модуль ASR stopASR() const cleanText = speech.trim().toLowerCase() if (!cleanText.length) { // если переменная с нулевой длиной, то это значит что сработал таймер тишины, // т.е. человек вообще ничего не ответил, и мы можем, например, повторить вопрос абоненту handleSilence() } else { ASREvents_Result(speech); } } function stopASR() { asr.stop() call.removeEventListener(CallEvents.PlaybackFinished) clearTimeout(timeouts.duration) } function startASR() { asr = VoxEngine.createASR({ lang: ASRLanguage.RUSSIAN_RU, profile: ASRProfileList.YandexV3.ru_RU, interimResults: true }) asr.addEventListener(ASREvents.InterimResult, e => { clearTimeout(timeouts.pause) clearTimeout(timeouts.silence) timeouts.pause = setTimeout(speechAnalysis, 3000) call.stopPlayback() }) asr.addEventListener(ASREvents.Result, e => { // Складываем распознаваемые ответы if (speech.indexOf(e.text) === -1) { speech += " " + e.text; } }) // направляем поток в ASR call.sendMediaTo(asr) } function handleSilence() { // Тут можно что-то сказать в линию чтобы "скрасить" паузы // Начнём слушать через 3 секунды и дадим возможность с этого момента перебивать робота setTimeout(startASR, 3000) call.addEventListener(CallEvents.PlaybackFinished, startSilenceAndDurationTimeouts) } function startSilenceAndDurationTimeouts() { timeouts.silence = setTimeout(speechAnalysis, 8000) timeouts.duration = setTimeout(speechAnalysis, 30000) } // Данный метод отправляет текст в API по синтезу голоса по текстовому сообщению function sendMessage(call, text) { const textToSynthesize = encodeURIComponent(text); const speechSynthesisApiUrl = `https://__ПЛАТФОРМА_НЕЙРО_СОТРУДНИКОВ__/api/v1.0/tts?voice=${voice}&text=${textToSynthesize}`; Net.httpRequest(speechSynthesisApiUrl, (res) => { if (res.code === 200) { let audioUrl = res.text; Logger.write(res.code + " sendMessage: " + text); call.startPlayback(audioUrl); ai_say = true; call.addEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); } else { Logger.write(`Ошибка: ${res.code} - ${res.text}`); } }, {method: 'GET'}); return 'OK' } // Воспроизведение закончилось function handlePlaybackFinished(e) { Logger.write('--->>> handlePlaybackFinished'); ai_busy = false; ai_say = false; e.call.removeEventListener(CallEvents.PlaybackFinished, handlePlaybackFinished); startASR(); } function sendMessageURL(call, mp3_url) { call.startPlayback(mp3_url); return 'OK' } // Эта функция выбирает музыку во время ожидания ответа от ChatGPT function sendBeforeMessage(call) { const messages = [ //'https://activeai.aura-s.com/wp-content/uploads/2023/12/ai_thinking.mp3', //'https://mvp.atiks.org/wp-content/uploads/2023/12/8192dd7301e4c1a.mp3', //'https://mvp.atiks.org/wp-content/uploads/2023/12/7e7352510ae830e.mp3', 'https://mvp.atiks.org/wp-content/uploads/2023/12/3c72bb47cbe8153.mp3', ]; const randomIndex = Math.floor(Math.random() * messages.length); const messageURL = messages[randomIndex]; sendMessageURL(call, messageURL); } // Воспроизведение закончилось function StarthandlePlaybackFinished(e) { Logger.write('--->>> handlePlaybackFinished'); e.call.removeEventListener(CallEvents.PlaybackFinished, StarthandlePlaybackFinished); e.call.sendMediaTo(asr); } // Callback для обработки события окончания вызова function onCallDisconnected(e) { sendEmail('web@atiks.org'); Logger.write(`Call disconnected`); } // Callback для обработки неудачного вызова function onCallFailed(e) { Logger.write(`Call failed`); } function onCallConnected(e) { sendBeforeMessage(call) sendMessage(e.call, hello_text); e.call.addEventListener(CallEvents.PlaybackFinished, StarthandlePlaybackFinished); } // Обработчик стартового события VoxEngine.addEventListener(AppEvents.Started, (e) => { let data = VoxEngine.customData(); Logger.write(`customData: ${data}`); data = JSON.parse(data); changeRole(data.script_id); model = data.model; call = VoxEngine.callPSTN(data.phone, "73432472939"); call.addEventListener(CallEvents.Connected, onCallConnected); call.addEventListener(CallEvents.Disconnected, onCallDisconnected); call.addEventListener(CallEvents.Failed, onCallFailed); startASR(); }); // Эта функция загружай роль с нашей платформы нейро-сотрудников function changeRole(script_id) { const speechSynthesisApiUrl = `https://__ПЛАТФОРМА_НЕЙРО_СОТРУДНИКОВ__/api/v1.0/get_promt_text?script_id=${script_id}`; Net.httpRequest(speechSynthesisApiUrl, (res) => { if (res.code === 200) { const promt = res.text.split("###"); messages[0].content = promt[0]; hello_text = promt[1]; voice = promt[2]; Logger.write(`changeRole: ${hello_text} - ${voice}`); } else { Logger.write(`Ошибка: ${res.code} - ${res.text}`); } }, {method: 'GET'}); return 'OK' } // Отправка расшифровки диалога async function sendEmail(mail_to) { Logger.write(`--->>> sendEmail ${messages}`); const dialogText = messages .filter(message => message.role !== "system") .map(message => { // Преобразуем role в форматированную строку "ИИ" или "Соискатель" const role = message.role === "assistant" ? "ИИ" : "Соискатель"; return `${role}: ${message.content}`; }) .join('\n') // Далее код отрвавки на email // ... } async function ASREvents_Result(text) { // Добавляем распознанный текст от абонента в массив сообщений messages.push({ "role": "user", "content": text }) speech = ""; sendBeforeMessage(call); Logger.write("Sending data to the OpenAI endpoint"); let ts1 = Date.now(); if ((ai_busy == false) && (ai_say == false)) { ai_busy = true; var res = await requestCompletion(); let ts2 = Date.now(); Logger.write("Request complete in " + (ts2 - ts1) + " ms") if (res.code == 200) { let jsData = JSON.parse(res.text) sendMessage(call, jsData.choices[0].message.content); messages.push({ "role": "assistant", "content": jsData.choices[0].message.content }) call.sendMediaTo(asr); } } else { // Тут можно что-то говорить в линию пока ChatGPT придумывает ответ } call.sendMediaTo(asr); }