calls_push_certainty.go
package calls
import (
"fmt"
"skraak/datafile"
)
// PushCertaintyConfig holds the configuration for push-certainty
type PushCertaintyConfig struct {
Folder string
File string
Filter string
Species string
CallType string
Night bool
Day bool
Lat float64
Lng float64
Timezone string
Reviewer string
}
// PushCertaintyResult holds the result of push-certainty
type PushCertaintyResult struct {
SegmentsUpdated int `json:"segments_updated"`
FilesUpdated int `json:"files_updated"`
TimeFilteredCount int `json:"time_filtered_count"`
}
// PushCertainty promotes all certainty=90 segments matching the filter scope to certainty=100.
// Uses identical filtering logic to LoadDataFiles so the scope matches calls classify exactly.
func PushCertainty(config PushCertaintyConfig) (*PushCertaintyResult, error) {
state, err := LoadDataFiles(ClassifyConfig{
Folder: config.Folder,
File: config.File,
Filter: config.Filter,
Species: config.Species,
CallType: config.CallType,
Certainty: 90,
Sample: -1,
Night: config.Night,
Day: config.Day,
Lat: config.Lat,
Lng: config.Lng,
Timezone: config.Timezone,
})
if err != nil {
return nil, err
}
var segsUpdated, filesUpdated int
for i, df := range state.DataFiles {
changed := false
for _, seg := range state.FilteredSegs()[i] {
for _, label := range seg.Labels {
if labelMatchesPush(label, config.Filter, config.Species, config.CallType) {
label.Certainty = 100
changed = true
segsUpdated++
}
}
}
if changed {
df.Meta.Reviewer = config.Reviewer
if err := df.Write(df.FilePath); err != nil {
return nil, fmt.Errorf("write %s: %w", df.FilePath, err)
}
filesUpdated++
}
}
return &PushCertaintyResult{
SegmentsUpdated: segsUpdated,
FilesUpdated: filesUpdated,
TimeFilteredCount: state.TimeFilteredCount,
}, nil
}
// labelMatchesPush returns true if the label matches the push scope and has certainty=90.
// Certainty is already guaranteed by LoadDataFiles, but we re-check to target only the
// specific label that matched (a segment may carry labels from multiple filters).
func labelMatchesPush(label *datafile.Label, filter, species, callType string) bool {
if filter != "" && label.Filter != filter {
return false
}
if species != "" && label.Species != species {
return false
}
if callType != "" && label.CallType != callType {
return false
}
return label.Certainty == 90
}