diff --git a/app/layout.tsx b/app/layout.tsx index d3c7385..4f6cd8a 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,5 @@ import type { Metadata } from "next"; +import ChatWidget from "@/components/ChatWidget"; import { Varela_Round } from "next/font/google"; import "./globals.css"; @@ -31,6 +32,7 @@ export default function RootLayout({ className={`${varelaRound.variable} antialiased font-varela`} > {children} + ); diff --git a/components/ChatWidget.tsx b/components/ChatWidget.tsx new file mode 100644 index 0000000..eba076e --- /dev/null +++ b/components/ChatWidget.tsx @@ -0,0 +1,171 @@ +"use client"; + +import Image from "next/image"; + +import { useState, useRef, useEffect } from "react"; + +interface Message { + role: "user" | "assistant"; + content: string; +} + +const RAG_API_URL = "https://ai.apply4jobs.de/api/v1/chat/completions"; + +export default function ChatWidget() { + const [isOpen, setIsOpen] = useState(false); + const [messages, setMessages] = useState([ + { + role: "assistant", + content: + "Hallo! Ich bin Sebastians KI-Assistent. Stellen Sie mir gerne Fragen zu seiner Berufserfahrung, seinen Fähigkeiten oder Projekten. 👋\n\nHello! I'm Sebastian's AI assistant. Feel free to ask me about his professional experience, skills or projects.", + }, + ]); + const [input, setInput] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const messagesEndRef = useRef(null); + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages, isLoading]); + + const sendMessage = async () => { + if (!input.trim() || isLoading) return; + + const userMessage: Message = { role: "user", content: input.trim() }; + setMessages((prev) => [...prev, userMessage]); + setInput(""); + setIsLoading(true); + + try { + const response = await fetch(RAG_API_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + model: "sebastian-rag", + messages: [...messages, userMessage], + stream: false, + }), + }); + + const data = await response.json(); + const assistantContent = + data?.choices?.[0]?.message?.content ?? "Entschuldigung, ich konnte keine Antwort generieren."; + + setMessages((prev) => [ + ...prev, + { role: "assistant", content: assistantContent }, + ]); + } catch { + setMessages((prev) => [ + ...prev, + { + role: "assistant", + content: "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.", + }, + ]); + } finally { + setIsLoading(false); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }; + + return ( + <> + {/* Chat Window */} + {isOpen && ( +
+ {/* Header */} +
+
+
+ Sebastian Fröhlich +
+
+

Sebastian Fröhlich

+

KI-Assistent · AI Assistant

+
+
+ +
+ + {/* Messages */} +
+ {messages.map((msg, i) => ( +
+
+ {msg.content} +
+
+ ))} + {isLoading && ( +
+
+ + + + + + Antwort wird generiert… +
+
+ )} +
+
+ + {/* Input */} +
+