shit
This commit is contained in:
parent
5c16d12f77
commit
1515ee0589
6 changed files with 118 additions and 28 deletions
|
|
@ -5,7 +5,6 @@ function App() {
|
||||||
return (
|
return (
|
||||||
<div className="dark min-h-screen bg-gray-950 text-white flex justify-center pt-12">
|
<div className="dark min-h-screen bg-gray-950 text-white flex justify-center pt-12">
|
||||||
<ChatLayout />
|
<ChatLayout />
|
||||||
<div></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,22 @@ import React, { useState } from "react";
|
||||||
import ChatHeader from "src/components/ui/chat/chat-header";
|
import ChatHeader from "src/components/ui/chat/chat-header";
|
||||||
import ChatWindow from "src/components/ui/chat/chat-window";
|
import ChatWindow from "src/components/ui/chat/chat-window";
|
||||||
import MessageInput from "src/components/ui/chat/message-input";
|
import MessageInput from "src/components/ui/chat/message-input";
|
||||||
|
import { GoogleGenAI } from "@google/genai";
|
||||||
|
import { useChatBackend } from "src/context/chat-backend-context";
|
||||||
|
|
||||||
|
const ai = new GoogleGenAI({ apiKey: import.meta.env.GEMINI_API_KEY });
|
||||||
|
|
||||||
|
async function AIResponse(userInputArray) {
|
||||||
|
const response = await ai.models.generateContent({
|
||||||
|
model: "gemini-2.5-flash",
|
||||||
|
|
||||||
|
contents: userInputArray,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
let userInput = [];
|
||||||
|
|
||||||
export default function ChatLayout() {
|
export default function ChatLayout() {
|
||||||
const [messages, setMessages] = useState([
|
const [messages, setMessages] = useState([
|
||||||
|
|
@ -11,29 +27,6 @@ export default function ChatLayout() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function addMessage(role, content) {
|
|
||||||
const msg = { role, content };
|
|
||||||
setMessages((s) => [...s, msg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSend(text) {
|
|
||||||
const userMsg = { role: "user", content: text };
|
|
||||||
setMessages((s) => [...s, userMsg]);
|
|
||||||
|
|
||||||
// fake assistant reply after short delay
|
|
||||||
setTimeout(() => {
|
|
||||||
setMessages((s) => [
|
|
||||||
...s,
|
|
||||||
{ role: "assistant", content: `You said: ${text}` },
|
|
||||||
]);
|
|
||||||
}, 600);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDeleteAll() {
|
|
||||||
if (!window.confirm("Delete all messages?")) return;
|
|
||||||
setMessages([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col flex-start w-full max-w-3xl gap-4 p-4">
|
<div className="flex flex-col flex-start w-full max-w-3xl gap-4 p-4">
|
||||||
<ChatHeader onDeleteAll={handleDeleteAll} />
|
<ChatHeader onDeleteAll={handleDeleteAll} />
|
||||||
|
|
@ -46,3 +39,42 @@ export default function ChatLayout() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMessage(role, content) {
|
||||||
|
const msg = { role, content };
|
||||||
|
setMessages((s) => [...s, msg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSend(text) {
|
||||||
|
const { setMessages } = useChatBackend();
|
||||||
|
const userMsg = { role: "user", content: text };
|
||||||
|
|
||||||
|
switch (setMessages) {
|
||||||
|
case "gemini":
|
||||||
|
userInput.push(text);
|
||||||
|
const res = await AIResponse(userInput);
|
||||||
|
setMessages((s) => [...s, userMsg]);
|
||||||
|
setTimeout(() => {
|
||||||
|
setMessages((s) => [...s, { role: "assistant", content: res }]);
|
||||||
|
}, 600);
|
||||||
|
break;
|
||||||
|
case "rust":
|
||||||
|
setMessages((s) => [...s, userMsg]);
|
||||||
|
|
||||||
|
// fake assistant reply after short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
setMessages((s) => [
|
||||||
|
...s,
|
||||||
|
{ role: "assistant", content: `You said: ${text}` },
|
||||||
|
]);
|
||||||
|
}, 600);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDeleteAll() {
|
||||||
|
if (!window.confirm("Delete all messages?")) return;
|
||||||
|
setMessages([]);
|
||||||
|
}
|
||||||
|
|
|
||||||
26
web-app/src/components/ui/button/backend-toggle.jsx
Normal file
26
web-app/src/components/ui/button/backend-toggle.jsx
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React from "react";
|
||||||
|
import { motion } from "motion/react";
|
||||||
|
import { Cpu } from "lucide-react";
|
||||||
|
import { useChatBackend } from "src/context/chat-backend-context";
|
||||||
|
|
||||||
|
export default function BackendToggle({ className }) {
|
||||||
|
const { backend, toggleBackend } = useChatBackend();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleBackend();
|
||||||
|
}}
|
||||||
|
className={`bg-gray-700 p-2 rounded-2xl file-input border-2 border-gray-600 text-md flex items-center gap-2 ${className || ""}`}
|
||||||
|
whileHover={{ scale: 1.05 }}
|
||||||
|
whileTap={{ scale: 0.95 }}
|
||||||
|
title={`${backend}`}
|
||||||
|
>
|
||||||
|
<Cpu className="w-4 h-4" />
|
||||||
|
<span className="uppercase">
|
||||||
|
{backend === "rust" ? "rust" : "gemini"}
|
||||||
|
</span>
|
||||||
|
</motion.button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import DownButton from "src/components/ui/button/down-button";
|
import DownButton from "src/components/ui/button/down-button";
|
||||||
|
import BackendToggle from "src/components/ui/button/backend-toggle";
|
||||||
|
import ChatBackendContext from "src/context/chat-backend-context";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
import { BotMessageSquare } from "lucide-react";
|
import { BotMessageSquare } from "lucide-react";
|
||||||
|
|
||||||
|
|
@ -59,7 +61,6 @@ export default function MessageInput({ onSend, onMessage }) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
if (onMessage) onMessage("assistant", `Error: ${err.message}`);
|
if (onMessage) onMessage("assistant", `Error: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setText("");
|
setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,9 +68,13 @@ export default function MessageInput({ onSend, onMessage }) {
|
||||||
<div className="w-full flex justify-center">
|
<div className="w-full flex justify-center">
|
||||||
<footer className="fixed bottom-6 max-w-3xl w-full px-4">
|
<footer className="fixed bottom-6 max-w-3xl w-full px-4">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div className="flex justify-between items-center">
|
||||||
<DownButton></DownButton>
|
<div className="flex items-center gap-2">
|
||||||
|
<DownButton />
|
||||||
|
<BackendToggle />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className="bg-gray-900 rounded-2xl border-2 border-gray-800 shadow-lg shadow-indigo-600"
|
className="bg-gray-900 rounded-2xl border-2 border-gray-800 shadow-lg shadow-indigo-600"
|
||||||
|
|
|
||||||
25
web-app/src/context/chat-backend-context.jsx
Normal file
25
web-app/src/context/chat-backend-context.jsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React, { createContext, useContext, useState } from "react";
|
||||||
|
|
||||||
|
const ChatBackendContext = createContext(null);
|
||||||
|
|
||||||
|
export function ChatBackendProvider({ children }) {
|
||||||
|
const [backend, setBackend] = useState("gemini"); // default
|
||||||
|
|
||||||
|
function toggleBackend() {
|
||||||
|
setBackend((b) => (b === "gemini" ? "rust" : "gemini"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChatBackendContext.Provider value={{ backend, setBackend, toggleBackend }}>
|
||||||
|
{children}
|
||||||
|
</ChatBackendContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useChatBackend() {
|
||||||
|
const ctx = useContext(ChatBackendContext);
|
||||||
|
if (!ctx) throw new Error("useChatBackend must be used within ChatBackendProvider");
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChatBackendContext;
|
||||||
|
|
@ -2,9 +2,12 @@ import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import App from "./app/index.jsx";
|
import App from "./app/index.jsx";
|
||||||
|
import { ChatBackendProvider } from "./context/chat-backend-context";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")).render(
|
createRoot(document.getElementById("root")).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<ChatBackendProvider>
|
||||||
|
<App />
|
||||||
|
</ChatBackendProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue