Some checks failed
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
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
ci/woodpecker/push/integration Pipeline failed
ci/woodpecker/push/main Pipeline failed
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Add complete Academy backend (Go) and frontend (Next.js) for DSGVO/IT-Security/AI-Literacy compliance training: - Go backend: Course CRUD, enrollments, quiz evaluation, PDF certificates (gofpdf), video generation pipeline (ElevenLabs + HeyGen) - In-memory data store with PostgreSQL migration for future DB support - Frontend: Course creation (AI + manual), lesson viewer, interactive quiz, certificate viewer with PDF download - Fix existing compile errors in generate.go (SearchResult type mismatch), llm/service.go (unused var), rag/service.go (Unicode chars) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package academy
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
// VideoGenerator orchestrates video generation with 3-tier fallback:
|
|
// 1. HeyGen + ElevenLabs -> Avatar video with voice
|
|
// 2. ElevenLabs only -> Audio podcast style
|
|
// 3. No external services -> Text + Quiz only
|
|
type VideoGenerator struct {
|
|
elevenLabs *ElevenLabsClient
|
|
heyGen *HeyGenClient
|
|
}
|
|
|
|
// NewVideoGenerator creates a new video generator
|
|
func NewVideoGenerator() *VideoGenerator {
|
|
return &VideoGenerator{
|
|
elevenLabs: NewElevenLabsClient(),
|
|
heyGen: NewHeyGenClient(),
|
|
}
|
|
}
|
|
|
|
// GenerationMode describes the available generation mode
|
|
type GenerationMode string
|
|
|
|
const (
|
|
ModeAvatarVideo GenerationMode = "avatar_video" // HeyGen + ElevenLabs
|
|
ModeAudioOnly GenerationMode = "audio_only" // ElevenLabs only
|
|
ModeTextOnly GenerationMode = "text_only" // No external services
|
|
)
|
|
|
|
// GetAvailableMode returns the best available generation mode
|
|
func (vg *VideoGenerator) GetAvailableMode() GenerationMode {
|
|
if vg.heyGen.IsConfigured() && vg.elevenLabs.IsConfigured() {
|
|
return ModeAvatarVideo
|
|
}
|
|
if vg.elevenLabs.IsConfigured() {
|
|
return ModeAudioOnly
|
|
}
|
|
return ModeTextOnly
|
|
}
|
|
|
|
// GenerateAudio generates audio from text using ElevenLabs
|
|
func (vg *VideoGenerator) GenerateAudio(text string) ([]byte, error) {
|
|
if !vg.elevenLabs.IsConfigured() {
|
|
return nil, fmt.Errorf("ElevenLabs not configured")
|
|
}
|
|
|
|
log.Printf("Generating audio for text (%d chars)...", len(text))
|
|
return vg.elevenLabs.TextToSpeech(text)
|
|
}
|
|
|
|
// GenerateVideo generates a video from audio using HeyGen
|
|
func (vg *VideoGenerator) GenerateVideo(audioURL string) (string, error) {
|
|
if !vg.heyGen.IsConfigured() {
|
|
return "", fmt.Errorf("HeyGen not configured")
|
|
}
|
|
|
|
log.Printf("Creating HeyGen video with audio: %s", audioURL)
|
|
resp, err := vg.heyGen.CreateVideo(audioURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return resp.Data.VideoID, nil
|
|
}
|
|
|
|
// CheckVideoStatus checks if a HeyGen video is ready
|
|
func (vg *VideoGenerator) CheckVideoStatus(videoID string) (string, string, error) {
|
|
if !vg.heyGen.IsConfigured() {
|
|
return "", "", fmt.Errorf("HeyGen not configured")
|
|
}
|
|
|
|
status, err := vg.heyGen.GetVideoStatus(videoID)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return status.Data.Status, status.Data.VideoURL, nil
|
|
}
|
|
|
|
// GetStatus returns the configuration status
|
|
func (vg *VideoGenerator) GetStatus() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"mode": string(vg.GetAvailableMode()),
|
|
"elevenLabsConfigured": vg.elevenLabs.IsConfigured(),
|
|
"heyGenConfigured": vg.heyGen.IsConfigured(),
|
|
}
|
|
}
|