Compare commits
2 Commits
76038c43fd
...
71bc48449d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71bc48449d | ||
|
|
e5cb5e37ad |
@@ -10,6 +10,7 @@ import {
|
|||||||
CourseCategory,
|
CourseCategory,
|
||||||
CourseCreateRequest,
|
CourseCreateRequest,
|
||||||
CourseUpdateRequest,
|
CourseUpdateRequest,
|
||||||
|
GenerateCourseRequest,
|
||||||
Enrollment,
|
Enrollment,
|
||||||
EnrollmentStatus,
|
EnrollmentStatus,
|
||||||
EnrollmentListResponse,
|
EnrollmentListResponse,
|
||||||
@@ -273,6 +274,52 @@ export async function fetchAcademyStatistics(): Promise<AcademyStatistics> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// COURSE GENERATION (via Training Engine)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KI-gestuetzten Kurs generieren (nutzt intern Training Content Pipeline)
|
||||||
|
*/
|
||||||
|
export async function generateCourse(request: GenerateCourseRequest): Promise<Course> {
|
||||||
|
return fetchWithTimeout<Course>(
|
||||||
|
`${ACADEMY_API_BASE}/courses/generate`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(request)
|
||||||
|
},
|
||||||
|
120000 // 2 min timeout for LLM generation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Videos fuer alle Lektionen eines Kurses generieren
|
||||||
|
*/
|
||||||
|
export async function generateVideos(courseId: string): Promise<{ status: string; jobId?: string }> {
|
||||||
|
return fetchWithTimeout<{ status: string; jobId?: string }>(
|
||||||
|
`${ACADEMY_API_BASE}/courses/${courseId}/generate-videos`,
|
||||||
|
{
|
||||||
|
method: 'POST'
|
||||||
|
},
|
||||||
|
300000 // 5 min timeout for video generation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Video-Generierungsstatus abrufen
|
||||||
|
*/
|
||||||
|
export async function getVideoStatus(courseId: string): Promise<{
|
||||||
|
status: string
|
||||||
|
total: number
|
||||||
|
completed: number
|
||||||
|
failed: number
|
||||||
|
videos: Array<{ lessonId: string; status: string; url?: string }>
|
||||||
|
}> {
|
||||||
|
return fetchWithTimeout(
|
||||||
|
`${ACADEMY_API_BASE}/courses/${courseId}/video-status`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// SDK PROXY FUNCTION (wraps fetchCourses + fetchAcademyStatistics)
|
// SDK PROXY FUNCTION (wraps fetchCourses + fetchAcademyStatistics)
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -215,6 +215,15 @@ export interface CourseUpdateRequest {
|
|||||||
requiredForRoles?: string[]
|
requiredForRoles?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GenerateCourseRequest {
|
||||||
|
title: string
|
||||||
|
category: CourseCategory
|
||||||
|
description?: string
|
||||||
|
regulationArea?: string
|
||||||
|
language?: string
|
||||||
|
durationMinutes?: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface EnrollUserRequest {
|
export interface EnrollUserRequest {
|
||||||
courseId: string
|
courseId: string
|
||||||
userId: string
|
userId: string
|
||||||
|
|||||||
@@ -292,11 +292,11 @@ export async function getModuleMedia(moduleId: string): Promise<{ media: Trainin
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getMediaURL(mediaId: string): Promise<{ bucket: string; object_key: string; mime_type: string }> {
|
export async function getMediaURL(mediaId: string): Promise<{ bucket: string; object_key: string; mime_type: string }> {
|
||||||
return apiFetch(`/media/module/${mediaId}/url`)
|
return apiFetch(`/media/${mediaId}/url`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function publishMedia(mediaId: string, publish?: boolean): Promise<{ status: string; is_published: boolean }> {
|
export async function publishMedia(mediaId: string, publish?: boolean): Promise<{ status: string; is_published: boolean }> {
|
||||||
return apiFetch(`/media/module/${mediaId}/publish`, {
|
return apiFetch(`/media/${mediaId}/publish`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ publish: publish !== false }),
|
body: JSON.stringify({ publish: publish !== false }),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/breakpilot/ai-compliance-sdk/internal/academy"
|
"github.com/breakpilot/ai-compliance-sdk/internal/academy"
|
||||||
"github.com/breakpilot/ai-compliance-sdk/internal/incidents"
|
"github.com/breakpilot/ai-compliance-sdk/internal/incidents"
|
||||||
"github.com/breakpilot/ai-compliance-sdk/internal/roadmap"
|
"github.com/breakpilot/ai-compliance-sdk/internal/roadmap"
|
||||||
|
"github.com/breakpilot/ai-compliance-sdk/internal/training"
|
||||||
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
||||||
"github.com/breakpilot/ai-compliance-sdk/internal/whistleblower"
|
"github.com/breakpilot/ai-compliance-sdk/internal/whistleblower"
|
||||||
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
|
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
|
||||||
@@ -69,6 +70,7 @@ func main() {
|
|||||||
incidentStore := incidents.NewStore(pool)
|
incidentStore := incidents.NewStore(pool)
|
||||||
vendorStore := vendor.NewStore(pool)
|
vendorStore := vendor.NewStore(pool)
|
||||||
iaceStore := iace.NewStore(pool)
|
iaceStore := iace.NewStore(pool)
|
||||||
|
trainingStore := training.NewStore(pool)
|
||||||
|
|
||||||
// Initialize services
|
// Initialize services
|
||||||
rbacService := rbac.NewService(rbacStore)
|
rbacService := rbac.NewService(rbacStore)
|
||||||
@@ -90,6 +92,10 @@ func main() {
|
|||||||
// Initialize PII detector
|
// Initialize PII detector
|
||||||
piiDetector := llm.NewPIIDetectorWithPatterns(llm.AllPIIPatterns())
|
piiDetector := llm.NewPIIDetectorWithPatterns(llm.AllPIIPatterns())
|
||||||
|
|
||||||
|
// Initialize TTS client and content generator for training
|
||||||
|
ttsClient := training.NewTTSClient(cfg.TTSServiceURL)
|
||||||
|
contentGenerator := training.NewContentGenerator(providerRegistry, piiDetector, trainingStore, ttsClient)
|
||||||
|
|
||||||
// Initialize access gate
|
// Initialize access gate
|
||||||
accessGate := llm.NewAccessGate(policyEngine, piiDetector, providerRegistry)
|
accessGate := llm.NewAccessGate(policyEngine, piiDetector, providerRegistry)
|
||||||
|
|
||||||
@@ -113,6 +119,7 @@ func main() {
|
|||||||
incidentHandlers := handlers.NewIncidentHandlers(incidentStore)
|
incidentHandlers := handlers.NewIncidentHandlers(incidentStore)
|
||||||
vendorHandlers := handlers.NewVendorHandlers(vendorStore)
|
vendorHandlers := handlers.NewVendorHandlers(vendorStore)
|
||||||
iaceHandler := handlers.NewIACEHandler(iaceStore)
|
iaceHandler := handlers.NewIACEHandler(iaceStore)
|
||||||
|
trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator)
|
||||||
|
|
||||||
// Initialize middleware
|
// Initialize middleware
|
||||||
rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine)
|
rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine)
|
||||||
@@ -478,6 +485,74 @@ func main() {
|
|||||||
academyRoutes.GET("/stats", academyHandlers.GetStatistics)
|
academyRoutes.GET("/stats", academyHandlers.GetStatistics)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Training Engine routes - Compliance Training Content Pipeline
|
||||||
|
trainingRoutes := v1.Group("/training")
|
||||||
|
{
|
||||||
|
// Module CRUD
|
||||||
|
trainingRoutes.GET("/modules", trainingHandlers.ListModules)
|
||||||
|
trainingRoutes.GET("/modules/:id", trainingHandlers.GetModule)
|
||||||
|
trainingRoutes.POST("/modules", trainingHandlers.CreateModule)
|
||||||
|
trainingRoutes.PUT("/modules/:id", trainingHandlers.UpdateModule)
|
||||||
|
|
||||||
|
// Compliance Training Matrix (CTM)
|
||||||
|
trainingRoutes.GET("/matrix", trainingHandlers.GetMatrix)
|
||||||
|
trainingRoutes.GET("/matrix/:role", trainingHandlers.GetMatrixForRole)
|
||||||
|
trainingRoutes.POST("/matrix", trainingHandlers.SetMatrixEntry)
|
||||||
|
trainingRoutes.DELETE("/matrix/:role/:moduleId", trainingHandlers.DeleteMatrixEntry)
|
||||||
|
|
||||||
|
// Assignments
|
||||||
|
trainingRoutes.POST("/assignments/compute", trainingHandlers.ComputeAssignments)
|
||||||
|
trainingRoutes.GET("/assignments", trainingHandlers.ListAssignments)
|
||||||
|
trainingRoutes.GET("/assignments/:id", trainingHandlers.GetAssignment)
|
||||||
|
trainingRoutes.POST("/assignments/:id/start", trainingHandlers.StartAssignment)
|
||||||
|
trainingRoutes.POST("/assignments/:id/progress", trainingHandlers.UpdateAssignmentProgress)
|
||||||
|
trainingRoutes.POST("/assignments/:id/complete", trainingHandlers.CompleteAssignment)
|
||||||
|
|
||||||
|
// Quiz
|
||||||
|
trainingRoutes.GET("/quiz/:moduleId", trainingHandlers.GetQuiz)
|
||||||
|
trainingRoutes.POST("/quiz/:moduleId/submit", trainingHandlers.SubmitQuiz)
|
||||||
|
trainingRoutes.GET("/quiz/attempts/:assignmentId", trainingHandlers.GetQuizAttempts)
|
||||||
|
|
||||||
|
// Content Generation (LLM)
|
||||||
|
trainingRoutes.POST("/content/generate", trainingHandlers.GenerateContent)
|
||||||
|
trainingRoutes.POST("/content/generate-quiz", trainingHandlers.GenerateQuiz)
|
||||||
|
trainingRoutes.POST("/content/generate-all", trainingHandlers.GenerateAllContent)
|
||||||
|
trainingRoutes.POST("/content/generate-all-quiz", trainingHandlers.GenerateAllQuizzes)
|
||||||
|
trainingRoutes.GET("/content/:moduleId", trainingHandlers.GetContent)
|
||||||
|
// PublishContent expects c.Param("id") but route uses :moduleId for Gin compatibility
|
||||||
|
trainingRoutes.POST("/content/:moduleId/publish", func(c *gin.Context) {
|
||||||
|
c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("moduleId")})
|
||||||
|
trainingHandlers.PublishContent(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Media (Audio/Video via TTS Service)
|
||||||
|
trainingRoutes.POST("/content/:moduleId/generate-audio", trainingHandlers.GenerateAudio)
|
||||||
|
trainingRoutes.POST("/content/:moduleId/generate-video", trainingHandlers.GenerateVideo)
|
||||||
|
trainingRoutes.POST("/content/:moduleId/preview-script", trainingHandlers.PreviewVideoScript)
|
||||||
|
trainingRoutes.GET("/media/module/:moduleId", trainingHandlers.GetModuleMedia)
|
||||||
|
// Media detail routes use :mediaId consistently
|
||||||
|
trainingRoutes.GET("/media/:mediaId/url", func(c *gin.Context) {
|
||||||
|
c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")})
|
||||||
|
trainingHandlers.GetMediaURL(c)
|
||||||
|
})
|
||||||
|
trainingRoutes.POST("/media/:mediaId/publish", func(c *gin.Context) {
|
||||||
|
c.Params = append(c.Params, gin.Param{Key: "id", Value: c.Param("mediaId")})
|
||||||
|
trainingHandlers.PublishMedia(c)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Deadlines & Escalation
|
||||||
|
trainingRoutes.GET("/deadlines", trainingHandlers.GetDeadlines)
|
||||||
|
trainingRoutes.GET("/deadlines/overdue", trainingHandlers.GetOverdueDeadlines)
|
||||||
|
trainingRoutes.POST("/escalation/check", trainingHandlers.CheckEscalation)
|
||||||
|
|
||||||
|
// Audit & Statistics
|
||||||
|
trainingRoutes.GET("/audit-log", trainingHandlers.GetAuditLog)
|
||||||
|
trainingRoutes.GET("/stats", trainingHandlers.GetStats)
|
||||||
|
|
||||||
|
// Certificates
|
||||||
|
trainingRoutes.GET("/certificates/:id/verify", trainingHandlers.VerifyCertificate)
|
||||||
|
}
|
||||||
|
|
||||||
// Whistleblower routes - Hinweisgebersystem (HinSchG)
|
// Whistleblower routes - Hinweisgebersystem (HinSchG)
|
||||||
whistleblowerRoutes := v1.Group("/whistleblower")
|
whistleblowerRoutes := v1.Group("/whistleblower")
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user