added a exit button on the chat bot and make sure it still working

This commit is contained in:
Rainyy21
2025-11-09 01:31:32 -05:00
parent 3686ae72da
commit ed00148f58
8 changed files with 56 additions and 13 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ export async function POST(request: Request) {
catch(error){ catch(error){
console.error(error); console.error(error);
return NextResponse.json( return NextResponse.json(
{error: "Error with the model response "}, {error: "Error with the model response " + String(error)},
{status : 500} {status : 500}
); );
} }
+17 -3
View File
@@ -1,20 +1,22 @@
"use client"; "use client";
import { useState, useEffect, useRef, useCallback } from "react"; import { useState, useEffect, useRef, useCallback } from "react";
import { useSearchParams } from "next/navigation"; import { useSearchParams, useRouter } from "next/navigation";
import ChatInput from "../utils/component/ui/ChatInput"; import ChatInput from "../utils/component/ui/ChatInput";
import MessageWindow from "../utils/component/ui/MessageWindow"; import MessageWindow from "../utils/component/ui/MessageWindow";
import { ChatHistory, ChatSetting, Message , MessageRole } from "@/app/exportType/types"; import { ChatHistory, ChatSetting, Message , MessageRole } from "@/app/exportType/types";
export default function Home(){ export default function Home(){
const [history, setHistory] = useState<ChatHistory>([]) const [history, setHistory] = useState<ChatHistory>([])
const [loading, setLoading] = useState(false);
const historyRef = useRef<ChatHistory>([]); // Create a ref for history const historyRef = useRef<ChatHistory>([]); // Create a ref for history
const [settings] = useState<ChatSetting>({ const [settings] = useState<ChatSetting>({
temperature:1, temperature:1,
model:"gemini-2.5-pro", model:"gemini-2.5-pro",
sysTemInstructions:"you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job" systemInstruction:"you are a ai helper. Your goal is to expand the project idea and interact with the user on any problem or question they have with the project. You are not allow to code the project for them and stray away from your job"
}); });
const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const initialMessageSent = useRef(false); const initialMessageSent = useRef(false);
@@ -32,6 +34,7 @@ export default function Home(){
const currentHistory = [...prevHistory, newUserMessage]; const currentHistory = [...prevHistory, newUserMessage];
const sendApiRequest = async () => { const sendApiRequest = async () => {
setLoading(true);
try{ try{
const response = await fetch("/api/chat", { const response = await fetch("/api/chat", {
method: "POST", method: "POST",
@@ -49,6 +52,7 @@ export default function Home(){
if (data.error) { if (data.error) {
console.error("AI Error:", data.error); console.error("AI Error:", data.error);
setLoading(false);
return; return;
} }
@@ -63,6 +67,7 @@ export default function Home(){
catch (error) { catch (error) {
console.error("Request Failed:", error); console.error("Request Failed:", error);
} }
setLoading(false);
}; };
sendApiRequest(); sendApiRequest();
@@ -88,6 +93,7 @@ export default function Home(){
}, 0); }, 0);
const sendInitialApiRequest = async () => { const sendInitialApiRequest = async () => {
setLoading(true);
try { try {
const response = await fetch("/api/chat", { const response = await fetch("/api/chat", {
method: "POST", method: "POST",
@@ -105,6 +111,7 @@ export default function Home(){
if (data.error) { if (data.error) {
console.error("AI Error:", data.error); console.error("AI Error:", data.error);
setLoading(false);
return; return;
} }
@@ -117,6 +124,7 @@ export default function Home(){
} catch (error) { } catch (error) {
console.error("Request Failed:", error); console.error("Request Failed:", error);
} }
setLoading(false);
}; };
sendInitialApiRequest(); sendInitialApiRequest();
@@ -128,7 +136,13 @@ export default function Home(){
return ( return (
<div className="flex flex-col py-32"> <div className="flex flex-col py-32">
<MessageWindow history={history} /> <button
onClick={() => router.push('/Dashboard')}
className="absolute top-4 right-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
>
Exit
</button>
<MessageWindow history={history} isLoading={loading} />
<ChatInput onSend={handleSend} onOpenSettings={() => {}} /> <ChatInput onSend={handleSend} onOpenSettings={() => {}} />
</div> </div>
); );
+1 -1
View File
@@ -19,7 +19,7 @@ export interface GenerateConfig{
export interface ChatSetting{ export interface ChatSetting{
temperature :number; temperature :number;
model: string; model: string;
sysTemInstructions: string; systemInstruction: string;
} }
export interface CardData { export interface CardData {
+1 -1
View File
@@ -34,7 +34,7 @@ export default function Home() {
const [settings] = useState<ChatSetting>({ const [settings] = useState<ChatSetting>({
temperature: 1, temperature: 1,
model: "gemini-2.5-flash-lite", model: "gemini-2.5-flash-lite",
sysTemInstructions: `You are an elite hackathon idea generator. Your task is to choose at lease two track and generate five different creative, feasible, and relevant project idea. systemInstruction: `You are an elite hackathon idea generator. Your task is to choose at lease two track and generate five different creative, feasible, and relevant project idea.
The output MUST be in Markdown format and strictly follow this structure: The output MUST be in Markdown format and strictly follow this structure:
### Project Idea Title ### Project Idea Title
**Track** [print out the track you used] **Track** [print out the track you used]
+5 -3
View File
@@ -5,11 +5,13 @@ import { useRouter } from 'next/navigation';
import Image from 'next/image'; import Image from 'next/image';
import ProtectedNavButton from "../components/ProtectedNavButton"; import ProtectedNavButton from "../components/ProtectedNavButton";
import Link from 'next/link'; import Link from 'next/link';
import { style } from 'framer-motion/client';
export default function Page() { export default function Page() {
  return (   return (
    <div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">     <div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
      <header className="absolute top-6 left-8 right-8 flex items-center justify-between text-sm font-medium text-zinc-700 dark:text-zinc-300">       <header className="absolute top-6 left-8 right-8 flex items-center justify-between text-sm font-medium text-zinc-700 dark:text-zinc-300 background-blue-300">
        <Image         <Image
          className=""           className=""
          src="/logo.svg"           src="/logo.svg"
@@ -19,10 +21,10 @@ export default function Page() {
          priority           priority
        />         />
        <div  className="flex items-center gap-4">         <div  className="flex items-center gap-4">
          <Link href = "/auth/login" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">           <Link href = "/auth/login" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors container">
            Sign in             Sign in
          </Link>           </Link>
          <Link href = "/auth/logout" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">           <Link href = "/auth/logout" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors container">
            Log out             Log out
          </Link>           </Link>
        </div>         </div>
+18 -3
View File
@@ -4,11 +4,12 @@ import { ChatHistory } from "@/app/exportType/types";
import {User, Bot} from "lucide-react" import {User, Bot} from "lucide-react"
interface MessageWindowProps{ interface MessageWindowProps{
history :ChatHistory history :ChatHistory;
isLoading: boolean;
} }
export default function MessageWindow({history}:MessageWindowProps){ export default function MessageWindow({history, isLoading}:MessageWindowProps){
const messageEndRef = useRef<HTMLDivElement>(null); const messageEndRef = useRef<HTMLDivVElement>(null);
useEffect(() =>{ useEffect(() =>{
messageEndRef.current?.scrollIntoView({behavior:"smooth"}); messageEndRef.current?.scrollIntoView({behavior:"smooth"});
@@ -52,6 +53,20 @@ export default function MessageWindow({history}:MessageWindowProps){
); );
})} })}
{isLoading && (
<div className="flex justify-start">
<div className="mr-2">
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-gray">
<Bot size={15} className="text-gray-700" />
</div>
</div>
<div className="px-4 py-2 shadow-sm rounded-lg bg-white text-gray-800 rounded-bl-none max-w-xs sm:max-w-md">
<div className="whitespace-pre-wrap break-words">
<span>Loading...</span>
</div>
</div>
</div>
)}
{/* Invisible element to help scroll to bottom */} {/* Invisible element to help scroll to bottom */}
<div ref={messageEndRef} /> <div ref={messageEndRef} />
</div> </div>
+1 -1
View File
@@ -16,7 +16,7 @@ export async function chatToGemini(
):Promise<string>{ ):Promise<string>{
const model = genAI.getGenerativeModel({ const model = genAI.getGenerativeModel({
model:settings.model || "gemini-2.5-flash", model:settings.model || "gemini-2.5-flash",
systemInstruction: settings.sysTemInstructions || "you are going to create a project idea, explain it in summery first before going to detail", systemInstruction: settings.systemInstruction || "you are going to create a project idea, explain it in summery first before going to detail",
}); });
const generationConfig:GenerateConfig = { const generationConfig:GenerateConfig = {
+12
View File
@@ -66,6 +66,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5", "@babel/generator": "^7.28.5",
@@ -1470,6 +1471,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
@@ -1526,6 +1528,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.3.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.3.tgz",
"integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.46.3", "@typescript-eslint/scope-manager": "8.46.3",
"@typescript-eslint/types": "8.46.3", "@typescript-eslint/types": "8.46.3",
@@ -2023,6 +2026,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -2341,6 +2345,7 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.19", "baseline-browser-mapping": "^2.8.19",
"caniuse-lite": "^1.0.30001751", "caniuse-lite": "^1.0.30001751",
@@ -2870,6 +2875,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -3047,6 +3053,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
@@ -5123,6 +5130,7 @@
"version": "19.2.0", "version": "19.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -5131,6 +5139,7 @@
"version": "19.2.0", "version": "19.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -5776,6 +5785,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -5927,6 +5937,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -6187,6 +6198,7 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
"dev": true, "dev": true,
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }