"use client"; import { useState, useRef, useEffect } from "react"; import { ChatMessage } from "@/lib/types"; import { ChatMessageItem } from "@/components/chat-completions/chat-messasge-item"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Send, Loader2, ChevronDown } from "lucide-react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useAuthClient } from "@/hooks/use-auth-client"; import type { CompletionCreateParams } from "llama-stack-client/resources/chat/completions"; import type { Model } from "llama-stack-client/resources/models"; export default function ChatPlaygroundPage() { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(""); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [models, setModels] = useState([]); const [selectedModel, setSelectedModel] = useState(""); const [modelsLoading, setModelsLoading] = useState(true); const [modelsError, setModelsError] = useState(null); const messagesEndRef = useRef(null); const client = useAuthClient(); const isModelsLoading = modelsLoading ?? true; const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { scrollToBottom(); }, [messages]); useEffect(() => { const fetchModels = async () => { try { setModelsLoading(true); setModelsError(null); const modelList = await client.models.list(); const llmModels = modelList.filter(model => model.model_type === 'llm'); setModels(llmModels); if (llmModels.length > 0) { setSelectedModel(llmModels[0].identifier); } } catch (err) { console.error("Error fetching models:", err); setModelsError("Failed to fetch available models"); } finally { setModelsLoading(false); } }; fetchModels(); }, [client]); const extractTextContent = (content: any): string => { if (typeof content === 'string') { return content; } if (Array.isArray(content)) { return content .filter(item => item.type === 'text') .map(item => item.text) .join(''); } if (content && content.type === 'text') { return content.text || ''; } return ''; }; const handleSendMessage = async () => { if (!inputMessage.trim() || isLoading || !selectedModel) return; const userMessage: ChatMessage = { role: "user", content: inputMessage.trim(), }; setMessages(prev => [...prev, userMessage]); setInputMessage(""); setIsLoading(true); setError(null); try { const messageParams: CompletionCreateParams["messages"] = [...messages, userMessage].map(msg => { const content = typeof msg.content === 'string' ? msg.content : extractTextContent(msg.content); if (msg.role === "user") { return { role: "user" as const, content }; } else if (msg.role === "assistant") { return { role: "assistant" as const, content }; } else { return { role: "system" as const, content }; } }); const response = await client.chat.completions.create({ model: selectedModel, messages: messageParams, stream: false, }); if ('choices' in response && response.choices && response.choices.length > 0) { const choice = response.choices[0]; if ('message' in choice && choice.message) { const assistantMessage: ChatMessage = { role: "assistant", content: extractTextContent(choice.message.content), }; setMessages(prev => [...prev, assistantMessage]); } } } catch (err) { console.error("Error sending message:", err); setError("Failed to send message. Please try again."); } finally { setIsLoading(false); } }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSendMessage(); } }; const clearChat = () => { setMessages([]); setError(null); }; return (

Chat Playground

{models.map((model) => ( setSelectedModel(model.identifier)} > {model.identifier} ))}
Chat Messages
{messages.length === 0 ? (

Start a conversation by typing a message below.

) : ( messages.map((message, index) => ( )) )} {isLoading && (
Thinking...
)}
{modelsError && (

{modelsError}

)} {error && (

{error}

)}
setInputMessage(e.target.value)} onKeyPress={handleKeyPress} placeholder="Type your message here..." disabled={isLoading} className="flex-1" />
); }