Accesăm link-ul https://platform.openai.com/login și ne facem un cont pentru a putea genera o cheie secretă prin care o să avem dreptul să utilizăm ChatGPT.
După autentificare, selectăm varianta API.
Urmează să mergem la secțiunea dedicată cheilor API.
Apăsăm pe butonul de creat o nouă cheie secretă, îi dăm o denumire, îi alocăm toate permisiunile și apăsăm să o creăm.
Avem grijă să copiem cheia generată și să o mutăm în cadrul fișierului cu chei de mediu.
Este singura dată când putem să vedem cheia.
Fișierul nostru de .env ar trebui să arate ceva de genul acesta:
Pentru activarea API key-ului, este nevoie să adăugăm o metodă de plată.
Nicio sumă de bani nu va fi retrasă de pe cont pentru verificare.
Activarea API KEY-ului presupune adăugarea unui credit de minim de 5 euro pentru a putea folosi cheia.
4. Configurarea chatbot-ului
Mergem în cadrul folderului lib și adăugăm un nou fișier, numit openai.js.
Acest fișier are rolul de a ne genera o instanță de openai, prin intermediul căreia o să putem face cereri.
Dacă nu ați repornit aplicația după ce ați adăugat noua cheia de mediu, o să trebuiască să îl reporniți pentru a prelua și noua cheie pe care tocmai am adăugat-o.
import OpenAI from'openai';constapiKey=process.env.OPENAI_API_KEY;if (!apiKey) {thrownewError("Please define OPENAI_API_KEY in your environment variables");}constopenai=newOpenAI(apiKey);exportdefault openai;
5. Configurare API
Ne mutăm în folderul api și adăugăm un nou fișier numit answer.js.
// /pages/api/answer.jsimport openai from"@/lib/openai";import { sendBadRequest, sendMethodNotAllowed, sendOk } from"@/utils/apiMethods";constSYSTEM_PROMPTS= { SIMPLE_ASSISTANT: { MESSAGE: {'role':'system','content':'You are a simple assistant. You respond with simple sentences.', }, TEMPERATURE:1, MAX_TOKENS:50, TYPE:'simple_assistant', }, USER: { MESSAGE: {'role':'system','content':'You are a user. You respond with normal sentences.', }, TEMPERATURE:1, MAX_TOKENS:100, TYPE:'user', },};constERRORS= { DATABASE_ERROR: { type:'database_error', message:'Error while processing the request.', }, WRONG_CONVERSATION_TYPE: { type:'wrong_conversation_type', message:'The conversation type is not known.', }, OPEN_AI_ERROR: { type:'open_ai_error', message:'Error while processing the request.', },};constchatCompletion=async (messagesArray, max_tokens, temperature) => {constrawResponse=awaitopenai.chat.completions.create({ model:'gpt-3.5-turbo', messages: messagesArray, max_tokens: max_tokens, temperature: temperature, });returnrawResponse?.choices[0];}constconverseChat=async (res, inputChat, useCase) => {try{constMAX_MEMORY=3;let userMessagesArray = [];if (inputChat.length>MAX_MEMORY) { userMessagesArray =inputChat.slice(-MAX_MEMORY); }else { userMessagesArray = inputChat; }constmessagesArray= [useCase.MESSAGE,...userMessagesArray ];constresponse=awaitchatCompletion(messagesArray,useCase.MAX_TOKENS,useCase.TEMPERATURE);returnsendOk(res, response); }catch(error) {console.error(error);returnsendBadRequest(res,ERRORS.OPEN_AI_ERROR.type,ERRORS.OPEN_AI_ERROR.message); }}constconverse= (res, messages, type) => {switch (type) {caseSYSTEM_PROMPTS.SIMPLE_ASSISTANT.TYPE:returnconverseChat(res, messages,SYSTEM_PROMPTS.SIMPLE_ASSISTANT);caseSYSTEM_PROMPTS.USER.TYPE:returnconverseChat(res, messages,SYSTEM_PROMPTS.USER);default:returnsendBadRequest(res,'wrong_conversation_type'); }}exportdefaultasyncfunctionhandler(req, res) {constisAllowedMethod=req.method ==='POST';const { messages,type } =req.body;if (!isAllowedMethod) {returnsendMethodNotAllowed() }elseif (!messages) {returnsendBadRequest(res,'Missing input'); }elseif(!type) {returnsendBadRequest(res,'wrong_conversation_type'); }try{returnconverse(res, messages, type); }catch(error) {console.error(error); }}
Cum functionează codul din acest template de cod:
În primă instanță, avem declarat un obiect SYSTEM_PROMPTS, care are scopul de a defini cele 2 roluri din cadrul chat-ului, și anume asistentul virtual și persoana care i se adresează.
Ulterior, fiecare rol primește mai multe setări, printre care TEMPERATURE (cu cât temperatura este mai mare, cu atât este mai probabil ca modelul să genereze răspunsuri neașteptate sau creative) și MAX_TOKENS (Cu cât este mai mare acest număr, cu atât răspunsul poate fi mai lung și mai detaliat).
Avem un obiect ERRORS care definește tipurile de erori pe care le putem întâmpina.
Definim o funcție async numită chatCompletion care are rolul de a întreba asistentul, cu versiunea gpt-3.5-turbo și de a returna răspunsul.
Alte modele în afară de gpt-3.5-turbo poate avea ca și consecințte costuri suplimentare. Lista cu toate tipurile de modele: https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
Funcția converseChat are rolul de a iniția o conversație între utilizator și un asistent AI folosind modelul GPT-3.5. Funcția începe prin a verifica dacă numărul de mesaje trimise de utilizator depășește un anumit prag și, în funcție de acest lucru, selectează ultimele MAX_MEMORYmesaje sau toate mesajele dacă numărul acestora este mai mic decât pragul. Apoi, construiește un array de mesaje care include mesajele predefinite pentru tipul de conversație și mesajele utilizatorului.
Funcțiaconverseeste funcția principală care gestionează conversația între utilizator și asistentul AI. Ea verifică tipul de conversație specificat și apoi apelează funcția converseChatpentru a începe conversația corespunzătoare.
Funcțiahandlereste funcția de bază care servește drept punct de intrare pentru gestionarea cererilor HTTP către server. Această funcție primește un obiect req care reprezintă cererea HTTP primită de server și un obiect res care reprezintă răspunsul pe care serverul îl va trimite înapoi către client.
6. Definirea unei noi rute pe partea de frontend
Ne mutăm în folderul pages și o să adăugăm o noua pagină, numită chat.jsx
La începutul componentei, observăm că avem 3 state-uri:
chatMessages -> salvează toată conversația între utilizator și chatbot
isLoading -> folosit pentru a da disable la input cât timp request-ul este încă în lucru
userInput -> textul curent pe care îl scrie utilizatorul
Principalele funcții:
FuncțiafilterChatHistoryeste responsabilă pentru filtrarea istoricului de conversație pentru a elimina mesajele redundante și erorile din istoricul chatului. Această funcție primește ca parametru istoricul de chat și returnează un nou array care conține doar mesajele relevante pentru afișare.
FuncțiabuildResponseMessageObjecteste responsabilă pentru construirea unui obiect de mesaj din răspunsul primit de la server în urma unei solicitări către API-ul de procesare a mesajelor. Această funcție primește ca parametru răspunsul JSON primit de la server și returnează un obiect de mesaj care poate fi adăugat la istoricul de chat și afișat utilizatorului.
FuncțiahandleKeyDowneste un handler de eveniment care este activat atunci când utilizatorul apasă o tastă în câmpul de introducere a textului. Ulterior, face requestul de interogare a asistentului virtual și afișarea răspunsului.
În final, mesajele sunt transmise către o altă componentă, numită MessageBox, care are rolul să afișeze mesajele.
Tot în folderul components, adăugăm fișierul MessageBox.jsx.