Skip to content

Commit e429383

Browse files
authored
Merge pull request #26 from SwanHacks2025/gemini
Gemini
2 parents f5f5089 + 883a327 commit e429383

17 files changed

Lines changed: 1917 additions & 20 deletions

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"lint": "eslint"
1111
},
1212
"dependencies": {
13+
"@google/genai": "^1.29.1",
1314
"@radix-ui/react-accordion": "^1.2.12",
1415
"@radix-ui/react-avatar": "^1.1.11",
1516
"@radix-ui/react-checkbox": "^1.3.3",

src/app/api/gemini/search/route.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { GoogleGenAI } from '@google/genai';
3+
4+
export interface GeminiEventResult {
5+
name: string;
6+
description: string;
7+
category?: string;
8+
location: string;
9+
date?: string;
10+
time?: string;
11+
sourceUrl?: string;
12+
}
13+
14+
export async function POST(request: NextRequest) {
15+
try {
16+
const { query, location } = await request.json();
17+
18+
if (!query || typeof query !== 'string') {
19+
return NextResponse.json(
20+
{ error: 'Query is required' },
21+
{ status: 400 }
22+
);
23+
}
24+
25+
const apiKey = process.env.NEXT_PUBLIC_GOOGLE_GEMINI_KEY;
26+
if (!apiKey) {
27+
return NextResponse.json(
28+
{ error: 'Gemini API key not configured' },
29+
{ status: 500 }
30+
);
31+
}
32+
33+
const genAI = new GoogleGenAI({ apiKey });
34+
35+
// Construct the search prompt
36+
const searchLocation = location ? ` in ${location}` : '';
37+
const prompt = `Search the web for upcoming volunteer events, community events, and local activities${searchLocation} related to: "${query}"
38+
39+
Please provide a JSON array of events with the following structure for each event:
40+
{
41+
"name": "Event name",
42+
"description": "Brief description of the event",
43+
"category": "One of: Volunteering, Sports, Tutoring, or other relevant category",
44+
"location": "Full address or location name",
45+
"date": "Date in YYYY-MM-DD format if available",
46+
"time": "Time in HH:MM format if available",
47+
"sourceUrl": "URL where this event was found (if available)"
48+
}
49+
50+
Return only valid JSON array, no additional text. If you find events, return an array. If no events are found, return an empty array [].`;
51+
52+
try {
53+
const response = await genAI.models.generateContent({
54+
model: 'gemini-2.0-flash-exp', // Updated to use a more recent model
55+
contents: prompt,
56+
});
57+
58+
const text = response.text || '';
59+
60+
if (!text) {
61+
console.error('Empty response from Gemini API');
62+
return NextResponse.json(
63+
{ error: 'Empty response from AI', events: [] },
64+
{ status: 500 }
65+
);
66+
}
67+
68+
// Try to extract JSON from the response
69+
let events: GeminiEventResult[] = [];
70+
try {
71+
// Remove markdown code blocks if present
72+
const jsonMatch = text.match(/\[[\s\S]*\]/);
73+
if (jsonMatch) {
74+
events = JSON.parse(jsonMatch[0]);
75+
} else {
76+
// Try parsing the entire text
77+
events = JSON.parse(text);
78+
}
79+
} catch (parseError) {
80+
console.error('Failed to parse Gemini response:', parseError);
81+
console.error('Response text:', text);
82+
// Return empty array if parsing fails
83+
events = [];
84+
}
85+
86+
// Validate and clean the events
87+
const validEvents = events
88+
.filter((event) => event.name && event.location)
89+
.map((event) => ({
90+
name: event.name.trim(),
91+
description: event.description?.trim() || '',
92+
category: event.category?.trim() || 'Volunteering',
93+
location: event.location.trim(),
94+
date: event.date?.trim(),
95+
time: event.time?.trim(),
96+
sourceUrl: event.sourceUrl?.trim(),
97+
}));
98+
99+
return NextResponse.json({ events: validEvents });
100+
} catch (apiError) {
101+
console.error('Gemini API call error:', apiError);
102+
const errorMessage = apiError instanceof Error ? apiError.message : 'Unknown API error';
103+
const errorStack = apiError instanceof Error ? apiError.stack : undefined;
104+
console.error('Error stack:', errorStack);
105+
106+
return NextResponse.json(
107+
{
108+
error: 'Failed to call Gemini API',
109+
details: errorMessage,
110+
events: []
111+
},
112+
{ status: 500 }
113+
);
114+
}
115+
} catch (error) {
116+
console.error('Request processing error:', error);
117+
return NextResponse.json(
118+
{
119+
error: 'Failed to process request',
120+
details: error instanceof Error ? error.message : 'Unknown error',
121+
events: []
122+
},
123+
{ status: 500 }
124+
);
125+
}
126+
}
127+

0 commit comments

Comments
 (0)