d4b7943d54
Library Extensions: - 15 new components (C121-C135): knee lever, hydraulic ram, lubrication system, extraction system, vibrating plate, die tooling, transfer system, hoist, chute, oil drip tray, pressure relief valve, die space, flywheel, bin changeover station, inspection scale - 8 new tags: person_under_load, two_hand_control_required, thermal_accumulation, mechanical_transmission, oil_mist_risk, rapid_energy_release, gravity_suspended_load, bypass_risk - 14 new patterns (HP045-HP058): ram drop, die space crushing, oil mist inhalation, hot workpiece burns, suspended load, transfer draw-in, ejection fall, accumulator pressure release, impact noise, flywheel residual energy, guard bypass, two-hand misoperation, oil leakage, ergonomic bin changeover Deterministic Parser (NO LLM): - keyword_dictionary.go: ~100 entries mapping DE/EN keywords to component IDs, energy source IDs, and tags - narrative_parser.go: ParseNarrative() extracts components, energy sources, lifecycle phases, roles, tech specs, and context tags from free-text machine descriptions via keyword matching + regex - Tech spec regex: extracts kN, V, °C, bar, kW, rpm values and derives energy sources + severity tags automatically - iace_handler_parser.go: POST /projects/:id/parse-narrative endpoint chains parser → pattern engine → hazard suggestions Test: Paste Kniehebelpresse description → should detect 10+ components, 15+ hazards, all deterministically without LLM. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
3.3 KiB
Go
100 lines
3.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// ParseNarrativeRequest is the request body for POST /projects/:id/parse-narrative.
|
|
type ParseNarrativeRequest struct {
|
|
NarrativeText string `json:"narrative_text" binding:"required"`
|
|
}
|
|
|
|
// ParseNarrativeResponse contains the deterministic parsing results.
|
|
type ParseNarrativeResponse struct {
|
|
Components []iace.ComponentMatch `json:"components"`
|
|
EnergySources []iace.EnergyMatch `json:"energy_sources"`
|
|
LifecyclePhases []string `json:"lifecycle_phases"`
|
|
Roles []string `json:"roles"`
|
|
Tags []string `json:"tags"`
|
|
TechSpecs []iace.TechSpec `json:"tech_specs"`
|
|
Confidence float64 `json:"confidence"`
|
|
// Pattern match results (from feeding parsed data into pattern engine)
|
|
MatchedPatterns int `json:"matched_patterns"`
|
|
SuggestedHazards []struct {
|
|
Category string `json:"category"`
|
|
PatternID string `json:"pattern_id"`
|
|
PatternName string `json:"pattern_name"`
|
|
Priority int `json:"priority"`
|
|
} `json:"suggested_hazards"`
|
|
}
|
|
|
|
// ParseNarrative handles POST /projects/:id/parse-narrative
|
|
// Deterministically extracts components, energy sources, lifecycle phases,
|
|
// roles, and hazard patterns from a free-text machine description.
|
|
// NO LLM required — pure keyword matching + pattern engine.
|
|
func (h *IACEHandler) ParseNarrative(c *gin.Context) {
|
|
var req ParseNarrativeRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "narrative_text is required"})
|
|
return
|
|
}
|
|
|
|
// 1. Parse narrative text deterministically
|
|
parseResult := iace.ParseNarrative(req.NarrativeText)
|
|
|
|
// 2. Feed parsed tags into pattern engine
|
|
// Collect all component IDs for tag resolution
|
|
var componentIDs []string
|
|
for _, comp := range parseResult.Components {
|
|
componentIDs = append(componentIDs, comp.LibraryID)
|
|
}
|
|
var energyIDs []string
|
|
for _, e := range parseResult.EnergySources {
|
|
energyIDs = append(energyIDs, e.SourceID)
|
|
}
|
|
|
|
// Run pattern matching via PatternEngine
|
|
engine := iace.NewPatternEngine()
|
|
matchInput := iace.MatchInput{
|
|
ComponentLibraryIDs: componentIDs,
|
|
EnergySourceIDs: energyIDs,
|
|
LifecyclePhases: parseResult.LifecyclePhases,
|
|
CustomTags: parseResult.CustomTags,
|
|
}
|
|
matchOutput := engine.Match(matchInput)
|
|
|
|
// 3. Build response
|
|
resp := ParseNarrativeResponse{
|
|
Components: parseResult.Components,
|
|
EnergySources: parseResult.EnergySources,
|
|
LifecyclePhases: parseResult.LifecyclePhases,
|
|
Roles: parseResult.Roles,
|
|
Tags: parseResult.CustomTags,
|
|
TechSpecs: parseResult.TechSpecs,
|
|
Confidence: parseResult.Confidence,
|
|
MatchedPatterns: len(matchOutput.MatchedPatterns),
|
|
}
|
|
|
|
// Add suggested hazards from matched patterns
|
|
for _, mp := range matchOutput.MatchedPatterns {
|
|
for _, cat := range mp.GeneratedHazardCats {
|
|
resp.SuggestedHazards = append(resp.SuggestedHazards, struct {
|
|
Category string `json:"category"`
|
|
PatternID string `json:"pattern_id"`
|
|
PatternName string `json:"pattern_name"`
|
|
Priority int `json:"priority"`
|
|
}{
|
|
Category: cat,
|
|
PatternID: mp.ID,
|
|
PatternName: mp.NameDE,
|
|
Priority: mp.Priority,
|
|
})
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|