Files
audita/internal/framework/validators/llm_context.go

63 lines
2.2 KiB
Go

package validators
import (
"gitea.maximumdirect.net/eric/audita/internal/core/chunking"
"gitea.maximumdirect.net/eric/audita/internal/core/schema"
)
// validationContext supplies adjacent source segments within the current chunk
// and glossary definitions mentioned in the candidate or that local context.
// These fields travel in each item so batching accounts for their size.
func validationContext(segments []schema.Segment, position int, glossary *schema.Glossary, vocabulary ProtectedVocabulary, corrected string) ([]NeighboringSegment, []schema.GlossaryEntry) {
var neighbors []NeighboringSegment
source := segments[position].Text
if position > 0 {
neighbors = append(neighbors, neighboringSegment("preceding", segments[position-1]))
}
if position+1 < len(segments) {
neighbors = append(neighbors, neighboringSegment("following", segments[position+1]))
}
texts := []string{source, corrected}
for _, neighbor := range neighbors {
texts = append(texts, neighbor.Text)
}
var entries []schema.GlossaryEntry
if glossary != nil {
mentioned := make(map[int]bool)
for _, text := range texts {
for identity := range vocabulary.occurrencesByIdentity(text) {
mentioned[identity] = true
}
}
for i, entry := range glossary.Entries {
if mentioned[i] {
entries = append(entries, entry)
}
}
}
return neighbors, entries
}
// fitValidationContext drops optional context before treating required candidate
// text as oversized. Glossary definitions take priority over adjacent segments.
func fitValidationContext(item LLMValidationItem, budget int, estimator chunking.TokenEstimator) LLMValidationItem {
for {
tokens, err := estimateBatchTokens(estimator, []LLMValidationItem{item})
if err != nil || tokens <= budget {
return item
}
if len(item.NeighboringSegments) > 0 {
item.NeighboringSegments = item.NeighboringSegments[:len(item.NeighboringSegments)-1]
} else if len(item.GlossaryEntries) > 0 {
item.GlossaryEntries = item.GlossaryEntries[:len(item.GlossaryEntries)-1]
} else {
return item
}
}
}
func neighboringSegment(position string, segment schema.Segment) NeighboringSegment {
return NeighboringSegment{Position: position, Speaker: segment.Speaker, Text: segment.Text, Categories: segment.Categories}
}