This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/ai-content-generator/app/main.py
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

271 lines
6.9 KiB
Python

"""
AI Content Generator Service - Main Application
FastAPI Service für automatische H5P Content-Generierung
"""
from fastapi import FastAPI, File, UploadFile, Form, HTTPException, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from typing import List, Optional
from pydantic import BaseModel
import os
from datetime import datetime
from app.services.claude_service import ClaudeService
from app.services.youtube_service import YouTubeService
from app.services.content_generator import ContentGenerator
from app.services.material_analyzer import MaterialAnalyzer
from app.models.generation_job import GenerationJob, JobStatus
from app.utils.job_store import JobStore
app = FastAPI(
title="BreakPilot AI Content Generator",
description="Automatische H5P Content-Generierung mit Claude AI",
version="1.0.0"
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Services
claude_service = ClaudeService()
youtube_service = YouTubeService()
content_generator = ContentGenerator(claude_service, youtube_service)
material_analyzer = MaterialAnalyzer()
job_store = JobStore()
# Models
class GenerateContentRequest(BaseModel):
topic: str
description: Optional[str] = None
target_grade: Optional[str] = None # z.B. "5-6"
language: str = "de"
class GenerationResponse(BaseModel):
job_id: str
status: str
message: str
class JobStatusResponse(BaseModel):
job_id: str
status: str
progress: int
message: str
result: Optional[dict] = None
error: Optional[str] = None
created_at: datetime
updated_at: datetime
@app.get("/")
async def root():
"""Service Info"""
return {
"service": "AI Content Generator",
"version": "1.0.0",
"status": "running",
"features": [
"Material Analysis",
"Claude AI Integration",
"YouTube Video Crawler",
"8 H5P Content Types",
"Background Jobs"
]
}
@app.get("/health")
async def health():
"""Health Check"""
return {
"status": "healthy",
"claude_api": claude_service.is_configured(),
"youtube_api": youtube_service.is_configured()
}
@app.post("/api/generate-content", response_model=GenerationResponse)
async def generate_content(
background_tasks: BackgroundTasks,
topic: str = Form(...),
description: Optional[str] = Form(None),
target_grade: Optional[str] = Form("5-6"),
files: List[UploadFile] = File(default=[])
):
"""
Generiere H5P Content aus hochgeladenen Materialien
Args:
topic: Thema (z.B. "Das menschliche Auge")
description: Zusätzliche Beschreibung/Lernziele
target_grade: Klassenstufe (z.B. "5-6")
files: Hochgeladene Materialien (PDF, Images, DOCX)
Returns:
job_id und Status für Tracking
"""
try:
# Job erstellen
job = GenerationJob(
topic=topic,
description=description,
target_grade=target_grade,
material_count=len(files)
)
job_store.save(job)
# Background Task starten
background_tasks.add_task(
process_content_generation,
job.job_id,
topic,
description,
target_grade,
files
)
return GenerationResponse(
job_id=job.job_id,
status="processing",
message=f"Content-Generierung gestartet für Thema: {topic}"
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/generation-status/{job_id}", response_model=JobStatusResponse)
async def get_generation_status(job_id: str):
"""
Hole Status eines Content-Generierungs-Jobs
Args:
job_id: Job ID aus der generate-content Response
Returns:
Aktueller Status, Progress und ggf. Ergebnis
"""
job = job_store.get(job_id)
if not job:
raise HTTPException(status_code=404, detail="Job not found")
return JobStatusResponse(
job_id=job.job_id,
status=job.status.value,
progress=job.progress,
message=job.message,
result=job.result,
error=job.error,
created_at=job.created_at,
updated_at=job.updated_at
)
@app.get("/api/generated-content/{job_id}")
async def get_generated_content(job_id: str):
"""
Hole das generierte Content-Paket
Returns:
Alle 8 generierten H5P Content-Typen
"""
job = job_store.get(job_id)
if not job:
raise HTTPException(status_code=404, detail="Job not found")
if job.status != JobStatus.COMPLETED:
raise HTTPException(
status_code=400,
detail=f"Job not completed yet. Current status: {job.status.value}"
)
return {
"job_id": job_id,
"topic": job.topic,
"content": job.result
}
@app.post("/api/youtube-search")
async def search_youtube_videos(
query: str = Form(...),
max_results: int = Form(5)
):
"""
Suche passende YouTube Videos zum Thema
Args:
query: Suchbegriff
max_results: Maximale Anzahl Ergebnisse
Returns:
Liste von Video-Infos mit Transkript-Verfügbarkeit
"""
try:
videos = await youtube_service.search_videos(query, max_results)
return {"videos": videos}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
async def process_content_generation(
job_id: str,
topic: str,
description: Optional[str],
target_grade: str,
files: List[UploadFile]
):
"""Background Task für Content-Generierung"""
job = job_store.get(job_id)
try:
# 1. Materialien analysieren
job.update_progress(10, "Analysiere hochgeladene Materialien...")
job_store.save(job)
materials = []
for file in files:
content = await file.read()
analysis = await material_analyzer.analyze(file.filename, content)
materials.append(analysis)
# 2. YouTube Videos suchen
job.update_progress(30, "Suche passende YouTube Videos...")
job_store.save(job)
videos = await youtube_service.search_videos(topic, max_results=3)
# 3. Content generieren
job.update_progress(50, "Generiere H5P Content mit Claude AI...")
job_store.save(job)
generated_content = await content_generator.generate_all_content_types(
topic=topic,
description=description,
target_grade=target_grade,
materials=materials,
videos=videos
)
# 4. Fertig
job.complete(generated_content)
job_store.save(job)
except Exception as e:
job.fail(str(e))
job_store.save(job)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8004)