Split 4 oversized files (503-679 LOC each) into focused units all under 500 LOC: - tech_file_generator.go → +_prompts, +_prompt_builder, +_fallback - hazard_patterns_extended.go → +_extended2.go (HP074-HP102 extracted) - models.go → +_entities.go, +_api.go (enums / DB entities / API types) - completeness.go → +_gates.go (gate definitions extracted) All files remain in package iace. Zero behavior changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
142 lines
4.7 KiB
Go
142 lines
4.7 KiB
Go
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] + "..."
|
|
}
|