From 8a4ca5a23d86cc3f8f9aa520a28aef49f9cacd7f Mon Sep 17 00:00:00 2001 From: ernestocarocca <113439130+ernestocarocca@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:58:41 +0100 Subject: [PATCH] fix: correct dotenv import and enhance error handling for OpenAI API key feat: implement chat functionality in api_service and update API routes --- src/api.ts | 47 ++++++--------------------------------------- src/api_service.ts | 27 ++++++++++++++++++++++++-- src/app/globals.css | 15 ++++++++++++++- src/app/layout.tsx | 4 ++-- src/app/page.tsx | 27 ++++++++++++++------------ 5 files changed, 62 insertions(+), 58 deletions(-) diff --git a/src/api.ts b/src/api.ts index cdfec86..2980985 100644 --- a/src/api.ts +++ b/src/api.ts @@ -6,10 +6,8 @@ import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'; import { Static, Type } from '@sinclair/typebox'; import { FastifyPluginCallback } from 'fastify'; import apiService from './api_service'; - -import { OpenAI } from 'openai'; -import dotenv from 'dotenv'; -dotenv.config(); +import dotnev from 'dotenv'; +dotnev.config(); const HelloWorld = Type.String({ description: 'The magical words!' @@ -40,42 +38,7 @@ const healthcheck: FastifyPluginCallback = ( ); next(); }; -const aiMassage: FastifyPluginCallback = (fastify, opts, next) => { - async function chat(reply: any, userMessage: string) { - const openai = process.env.OPENAI_API_KEY as string; - if (!openai) { - throw new Error( - 'The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: "My API Key" }).' - ); - } - const client = new OpenAI({ apiKey: openai }); - reply.raw.setHeader('Content-Type', 'text/event-stream'); - reply.raw.setHeader('Cache-Control', 'no-cache'); - reply.raw.setHeader('Connection', 'keep-alive'); - const chatCompletion = await client.chat.completions.create({ - model: 'gpt-4', - messages: [ - { role: 'system', content: 'You are a helpful assistant.' }, - { - role: 'assistant', - content: [{ type: 'text', text: "Who's there?" }] - }, - { role: 'user', content: userMessage } - ] - }); - - return reply.send(chatCompletion.choices[0].message.content); - } - fastify.get('/chat', async (_, reply) => { - await chat(reply, 'Hello'); - }); - fastify.post('/chat/message', async (request, reply) => { - const userMessage = request.body as string; - await chat(reply, userMessage); - }); - next(); -}; export interface ApiOptions { title: string; } @@ -104,10 +67,12 @@ export default (opts: ApiOptions) => { api.register(healthcheck, { prefix: '/api', title: opts.title }); // register other API routes here - api.register(aiMassage); + console.log('process.env.OPENAI_API_KEY', process.env.OPENAI_API_KEY); if (!process.env.OPENAI_API_KEY) { - throw new Error('OPENAI_API_KEY is required'); + throw new Error( + 'The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: "My API Key" }).' + ); } api.register(apiService, { prefix: '/api/v1', diff --git a/src/api_service.ts b/src/api_service.ts index 7bc984a..a65f88f 100644 --- a/src/api_service.ts +++ b/src/api_service.ts @@ -1,4 +1,5 @@ -import { FastifyPluginCallback } from 'fastify'; +import { FastifyPluginCallback, FastifyReply } from 'fastify'; +import OpenAI from 'openai'; export interface ApiServiceOptions { openAiApiKey: string; @@ -9,11 +10,33 @@ const apiService: FastifyPluginCallback = ( opts, next ) => { + fastify.post('/message', async (request, reply) => { + console.log('request.body', request.body); + const userMessage = request.body as string; + await chat(reply, userMessage); + }); fastify.setErrorHandler((error, request, reply) => { reply.code(500).send({ reason: error.message }); }); - // Insert routes here + async function chat(reply: FastifyReply, userMessage: string) { + const openai = opts.openAiApiKey; + + const client = new OpenAI({ apiKey: openai }); + reply.raw.setHeader('Content-Type', 'text/event-stream'); + reply.raw.setHeader('Cache-Control', 'no-cache'); + reply.raw.setHeader('Connection', 'keep-alive'); + + const chatCompletion = await client.chat.completions.create({ + model: 'gpt-4', + messages: [ + { role: 'system', content: 'You are a helpful assistant.' }, + { role: 'user', content: userMessage } + ] + }); + + return reply.send(chatCompletion.choices[0].message.content); + } next(); }; diff --git a/src/app/globals.css b/src/app/globals.css index a5aad31..2bdf7c4 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,7 +3,7 @@ @tailwind utilities; :root { - --background: #0a0a0a; + --background: transparent; --foreground: #ededed; } @@ -18,3 +18,16 @@ body { text-wrap: balance; } } +.glassmorphism { + background: linear-gradient(to bottom, right, to right, #7e57c2, #00bcd4); + backdrop-filter: blur(7px); + border: 2px solid rgba(205, 118, 205, 0.2); + border-radius: 10px; +} +.gradient-text { + background: linear-gradient(to right, rgb(140, 96, 214), #00bcd4); + -webkit-text-fill-color: transparent; +} +.gradient-bg { + background: linear-gradient(to bottom, right, to right, #7e57c2, #00bcd4); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3b7b29c..a7bc632 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,8 +7,8 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + {children} diff --git a/src/app/page.tsx b/src/app/page.tsx index c35d92c..08ccc68 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,12 +4,14 @@ import { Card, CardHeader, CardBody } from '@nextui-org/card'; import { Button, Spacer } from '@nextui-org/react'; import { IconArrowUp, IconTrash } from '@tabler/icons-react'; import { Textarea } from '@nextui-org/input'; +import { useApiUrl } from '@/hooks/useApiUrl'; export default function Page() { const [response, setResponse] = useState(''); const [loading, setLoading] = useState(false); const [input, setInput] = useState(''); const [error, setError] = useState(''); + const url = useApiUrl(); const handleInputChange = (event: ChangeEvent) => { setInput(event.target.value); @@ -19,7 +21,7 @@ export default function Page() { setLoading(true); try { - const response = await fetch('http://localhost:8000/chat/message', { + const response = await fetch(`${url}/message`, { method: 'POST', body: JSON.stringify({ userMessage: input }) }); @@ -34,27 +36,28 @@ export default function Page() { }; return ( -
- +
+
- - - Chat with AI + + Chat-Agent by Eyevinn Technology OSC
- - + + {loading &&

Loading...

} {error &&

{error}

} {response &&

{response}

}
-
+