diff --git a/src/app/(dashboard)/dashboard/playground/ChatPlayground.tsx b/src/app/(dashboard)/dashboard/playground/ChatPlayground.tsx deleted file mode 100644 index ff0875e436..0000000000 --- a/src/app/(dashboard)/dashboard/playground/ChatPlayground.tsx +++ /dev/null @@ -1,329 +0,0 @@ -"use client"; - -import { useState, useRef, useEffect } from "react"; -import { useTranslations } from "next-intl"; -import { Card, Button, Select, Badge } from "@/shared/components"; - -interface Message { - role: "system" | "user" | "assistant"; - content: string; -} - -interface ChatPlaygroundProps { - selectedProvider: string; - selectedModel: string; - selectedConnection: string; - models: any[]; - providers: any[]; - providerConnections: any[]; - onProviderChange: (p: string) => void; - onModelChange: (m: string) => void; - onConnectionChange: (c: string) => void; - noAccountsString: string; - autoAccountsString: string; -} - -export default function ChatPlayground({ - selectedProvider, - selectedModel, - selectedConnection, - models, - providers, - providerConnections, - onProviderChange, - onModelChange, - onConnectionChange, - noAccountsString, - autoAccountsString, -}: ChatPlaygroundProps) { - const t = useTranslations("playground"); - const [messages, setMessages] = useState([ - { role: "system", content: "You are a helpful assistant." }, - ]); - const [input, setInput] = useState(""); - const [loading, setLoading] = useState(false); - const [responseStatus, setResponseStatus] = useState(null); - const [responseDuration, setResponseDuration] = useState(null); - const [error, setError] = useState(null); - const messagesEndRef = useRef(null); - const abortRef = useRef(null); - - const filteredModels = (() => { - const seen = new Set(); - const out: Array<{ value: string; label: string }> = []; - for (const m of models) { - if (typeof m?.id !== "string") continue; - if (selectedProvider && !m.id.startsWith(selectedProvider + "/")) continue; - if (seen.has(m.id)) continue; - seen.add(m.id); - out.push({ value: m.id, label: m.id }); - } - return out; - })(); - - const scrollToBottom = () => { - messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); - }; - - useEffect(() => { - scrollToBottom(); - }, [messages]); - - const handleSend = async () => { - if (!input.trim() || !selectedModel) return; - - const userMessage: Message = { role: "user", content: input }; - const currentMessages = [...messages, userMessage]; - setMessages(currentMessages); - setInput(""); - setLoading(true); - setError(null); - setResponseStatus(null); - setResponseDuration(null); - - const controller = new AbortController(); - abortRef.current = controller; - const startTime = Date.now(); - - try { - const fetchHeaders: Record = { "Content-Type": "application/json" }; - if (selectedConnection) { - fetchHeaders["X-OmniRoute-Connection"] = selectedConnection; - } - - const res = await fetch("/api/v1/chat/completions", { - method: "POST", - headers: fetchHeaders, - body: JSON.stringify({ - model: selectedModel, - messages: currentMessages, - stream: true, - }), - signal: controller.signal, - }); - - setResponseStatus(res.status); - - if (!res.ok) { - const errorData = await res.json().catch(() => ({})); - setError(errorData.error?.message || errorData.error || `Error ${res.status}`); - setLoading(false); - setResponseDuration(Date.now() - startTime); - return; - } - - // Read SSE stream - const reader = res.body?.getReader(); - const decoder = new TextDecoder(); - let assistantResponse = ""; - - setMessages((prev) => [...prev, { role: "assistant", content: "" }]); - - if (reader) { - while (true) { - const { done, value } = await reader.read(); - if (done) break; - const chunk = decoder.decode(value, { stream: true }); - const lines = chunk.split("\n"); - for (const line of lines) { - if (line.startsWith("data: ") && line !== "data: [DONE]") { - try { - const parsed = JSON.parse(line.slice(6)); - const delta = parsed.choices[0]?.delta?.content || ""; - assistantResponse += delta; - setMessages((prev) => { - const newMsgs = [...prev]; - newMsgs[newMsgs.length - 1].content = assistantResponse; - return newMsgs; - }); - } catch (e) { - // ignore parse errors for partial chunks - } - } - } - } - } - } catch (err: any) { - if (err.name === "AbortError") { - setError("Request cancelled"); - } else { - setError(err.message || "Network error"); - } - } - - setResponseDuration(Date.now() - startTime); - setLoading(false); - }; - - const handleCancel = () => { - abortRef.current?.abort(); - }; - - const handleClear = () => { - setMessages([{ role: "system", content: "You are a helpful assistant." }]); - setError(null); - setResponseStatus(null); - setResponseDuration(null); - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter" && !e.shiftKey) { - e.preventDefault(); - handleSend(); - } - }; - - const noModels = filteredModels.length === 0; - - return ( -
- -
-
- - onModelChange(e.target.value)} - options={filteredModels} - className="w-full" - /> -
- -
- -