Skip to content

Commit 9113dad

Browse files
committed
feat: Integrate Google Gemini AI for repository structure analysis
1 parent 9c597f6 commit 9113dad

File tree

4 files changed

+94
-55
lines changed

4 files changed

+94
-55
lines changed

package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@google/generative-ai": "^0.21.0",
1213
"@octokit/rest": "^21.0.2",
1314
"@radix-ui/react-dialog": "^1.1.2",
1415
"@radix-ui/react-form": "^0.1.0",

src/app/api/feedback/route.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { GoogleGenerativeAI } from '@google/generative-ai';
2+
import { NextResponse } from 'next/server';
3+
4+
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_GEMINI_API_KEY || '');
5+
6+
export async function POST(req: Request) {
7+
try {
8+
const { prompt } = await req.json();
9+
10+
// Add input validation
11+
if (!prompt) {
12+
return NextResponse.json(
13+
{ error: 'Prompt is required' },
14+
{ status: 400 }
15+
);
16+
}
17+
18+
const model = genAI.getGenerativeModel({ model: "gemini-pro"});
19+
20+
const result = await model.generateContent(prompt);
21+
const response = await result.response;
22+
const feedback = response.text();
23+
24+
return NextResponse.json({ feedback });
25+
} catch (error) {
26+
console.error('Gemini API error:', error);
27+
28+
// More detailed error response
29+
return NextResponse.json(
30+
{
31+
error: 'Failed to generate feedback',
32+
details: error instanceof Error ? error.message : 'Unknown error'
33+
},
34+
{ status: 500 }
35+
);
36+
}
37+
}

src/components/ai-feedback.tsx

Lines changed: 47 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default function AIFeedback({
2424
const [isOpen, setIsOpen] = useState(false);
2525
const [isGenerating, setIsGenerating] = useState(false);
2626
const [generatedDocs, setGeneratedDocs] = useState<string | null>(null);
27+
const [error, setError] = useState<string | null>(null);
2728

2829
const generateStructureDocs = (
2930
structure: StructureMap,
@@ -46,61 +47,50 @@ export default function AIFeedback({
4647

4748
const generatePrompt = (structure: StructureMap): string => {
4849
const structureDocs = generateStructureDocs(structure);
49-
return `As an expert software architect, provide a 2-3 sentence feedback on the repository structure.
50+
return `You are an expert software architect. Analyze this repository structure and provide concise, actionable feedback on:
51+
1. Code organization and modularity.
52+
2. Best practices or areas for improvement.
53+
3. Architectural concerns, if any.
5054
5155
Project Structure:
52-
56+
5357
${structureDocs}
54-
55-
Feedback:`;
56-
};
57-
58-
const extractFeedback = (response: string): string => {
59-
const feedbackIndex = response.indexOf('Feedback:');
60-
return feedbackIndex !== -1
61-
? response.slice(feedbackIndex + 9).trim()
62-
: response.trim();
58+
59+
Provide your feedback in a structured format, using bullet points or numbered lists. Keep your response practical and to the point, limited to 2-3 sentences.`;
6360
};
6461

6562
const handleGenerate = async () => {
63+
// Reset previous states
6664
setIsGenerating(true);
65+
setGeneratedDocs(null);
66+
setError(null);
6767

6868
try {
6969
const prompt = generatePrompt(structureMap);
70-
const response = await fetch(
71-
'https://api-inference.huggingface.co/models/Qwen/Qwen2.5-1.5B-Instruct',
72-
{
73-
method: 'POST',
74-
headers: {
75-
'Content-Type': 'application/json',
76-
Authorization: `Bearer ${process.env.NEXT_PUBLIC_HUGGINGFACE_API_KEY}`,
77-
},
78-
body: JSON.stringify({
79-
inputs: prompt,
80-
parameters: {
81-
max_length: 12000,
82-
temperature: 0.9,
83-
top_p: 0.95,
84-
},
85-
}),
70+
const response = await fetch('/api/feedback', {
71+
method: 'POST',
72+
headers: {
73+
'Content-Type': 'application/json',
8674
},
87-
);
75+
body: JSON.stringify({ prompt }),
76+
});
77+
78+
const responseData = await response.json();
8879

8980
if (!response.ok) {
90-
throw new Error('Failed to generate feedback');
81+
throw new Error(responseData.error || 'Failed to generate feedback');
9182
}
9283

93-
const result = await response.json();
94-
95-
if (result && result[0]?.generated_text) {
96-
const feedback = extractFeedback(result[0].generated_text);
97-
setGeneratedDocs(feedback);
98-
} else {
99-
throw new Error('Invalid response format');
100-
}
84+
setGeneratedDocs(responseData.feedback);
10185
} catch (error) {
10286
console.error('Error generating feedback:', error);
103-
setGeneratedDocs('Error generating feedback. Please try again.');
87+
88+
const errorMessage = error instanceof Error
89+
? error.message
90+
: 'An unexpected error occurred';
91+
92+
setError(errorMessage);
93+
setGeneratedDocs(null);
10494
} finally {
10595
setIsGenerating(false);
10696
}
@@ -109,38 +99,41 @@ Feedback:`;
10999
return (
110100
<>
111101
<Button onClick={() => setIsOpen(true)} className="mt-4 w-full md:w-auto">
112-
<MessageSquare className="h-4 w-4" /> Generate Feedback
102+
<MessageSquare className="h-4 w-4 mr-2" /> Generate Feedback
113103
</Button>
114104
<Dialog open={isOpen} onOpenChange={setIsOpen}>
115105
<DialogContent className="sm:max-w-[800px] max-h-[90vh] flex flex-col">
116106
<DialogHeader>
117-
<DialogTitle>Generate AI Feedback</DialogTitle>
107+
<DialogTitle>AI Repository Analysis</DialogTitle>
118108
<DialogDescription>
119-
Get feedback on your repository structure.
120-
<em className="block mt-2">
121-
Instructions: First, generate your repository structure, then
122-
click Generate Feedback.
123-
</em>
109+
Get expert feedback on your repository structure and organization using Gemini AI.
124110
</DialogDescription>
125111
</DialogHeader>
126112

127113
<div className="flex-grow overflow-hidden my-6">
128114
{isGenerating ? (
129115
<div className="flex flex-col items-center justify-center h-full space-y-4">
130116
<Loader2 className="h-6 w-6 animate-spin" />
131-
<p className="text-sm text-gray-500">Generating feedback...</p>
117+
<p className="text-sm text-gray-500">Analyzing repository structure...</p>
118+
</div>
119+
) : error ? (
120+
<div className="text-center text-red-500">
121+
<p>Error: {error}</p>
122+
<p className="text-sm text-gray-500 mt-2">Please try again or check your API setup.</p>
132123
</div>
133124
) : generatedDocs ? (
134125
<div className="h-full overflow-y-auto">
135126
<Card>
136127
<div className="p-4 h-full overflow-y-auto">
137-
<p className="text-sm whitespace-pre-wrap">
138-
{generatedDocs}
139-
</p>
128+
<p className="text-sm whitespace-pre-wrap">{generatedDocs}</p>
140129
</div>
141130
</Card>
142131
</div>
143-
) : null}
132+
) : (
133+
<div className="text-center text-gray-500">
134+
Click Generate to analyze your repository structure
135+
</div>
136+
)}
144137
</div>
145138

146139
<DialogFooter>
@@ -151,18 +144,17 @@ Feedback:`;
151144
>
152145
{isGenerating ? (
153146
<>
154-
<Loader2 className="h-4 w-4 animate-spin" />
155-
Generating...
147+
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
148+
Analyzing...
156149
</>
157150
) : (
158-
'Generate'
151+
'Generate Analysis'
159152
)}
160153
</Button>
161154
</DialogFooter>
162155
<p className="mt-4 text-sm text-gray-600">
163156
<em>
164-
Note: This feedback is generated by an AI model and may not always
165-
be accurate. Use it as a general guideline.
157+
Note: This feedback is AI-generated and meant as a general guide.
166158
</em>
167159
</p>
168160
</DialogContent>

0 commit comments

Comments
 (0)