""" Claude Service Integration mit Claude API für Content-Generierung """ import os from typing import List, Dict, Any, Optional from anthropic import Anthropic class ClaudeService: """Claude API Service""" def __init__(self): self.api_key = os.getenv("ANTHROPIC_API_KEY") self.client = Anthropic(api_key=self.api_key) if self.api_key else None self.model = "claude-sonnet-4-5-20251101" # Latest model def is_configured(self) -> bool: """Check if API key is configured""" return self.client is not None async def generate_content( self, prompt: str, system_prompt: Optional[str] = None, max_tokens: int = 4000, temperature: float = 1.0 ) -> str: """ Generate content with Claude Args: prompt: User prompt system_prompt: System prompt (optional) max_tokens: Maximum tokens to generate temperature: Sampling temperature Returns: Generated text """ if not self.client: raise ValueError("Claude API not configured. Set ANTHROPIC_API_KEY environment variable.") messages = [{"role": "user", "content": prompt}] kwargs = { "model": self.model, "max_tokens": max_tokens, "temperature": temperature, "messages": messages } if system_prompt: kwargs["system"] = system_prompt response = self.client.messages.create(**kwargs) return response.content[0].text async def generate_quiz_questions( self, topic: str, materials: List[Dict[str, Any]], target_grade: str, num_questions: int = 10 ) -> List[Dict[str, Any]]: """Generate Quiz questions""" material_text = self._format_materials(materials) prompt = f"""Erstelle {num_questions} Multiple-Choice-Fragen zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Erstelle Fragen die: 1. Das Verständnis testen 2. Auf den Materialien basieren 3. Altersgerecht sind 4. 4 Antwortmöglichkeiten haben (1 richtig, 3 falsch) Formatiere die Ausgabe als JSON-Array: [ {{ "question": "Frage text?", "options": ["Option A", "Option B", "Option C", "Option D"], "correct_answer": 0, "explanation": "Erklärung warum die Antwort richtig ist" }} ] Nur das JSON-Array zurückgeben, keine zusätzlichen Texte.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein pädagogischer Experte der Quizfragen erstellt." ) # Parse JSON import json try: questions = json.loads(response) return questions except json.JSONDecodeError: # Try to extract JSON from response import re json_match = re.search(r'\[.*\]', response, re.DOTALL) if json_match: questions = json.loads(json_match.group()) return questions raise ValueError("Could not parse quiz questions from Claude response") async def generate_flashcards( self, topic: str, materials: List[Dict[str, Any]], target_grade: str, num_cards: int = 15 ) -> List[Dict[str, str]]: """Generate Flashcards""" material_text = self._format_materials(materials) prompt = f"""Erstelle {num_cards} Lernkarten (Flashcards) zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Erstelle Karten die: 1. Wichtige Begriffe und Konzepte abdecken 2. Kurz und prägnant sind 3. Zum Wiederholen geeignet sind Formatiere die Ausgabe als JSON-Array: [ {{ "front": "Begriff oder Frage", "back": "Definition oder Antwort" }} ] Nur das JSON-Array zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für Lernkarten-Design." ) import json import re json_match = re.search(r'\[.*\]', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) async def generate_fill_blanks_text( self, topic: str, materials: List[Dict[str, Any]], target_grade: str ) -> Dict[str, Any]: """Generate Fill-in-the-Blanks exercise""" material_text = self._format_materials(materials) prompt = f"""Erstelle einen Lückentext zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Erstelle einen Text mit 10-15 Lücken. Markiere Lücken mit *Wort*. Formatiere als JSON: {{ "title": "Titel des Lückentexts", "text": "Der Text mit *Lücken* markiert...", "hints": "Hilfreiche Hinweise" }} Nur JSON zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für Lückentexte." ) import json import re json_match = re.search(r'\{.*\}', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) async def generate_drag_drop_exercise( self, topic: str, materials: List[Dict[str, Any]], target_grade: str ) -> Dict[str, Any]: """Generate Drag-and-Drop exercise""" material_text = self._format_materials(materials) prompt = f"""Erstelle eine Drag-and-Drop Zuordnungsaufgabe zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Erstelle 3-4 Kategorien (Zonen) und 8-12 Elemente zum Zuordnen. Formatiere als JSON: {{ "title": "Titel der Aufgabe", "question": "Aufgabenstellung", "zones": [ {{ "id": 1, "name": "Kategorie 1" }}, {{ "id": 2, "name": "Kategorie 2" }} ], "draggables": [ {{ "id": 1, "text": "Element 1", "correctZoneId": 1 }}, {{ "id": 2, "text": "Element 2", "correctZoneId": 2 }} ] }} Nur JSON zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für interaktive Lernaufgaben." ) import json import re json_match = re.search(r'\{.*\}', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) async def generate_memory_pairs( self, topic: str, materials: List[Dict[str, Any]], target_grade: str, num_pairs: int = 8 ) -> List[Dict[str, str]]: """Generate Memory Game pairs""" material_text = self._format_materials(materials) prompt = f"""Erstelle {num_pairs} Memory-Paare zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Jedes Paar besteht aus zwei zusammengehörigen Begriffen/Konzepten. Formatiere als JSON-Array: [ {{ "card1": "Begriff 1", "card2": "Zugehöriger Begriff" }} ] Nur JSON zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für Memory-Spiele." ) import json import re json_match = re.search(r'\[.*\]', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) async def generate_timeline_events( self, topic: str, materials: List[Dict[str, Any]], target_grade: str ) -> List[Dict[str, Any]]: """Generate Timeline events""" material_text = self._format_materials(materials) prompt = f"""Erstelle eine Timeline mit 5-8 Ereignissen zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Formatiere als JSON-Array: [ {{ "year": "Jahr oder Zeitpunkt", "title": "Ereignis Titel", "description": "Kurze Beschreibung" }} ] Nur JSON zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für chronologische Darstellungen." ) import json import re json_match = re.search(r'\[.*\]', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) async def generate_presentation_slides( self, topic: str, materials: List[Dict[str, Any]], target_grade: str, num_slides: int = 5 ) -> List[Dict[str, str]]: """Generate Presentation slides""" material_text = self._format_materials(materials) prompt = f"""Erstelle {num_slides} Präsentationsfolien zum Thema "{topic}" für Klassenstufe {target_grade}. Materialien: {material_text} Formatiere als JSON-Array: [ {{ "title": "Folien Titel", "content": "Folien Inhalt (2-4 Sätze)", "backgroundColor": "#ffffff" }} ] Nur JSON zurückgeben.""" response = await self.generate_content( prompt=prompt, system_prompt="Du bist ein Experte für Präsentationen." ) import json import re json_match = re.search(r'\[.*\]', response, re.DOTALL) if json_match: return json.loads(json_match.group()) return json.loads(response) def _format_materials(self, materials: List[Dict[str, Any]]) -> str: """Format materials for prompt""" if not materials: return "Keine Materialien vorhanden." formatted = [] for i, material in enumerate(materials, 1): formatted.append(f"Material {i} ({material.get('type', 'unknown')}):") formatted.append(material.get('content', '')[:2000]) # Limit content formatted.append("") return "\n".join(formatted)