mirror of
https://github.com/PinkSheep27/SBU-Hackathon.git
synced 2026-10-11 00:30:26 -04:00
got rid of the excess whitespaces and added the maxOutputTokens into the GenerateConfig in the types.ts
This commit is contained in:
+10
-10
@@ -2,9 +2,9 @@
|
||||
|
||||
import React, { useState } from "react";
|
||||
|
||||
import {
|
||||
FormData,
|
||||
PROFICIENCY_LEVELS
|
||||
import {
|
||||
FormData,
|
||||
PROFICIENCY_LEVELS
|
||||
} from './formTypes'; // Ensure path is correct
|
||||
|
||||
interface FormPageProps {
|
||||
@@ -16,9 +16,9 @@ const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
||||
Hackathon: '',
|
||||
mainTheme: '',
|
||||
tracksStack: [''],
|
||||
students: [{
|
||||
studentName: '',
|
||||
skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
||||
students: [{
|
||||
studentName: '',
|
||||
skills: [{ skillName: '', proficiency: PROFICIENCY_LEVELS[1] }]
|
||||
}],
|
||||
});
|
||||
|
||||
@@ -121,12 +121,12 @@ const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
||||
<label htmlFor="hackathonName" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Hackathon Name
|
||||
</label>
|
||||
<input
|
||||
<input
|
||||
id="hackathonName"
|
||||
required
|
||||
type="text"
|
||||
placeholder="e.g., Google Code Jam"
|
||||
name="Hackathon"
|
||||
name="Hackathon"
|
||||
value={formData.Hackathon}
|
||||
onChange={handleChange}
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
||||
@@ -142,7 +142,7 @@ const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
||||
required
|
||||
type="text"
|
||||
placeholder="e.g., Sustainability or AI Ethics"
|
||||
name="mainTheme"
|
||||
name="mainTheme"
|
||||
value={formData.mainTheme}
|
||||
onChange={handleChange}
|
||||
className="mt-1 block w-full px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 transition duration-150"
|
||||
@@ -161,7 +161,7 @@ const FormPage: React.FC<FormPageProps> = ({ onFormSubmit }) => {
|
||||
type="text"
|
||||
required
|
||||
placeholder={`Tracks #${index + 1}`}
|
||||
name={`tracksStack-${index}`}
|
||||
name={`tracksStack-${index}`}
|
||||
value={tracks}
|
||||
onChange={(e) => handleTracksChange(e, index)}
|
||||
className="flex-grow px-4 py-2 border border-gray-300 rounded-lg shadow-sm focus:ring-green-500 focus:border-green-500 transition duration-150"
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface Student {
|
||||
// Updated main form interface
|
||||
export interface FormData {
|
||||
Hackathon: string;
|
||||
mainTheme: string;
|
||||
mainTheme: string;
|
||||
tracksStack: string[];
|
||||
students: Student[]; // Array for dynamic students
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
// IMPORTANT: The GEMINI_API_KEY should be an environment variable.
|
||||
const apiKey = process.env.GEMINI_API_KEY;
|
||||
|
||||
if(!apiKey){
|
||||
throw new Error("api key not found");
|
||||
if (!apiKey) {
|
||||
throw new Error("api key not found");
|
||||
}
|
||||
const ai = new GoogleGenerativeAI(apiKey);
|
||||
|
||||
@@ -24,7 +24,7 @@ export default async function handler(
|
||||
|
||||
// Destructure the data sent from the frontend
|
||||
let { prompt, settings } = req.body;
|
||||
|
||||
|
||||
// Basic validation
|
||||
if (!prompt || typeof prompt !== 'string') {
|
||||
return res.status(400).json({ error: 'Prompt is required' });
|
||||
@@ -37,32 +37,32 @@ export default async function handler(
|
||||
|
||||
try {
|
||||
// 1. Call the Gemini API using the correct method signature
|
||||
|
||||
|
||||
const model = settings?.model || 'gemini-2.5-flash-lite';
|
||||
const generativeModel = ai.getGenerativeModel({ model });
|
||||
|
||||
// 1. Define the generation configuration object
|
||||
// 1. Define the generation configuration object
|
||||
const generationConfig = {
|
||||
temperature: settings?.temperature || 0.9,
|
||||
// The SDK property name for system instructions is 'systemInstruction'
|
||||
systemInstruction: settings?.sysTemInstructions,
|
||||
systemInstruction: settings?.sysTemInstructions,
|
||||
};
|
||||
|
||||
// 2. Call generateContent with the single GenerateContentRequest object.
|
||||
const result = await generativeModel.generateContent({
|
||||
// contents must be an array of Content objects
|
||||
contents: [{
|
||||
role: "user",
|
||||
role: "user",
|
||||
parts: [{ text: prompt }]
|
||||
}],
|
||||
|
||||
}],
|
||||
|
||||
// The fixed property name that resolves the TypeScript error
|
||||
generationConfig: generationConfig,
|
||||
generationConfig: generationConfig,
|
||||
});
|
||||
|
||||
// 2. Extract the response text
|
||||
// The result object now contains a property 'text' at the top level for simple text generation
|
||||
const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
|
||||
const geminiResponseText = result.response.text(); res.status(200).json({ response: geminiResponseText });
|
||||
|
||||
} catch (error) {
|
||||
console.error("Gemini API Error:", error);
|
||||
|
||||
+69
-69
@@ -41,35 +41,35 @@ The output MUST be in Markdown format and strictly follow this structure:
|
||||
**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() !== "");
|
||||
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);
|
||||
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 !== '');
|
||||
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,
|
||||
ideas.push({
|
||||
id: index + 1,
|
||||
title,
|
||||
tracks,
|
||||
summary,
|
||||
});
|
||||
});
|
||||
});
|
||||
console.log("Parsed Cards:", ideas);
|
||||
return ideas;
|
||||
};
|
||||
console.log("Parsed Cards:", ideas);
|
||||
return ideas;
|
||||
};
|
||||
|
||||
const handleFormSubmitFromFormPage = (submittedData: FormData) => {
|
||||
setFormData(submittedData);
|
||||
@@ -80,14 +80,14 @@ const parseAiResponse = (markdownString: string): CardData[] => {
|
||||
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
||||
const generateIdeas = useCallback(async (dataToProcess: FormData) => {
|
||||
const submissionData: FormData = {
|
||||
...dataToProcess,
|
||||
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
|
||||
students: dataToProcess.students
|
||||
.map(student => ({
|
||||
...student,
|
||||
skills: student.skills.filter(skill => skill.skillName.trim() !== ''),
|
||||
}))
|
||||
.filter(student => student.studentName.trim() !== '' || student.skills.length > 0),
|
||||
...dataToProcess,
|
||||
tracksStack: dataToProcess.tracksStack.filter(tracks => tracks.trim() !== ''),
|
||||
students: dataToProcess.students
|
||||
.map(student => ({
|
||||
...student,
|
||||
skills: student.skills.filter(skill => skill.skillName.trim() !== ''),
|
||||
}))
|
||||
.filter(student => student.studentName.trim() !== '' || student.skills.length > 0),
|
||||
};
|
||||
|
||||
const prompt = `
|
||||
@@ -95,46 +95,46 @@ const parseAiResponse = (markdownString: string): CardData[] => {
|
||||
Main Theme: ${submissionData.mainTheme}
|
||||
Required Tracks Stack: ${submissionData.tracksStack.join(', ')}
|
||||
Team Members and Skills: ${submissionData.students.map(s =>
|
||||
`${s.studentName || 'Unamed Member'} (Skills: ${s.skills.map(sk => `${sk.skillName} - ${sk.proficiency}`).join(', ')})`
|
||||
`${s.studentName || 'Unamed Member'} (Skills: ${s.skills.map(sk => `${sk.skillName} - ${sk.proficiency}`).join(', ')})`
|
||||
).join('; ')}
|
||||
|
||||
Using the SYSTEM INSTRUCTIONS, generate 5 project ideas based on the data above.`;
|
||||
|
||||
try {
|
||||
setIdeaResponse("Generating ideas... Please wait.");
|
||||
setGeneratedCards([]); // Clear previous cards
|
||||
const response = await fetch("/api/generate-idea", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prompt: prompt,
|
||||
settings: settings,
|
||||
}),
|
||||
});
|
||||
setIdeaResponse("Generating ideas... Please wait.");
|
||||
setGeneratedCards([]); // Clear previous cards
|
||||
const response = await fetch("/api/generate-idea", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prompt: prompt,
|
||||
settings: settings,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error || !response.ok) {
|
||||
console.error("AI Error:", data.error);
|
||||
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
|
||||
return;
|
||||
}
|
||||
if (data.error || !response.ok) {
|
||||
console.error("AI Error:", data.error);
|
||||
setIdeaResponse(`Error: Failed to generate idea. ${data.error || response.statusText}`);
|
||||
return;
|
||||
}
|
||||
|
||||
setIdeaResponse(data.response);
|
||||
const parsedCards = parseAiResponse(data.response);
|
||||
setGeneratedCards(parsedCards);
|
||||
setIdeaResponse(data.response);
|
||||
const parsedCards = parseAiResponse(data.response);
|
||||
setGeneratedCards(parsedCards);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Request Failed:", error);
|
||||
let errorMessage = "An unknown error occurred.";
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message;
|
||||
} else if (typeof error === 'string') {
|
||||
errorMessage = error;
|
||||
}
|
||||
setIdeaResponse(`A network error occurred. Please try again. Details: ${errorMessage}`);
|
||||
console.error("Request Failed:", error);
|
||||
let errorMessage = "An unknown error occurred.";
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message;
|
||||
} else if (typeof error === 'string') {
|
||||
errorMessage = error;
|
||||
}
|
||||
setIdeaResponse(`A network error occurred. Please try again. Details: ${errorMessage}`);
|
||||
}
|
||||
}, [setIdeaResponse, setGeneratedCards, settings, parseAiResponse]);
|
||||
|
||||
@@ -165,12 +165,12 @@ const parseAiResponse = (markdownString: string): CardData[] => {
|
||||
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>}
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user