Как создать чат-бот на основе искусственного интеллекта с помощью OpenAI, ChatGPT, Node.js и React

Как создать чат-бот на основе искусственного интеллекта с помощью OpenAI, ChatGPT, Node.js и React

Содержание
  1. Предварительные условия
  2. Как создать приложение искусственного интеллекта для чата с помощью CLI на Node.js
  3. Как создать приложение для чата с помощью React
  4. Как объединить React и Node.js для создания Fullstack-программы искусственного интеллекта для чата
    1. Как настроить проект
    2. Как построить сервер
    3. Как создать конечную точку
    4. Как подключиться к бэкенду из фронтенда.
  5. Заключение

Искусственный интеллект (ИИ) в последнее время набирает обороты, а ChatGPT произвел революцию в Интернете благодаря функции завершения чата.

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

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

Вы узнаете следующее:

  • Как создать чат-приложение с CLI, используя только Node.js.
  • Как создать чат-приложение, используя только React.
  • Как объединить React и Node.js для создания лучшего программного обеспечения с искусственным интеллектом для чатов.

В данном учебном пособии будет использована модель gpt-3.5-turbo .

Предварительные условия

Этот учебник требует базовых знаний JavaScript, CSS, React и Node.js.

Также необходима учетная запись на платформе OpenAI, где размещен chatGPT. Она бесплатна, и вы можете создать ее здесь.

Как создать приложение искусственного интеллекта для чата с помощью CLI на Node.js

В этом разделе мы рассмотрим создание чат-приложения, которое будет работать только в терминале, с использованием Node.js.

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

mkdir nodejs-chatgpt-tutorial

Перейдите в папку:

cd nodejs-chatgpt-tutorial

Инициализация проекта:

npm init -y


В результате будет создан файл package.json для хранения деталей проекта

Добавьте в файл следующую строку кода:

"type": "module"

Это позволит использовать оператор импорта модулей ES6.

Установите OpenAI с помощью приведенной ниже команды:

npm i openai


Создайте файл, в котором будет находиться весь код. Назовите его index.js :

touch index.js


Импортируйте Configuration и OpenAIApi из модуля OpenAI и readline из модуля readline:

import { Configuration, OpenAIApi } from 'openai';
import readline from 'readline';

Постройте конфигурацию OpenAI следующим образом:

const configuration = new Configuration({
	organization: 'org-0nmrFWw6wSm6xIJXSbx4FpTw',
	apiKey: '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',
});

Этот код создает новый экземпляр объекта Configuration . Внутри него вы введете значения для ваших organization и apiKey . Данные о вашей организации можно найти в настройках, а информацию о вашем apiKey - в API-ключах. Если у вас нет существующего ключа API, вы можете его создать.

Введите следующий код после конфигурации для создания нового экземпляра OpenAI API:

const openai = new OpenAIApi(configuration);

Вы будете использовать его на протяжении всего проекта.

Введите приведенный ниже код для проверки функции createChatCompletion :

openai
	.createChatCompletion({
		model: 'gpt-3.5-turbo',
		messages: [{ role: 'user', content: 'Hello' }],
	})
	.then((res) => {
		console.log(res.data.choices[0].message.content);
	})
	.catch((e) => {
		console.log(e);
	});

Этот код вызывает функцию createChatCompletion , которая запускает конечную точку ( https://api.openai.com/v1/chat/completions ). Функция принимает объект аргументов (используемый model chatGPT и массив messages между пользователем и ИИ. В следующем разделе мы рассмотрим, как использовать массив messages для ведения истории чата и улучшения приложения).

Каждое сообщение представляет собой объект, содержащий значение role (то есть кто отправил сообщение. Это значение может быть assistant , если оно исходит от ИИ, или user , если сообщение исходит от человека) и content (отправленная информация).

Наконец, код печатает ответ ( res.data.choices[0].message.content ) от ИИ. Запустите файл в терминале с помощью этой команды:

node index

Это приведет к получению ответа от искусственного интеллекта через несколько секунд.

И это все, что нужно для создания чатбота!

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

Чтобы сделать его интерактивным, удалите последний набранный код и добавьте следующий:

const userInterface = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});

Этот код создает в терминале пользовательский интерфейс, позволяющий пользователям вводить свои вопросы.

Затем предложите пользователю ввести сообщение, используя приведенный ниже код:

userInterface.prompt();

Наконец, введите следующий код:

userInterface.on('line', async (input) => {
	await openai
		.createChatCompletion({
			model: 'gpt-3.5-turbo',
			messages: [{ role: 'user', content: input }],
		})
		.then((res) => {
			console.log(res.data.choices[0].message.content);
			userInterface.prompt();
		})
		.catch((e) => {
			console.log(e);
		});
});

В приведенном выше коде,

  • Когда пользователь набирает текст и нажимает Enter , в приведенном выше коде срабатывает функция обратного вызова.
  • В качестве input передается все, что было набрано пользователем.
  • В качестве input теперь используется content .
  • После вывода на экран ответа ИИ пользователю предлагается ввести еще одно сообщение в блоке then .

Весь код можно посмотреть на GitHub.

Запустите файл и проведите беседу с ИИ. Он будет выглядеть так, как показано на рисунке ниже:

CLI-чат с искусственным интеллектом
CLI-чат с искусственным интеллектом

Отлично! Это интерактивный CLI-чат.

Это полезно нескольким людям (например, инженерам), но имеет хорошую безопасность, поскольку находится на стороне сервера.

Но как быть с теми, кто не понимает, как использовать CLI-приложение? Им нужно что-то более простое в использовании, с лучшим пользовательским интерфейсом (UI) и пользовательским опытом (UX). Следующий раздел посвящен созданию такого приложения с использованием React.

Как создать приложение для чата с помощью React

Этот раздел призван помочь фронтенд-разработчикам освоить API ChatGPT для создания чат-приложения и построить более совершенный пользовательский интерфейс, чтобы обеспечить пользователям лучший опыт. Полученные здесь знания можно применить к другим фронтенд-фреймворкам или библиотекам.

Первое, что необходимо сделать, - настроить базовый котел React. Для этого я буду использовать Vite. Vite можно использовать для построения любого современного фронтенд-проекта на JavaScript. Используйте команду, приведенную ниже:

npm create vite@latest


Эта команда предложит вам создать имя и папку для проекта, а также выбрать фреймворк или библиотеку (в данном учебном пособии используется React). После этого нужно перейти в папку и выполнить следующую команду:

npm install
npm run dev

Эти команды установят необходимые зависимости и запустят локальный сервер на порту 5173

Затем установите OpenAI с помощью приведенной ниже команды:

npm i openai


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

Теперь мы готовы приступить к написанию кода!

Перейдите в файл src/App.jsx и удалите все его содержимое. Затем добавьте следующие операторы импорта:

import { useState } from 'react';
import { Configuration, OpenAIApi } from 'openai';

Приведенный выше код импортирует Configuration для установки значений конфигурации и OpenAIApi для предоставления доступа к функциям завершения чата.

После этого постройте конфигурацию следующим образом:

const configuration = new Configuration({
	organization: 'org-0nmrFWw6wSm6xIJXSbx4FpTw',
	apiKey: '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',
});

Этот код создает новый экземпляр объекта Configuration . Внутри него вы вводите значения для своих organization и apiKey . Сведения о вашей организации можно найти в настройках, а информацию о вашем apiKey - в API-ключах. Если у вас нет существующего ключа API, вы можете его создать.

Введите следующий код после конфигурации для создания нового экземпляра OpenAI API:

const openai = new OpenAIApi(configuration);

Мы будем использовать его на протяжении всего проекта.

Создание и экспорт функции по умолчанию:

function App() {

  return (
    <main>
      <h1>Chat AI Tutorial</h1>
    <main/>
  );
}
export default App;

В этой функции будет находиться остальной код.

Перед оператором return установите следующие состояния:

const [message, setMessage] = useState('');
const [chats, setChats] = useState([]);
const [isTyping, setIsTyping] = useState(false);
  • В message будет храниться информация, передаваемая из приложения в ИИ.
  • В массиве chats будут храниться все сообщения, отправленные обеими сторонами (пользователем и ИИ).
  • Переменная isTyping будет сообщать пользователю, набирает ли бот текст или нет.

Введите следующие строки кода под тегом h1

<div className={isTyping ? '' : 'hide'}>
	<i>{isTyping ? 'Typing' : ''}</i>
</div>

Приведенный выше код будет отображать Typing всякий раз, когда пользователь ожидает ответа от ИИ.

Создайте форму, в которой пользователь может ввести сообщение, добавив в элемент main приведенный ниже код:

<form action="" onSubmit={(e) => chat(e, message)}>
	<input
		type="text"
		name="message"
		value={message}
		placeholder="Type a message here and hit Enter..."
		onChange={(e) => setMessage(e.target.value)}
	/>
</form>

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

Функция chat будет принимать два (2) аргумента ( e и message ) следующим образом:

const chat = async (e, message) => {};

Введите в функцию следующие строки:

e.preventDefault();

if (!message) return;
setIsTyping(true);

Приведенный выше код не позволяет form перезагрузить веб-страницу, проверяет, было ли набрано сообщение перед отправкой, и устанавливает isTyping в true , чтобы указать, что приложение начало работать с введенными данными.

В ChatGPT существует формат, в котором должны быть сообщения. Он принимает следующий вид:

{role: user | assistant, content: message to be sent


Каждое сообщение ( content ) должно показывать, кто его отправил. Роль assistant указывается, если сообщение отправлено искусственным интеллектом, но user - если человеком. Поэтому, прежде чем отправить сообщение, не забудьте правильно его оформить и добавить в массив ( chats ) следующим образом:

let msgs = chats;
msgs.push({ role: 'user', content: message });
setChats(msgs);

setMessage('');

Последняя строка очищает ввод, чтобы пользователь мог набрать еще одну заметку.

Теперь вызовем конечную точку createChatCompletion , вызвав функцию createChatCompletion с помощью приведенного ниже кода:

await openai.createChatCompletion({
	model: 'gpt-3.5-turbo',
	messages: [
		{
			role: 'system',
			content: 'You are a EbereGPT. You can help with graphic design tasks',
		},
		...chats,
	],
});

Функция createChatCompletion принимает не менее двух (2) аргументов ( model и messages ):

  • Модель определяет используемую версию chatGPT.
  • Сообщения - это список всех сообщений между пользователем и искусственным интеллектом на данный момент, а также системное сообщение, которое дает ИИ представление о том, какую помощь он может оказать.
{
	"role": "system",
	"content": "You are a EbereGPT. You can help with graphic design tasks"
}

Вы можете менять содержание по своему усмотрению.

В массиве messages не обязательно должно быть более одного объекта. Это может быть просто одно сообщение.

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

Функция createChatCompletion возвращает обещание. Поэтому для получения ответа используйте блок then…catch… .

   .then((res) => {
        msgs.push(res.data.choices[0].message);
        setChats(msgs);
        setIsTyping(false);
      })
      .catch((error) => {
        console.log(error);
      });

Этот код добавляет сообщение, полученное от ИИ, в массив chats и устанавливает значение isTyping в false, указывая на то, что ИИ закончил отвечать.

Теперь при отправке сообщения вы должны получать обратную связь ( Typing ):

Чат-приложение, выдающее обратную связь, когда ИИ собирается ответить
Чат-приложение, выдающее обратную связь, когда ИИ собирается ответить

Пришло время отобразить историю чата для просмотра пользователем.

Введите следующий код непосредственно под тегом h1 :

<section>
	{chats && chats.length
		? chats.map((chat, index) => (
				<p key={index} className={chat.role === 'user' ? 'user_msg' : ''}>
					<span>
						<b>{chat.role.toUpperCase()}</b>
					</span>
					<span>:</span>
					<span>{chat.content}</span>

		  ))
		: ''}
</section>

Приведенный выше код перебирает все chats и последовательно выводит их пользователю. Он выводит role в верхнем регистре и content сообщения рядом.

Вот как должен выглядеть вывод:

ChatBot работает как положено без CSS
ChatBot работает как положено без CSS

Это выглядит круто!

Но если добавить некоторые элементы оформления, то приложение приобретет привлекательный вид, как в WhatsApp или Messenger.

Замените содержимое файла src/index.css на следующее:

:root {
	font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
	line-height: 1.5;
	font-weight: 400;
	color-scheme: light dark;
	color: rgba(255, 255, 255, 0.87);
	background-color: #242424;
	font-synthesis: none;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	-webkit-text-size-adjust: 100%;
}
h1 {
	font-size: 3.2em;
	line-height: 1.1;
	text-align: center;
	position: sticky;
	top: 0;
	background-color: #242424;
}
main {
	max-width: 500px;
	margin: auto;
}
p {
	background-color: darkslategray;
	max-width: 70%;
	padding: 15px;
	border-radius: 50px;
}
p span {
	margin: 5px;
}
p span:first-child {
	margin-right: 0;
}
.user_msg {
	text-align: right;
	margin-left: 30%;
	display: flex;
	flex-direction: row-reverse;
}
.hide {
	visibility: hidden;
	display: none;
}
form {
	text-align: center;
	position: sticky;
	bottom: 0;
}
input {
	width: 100%;
	height: 40px;
	border: none;
	padding: 10px;
	font-size: 1.2rem;
}
input:focus {
	outline: none;
}

И удалите все стили из файла src/App.css .

Полный код можно найти на GitHub.

Теперь приложение должно иметь новый вид:

Чат-бот работает так, как ожидалось, с помощью CSS
Чат-бот работает так, как ожидалось, с помощью CSS

На этом создание чатбота с помощью React и ChatGPT завершено. Это не так сложно, как кажется.

Но фронтенд-приложения, подобные этому, лучше использовать для демонстрации, а не для производства. Проблема создания приложения таким образом заключается в том, что фронтенд подвергает API-ключ кибернетическим атакам.

Для решения этой проблемы целесообразно сохранить API Key и Organisation Id в безопасном месте в облаке и ссылаться на них, либо создать бэкенд для своего приложения с более высокой степенью защиты.

В следующем разделе будет рассмотрена эта проблема.

Как объединить React и Node.js для создания Fullstack-программы искусственного интеллекта для чата

В этом разделе мы объединим все возможности предыдущих разделов, чтобы создать более безопасное приложение с улучшенным пользовательским интерфейсом и UX.

Мы улучшим раздел Node, используя сервер для выставления конечной точки для потребления фронтендом и упростим взаимодействие фронтенда с бэкендом вместо прямого обращения к OpenAI.

Как настроить проект

В этой части будут созданы необходимые для проекта папки и файлы.

Создайте каталог проекта:

mkdir react-node-chatgpt-tutorial

Перейдите в папку:

cd react-node-chatgpt-tutorial


Установите React с помощью Vite и назовите папку frontend . Используйте эту команду:

npm create vite@latest


После этого перейдите в папку и выполните следующую команду:

npm install
npm run dev

Эти команды установят необходимые зависимости и запустят локальный сервер на порту 5173 .

Создайте папку backend:

mkdir backend


Теперь перейдите в папку backend и инициализируйте проект с помощью этой команды:

npm init -y


При этом будет создан файл package.json для хранения деталей проекта.

Добавьте в файл следующую строку кода:

"type": "module"

Это позволит использовать оператор импорта модулей ES6.

Установите OpenAI и другие зависимости с помощью приведенной ниже команды:

npm i openai body-parser cors express


Создайте файл, в котором будет находиться весь код. Назовите его index.js :

touch index.js


На этом настройка проекта завершена. Теперь есть две папки ( frontend и backend ).

Как построить сервер

В этой части мы рассмотрим создание локального сервера для прослушивания порта 8000 .

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

import { Configuration, OpenAIApi } from 'openai';
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';

Далее установите express , port для прослушивания, body-parser для приема входных данных и cors для свободного обмена данными между фронтендом и бэкендом. Используйте приведенный ниже код:

const app = express();
const port = 8000;
app.use(bodyParser.json());
app.use(cors());

Наконец, введите следующий код:

app.listen(port, () => {
	console.log(`listening on port ${port}`);
});

На этом настройка сервера завершена.

При выполнении команды index.js должен быть получен следующий результат:

listening on port 8000


Как создать конечную точку

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

Начните с установки параметров конфигурации, как мы это делали в предыдущих разделах:

const configuration = new Configuration({
	organization: 'org-0nmrFWw6wSm6xIJXSbx4FpTw',
	apiKey: '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',
});
const openai = new OpenAIApi(configuration);

Далее создайте асинхронный POST-маршрут, используя приведенный ниже код:

app.post('/', async (request, response) => {});

Вызов этой конечной точки будет осуществляться с помощью http://localhost:8000/

В функции обратного вызова введите приведенный ниже код для получения входных данных chats из тела запроса ( request.body ):

const { chats } = request.body;

Теперь вызовите конечную точку createChatCompletion , как мы это делали в разделе React:

const result = await openai.createChatCompletion({
	model: 'gpt-3.5-turbo',
	messages: [
		{
			role: 'system',
			content: 'You are a EbereGPT. You can help with graphic design tasks',
		},
		...chats,
	],
});

Разница заключается в том, что вместо использования блока then…catch… мы присвоили его переменной ( result ) и вернули ответ с помощью response.json() , как показано в следующем коде:

response.json({
	output: result.data.choices[0].message,
});

Код этой части можно найти на GitHub.

Вот вывод при тестировании на Postman:

Вывод от почтальона
Вывод от почтальона

На этом часть кода, посвященная бэкенду, завершена. В следующей части будет выполнено подключение фронтенда к бэкенду с помощью только что созданной конечной точки ( http://localhost:8000/ ).

Как подключиться к бэкенду из фронтенда.

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

Перейдите в файл frontend/src/App.jsx и введите следующий код:

import { useState } from 'react';

function App() {
	const [message, setMessage] = useState('');
	const [chats, setChats] = useState([]);
	const [isTyping, setIsTyping] = useState(false);

	const chat = async (e, message) => {
		e.preventDefault();

		if (!message) return;
		setIsTyping(true);

		let msgs = chats;
		msgs.push({ role: 'user', content: message });
		setChats(msgs);

		setMessage('');

		alert(message);
	};

	return (
		<main>
			<h1>FullStack Chat AI Tutorial</h1>

			<section>
				{chats && chats.length
					? chats.map((chat, index) => (
							<p key={index} className={chat.role === 'user' ? 'user_msg' : ''}>
								<span>
									<b>{chat.role.toUpperCase()}</b>
								</span>
								<span>:</span>
								<span>{chat.content}</span>

					  ))
					: ''}
			</section>

			<div className={isTyping ? '' : 'hide'}>

					<i>{isTyping ? 'Typing' : ''}</i>

			</div>

			<form action="" onSubmit={(e) => chat(e, message)}>
				<input
					type="text"
					name="message"
					value={message}
					placeholder="Type a message here and hit Enter..."
					onChange={(e) => setMessage(e.target.value)}
				/>
			</form>
		</main>
	);
}
export default App;

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

На данный момент при отправке формы на экран выводится предупреждение. Через некоторое время это изменится.

В функции чата избавьтесь от сообщения alert и наберите следующее:

fetch('http://localhost:8000/', {
	method: 'POST',
	headers: {
		'Content-Type': 'application/json',
	},
	body: JSON.stringify({
		chats,
	}),
})
	.then((response) => response.json())
	.then((data) => {
		msgs.push(data.output);
		setChats(msgs);
		setIsTyping(false);
	})
	.catch((error) => {
		console.log(error);
	});

Приведенный выше код вызывает созданную нами конечную точку и передает ей для обработки массив chats . Затем он возвращает ответ, который добавляется в массив chats и отображается в пользовательском интерфейсе.

Ниже показано, как выглядит пользовательский интерфейс на данный момент:

Fullstack Чат UI до стайлинга
Fullstack Чат UI до стайлинга

Пользовательский интерфейс может выглядеть лучше, если добавить в файл frontend/src/index.css следующие стили:

:root {
	font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
	line-height: 1.5;
	font-weight: 400;

	color-scheme: light dark;
	color: rgba(255, 255, 255, 0.87);
	background-color: #242424;

	font-synthesis: none;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	-webkit-text-size-adjust: 100%;
}

html,
body {
	scroll-behavior: smooth;
}

h1 {
	font-size: 3.2em;
	line-height: 1.1;
	text-align: center;
	position: sticky;
	top: 0;
	background-color: #242424;
}

main {
	max-width: 800px;
	margin: auto;
}

p {
	background-color: darkslategray;
	max-width: 70%;
	padding: 15px;
	border-radius: 50px;
}

p span {
	margin: 5px;
}

p span:first-child {
	margin-right: 0;
}

.user_msg {
	text-align: right;
	margin-left: 30%;
	display: flex;
	flex-direction: row-reverse;
}

.hide {
	visibility: hidden;
	display: none;
}

form {
	text-align: center;
	position: sticky;
	bottom: 0;
}

input {
	width: 100%;
	height: 40px;
	border: none;
	padding: 10px;
	font-size: 1.2rem;
	background-color: rgb(28, 23, 23);
}

input:focus {
	outline: none;
}

И удалите все стили из файла frontend/src/App.css .

Код для этой части находится на GitHub.

А вот и конечный результат:

FullStack ChatBot, работающий в соответствии с ожиданиями с помощью CSS
FullStack ChatBot, работающий в соответствии с ожиданиями с помощью CSS

Поздравляю с завершением проекта!

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

Код для этой секции можно найти на GitHub.

Заключение

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

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

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