iace_handler.go (2706 LOC) split into 9 files: - iace_handler.go: struct, constructor, shared helpers (~156 LOC) - iace_handler_projects.go: project CRUD + InitFromProfile (~310 LOC) - iace_handler_components.go: components + classification (~387 LOC) - iace_handler_hazards.go: hazard library, CRUD, risk assessment (~469 LOC) - iace_handler_mitigations.go: mitigations, evidence, verification plans (~293 LOC) - iace_handler_techfile.go: CE tech file generation/export (~452 LOC) - iace_handler_monitoring.go: monitoring events + audit trail (~134 LOC) - iace_handler_refdata.go: ISO 12100 ref data, patterns, suggestions (~465 LOC) - iace_handler_rag.go: RAG library search + section enrichment (~142 LOC) training_handlers.go (1864 LOC) split into 9 files: - training_handlers.go: struct + constructor (~23 LOC) - training_handlers_modules.go: module CRUD (~226 LOC) - training_handlers_matrix.go: CTM matrix endpoints (~95 LOC) - training_handlers_assignments.go: assignment lifecycle (~243 LOC) - training_handlers_quiz.go: quiz submit/grade/attempts (~185 LOC) - training_handlers_content.go: LLM content/audio/video generation (~274 LOC) - training_handlers_media.go: media, streaming, interactive video (~325 LOC) - training_handlers_blocks.go: block configs + canonical controls (~280 LOC) - training_handlers_stats.go: deadlines, escalation, audit, certificates (~290 LOC) All files remain in package handlers. Zero behavior changes. All exported function names preserved. All files under 500 LOC hard cap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ============================================================================
|
|
// RAG Library Search (Phase 6)
|
|
// ============================================================================
|
|
|
|
// IACELibrarySearchRequest represents a semantic search against the IACE library corpus.
|
|
type IACELibrarySearchRequest struct {
|
|
Query string `json:"query" binding:"required"`
|
|
Category string `json:"category,omitempty"`
|
|
TopK int `json:"top_k,omitempty"`
|
|
Filters []string `json:"filters,omitempty"`
|
|
}
|
|
|
|
// SearchLibrary handles POST /iace/library-search
|
|
// Performs semantic search across the IACE hazard/component/measure library in Qdrant.
|
|
func (h *IACEHandler) SearchLibrary(c *gin.Context) {
|
|
var req IACELibrarySearchRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
topK := req.TopK
|
|
if topK <= 0 || topK > 50 {
|
|
topK = 10
|
|
}
|
|
|
|
// Use regulation filter for category-based search within the IACE collection
|
|
var filters []string
|
|
if req.Category != "" {
|
|
filters = append(filters, req.Category)
|
|
}
|
|
filters = append(filters, req.Filters...)
|
|
|
|
results, err := h.ragClient.SearchCollection(
|
|
c.Request.Context(),
|
|
"bp_iace_libraries",
|
|
req.Query,
|
|
filters,
|
|
topK,
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "RAG search failed",
|
|
"details": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
if results == nil {
|
|
results = []ucca.LegalSearchResult{}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"query": req.Query,
|
|
"results": results,
|
|
"total": len(results),
|
|
})
|
|
}
|
|
|
|
// EnrichTechFileSection handles POST /projects/:id/tech-file/:section/enrich
|
|
// Uses RAG to find relevant library content for a specific tech file section.
|
|
func (h *IACEHandler) EnrichTechFileSection(c *gin.Context) {
|
|
projectID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
|
|
return
|
|
}
|
|
|
|
sectionType := c.Param("section")
|
|
if sectionType == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "section type required"})
|
|
return
|
|
}
|
|
|
|
project, err := h.store.GetProject(c.Request.Context(), projectID)
|
|
if err != nil || project == nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "project not found"})
|
|
return
|
|
}
|
|
|
|
// Build a contextual query based on section type and project data
|
|
queryParts := []string{project.MachineName, project.MachineType}
|
|
|
|
switch sectionType {
|
|
case "risk_assessment_report", "hazard_log_combined":
|
|
queryParts = append(queryParts, "Gefaehrdungen", "Risikobewertung", "ISO 12100")
|
|
case "essential_requirements":
|
|
queryParts = append(queryParts, "Sicherheitsanforderungen", "Maschinenrichtlinie")
|
|
case "design_specifications":
|
|
queryParts = append(queryParts, "Konstruktionsspezifikation", "Sicherheitskonzept")
|
|
case "test_reports":
|
|
queryParts = append(queryParts, "Pruefbericht", "Verifikation", "Nachweis")
|
|
case "standards_applied":
|
|
queryParts = append(queryParts, "harmonisierte Normen", "EN ISO")
|
|
case "ai_risk_management":
|
|
queryParts = append(queryParts, "KI-Risikomanagement", "AI Act", "Algorithmen")
|
|
case "ai_human_oversight":
|
|
queryParts = append(queryParts, "menschliche Aufsicht", "Human Oversight", "KI-Transparenz")
|
|
default:
|
|
queryParts = append(queryParts, sectionType)
|
|
}
|
|
|
|
query := strings.Join(queryParts, " ")
|
|
|
|
results, err := h.ragClient.SearchCollection(
|
|
c.Request.Context(),
|
|
"bp_iace_libraries",
|
|
query,
|
|
nil,
|
|
5,
|
|
)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "RAG enrichment failed",
|
|
"details": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
if results == nil {
|
|
results = []ucca.LegalSearchResult{}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"project_id": projectID.String(),
|
|
"section_type": sectionType,
|
|
"query": query,
|
|
"context": results,
|
|
"total": len(results),
|
|
})
|
|
}
|