feat: BreakPilot PWA - Full codebase (clean push without large binaries)
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
All services: admin-v2, studio-v2, website, ai-compliance-sdk, consent-service, klausur-service, voice-service, and infrastructure. Large PDFs and compiled binaries excluded via .gitignore.
This commit is contained in:
270
ai-content-generator/app/main.py
Normal file
270
ai-content-generator/app/main.py
Normal file
@@ -0,0 +1,270 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user