Skip to content

Commit

Permalink
feat: setup chat
Browse files Browse the repository at this point in the history
  • Loading branch information
ansh-saini committed Aug 24, 2024
1 parent aef9047 commit d74844f
Show file tree
Hide file tree
Showing 33 changed files with 158 additions and 2,749 deletions.
58 changes: 48 additions & 10 deletions src/app/api/assistant-v2/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { openai } from '@ai-sdk/openai';
import { convertToCoreMessages, streamText } from 'ai';
import { z } from 'zod';

import { getPersonName } from '@/app/api/assistant-v2/tools/get-person-name';

// Allow streaming responses up to 30 seconds
export const maxDuration = 30;

Expand All @@ -13,16 +15,14 @@ export async function POST(req: Request) {
messages: convertToCoreMessages(messages),
tools: {
// server-side tool with execute function:
getWeatherInformation: {
description: 'show the weather in a given city to the user',
parameters: z.object({ city: z.string() }),
// eslint-disable-next-line no-empty-pattern
execute: async ({}: { city: string }) => {
const weatherOptions = ['sunny', 'cloudy', 'rainy', 'snowy', 'windy'];
return weatherOptions[
Math.floor(Math.random() * weatherOptions.length)
];
},
getPersonName: {
description: "Parse the string to extract the user's name.",
parameters: z.object({
message: z
.string()
.describe('The message from which to extract the name.'),
}),
execute: getPersonName,
},
// client-side tool that starts user interaction:
askForConfirmation: {
Expand All @@ -42,3 +42,41 @@ export async function POST(req: Request) {

return result.toDataStreamResponse();
}

// export async function POST(req: Request) {
// const { messages } = await req.json();

// const result = await streamText({
// model: openai('gpt-4-turbo'),
// messages: convertToCoreMessages(messages),
// tools: {
// // server-side tool with execute function:
// getWeatherInformation: {
// description: 'show the weather in a given city to the user',
// parameters: z.object({ city: z.string() }),
// // eslint-disable-next-line no-empty-pattern
// execute: async ({}: { city: string }) => {
// const weatherOptions = ['sunny', 'cloudy', 'rainy', 'snowy', 'windy'];
// return weatherOptions[
// Math.floor(Math.random() * weatherOptions.length)
// ];
// },
// },
// // client-side tool that starts user interaction:
// askForConfirmation: {
// description: 'Ask the user for confirmation.',
// parameters: z.object({
// message: z.string().describe('The message to ask for confirmation.'),
// }),
// },
// // client-side tool that is automatically executed on the client:
// getLocation: {
// description:
// 'Get the user location. Always ask for confirmation before using this tool.',
// parameters: z.object({}),
// },
// },
// });

// return result.toDataStreamResponse();
// }
38 changes: 38 additions & 0 deletions src/app/api/assistant-v2/tools/get-person-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import OpenAI from 'openai';

import logger from '@/lib/logger';

const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});

interface Props {
message: string;
}
export const getPersonName = async ({ message }: Props) => {
const response = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [
{
role: 'system',
content:
"You are a string parser. You will be given a string that contains a person's name. You have to extract the name from the string. Only return the name and nothing else.",
},
{
role: 'user',
content: message,
},
],
temperature: 0.7,
max_tokens: 64,
top_p: 1,
});

const name = response.choices[0].message.content;
if (!name) {
logger('Response: ', JSON.stringify(response));
throw new Error('Name not found');
}
logger(`Got user ${name}`);
return name;
};
13 changes: 0 additions & 13 deletions src/app/api/employees/route.ts

This file was deleted.

75 changes: 23 additions & 52 deletions src/app/assistant/components/chat/chat-bottombar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,40 @@ import {
Paperclip,
PlusCircle,
SendHorizontal,
ThumbsUp,
} from 'lucide-react';
import Link from 'next/link';
import React, { useRef, useState } from 'react';

import { cn } from '@/lib/utils';

import { loggedInUserData, Message } from '@/app/data';

import { buttonVariants } from '../ui/button';
import { Button, buttonVariants } from '../ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import { Textarea } from '../ui/textarea';

interface ChatBottombarProps {
sendMessage: (newMessage: Message) => void;
isMobile: boolean;
handleInputChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
handleSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
}

export const BottombarIcons = [{ icon: FileImage }, { icon: Paperclip }];

export default function ChatBottombar({
sendMessage,
handleSubmit,
isMobile,
...props
}: ChatBottombarProps) {
const [message, setMessage] = useState('');
const inputRef = useRef<HTMLTextAreaElement>(null);

const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
props.handleInputChange(event);
setMessage(event.target.value);
};

const handleThumbsUp = () => {
const newMessage: Message = {
id: message.length + 1,
name: loggedInUserData.name,
avatar: loggedInUserData.avatar,
message: '👍',
};
sendMessage(newMessage);
setMessage('');
};

const handleSend = () => {
const handleSend = (e: React.FormEvent<HTMLFormElement>) => {
if (message.trim()) {
const newMessage: Message = {
id: message.length + 1,
name: loggedInUserData.name,
avatar: loggedInUserData.avatar,
message: message.trim(),
};
sendMessage(newMessage);
handleSubmit(e);
setMessage('');

if (inputRef.current) {
Expand All @@ -65,10 +48,10 @@ export default function ChatBottombar({
};

const handleKeyPress = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
handleSend();
}
// if (event.key === 'Enter' && !event.shiftKey) {
// event.preventDefault();
// handleSend();
// }

if (event.key === 'Enter' && event.shiftKey) {
event.preventDefault();
Expand Down Expand Up @@ -153,7 +136,9 @@ export default function ChatBottombar({
</div>

<AnimatePresence initial={false}>
<motion.div
<motion.form
id='chat-form'
onSubmit={handleSend}
key='input'
className='w-full relative'
layout
Expand All @@ -178,35 +163,21 @@ export default function ChatBottombar({
placeholder='Aa'
className=' w-full border rounded-full flex items-center h-9 resize-none overflow-hidden bg-background'
></Textarea>
<div className='absolute right-2 bottom-0.5 '>
<div>emoji picker</div>
</div>
</motion.div>
</motion.form>

{message.trim() ? (
<Link
href='#'
{message.trim() && (
<Button
variant='ghost'
size='icon'
className={cn(
buttonVariants({ variant: 'ghost', size: 'icon' }),
'h-9 w-9',
'dark:bg-muted dark:text-muted-foreground dark:hover:bg-muted dark:hover:text-white shrink-0'
)}
onClick={handleSend}
type='submit'
form='chat-form'
>
<SendHorizontal size={20} className='text-muted-foreground' />
</Link>
) : (
<Link
href='#'
className={cn(
buttonVariants({ variant: 'ghost', size: 'icon' }),
'h-9 w-9',
'dark:bg-muted dark:text-muted-foreground dark:hover:bg-muted dark:hover:text-white shrink-0'
)}
onClick={handleThumbsUp}
>
<ThumbsUp size={20} className='text-muted-foreground' />
</Link>
</Button>
)}
</AnimatePresence>
</div>
Expand Down
104 changes: 0 additions & 104 deletions src/app/assistant/components/chat/chat-layout.tsx

This file was deleted.

Loading

0 comments on commit d74844f

Please sign in to comment.