Restrict AI Studio to teachers/admins only + Save to Lesson feature
Access Control: - AI Studio view checks user role: only SCHOOL_ADMIN, SUPER_ADMIN, TEACHER, VICE_PRINCIPAL - Students and parents see 'Kein Zugriff' (No Access) message - AI Studio removed from student navigation - API routes (/api/ai/snapgen, /api/ai/perchance, /api/ai/lesson-plan, /api/ai/agent) enforce role checks New Features: - 'Save to Lesson' dialog in Video and Image generation tabs - Pick Subject > Topic > Lesson from existing curriculum - Saves AI video/image URL to SubjectLesson record - Stores prompt, provider, timestamp, and teacher who generated - Students will see this content in homework and lesson materials - AI Lesson Plan API route (/api/ai/lesson-plan) - AI Agent Chat API route (/api/ai/agent) with context-aware system prompts - SubjectLesson model: Added aiVideoUrl, aiImageUrl, aiThumbnailUrl, aiPrompt, aiProvider, aiGeneratedAt, aiGeneratedBy - Homework model: Added aiLessonId, aiVideoUrl, aiImageUrl for linking AI content Navigation: - Removed duplicate AI Studio entry from teacher nav - Removed AI Studio from student nav (students can't access)
This commit is contained in:
1 parent
763ebef22b
commit
fe3eb4a272
6 files changed
+422
-10
No files matched your search
@@ -0,0 +1,85 @@
|
||||
// @ts-nocheck
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import { getSession } from '@/lib/auth';
|
||||
import ZAI from 'z-ai-web-dev-sdk';
|
||||
|
||||
/**
|
||||
* AI Agent Chat API (Agentic Mode)
|
||||
* POST /api/ai/agent
|
||||
* Body: { message, context, language, conversationHistory }
|
||||
*
|
||||
* Only teachers and admins can use the agentic AI.
|
||||
*/
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const session = await getSession();
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||
}
|
||||
|
||||
// Only admin/teacher can use AI agent
|
||||
const role = session.user.role;
|
||||
if (role !== 'SCHOOL_ADMIN' && role !== 'SUPER_ADMIN' && role !== 'TEACHER' && role !== 'VICE_PRINCIPAL') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Only teachers and admins can use the AI agent' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { schoolId } = session.user;
|
||||
if (!schoolId) {
|
||||
return NextResponse.json({ error: 'No school assigned' }, { status: 403 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { message, context = 'teacher-assistant', language = 'de', conversationHistory = [] } = body;
|
||||
|
||||
if (!message || typeof message !== 'string') {
|
||||
return NextResponse.json({ error: 'Message is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Build system prompt based on context
|
||||
const systemPrompts: Record<string, string> = {
|
||||
'teacher-assistant': `Du bist ein KI-Assistent für Lehrkräfte an einer deutschen Schule.
|
||||
Du hilfst bei Unterrichtsvorbereitung, Bewertungsvorschlägen, Kompetenzanalyse und Differenzierung.
|
||||
Du kennst das deutsche Schulsystem (Grundschule, Gymnasium) und die kompetenzorientierte Beurteilung.
|
||||
Antworte auf Deutsch, es sei denn es wird explizit anders verlangt.
|
||||
Sei konkret, praktisch und praxisnah.`,
|
||||
'lesson-planner': `Du bist ein Experte für Unterrichtsplanung nach dem kompetenzorientierten Ansatz.
|
||||
Du erstellst strukturierte Unterrichtsentwürfe mit Phasen, Lernzielen und Differenzierung.`,
|
||||
'assessment-helper': `Du bist ein Experte für Leistungsbewertung.
|
||||
Du hilfst bei der Erstellung von Bewertungsrastern, Kompetenzchecklisten und Notenbegründungen.`,
|
||||
};
|
||||
|
||||
const systemPrompt = systemPrompts[context] || systemPrompts['teacher-assistant'];
|
||||
|
||||
// Build messages array
|
||||
const messages = [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
...conversationHistory.map((msg: any) => ({
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
})),
|
||||
{ role: 'user', content: message },
|
||||
];
|
||||
|
||||
// Generate using z-ai-web-dev-sdk
|
||||
const zai = await ZAI.create();
|
||||
const response = await zai.chat.completions.create({
|
||||
messages,
|
||||
thinking: { type: 'disabled' },
|
||||
});
|
||||
|
||||
const responseContent = response.choices?.[0]?.message?.content || 'Ich konnte keine Antwort generieren.';
|
||||
|
||||
return NextResponse.json({ response: responseContent });
|
||||
} catch (error) {
|
||||
console.error('AI Agent error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal server error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// @ts-nocheck
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import { getSession } from '@/lib/auth';
|
||||
import ZAI from 'z-ai-web-dev-sdk';
|
||||
|
||||
/**
|
||||
* AI Lesson Plan Generation API
|
||||
* POST /api/ai/lesson-plan
|
||||
* Body: { subject, topic, classLevel, duration, language }
|
||||
*
|
||||
* Only teachers and admins can generate lesson plans.
|
||||
*/
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const session = await getSession();
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||
}
|
||||
|
||||
// Only admin/teacher can generate lesson plans
|
||||
const role = session.user.role;
|
||||
if (role !== 'SCHOOL_ADMIN' && role !== 'SUPER_ADMIN' && role !== 'TEACHER' && role !== 'VICE_PRINCIPAL') {
|
||||
return NextResponse.json(
|
||||
{ error: 'Only teachers and admins can generate lesson plans' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const { schoolId } = session.user;
|
||||
if (!schoolId) {
|
||||
return NextResponse.json({ error: 'No school assigned' }, { status: 403 });
|
||||
}
|
||||
|
||||
// Check AI settings
|
||||
const aiSettings = await db.aISettings.findUnique({
|
||||
where: { schoolId },
|
||||
});
|
||||
|
||||
if (!aiSettings) {
|
||||
return NextResponse.json(
|
||||
{ error: 'AI settings not configured' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { subject, topic, classLevel, duration = 45, language = 'de' } = body;
|
||||
|
||||
if (!topic || typeof topic !== 'string') {
|
||||
return NextResponse.json({ error: 'Topic is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Build the lesson plan prompt
|
||||
const langText = language === 'de' ? 'Deutsch' : language === 'en' ? 'Englisch' : 'Türkçe';
|
||||
const prompt = `Erstelle einen detaillierten Unterrichtsentwurf auf ${langText}.
|
||||
|
||||
Fach: ${subject || 'Allgemein'}
|
||||
Thema: ${topic}
|
||||
Klassenstufe: ${classLevel || '3'}
|
||||
Dauer: ${duration} Minuten
|
||||
|
||||
Struktur:
|
||||
1. Lernziele (3-5 Ziele)
|
||||
2. Einstieg/Motivation (5-10 Min.)
|
||||
3. Erarbeitungsphase (15-20 Min.)
|
||||
4. Übungsphase (10-15 Min.)
|
||||
5. Sicherung/Reflexion (5-10 Min.)
|
||||
6. Differenzierungsmöglichkeiten
|
||||
7. Materialien/Medien
|
||||
8. Hausaufgabe
|
||||
|
||||
Bitte strukturiere die Antwort mit klaren Überschriften und Bulletpoints.`;
|
||||
|
||||
// Generate using z-ai-web-dev-sdk
|
||||
const zai = await ZAI.create();
|
||||
const response = await zai.chat.completions.create({
|
||||
messages: [
|
||||
{ role: 'system', content: 'Du bist ein erfahrener Lehrer und Unterrichtsplaner. Du erstellst detaillierte, praxisnahe Unterrichtsentwürfe.' },
|
||||
{ role: 'user', content: prompt },
|
||||
],
|
||||
thinking: { type: 'disabled' },
|
||||
});
|
||||
|
||||
const content = response.choices?.[0]?.message?.content || 'Keine Antwort generiert.';
|
||||
|
||||
return NextResponse.json({ content });
|
||||
} catch (error) {
|
||||
console.error('AI Lesson Plan error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal server error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,14 @@ const updateLessonSchema = z.object({
|
||||
difficulty: z.enum(['easy', 'medium', 'hard']).optional(),
|
||||
sortOrder: z.number().int().optional(),
|
||||
estimatedMinutes: z.number().int().optional().nullable(),
|
||||
// AI-generated content fields
|
||||
aiVideoUrl: z.string().optional().nullable(),
|
||||
aiImageUrl: z.string().optional().nullable(),
|
||||
aiThumbnailUrl: z.string().optional().nullable(),
|
||||
aiPrompt: z.string().optional().nullable(),
|
||||
aiProvider: z.string().optional().nullable(),
|
||||
aiGeneratedAt: z.date().optional().nullable(),
|
||||
aiGeneratedBy: z.string().optional().nullable(),
|
||||
});
|
||||
|
||||
async function updateLesson(
|
||||
|
||||
Reference in new issue
Block a user