package iace import ( "fmt" "strings" ) // ============================================================================ // Fallback content (when LLM is unavailable) // ============================================================================ func buildFallbackContent(sctx *SectionGenerationContext, sectionType string) string { var b strings.Builder b.WriteString("[Automatisch generiert — LLM nicht verfuegbar]\n\n") sectionTitle := sectionDisplayName(sectionType) b.WriteString(fmt.Sprintf("# %s\n\n", sectionTitle)) b.WriteString(fmt.Sprintf("**Maschine:** %s (%s)\n", sctx.Project.MachineName, sctx.Project.MachineType)) b.WriteString(fmt.Sprintf("**Hersteller:** %s\n", sctx.Project.Manufacturer)) if sctx.Project.Description != "" { b.WriteString(fmt.Sprintf("**Beschreibung:** %s\n", sctx.Project.Description)) } b.WriteString("\n") // Section-specific data summaries switch sectionType { case SectionComponentList, SectionGeneralDescription, SectionDesignSpecifications: if len(sctx.Components) > 0 { b.WriteString("## Komponenten\n\n") b.WriteString(fmt.Sprintf("Anzahl: %d\n\n", len(sctx.Components))) for _, c := range sctx.Components { safety := "" if c.IsSafetyRelevant { safety = " [SICHERHEITSRELEVANT]" } b.WriteString(fmt.Sprintf("- %s (Typ: %s)%s\n", c.Name, string(c.ComponentType), safety)) } b.WriteString("\n") } case SectionRiskAssessmentReport, SectionHazardLogCombined: b.WriteString("## Risikoueberblick\n\n") b.WriteString(fmt.Sprintf("Anzahl Gefaehrdungen: %d\n\n", len(sctx.Hazards))) riskCounts := countRiskLevels(sctx) for level, count := range riskCounts { b.WriteString(fmt.Sprintf("- %s: %d\n", level, count)) } b.WriteString("\n") for _, h := range sctx.Hazards { b.WriteString(fmt.Sprintf("- **%s** (%s) — Status: %s\n", h.Name, h.Category, string(h.Status))) } b.WriteString("\n") case SectionMitigationReport: design, protective, info := groupMitigations(sctx) total := len(design) + len(protective) + len(info) b.WriteString("## Massnahmenueberblick\n\n") b.WriteString(fmt.Sprintf("Gesamt: %d Massnahmen\n", total)) b.WriteString(fmt.Sprintf("- Design: %d\n- Schutzmassnahmen: %d\n- Benutzerinformation: %d\n\n", len(design), len(protective), len(info))) writeFallbackMitigationList(&b, "Design", design) writeFallbackMitigationList(&b, "Schutzmassnahmen", protective) writeFallbackMitigationList(&b, "Benutzerinformation", info) case SectionClassificationReport: if len(sctx.Classifications) > 0 { b.WriteString("## Klassifizierungen\n\n") for _, c := range sctx.Classifications { b.WriteString(fmt.Sprintf("- **%s:** %s (Risiko: %s)\n", string(c.Regulation), c.ClassificationResult, string(c.RiskLevel))) } b.WriteString("\n") } case SectionEvidenceIndex: b.WriteString("## Nachweisverzeichnis\n\n") b.WriteString(fmt.Sprintf("Anzahl Nachweise: %d\n\n", len(sctx.Evidence))) for _, e := range sctx.Evidence { desc := e.Description if desc == "" { desc = "(keine Beschreibung)" } b.WriteString(fmt.Sprintf("- %s — %s\n", e.FileName, desc)) } b.WriteString("\n") default: // Generic fallback data summary b.WriteString(fmt.Sprintf("- Komponenten: %d\n", len(sctx.Components))) b.WriteString(fmt.Sprintf("- Gefaehrdungen: %d\n", len(sctx.Hazards))) b.WriteString(fmt.Sprintf("- Klassifizierungen: %d\n", len(sctx.Classifications))) b.WriteString(fmt.Sprintf("- Nachweise: %d\n", len(sctx.Evidence))) b.WriteString("\n") } b.WriteString("---\n") b.WriteString("*Dieser Abschnitt wurde ohne LLM-Unterstuetzung erstellt und enthaelt nur eine Datenuebersicht. Bitte erneut generieren, wenn der LLM-Service verfuegbar ist.*\n") return b.String() } func writeFallbackMitigationList(b *strings.Builder, title string, measures []Mitigation) { if len(measures) == 0 { return } b.WriteString(fmt.Sprintf("### %s\n\n", title)) for _, m := range measures { b.WriteString(fmt.Sprintf("- %s [%s]\n", m.Name, string(m.Status))) } b.WriteString("\n") } // ============================================================================ // Utility helpers // ============================================================================ func countRiskLevels(sctx *SectionGenerationContext) map[string]int { counts := make(map[string]int) for _, h := range sctx.Hazards { if assessments, ok := sctx.Assessments[h.ID]; ok && len(assessments) > 0 { latest := assessments[len(assessments)-1] counts[string(latest.RiskLevel)]++ } } return counts } func acceptableLabel(isAcceptable bool) string { if isAcceptable { return "[AKZEPTABEL]" } return "[NICHT AKZEPTABEL]" } func truncateForPrompt(text string, maxLen int) string { if len(text) <= maxLen { return text } return text[:maxLen] + "..." }