'use client'; import { useState, useEffect, useRef } from 'react'; import type { Meta, StoryObj } from "@storybook/react"; import { ChatCompletionRequest, getPublicClient } from "../api"; const client = getPublicClient('f5d86791-d513-48de-8fd2-b6dbdd4abe9b'); export const AIChatbox = ({ useStreaming = true }) => { const [messages, setMessages] = useState([ { content: "Hello! I'm a friendly bot.", role: "assistant", id: 1, }, ]); const [title, setTitle] = useState(""); const [userInput, setUserInput] = useState(''); const chatEndRef: any = useRef(null); const timerRef: any = useRef(null); const scrollToBottom = () => { chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { scrollToBottom(); }, [messages]); const handleInputChange = (e: any) => { setUserInput(e.target.value); }; const handleSubmit = async (e: any) => { e.preventDefault(); if (!userInput.trim()) return; const newMessage = { content: userInput, role: 'user' }; setMessages((prevMessages: any) => [...prevMessages, newMessage]); const requestBody = { model: 'gpt-3.5-turbo', // model: 'gpt-4-turbo', messages: [{ role: 'system', content: 'You are a helpful assistant.' }, ...messages, newMessage], } as ChatCompletionRequest; let tempMessageId: any = null; try { setUserInput(''); // Reset input field after sending if (useStreaming) { // Add a temporary message that will be updated by the stream tempMessageId = new Date().getTime(); // Create a unique ID for the temporary message setMessages(prevMessages => [...prevMessages, { id: tempMessageId, content: '', role: 'assistant' }]); await client?.getCompletionStream(requestBody, (streamData) => { console.log('Stream data:', streamData); setMessages(prevMessages => prevMessages.map(msg => msg.id === tempMessageId ? { ...msg, content: msg.content + streamData } : msg )); }); } else { // Using the non-streaming function const response = await client?.getCompletion(requestBody); if (response && response.choices && response.choices.length > 0) { const aiText = response.choices[0].message.content; setMessages((prevMessages: any) => [...prevMessages, { content: aiText, role: 'assistant' }]); } } } catch (error) { console.error("Error fetching AI response:", error); setMessages(prevMessages => prevMessages.map(msg => msg.id === tempMessageId ? { ...msg, content: 'Error fetching response from AI.' } : msg )); } }; const generateTitle = async () => { try { const prompt = "Create a short 3-7 word title for the topic of the following conversation:\n\n" + messages.map(message => { return message.role + "\n" + message.content }).join('\n\n') + "\n\nTitle (no quotes): "; const response = await client?.getCompletion({ model: 'gpt-3.5-turbo', messages: [{ role: 'system', content: prompt }] }); if (response && response.choices && response.choices.length > 0) { setTitle(response.choices[0].message.content); } } catch (error) { console.error("Error fetching AI response:", error); setTitle('Conversation'); } }; // Generate title for conversation when there is three messages useEffect(() => { // Clear any existing timer to reset the countdown if (timerRef.current) { clearTimeout(timerRef.current); } // Set a new timer every time `messages` changes timerRef.current = setTimeout(() => { if (messages.length === 3) { generateTitle(); } }, 1000); // Set timeout for 1 second // Cleanup function to clear the timer when the component unmounts or before re-running the effect return () => { if (timerRef.current) { clearTimeout(timerRef.current); } }; }, [messages]); return (

{title}

{messages.map((message, index) => (
{message.content}
))}
); }; function ChatActionStory() { return (

Hello

); } //👇 This default export determines where your story goes in the story list const meta: Meta = { component: ChatActionStory, }; export default meta; type Story = StoryObj; export const FirstStory: Story = { // harded code values for now 😬 args: {}, };