fix the ai and it should be working

This commit is contained in:
Rainyy21
2025-11-09 03:03:37 -05:00
parent 507b256943
commit 3e3bff62fd
10 changed files with 160 additions and 731 deletions
+5 -6
View File
@@ -1,8 +1,7 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { useState } from "react";
// import { useRouter } from "next/navigation"; // Removed Next.js import import Link from 'next/link';
// import Link from 'next/link'; // Removed Next.js import
export default function Dashboard() { export default function Dashboard() {
// const router = useRouter(); // Removed Next.js hook // const router = useRouter(); // Removed Next.js hook
@@ -79,23 +78,23 @@ export default function Dashboard() {
className={`flex flex-col p-4 gap-3 text-zinc-700 dark:text-zinc-300 transition-opacity duration-200 ${sideBarOpen ? "opacity-100" : "opacity-0" className={`flex flex-col p-4 gap-3 text-zinc-700 dark:text-zinc-300 transition-opacity duration-200 ${sideBarOpen ? "opacity-100" : "opacity-0"
}`} }`}
> >
<a <Link
href="/" href="/"
className="hover:text-gray-200 transition-colors" className="hover:text-gray-200 transition-colors"
> >
Home Home
</a> </Link>
<p <p
className="hover:text-gray-200 transition-colors" className="hover:text-gray-200 transition-colors"
> >
Settings Settings
</p> </p>
<a <Link
href="/auth/logout" href="/auth/logout"
className="hover:text-gray-200 transition-colors" className="hover:text-gray-200 transition-colors"
> >
Logout Logout
</a> </Link>
</nav> </nav>
</aside> </aside>
+5 -8
View File
@@ -8,22 +8,19 @@ export async function POST(request: Request) {
const { userMessage, history, settings } = await request.json() as { const { userMessage, history, settings } = await request.json() as {
userMessage: string; userMessage: string;
history: ChatHistory; history: ChatHistory;
settings: ChatSetting; settings?: ChatSetting; // settings is optional from the request
}; };
const aiResponse = await chatToGemini(userMessage, history, settings); // Call the Gemini helper function
return NextResponse.json({ response: aiResponse }); const geminiResponse = await chatToGemini(userMessage, history, settings || {});
return NextResponse.json({ response: geminiResponse });
} }
catch (error) { catch (error) {
console.error(error); console.error(error);
return NextResponse.json( return NextResponse.json(
<<<<<<< HEAD
{error: "Error with the model response " + String(error)}, {error: "Error with the model response " + String(error)},
{status : 500} {status : 500}
=======
{ error: "Error with the model response " },
{ status: 500 }
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
); );
} }
} }
+44 -109
View File
@@ -1,90 +1,74 @@
"use client"; "use client";
import { useState, useEffect, useRef, useCallback } from "react"; import { useState, useEffect, useRef, useCallback, Suspense } from "react";
import { useSearchParams, useRouter } 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() {
return (
<Suspense fallback={<div>Loading chat...</div>}>
<ChatbotContent />
</Suspense>
);
}
function ChatbotContent() {
const [history, setHistory] = useState<ChatHistory>([]) const [history, setHistory] = useState<ChatHistory>([])
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const historyRef = useRef<ChatHistory>([]); // Create a ref for history
const [settings] = useState<ChatSetting>({ const [settings] = useState<ChatSetting>({
<<<<<<< HEAD
temperature:1,
model:"gemini-2.5-pro",
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"
=======
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"
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
}); });
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const initialMessageSent = useRef(false); const initialMessageSent = useRef(false);
useEffect(() => {
historyRef.current = history; // Keep the ref updated with the latest history
}, [history]);
const handleSend = useCallback(async (message: string) => { const handleSend = useCallback(async (message: string) => {
const newUserMessage: Message = { const newUserMessage: Message = {
role: "user", role: "user",
parts: [{ text: message }], parts: [{ text: message }],
}; };
setHistory(prevHistory => { const currentHistory = [...history, newUserMessage];
const currentHistory = [...prevHistory, newUserMessage]; setHistory(currentHistory);
setLoading(true);
const sendApiRequest = async () => { try {
<<<<<<< HEAD const response = await fetch("/api/chat", {
setLoading(true); method: "POST",
try{ headers: {
======= "Content-Type": "application/json",
try { },
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a body: JSON.stringify({
const response = await fetch("/api/chat", { userMessage: message,
method: "POST", history: currentHistory,
headers: { settings: settings,
"Content-Type": "application/json", }),
}, });
body: JSON.stringify({
userMessage: message,
history: historyRef.current, // Use the ref for history
settings: settings,
}),
});
const data = await response.json(); const data = await response.json();
if (data.error) { if (data.error) {
console.error("AI Error:", data.error); console.error("AI Error:", data.error);
setLoading(false);
return;
}
const aiMessage: Message = {
role: "model" as MessageRole,
parts: [{ text: data.response }],
};
setHistory(prevHistory => [...prevHistory, aiMessage]);
}
catch (error) {
console.error("Request Failed:", error);
}
setLoading(false); setLoading(false);
}; return;
sendApiRequest(); }
return currentHistory; const aiMessage: Message = {
}); role: "model" as MessageRole,
}, [settings]); // Now handleSend only depends on settings parts: [{ text: data.response }],
};
setHistory((prevHistory) => [...prevHistory, aiMessage]);
} catch (error) {
console.error("Request Failed:", error);
}
setLoading(false);
}, [history, settings]); // Dependencies for useCallback
useEffect(() => { useEffect(() => {
if (!initialMessageSent.current) { if (!initialMessageSent.current) {
@@ -93,61 +77,16 @@ export default function Home() {
if (title && summary) { if (title && summary) {
const message = `Explain the project titled '${title}' with the summary '${summary}' in detail, and suggest suitable roles for a team working on it.`; const message = `Explain the project titled '${title}' with the summary '${summary}' in detail, and suggest suitable roles for a team working on it.`;
// eslint-disable-next-line react-hooks/set-state-in-effect
const newUserMessage: Message = { handleSend(message);
role: "user",
parts: [{ text: message }],
};
setTimeout(() => {
setHistory((prevHistory) => [...prevHistory, newUserMessage]); // Add user message to history
}, 0);
const sendInitialApiRequest = async () => {
setLoading(true);
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userMessage: message,
history: [...historyRef.current, newUserMessage], // Use ref for history
settings: settings,
}),
});
const data = await response.json();
if (data.error) {
console.error("AI Error:", data.error);
setLoading(false);
return;
}
const aiMessage: Message = {
role: "model" as MessageRole,
parts: [{ text: data.response }],
};
setHistory((prevHistory) => [...prevHistory, aiMessage]);
} catch (error) {
console.error("Request Failed:", error);
}
setLoading(false);
};
sendInitialApiRequest();
initialMessageSent.current = true; initialMessageSent.current = true;
} }
} }
}, [searchParams, settings]); // Dependencies for this useEffect }, [searchParams, settings, handleSend]); // Dependencies for this useEffect
return ( return (
<div className="flex flex-col py-32"> <div className="flex flex-col py-32">
<<<<<<< HEAD
<button <button
onClick={() => router.push('/Dashboard')} 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" className="absolute top-4 right-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
@@ -156,10 +95,6 @@ export default function Home() {
</button> </button>
<MessageWindow history={history} isLoading={loading} /> <MessageWindow history={history} isLoading={loading} />
<ChatInput onSend={handleSend} onOpenSettings={() => {}} /> <ChatInput onSend={handleSend} onOpenSettings={() => {}} />
=======
<MessageWindow history={history} />
<ChatInput onSend={handleSend} onOpenSettings={() => { }} />
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
</div> </div>
); );
} }
+51 -121
View File
@@ -2,6 +2,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { motion, useMotionValue, useTransform } from "framer-motion"; import { motion, useMotionValue, useTransform } from "framer-motion";
import { useRouter } from "next/navigation";
// Removed local fallback JSX declaration — use the official React type definitions instead: // Removed local fallback JSX declaration — use the official React type definitions instead:
// install @types/react and @types/react-dom so JSX.IntrinsicElements is provided by those packages. // install @types/react and @types/react-dom so JSX.IntrinsicElements is provided by those packages.
@@ -29,126 +30,49 @@ interface CardData {
tracks: string[]; tracks: string[];
} }
const cardData: CardData[] = [
{
id: 1,
title: " WEBSITE", interface SwipeCardsProps {
initialCards: CardData[];
}
summary: const SwipeCards: React.FC<SwipeCardsProps> = ({ initialCards }) => {
const [cards, setCards] = useState<CardData[]>(initialCards);
"FFind out what makes GoonMAXXER unique.With this innovative website you will be able to explore various features and functionalities that set GoonMAXXER apart from the rest.", const router = useRouter();
tracks: ["Gemini", "Auth0", "VibeCODING", "SmellyMaxxing", "shitposting"],
},
{
id: 2,
title: "Intro to React",
summary:
"Learn the fundamentals of React, including components, state, and props.",
tracks: ["React", "JS", "Frontend"],
},
{
id: 3,
title: "State Management",
summary:
"Explore complex state solutions with Zustand, Redux, and Context API.",
tracks: ["React", "Zustand", "State"],
},
{
id: 4,
title: "Next.js 14",
summary: "Master the app router, server actions, and data fetching.",
tracks: ["Next.js", "React", "Fullstack"],
},
{
id: 5,
title: "UI/UX Principles",
summary:
"A complete guide to user-centric design, prototyping, and testing.",
tracks: ["Design", "UI", "UX"],
},
{
id: 6,
title: "Node.js Essentials",
summary:
"Build scalable, high-performance backend applications with Node.js.",
tracks: ["Node", "Backend", "JS"],
},
{
id: 7,
title: "TypeScript",
summary:
"Add static typing to your JavaScript projects for robust, large-scale apps.",
tracks: ["TypeScript", "JS", "DevOps"],
},
{
id: 8,
title: "Framer Motion",
summary: "Create production-ready animations for your React applications.",
tracks: ["React", "Animation", "Framer"],
},
].reverse();
const SwipeCards: React.FC = () => {
const [cards, setCards] = useState<CardData[]>(cardData);
const onSwipe = () => { const onSwipe = () => {
setCards((prev) => prev.slice(0, prev.length - 1)); setCards((prev) => prev.slice(0, prev.length - 1));
}; };
const handleRightSwipe = async (card: CardData) => {
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userMessage: `Explain the project: ${card.title}. Summary: ${card.summary}. Tracks: ${card.tracks.join(", ")}`,
history: [], // Provide an empty array for history
}),
});
if (!response.ok) {
const errorBody = await response.text(); // Read the response body
throw new Error(`HTTP error! status: ${response.status}, body: ${errorBody}`);
}
// Assuming the chat API handles the message and we can then navigate
router.push(`/chatbot?title=${encodeURIComponent(card.title)}&summary=${encodeURIComponent(card.summary)}`);
} catch (error) {
console.error("Error sending project to chatbot:", error);
// Optionally, handle error state or show a message to the user
}
onSwipe(); // Remove the card after swiping right
};
const handleReset = () => { const handleReset = () => {
setCards(cardData); setCards(initialCards);
}; };
return ( return (
@@ -171,6 +95,7 @@ const SwipeCards: React.FC = () => {
colorWay={colorWay} colorWay={colorWay}
isFront={index === cards.length - 1} isFront={index === cards.length - 1}
onSwipe={onSwipe} onSwipe={onSwipe}
onRightSwipe={handleRightSwipe}
/> />
); );
}) })
@@ -199,10 +124,11 @@ interface CardProps {
cardData: CardData; cardData: CardData;
colorWay: ColorWay; colorWay: ColorWay;
isFront: boolean; isFront: boolean;
onSwipe: () => void; onSwipe: () => void; // For left swipe (reject)
onRightSwipe: (card: CardData) => void; // For right swipe (accept)
} }
const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onSwipe }) => { const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onSwipe, onRightSwipe }) => {
const { title, summary, tracks } = cardData; const { title, summary, tracks } = cardData;
const x = useMotionValue(0); const x = useMotionValue(0);
@@ -218,14 +144,18 @@ const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onSwipe }) =>
const badgeRotate = useTransform(x, [-150, 150], [-15, 15]); const badgeRotate = useTransform(x, [-150, 150], [-15, 15]);
const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => { const handleDragEnd = (event: MouseEvent | TouchEvent | PointerEvent, info: { offset: { x: number } }) => {
if (Math.abs(info.offset.x) > 100) { if (info.offset.x > 100) {
// Swiped right
onRightSwipe(cardData);
} else if (info.offset.x < -100) {
// Swiped left
onSwipe(); onSwipe();
} }
}; };
return ( return (
<motion.div <motion.div
className="absolute flex h-[48rem] w-[36rem] flex-col justify-between overflow-hidden rounded-2xl p-6 shadow-2xl hover:cursor-grab active:cursor-grabbing" className="absolute flex h-[40rem] w-[30rem] flex-col justify-between overflow-hidden rounded-2xl p-6 shadow-2xl hover:cursor-grab active:cursor-grabbing"
style={{ style={{
x, x,
rotate, rotate,
@@ -249,37 +179,37 @@ const Card: React.FC<CardProps> = ({ cardData, colorWay, isFront, onSwipe }) =>
className="absolute left-10 top-10 z-10 rounded-2xl border-8 border-green-500 px-10 py-4" className="absolute left-10 top-10 z-10 rounded-2xl border-8 border-green-500 px-10 py-4"
style={{ opacity: acceptOpacity, rotate: badgeRotate }} style={{ opacity: acceptOpacity, rotate: badgeRotate }}
> >
<h3 className="text-5xl font-bold uppercase text-green-500">Accept</h3> <h3 className="text-2xl font-bold uppercase text-green-500">Accept</h3>
</motion.div> </motion.div>
<motion.div <motion.div
className="absolute right-10 top-10 z-10 rounded-2xl border-8 border-red-500 px-10 py-4" className="absolute right-10 top-10 z-10 rounded-2xl border-8 border-red-500 px-10 py-4"
style={{ opacity: rejectOpacity, rotate: badgeRotate }} style={{ opacity: rejectOpacity, rotate: badgeRotate }}
> >
<h3 className="text-5xl font-bold uppercase text-red-500">Reject</h3> <h3 className="text-2xl font-bold uppercase text-red-500">Reject</h3>
</motion.div> </motion.div>
{/* Card Content */} {/* Card Content */}
<div className="relative z-0"> <div className="relative z-0">
{/* 3. Applied the specific titleColor here */} {/* 3. Applied the specific titleColor here */}
<h2 <h2
className="mb-4 text-center text-7xl font-bold" className="mb-4 text-center text-2xl font-bold"
style={{ color: colorWay.titleColor }} style={{ color: colorWay.titleColor }}
> >
{title} {title}
</h2> </h2>
{/* This summary <p> will inherit colorWay.text from the parent */} {/* This summary <p> will inherit colorWay.text from the parent */}
<p className="text-center text-3xl font-light">{summary}</p> <p className="text-center text-sm font-light">{summary}</p>
</div> </div>
<div className="relative z-0 flex flex-wrap items-center justify-center gap-2"> <div className="relative z-0 flex flex-wrap items-center justify-center gap-2">
{/* This <h3> will also inherit colorWay.text */} {/* This <h3> will also inherit colorWay.text */}
<h3 className="mb-4 w-full text-center text-4xl font-semibold"> <h3 className="mb-4 w-full text-center text-md font-semibold">
Tracks Tracks
</h3> </h3>
{tracks.map((track) => ( {tracks.map((track) => (
<span <span
key={track} key={track}
className="flex items-center justify-center rounded-full px-8 py-3 text-2xl font-medium" className="flex items-center justify-center rounded-full px-2 py-1 text-xs font-medium"
style={{ style={{
// This logic now correctly contrasts with the main text color // This logic now correctly contrasts with the main text color
backgroundColor: backgroundColor:
+2 -1
View File
@@ -23,7 +23,8 @@ export default async function handler(
} }
// Destructure the data sent from the frontend // Destructure the data sent from the frontend
let { prompt, settings } = req.body; let prompt = req.body.prompt;
const settings = req.body.settings;
// Basic validation // Basic validation
if (!prompt || typeof prompt !== 'string') { if (!prompt || typeof prompt !== 'string') {
+44 -130
View File
@@ -1,6 +1,8 @@
"use client"; "use client";
import React, { useState, useEffect, useCallback } from "react"; import React, { useState, useEffect, useCallback, useRef } from "react";
import FormPage from './FormPage'; import FormPage from './FormPage';
import { CardData } from "../exportType/types";
import SwipeCards from "../components/Cards";
import { ChatSetting } from "../exportType/types"; import { ChatSetting } from "../exportType/types";
import { FormData, PROFICIENCY_LEVELS } from './formTypes'; import { FormData, PROFICIENCY_LEVELS } from './formTypes';
@@ -40,87 +42,51 @@ const getInitialState = () => {
}; };
}; };
<<<<<<< HEAD export default function Home() {
const [ideaResponse, setIdeaResponse] = useState<string>(""); const [ideaResponse, setIdeaResponse] = useState<string>("");
const [generatedCards, setGeneratedCards] = useState<CardData[]>([]); // New state for parsed cards const [generatedCards, setGeneratedCards] = useState<CardData[]>([]); // New state for parsed cards
const [initialState] = useState(getInitialState);
const [showForm, setShowForm] = useState(initialState.showForm);
const initialIdeaGenerationAttempted = useRef(false);
const [settings] = useState<ChatSetting>({ const [settings] = useState<ChatSetting>({
temperature: 1, temperature: 1,
model: "gemini-2.5-flash-lite", model: "gemini-2.5-flash-lite",
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. 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.
=======
// FIX 1 (Memoization): Moved settings OUTSIDE the component.
// This makes it a true constant.
const AI_SETTINGS: ChatSetting = {
temperature: 1,
model: "gemini-2.5-pro",
sysTemInstructions: `You are an elite hackathon idea generator. Your task is to generate five different creative, feasible, and relevant project idea.
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
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
<<<<<<< HEAD
**Track** [print out the track you used] **Track** [print out the track you used]
**Concept:** [A concise, single paragraph description of the product and its primary function.]`, **Concept:** [A concise, single paragraph description of the product and its primary function.]`,
}); });
const parseAiResponse = (markdownString: string): CardData[] => {
console.log("Raw AI Response:", markdownString);
const ideas: CardData[] = [];
const ideaBlocks = markdownString.split("### ").filter(block => block.trim() !== "");
ideaBlocks.forEach((block, index) => {
// Match title: anything from the start of the block until the first newline or the start of "**Track**"
const titleMatch = block.match(/^(.*?)(?=\n\*\*Track\*\*|$)/s);
// Match track: "**Track**" followed by optional whitespace and then capture everything until the next "**Concept**" or end of block/line
const trackMatch = block.match(/\*\*Track\*\*\s*:\s*(.*?)(?=\n\*\*Concept\*\*|$)/s); // Added ':' and made whitespace more flexible
// Match concept: "**Concept:**" followed by optional whitespace and then capture everything until the end of the block
const conceptMatch = block.match(/\*\*Concept:\*\*\s*(.*)/s);
const title = titleMatch ? titleMatch[1].trim() : `Idea ${index + 1}`;
const summary = conceptMatch ? conceptMatch[1].trim() : "No concept provided.";
const tracksRaw = trackMatch ? trackMatch[1].trim() : "";
console.log("tracksRaw:", tracksRaw); // Added console.log for debugging
const tracks = tracksRaw.split(',').map(track => track.trim()).filter(track => track !== '');
ideas.push({
id: index + 1,
title,
tracks,
summary,
});
});
console.log("Parsed Cards:", ideas);
return ideas;
};
=======
**Relevance to Theme:** [Explain briefly]
**Core Technology:** [List 3-5 primary technologies]
**Team Fit:** [How the team's skills apply]
**Concept:** [A concise, single paragraph description of the product and its primary function.]
**Bonus Feature:** [A single, ambitious feature to impress judges.]`,
};
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
// ------------------------------------------------
export default function Home() {
const [initialState] = useState(getInitialState);
const [showForm, setShowForm] = useState(initialState.showForm);
const [formData, setFormData] = useState<FormData>(initialState.data);
const [ideaResponse, setIdeaResponse] = useState<string>("");
// The 'settings' state [useState] is now removed from here.
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
setFormData(submittedData);
setShowForm(false);
generateIdeas(submittedData);
};
// Wrapped generateIdeas in useCallback
const generateIdeas = useCallback(async (dataToProcess: FormData) => { const generateIdeas = useCallback(async (dataToProcess: FormData) => {
// 1. Data Cleaning const parseAiResponse = (markdownString: string): CardData[] => {
console.log("Raw AI Response:", markdownString);
const ideas: CardData[] = [];
const ideaBlocks = markdownString.split("### ").filter(block => block.trim() !== "");
ideaBlocks.forEach((block, index) => {
const titleMatch = block.match(/^(.*?)(?=\n\*\*Track\*\*|$)/s);
const trackMatch = block.match(/\*\*Track\*\*\s*:\s*(.*?)(?=\n\*\*Concept\*\*|$)/s);
const conceptMatch = block.match(/\*\*Concept:\*\*\s*(.*)/s);
const title = titleMatch ? titleMatch[1].trim() : `Idea ${index + 1}`;
const summary = conceptMatch ? conceptMatch[1].trim() : "No concept provided.";
const tracksRaw = trackMatch ? trackMatch[1].trim() : "";
const tracks = tracksRaw.split(',').map(track => track.trim()).filter(track => track !== '');
ideas.push({
id: index + 1,
title,
tracks,
summary,
});
});
console.log("Parsed Cards:", ideas);
return ideas;
};
const submissionData: FormData = { const submissionData: FormData = {
...dataToProcess, ...dataToProcess,
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''), tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
@@ -132,7 +98,6 @@ export default function Home() {
.filter(student => student.studentName.trim() !== '' || student.skills.length > 0), .filter(student => student.studentName.trim() !== '' || student.skills.length > 0),
}; };
// 2. Prompt Construction
const prompt = ` const prompt = `
Hackathon: ${submissionData.Hackathon} Hackathon: ${submissionData.Hackathon}
Main Theme: ${submissionData.mainTheme} Main Theme: ${submissionData.mainTheme}
@@ -143,11 +108,9 @@ export default function Home() {
Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`; Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`;
// 3. API Call
try { try {
setIdeaResponse("Generating ideas... Please wait."); setIdeaResponse("Generating ideas... Please wait.");
<<<<<<< HEAD setGeneratedCards([]);
setGeneratedCards([]); // Clear previous cards
const response = await fetch("/api/generate-idea", { const response = await fetch("/api/generate-idea", {
method: "POST", method: "POST",
headers: { headers: {
@@ -161,24 +124,10 @@ export default function Home() {
const data = await response.json(); const data = await response.json();
=======
const response = await fetch("/api/generate-idea", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: prompt,
settings: AI_SETTINGS, // Use the constant
}),
});
const data = await response.json();
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
if (data.error || !response.ok) { if (data.error || !response.ok) {
console.error("AI Error:", data.error); console.error("AI Error:", data.error);
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`); setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
return; return;
<<<<<<< HEAD
} }
setIdeaResponse(data.response); setIdeaResponse(data.response);
@@ -195,42 +144,21 @@ export default function Home() {
} }
setIdeaResponse(`A network error occurred. Please try again. Details: ${errorMessage}`); setIdeaResponse(`A network error occurred. Please try again. Details: ${errorMessage}`);
} }
}, [setIdeaResponse, setGeneratedCards, settings, parseAiResponse]); }, [settings]);
useEffect(() => { useEffect(() => {
if (typeof window !== 'undefined') { if (initialState.runEffect && !initialIdeaGenerationAttempted.current) {
const storedFormData = localStorage.getItem('formData'); // eslint-disable-next-line react-hooks/set-state-in-effect
if (storedFormData) {
const parsedData: FormData = JSON.parse(storedFormData);
setTimeout(() => setShowForm(false), 0);
generateIdeas(parsedData);
localStorage.removeItem('formData');
=======
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
}
setIdeaResponse(data.response);
// FIX 2 (Unexpected any): Changed 'any' to 'unknown' and added a type check.
} catch (error: unknown) {
console.error("Request Failed:", error);
let errorMessage = "A network error occurred. Please try again.";
if (error instanceof Error) {
errorMessage += ` Details: ${error.message}`;
}
setIdeaResponse(errorMessage);
}
// FIX 3 (Linter): Disable the faulty memoization rule.
// The empty array is correct because setIdeaResponse is a stable state setter.
// eslint-disable-next-line react-hooks/preserve-manual-memoization
}, []);
// Replaced useEffect
useEffect(() => {
if (initialState.runEffect) {
generateIdeas(initialState.data); generateIdeas(initialState.data);
initialIdeaGenerationAttempted.current = true;
} }
}, [initialState, generateIdeas]); }, [initialState, generateIdeas]);
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
setShowForm(false);
generateIdeas(submittedData);
};
// --- JSX Rendering --- // --- JSX Rendering ---
return ( return (
<main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter"> <main className="min-h-screen bg-gray-50 flex items-start justify-center p-4 sm:p-6 font-inter">
@@ -239,7 +167,6 @@ export default function Home() {
<FormPage onFormSubmit={handleFormSubmitFromFormPage} /> <FormPage onFormSubmit={handleFormSubmitFromFormPage} />
) : ( ) : (
<> <>
<<<<<<< HEAD
{generatedCards.length > 0 ? ( {generatedCards.length > 0 ? (
<SwipeCards initialCards={generatedCards} /> <SwipeCards initialCards={generatedCards} />
) : ( ) : (
@@ -257,19 +184,6 @@ export default function Home() {
</div> </div>
</> </>
)} )}
=======
<h1 className="text-3xl font-extrabold text-center text-gray-800 mb-8 tracking-tight">
Generated Project Idea 💡
</h1>
<div className="mt-8 p-4 bg-yellow-50 rounded-lg border border-yellow-200">
<h2 className="text-xl font-bold text-gray-700 mb-2">Generated Ideas:</h2>
<div
className="prose max-w-none"
dangerouslySetInnerHTML={{ __html: ideaResponse.replace(/\n/g, '<br/>') }}
/>
{ideaResponse === "" && <p className="text-gray-500">Submit the form to generate project ideas.</p>}
</div>
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
<button <button
onClick={() => setShowForm(true)} onClick={() => setShowForm(true)}
className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150" className="mt-6 w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-lg text-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition duration-150"
+1 -36
View File
@@ -1,35 +1,6 @@
<<<<<<< HEAD
=======
/* @import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
:root {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
} */
/* 1. Import BOTH fonts in one go */ /* 1. Import BOTH fonts in one go */
@import url('https://fonts.googleapis.com/css2?family=Concert+One&family=Pixelify+Sans:wght@400;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Concert+One&family=Pixelify+Sans:wght@400;700&display=swap');
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
@import "tailwindcss"; @import "tailwindcss";
:root { :root {
@@ -43,18 +14,12 @@ body {
/* 3. Assign fonts to Tailwind's theme */ /* 3. Assign fonts to Tailwind's theme */
<<<<<<< HEAD
/* Tell Tailwind to use the variables already defined in app/layout.tsx */
--font-sans: var(--font-sans);
--font-header: var(--font-header);
=======
/* --font-sans is for regular text (Concert One) */ /* --font-sans is for regular text (Concert One) */
--font-sans: var(--font-concert-one); --font-sans: var(--font-concert-one);
/* We add a new font family for headers (Pixelify Sans) */ /* We add a new font family for headers (Pixelify Sans) */
/* This also creates a 'font-header' utility class */ /* This also creates a 'font-header' utility class */
--font-header: var(--font-pixelify); --font-header: var(--font-pixelify);
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
--font-mono: var(--font-geist-mono); --font-mono: var(--font-geist-mono);
} }
@@ -82,4 +47,4 @@ h4,
h5, h5,
h6 { h6 {
font-family: var(--font-header); font-family: var(--font-header);
} }
-281
View File
@@ -1,15 +1,6 @@
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
<<<<<<< HEAD
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
import ProtectedNavButton from "../components/ProtectedNavButton";
import Link from 'next/link';
import { style } from 'framer-motion/client';
=======
export default function Home() { export default function Home() {
return ( return (
<div <div
@@ -34,151 +25,7 @@ export default function Home() {
</a> </a>
</div> </div>
</header> </header>
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
<<<<<<< HEAD
export default function Page() {
<<<<<<< HEAD
  return (
    <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 background-blue-300">
        <Image
          className=""
          src="/logo.svg"
          alt="logo"
          width={100}
          height={20}
          priority
        />
        <div  className="flex items-center gap-4">
          <Link href = "/auth/login" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors container">
            Sign in
          </Link>
          <Link href = "/auth/logout" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors container">
            Log out
          </Link>
        </div>
      </header>
=======
return (
<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">
<Image
className=""
src="/logo.svg"
alt="logo"
width={100}
height={20}
priority
/>
<div className="flex items-center gap-4">
<Link href="/auth/login" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Sign in
</Link>
<Link href="/auth/logout" className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
Log out
</Link>
</div>
</header>
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
<main className="flex min-h-screen w-full flex-col justify-between py-32 px-16 bg-white dark:bg-black">
<div className="flex flex-col sm:flex-row items-start justify-between gap-12 text-left w-full">
<div className="flex-1 flex flex-col gap-5 justify-center">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
(project name)
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<Link
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</Link>{" "}
or the{" "}
<Link
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</Link>{" "}
center.
</p>
<ProtectedNavButton>Get Started</ProtectedNavButton>
</div>
<div className="flex-1 flex justify-center">
<div className="w-full max-w-[400px] h-[300px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500">
Image Placeholder
</div>
</div>
</div>
<section className="mt-32 w-full flex flex-col items-start gap-12">
<div>
<h2 className="text-[28px] font-semibold text-black dark:text-zinc-50 leading-9">
Guide:
</h2>
</div>
<div className="flex flex-col sm:flex-row items-start justify-between gap-8 w-full">
<div className="w-full max-w-xl">
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
First Text Block
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
This is the content for the first text block. You can write anything here.
</p>
</div>
<div className="sm:w-1/2 flex justify-center items-center">
<div className="w-full max-w-[300px] h-[200px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500">
Image Placeholder
</div>
</div>
</div>
<div className="flex flex-col sm:flex-row items-start justify-between gap-8 w-full">
<div className="sm:w-1/2 flex justify-center items-center">
<div className="w-full max-w-[300px] h-[200px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500">
Image Placeholder
</div>
</div>
<div className="flex w-full justify-end">
<div className="w-full max-w-xl">
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
Second Text Block
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
This is the content for the second text block. You can write anything here.
</p>
</div>
</div>
</div>
<div className="flex flex-col sm:flex-row items-start justify-between gap-8 w-full">
<div className="w-full max-w-xl">
<h2 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-2">
Third Text Block
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
This is the content for the third text block. You can write anything here.
</p>
</div>
<div className="sm:w-1/2 flex justify-center items-center">
<div className="w-full max-w-[300px] h-[200px] bg-zinc-200 dark:bg-zinc-800 rounded-xl shadow-md flex items-center justify-center text-zinc-500">
Image Placeholder
</div>
</div>
</div>
</section>
</main>
</div>
);
=======
<main className="flex min-h-screen w-full flex-col justify-between py-32 max-w-[1200px] mx-auto"> <main className="flex min-h-screen w-full flex-col justify-between py-32 max-w-[1200px] mx-auto">
<div className="flex flex-col sm:flex-row items-center justify-center gap-12 text-left w-full max-w-[1200px] mx-auto"> <div className="flex flex-col sm:flex-row items-center justify-center gap-12 text-left w-full max-w-[1200px] mx-auto">
<div className="flex-1 flex flex-col gap-5 justify-center items-start"> <div className="flex-1 flex flex-col gap-5 justify-center items-start">
@@ -297,132 +144,4 @@ export default function Page() {
</main> </main>
</div> </div>
); );
>>>>>>> 44b5a4dc49ea757e9790ba8309edc6b37d764105
} }
// {/* <div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
//           <a
//             className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
//             href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
//             target="_blank"
//             rel="noopener noreferrer"
//           >
//             <Image
//               className="dark:invert"
//               src="/vercel.svg"
//               alt="Vercel logomark"
//               width={16}
//               height={16}
//             />
//             Deploy Now
//           </a>
//           <a
//             className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
//             href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
//             target="_blank"
//             rel="noopener noreferrer"
//           >
//             Documentation
//           </a>
//         </div> */}
// "use client";
// import React, { use, useState } from "react";
// import { useRouter } from "next/navigation";
// export default function Dashboard() {
//   const router = useRouter();  
//   const[query, setQuery] = useState("");
//   // const [projects, setProjects] = useState( [
//   //     { id: 1, name: "Alpha Project", createdAt: new Date("2025-01-01")},
//   //     { id: 2, name: "Beta Board", createdAt: new Date("2025-02-15")},
//   //     { id: 3, name: "Gamma Task", createdAt: new Date("2025-03-10")}
//   // ]);
//   // const [newProjectName, setNewProjectName] = useState("");
//   // const filtered = projects.filter( (p) => p.name.toLowerCase().includes(query.toLowerCase()) );
//   // const handleCreate = () => {
//   //   if(!newProjectName.trim()) return;
//   //   const newProject = {
//   //     id: projects.length+1, name: newProjectName, createdAt: new Date(),
//   //   };
//   // };
//   const projects = [
//     {name: "Alpha Project", createdAt: "2025-01-01"},
//     {name: "Beta Board", createdAt: "2025-02-15"},
//     {name: "Gamma Tasl", createdAt: "2025-03-10"},
//   ]
//   const filtered = projects.filter(
//     (p) => p.name.toLowerCase().includes(query.toLowerCase())
//   );
//  return (
//    <div className="min-h-screen bg-zinc-50 dark:bg-black font-sans">
//      <header className="sticky top-0 z-10 bg-white dark:bg-black/80 backdrop-blur-sm border-b border-zinc-200 dark:border-zinc-800">
//        <div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between gap-4">
//          <div className="flex-1">
//            {/* <label htmlFor="dashboard-search" className="sr-only">
//              Search
//            </label> */}
//            <input
//              id="dashboard-search"
//              value={query}
//              onChange={(e) => setQuery(e.target.value)}
//              placeholder="Search projects, boards or tasks..."
//              className="w-full max-w-md px-4 py-2 rounded-md border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
//            />
//          </div>
//          <div className="flex items-center gap-2">
//            {/* <input
//               type = "text"
//               value = {newProjectName}
//               onChange = { (e) => setNewProjectName(e.target.value)}
//               placeholder="New Project Name"
//               className="px-3 py-2 rounded-md border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900  text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
//             /> */}
//             <button
//              type="button"
//              // className="ml-4 inline-flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md shadow-sm"
//              // onClick={() => alert("Create clicked — wire up creation flow here.")}
//               onClick={ () => router.push("/dashbaord/create")}
//               className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md shadow-sm"
//            >
//              Create
//            </button>
//          </div>
//        </div>
//      </header>
//      <main className="max-w-7xl mx-auto px-6 py-10">
//        <h1 className="text-2xl font-semibold text-black dark:text-zinc-50 mb-4">
//          Project Names
//        </h1>
//        <section>
//          <ul className="space-y-3">
//            {filtered.map((project, index) => (
//              <li
//                key={index}
//                // className="p-4 bg-white dark:bg-zinc-900 border border-zinc-100 dark:border-zinc-800 rounded-md text-zinc-800 dark:text-zinc-100"
//                 className="flex justify-between p-4 bg-white dark:bg-zinc-900 border border-zinc-100 dark:border-zinc-800 rounded-md text-zinc-800 dark:text-zinc-100"
//               >
//                <span>{project.name}</span>
//                 <span className="text-zinc-500 dark:text-zinc-400 text-sm">
//                   {/* {project.createdAt.toLocaleDateString()} */}
//                   Created: {project.createdAt}
//                 </span>
//              </li>
//            ))}
//            {filtered.length === 0 && (
//              <li className="text-zinc-500">No results found</li>
//            )}
//          </ul>
//        </section>
//      </main>
//    </div>
//  );
// }
+1 -18
View File
@@ -3,22 +3,13 @@ import { useRef, useEffect } from "react";
import { ChatHistory } from "@/app/exportType/types"; import { ChatHistory } from "@/app/exportType/types";
import { User, Bot } from "lucide-react" import { User, Bot } from "lucide-react"
<<<<<<< HEAD
interface MessageWindowProps{ interface MessageWindowProps{
history :ChatHistory; history :ChatHistory;
isLoading: boolean; isLoading: boolean;
} }
export default function MessageWindow({history, isLoading}:MessageWindowProps){ export default function MessageWindow({history, isLoading}:MessageWindowProps){
const messageEndRef = useRef<HTMLDivVElement>(null);
=======
interface MessageWindowProps {
history: ChatHistory
}
export default function MessageWindow({ history }: MessageWindowProps) {
const messageEndRef = useRef<HTMLDivElement>(null); const messageEndRef = useRef<HTMLDivElement>(null);
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
useEffect(() => { useEffect(() => {
messageEndRef.current?.scrollIntoView({ behavior: "smooth" }); messageEndRef.current?.scrollIntoView({ behavior: "smooth" });
@@ -59,7 +50,6 @@ export default function MessageWindow({ history }: MessageWindowProps) {
</div> </div>
)} )}
</div> </div>
<<<<<<< HEAD
); );
})} })}
@@ -79,14 +69,7 @@ export default function MessageWindow({ history }: MessageWindowProps) {
)} )}
{/* Invisible element to help scroll to bottom */} {/* Invisible element to help scroll to bottom */}
<div ref={messageEndRef} /> <div ref={messageEndRef} />
=======
);
})}
{/* Invisible element to help scroll to bottom */}
<div ref={messageEndRef} />
</div>
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
</div> </div>
</div>
); );
} }
+7 -21
View File
@@ -10,7 +10,6 @@ if (!apiKey) {
const genAI = new GoogleGenerativeAI(apiKey); const genAI = new GoogleGenerativeAI(apiKey);
export async function chatToGemini( export async function chatToGemini(
<<<<<<< HEAD
userMessage:string , userMessage:string ,
history:ChatHistory, history:ChatHistory,
settings:ChatSetting settings:ChatSetting
@@ -26,23 +25,6 @@ export async function chatToGemini(
responseMimeType: "text/plain", responseMimeType: "text/plain",
maxOutputTokens: 1900, // Increased to allow for longer responses maxOutputTokens: 1900, // Increased to allow for longer responses
} }
=======
userMessage: string,
history: ChatHistory,
settings: ChatSetting
): Promise<string> {
const model = genAI.getGenerativeModel({
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",
});
>>>>>>> ce9e6f34ed31b7bff736cc9ba9a1b8dcdec85f3a
const generationConfig: GenerateConfig = {
temperature: settings.temperature || 1,
topP: 0.9,
responseMimeType: "text/plain",
maxOutputTokens: 1900, // Increased to allow for longer responses
}
const chatSession = model.startChat({ const chatSession = model.startChat({
generationConfig, generationConfig,
@@ -53,8 +35,12 @@ export async function chatToGemini(
const result = await chatSession.sendMessage(userMessage); const result = await chatSession.sendMessage(userMessage);
return result.response.text(); return result.response.text();
} }
catch (error) { catch (error: unknown) {
console.error(error) if (error instanceof Error) {
throw error console.error("Error in chatToGemini:", error.name, error.message, error);
} else {
console.error("Unknown error in chatToGemini:", error);
}
throw error;
} }
} }