149 lines
5.4 KiB
Go
149 lines
5.4 KiB
Go
package validators
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type ConfidenceThresholdValidator struct{}
|
|
|
|
func (v ConfidenceThresholdValidator) Name() string { return "confidence_threshold" }
|
|
|
|
func (v ConfidenceThresholdValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
threshold := confidenceThresholdForModule(req.ModuleKey, req.Config)
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
if c.Confidence < threshold {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonLowConfidence, fmt.Sprintf("confidence %.4f below threshold %.4f", c.Confidence, threshold)))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
type OriginalTextPresenceValidator struct{}
|
|
|
|
func (v OriginalTextPresenceValidator) Name() string { return "original_text_presence" }
|
|
|
|
func (v OriginalTextPresenceValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
byID := make(map[int]string)
|
|
if req.WorkingTranscript != nil {
|
|
for _, seg := range req.WorkingTranscript.Segments {
|
|
byID[seg.ID] = seg.Text
|
|
}
|
|
}
|
|
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
text, ok := byID[c.TargetSegmentID]
|
|
if !ok {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonMissingTargetSegment, "target segment was not found"))
|
|
continue
|
|
}
|
|
if !strings.Contains(text, c.OriginalText) {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonMissingOriginalText, "original_text was not found in current segment text"))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
type NonEmptyCorrectionValidator struct{}
|
|
|
|
func (v NonEmptyCorrectionValidator) Name() string { return "non_empty_correction" }
|
|
|
|
func (v NonEmptyCorrectionValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
if strings.TrimSpace(c.CorrectedText) == "" {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonEmptyCorrectedText, "corrected_text must not be empty"))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
type NoEffectValidator struct{}
|
|
|
|
func (v NoEffectValidator) Name() string { return "no_effect" }
|
|
|
|
func (v NoEffectValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
if c.OriginalText == c.CorrectedText {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonNoEffect, "original_text and corrected_text are identical"))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
type ProtectedGlossaryTermValidator struct{}
|
|
|
|
func (v ProtectedGlossaryTermValidator) Name() string { return "protected_glossary_terms" }
|
|
|
|
func (v ProtectedGlossaryTermValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
if req.ModuleKey == "glossary" {
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
vocab := NewProtectedVocabulary(req.Glossary)
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
reason := vocab.violationReason(c.OriginalText, c.CorrectedText)
|
|
if reason != "" {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonProtectedGlossaryTerm, reason))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|
|
|
|
type GlossaryStageProtectedGlossaryTermValidator struct{}
|
|
|
|
func (v GlossaryStageProtectedGlossaryTermValidator) Name() string {
|
|
return "glossary_stage_protected_glossary_terms"
|
|
}
|
|
|
|
func (v GlossaryStageProtectedGlossaryTermValidator) Validate(_ context.Context, req Request) (Result, error) {
|
|
vocab := NewProtectedVocabulary(req.Glossary)
|
|
decisions := make([]Decision, 0, len(req.CandidateProposal))
|
|
for _, c := range req.CandidateProposal {
|
|
reason := vocab.glossaryStageViolationReason(c.OriginalText, c.CorrectedText)
|
|
if reason != "" {
|
|
decisions = append(decisions, rejection(c.ProposalIndex, ReasonProtectedGlossaryTerm, reason))
|
|
continue
|
|
}
|
|
decisions = append(decisions, approval(c.ProposalIndex))
|
|
}
|
|
if err := EnforceDecisionCardinality(req.CandidateProposal, decisions); err != nil {
|
|
return Result{}, err
|
|
}
|
|
return Result{ValidatorName: v.Name(), Decisions: decisions}, nil
|
|
}
|