Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:

permissions:
contents: read
pull-requests: write

steps:
- name: Checkout
Expand Down
25 changes: 18 additions & 7 deletions src/app/ai-generator/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use client';
'use client';

import { useState } from 'react';
import { Button } from '@/components/ui/button';
Expand All @@ -7,11 +7,13 @@ import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Download, FileText, Loader2, Sparkles, Brain, Upload, X, Send, MessageSquare, Plus } from 'lucide-react';
import { Download, FileText, Loader2, Sparkles, Upload, X, Send, MessageSquare, Plus, Brain } from 'lucide-react';
import { exportToPDF, exportToWord } from '@/lib/document-utils';


import Aurora from '@/components/Backgrounds/Aurora';
import { NavbarDemo } from '@/components/nav';
import Footer from '@/components/footer';

export default function AIGenerator() {
const [formData, setFormData] = useState({
Expand Down Expand Up @@ -95,7 +97,6 @@ export default function AIGenerator() {
setGeneratedContent(cleanContent);
setStatusMessage({type: 'success', text: 'Assignment generated successfully!'});
setChatMessages([]);
setShowChat(true);

updateUsage('generation');
} catch (error) {
Expand Down Expand Up @@ -133,16 +134,16 @@ export default function AIGenerator() {
});

const data = await response.json();
if (data.error) throw new Error(data.error);
if (data.error) throw new Error(data.error as string);

// Add assistant response and update content if modified
setChatMessages(prev => [...prev, { role: 'assistant', content: data.response }]);
if (data.updatedContent) {
setGeneratedContent(data.updatedContent);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
setChatMessages(prev => [...prev, { role: 'assistant', content: 'Sorry, I encountered an error. Please try again.' }]);
const errorMsg = (error as Error).message || 'Unknown error';
setChatMessages(prev => [...prev, { role: 'assistant', content: `Sorry, I encountered an error: ${errorMsg}. Please try again.` }]);
} finally {
setIsChatting(false);
}
Expand Down Expand Up @@ -185,6 +186,8 @@ export default function AIGenerator() {

return (
<div className="relative bg-slate-900 min-h-screen">
{/* Navbar */}
<NavbarDemo />
{/* Simple Header */}
<div className="relative z-10 bg-slate-900/50 backdrop-blur-sm border-b border-white/10">
<div className="max-w-7xl mx-auto px-4 py-4">
Expand All @@ -211,7 +214,7 @@ export default function AIGenerator() {
/>
</div>

<div className="relative z-10 pt-20 pb-16">
<div className="relative z-10 pt-24 pb-16">
<div className="max-w-7xl mx-auto px-4">
{/* Hero Section */}
<div className="text-center mb-12">
Expand Down Expand Up @@ -263,6 +266,7 @@ export default function AIGenerator() {
onChange={(e) => setFormData({...formData, topic: e.target.value})}
placeholder="Enter assignment topic"
className="bg-white/10 border-white/20 text-white placeholder:text-white/60"
suppressHydrationWarning
/>
</div>

Expand All @@ -274,6 +278,7 @@ export default function AIGenerator() {
onChange={(e) => setFormData({...formData, subject: e.target.value})}
placeholder="e.g., Computer Science, History"
className="bg-white/10 border-white/20 text-white placeholder:text-white/60"
suppressHydrationWarning
/>
</div>

Expand Down Expand Up @@ -344,6 +349,7 @@ export default function AIGenerator() {
onChange={(e) => setFormData({...formData, imageQuery: e.target.value})}
placeholder="e.g., sunflower, DNA structure, solar system"
className="bg-white/10 border-white/20 text-white placeholder:text-white/60"
suppressHydrationWarning
/>
</div>
)}
Expand Down Expand Up @@ -487,6 +493,7 @@ export default function AIGenerator() {
<div className="text-center text-white/60 py-8">
<MessageSquare className="mx-auto h-8 w-8 mb-2 opacity-50" />
<p className="text-sm">Ask me to modify your assignment!</p>
<p className="text-xs mt-1 opacity-75">Try: &quot;Make it shorter&quot; or &quot;Add examples&quot;</p>
<p className="text-xs mt-1 opacity-75">Try: &ldquo;Make it shorter&rdquo; or &ldquo;Add examples&rdquo;</p>
</div>
) : (
Expand Down Expand Up @@ -520,6 +527,7 @@ export default function AIGenerator() {
className="bg-white/10 border-white/20 text-white placeholder:text-white/60 text-sm"
onKeyPress={(e) => e.key === 'Enter' && !e.shiftKey && handleChatSubmit()}
disabled={isChatting}
suppressHydrationWarning
/>
<Button
onClick={handleChatSubmit}
Expand All @@ -538,6 +546,9 @@ export default function AIGenerator() {
</div>
</div>
</div>

{/* Footer */}
<Footer />
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/app/api/chat-assignment/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Please provide a helpful response about the assignment. If the user is asking fo
} catch (error: unknown) {
console.error('Chat error:', error);
return NextResponse.json({
error: error instanceof Error ? error.message : 'Failed to process chat request'
error: (error as Error).message || 'Failed to process chat request'
}, { status: 500 });
}
Expand Down
1 change: 1 addition & 0 deletions src/app/api/export-document/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export async function POST(req: NextRequest) {
filename: `${title || 'assignment'}.pdf`
});
} catch (error: unknown) {
return NextResponse.json({ error: error instanceof Error ? error.message : 'Export failed' }, { status: 500 });
return NextResponse.json({ error: (error as Error).message || 'Export failed' }, { status: 500 });
}
}
1 change: 1 addition & 0 deletions src/app/api/fetch-image/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export async function POST(req: NextRequest) {

return NextResponse.json({ error: 'No images found' }, { status: 404 });
} catch (error: unknown) {
return NextResponse.json({ error: error instanceof Error ? error.message : 'Image fetch failed' }, { status: 500 });
return NextResponse.json({ error: (error as Error).message || 'Image fetch failed' }, { status: 500 });
}
}
33 changes: 27 additions & 6 deletions src/app/api/generate-assignment/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,8 @@ export async function POST(req: NextRequest) {

for (const [, file] of files) {
if (file instanceof File) {
try {
const text = await file.text();
fileContent += `\n\nReference from ${file.name}:\n${text}\n`;
} catch (error) {
console.error(`Failed to read file ${file.name}:`, error);
}
const text = await file.text();
fileContent += `\n--- Content from ${file.name} ---\n${text}\n\n`;
}
}

Expand All @@ -76,6 +72,8 @@ export async function POST(req: NextRequest) {
const prompt = `Generate a comprehensive academic assignment on "${topic}" for ${subject} at ${level || 'undergraduate'} level.
Target word count: ${wordCount || 1000} words.
${requirements ? `Additional requirements: ${requirements}` : ''}
${fileContent ? `\nReference materials:\n${fileContent}` : ''}

${fileContent ? `\n\nReference materials provided:\n${fileContent}\n\nPlease incorporate relevant information from these reference materials into the assignment.` : ''}

Structure the assignment with:
Expand All @@ -85,6 +83,29 @@ export async function POST(req: NextRequest) {
4. Conclusion
5. References (if applicable)

Format the response as structured HTML with proper headings, paragraphs, and formatting.`;

const result = await model.generateContent(prompt);
const content = result.response.text();

// Fetch image if requested
let finalContent = content;
if (includeImages && imageQuery) {
const imageData = await fetchRelevantImage(imageQuery);
if (imageData) {
finalContent = `<div style="text-align: center; margin: 20px 0;">
<img src="${imageData.url}" alt="${imageData.alt}" style="max-width: 100%; height: auto; border-radius: 8px;" />
</div>\n${content}`;
}
}

return NextResponse.json({ content: finalContent });
} catch (error: unknown) {
console.error('Assignment generation failed:', error);
const errorObj = error as Error;
const errorMessage = errorObj.message?.includes('limit') || errorObj.message?.includes('quota')
? 'Your limit for today has exceeded. Please try again tomorrow.'
: errorObj.message || 'Assignment generation failed';
${includeImages ? `Also suggest 1 relevant image search term that would enhance this assignment. Use the main topic "${topic}" as the search term unless a more specific term would be better. Add this term as a JSON array in an HTML comment at the very end: <!-- ["term1"] -->` : ''}

Format the response as structured HTML with proper headings, paragraphs, and formatting.`;
Expand Down
Loading