package cmd
import (
"encoding/json"
"fmt"
"os"
"skraak/tools"
)
func printDetectAnomaliesUsage() {
fmt.Fprintf(os.Stderr, "Usage: skraak calls detect-anomalies [options]\n\n")
fmt.Fprintf(os.Stderr, "Compare corresponding segments across ML model filters and flag disagreements.\n")
fmt.Fprintf(os.Stderr, "Segments are matched by time overlap. Lonely segments (no overlap in all models) are skipped.\n\n")
fmt.Fprintf(os.Stderr, "Options:\n")
fmt.Fprintf(os.Stderr, " --folder <path> Folder containing .data files (required)\n")
fmt.Fprintf(os.Stderr, " --model <name> Filter name to compare (required, repeat for each model, min 2)\n")
fmt.Fprintf(os.Stderr, " --species <name> Scope to species or species+calltype (optional, repeat to add more)\n")
fmt.Fprintf(os.Stderr, "\nAnomaly types:\n")
fmt.Fprintf(os.Stderr, " label_mismatch Species or calltype disagrees across models\n")
fmt.Fprintf(os.Stderr, " certainty_mismatch Labels agree but certainty values differ\n")
fmt.Fprintf(os.Stderr, "\nExamples:\n")
fmt.Fprintf(os.Stderr, " skraak calls detect-anomalies --folder ./data \\\n")
fmt.Fprintf(os.Stderr, " --model opensoundscape-kiwi-1.0 --model opensoundscape-kiwi-1.2\n")
fmt.Fprintf(os.Stderr, " skraak calls detect-anomalies --folder ./data \\\n")
fmt.Fprintf(os.Stderr, " --model opensoundscape-kiwi-1.0 --model opensoundscape-kiwi-1.2 --model opensoundscape-kiwi-1.5 \\\n")
fmt.Fprintf(os.Stderr, " --species Kiwi+Duet --species Kiwi+Male\n")
}
func runCallsDetectAnomalies(args []string) {
var folder string
var models []string
var species []string
i := 0
for i < len(args) {
arg := args[i]
switch arg {
case "--folder":
if i+1 >= len(args) {
fmt.Fprintf(os.Stderr, "Error: --folder requires a value\n")
os.Exit(1)
}
folder = args[i+1]
i += 2
case "--model":
if i+1 >= len(args) {
fmt.Fprintf(os.Stderr, "Error: --model requires a value\n")
os.Exit(1)
}
models = append(models, args[i+1])
i += 2
case "--species":
if i+1 >= len(args) {
fmt.Fprintf(os.Stderr, "Error: --species requires a value\n")
os.Exit(1)
}
species = append(species, args[i+1])
i += 2
case "--help", "-h":
printDetectAnomaliesUsage()
os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "Error: unknown flag: %s\n\n", arg)
printDetectAnomaliesUsage()
os.Exit(1)
}
}
if folder == "" {
fmt.Fprintf(os.Stderr, "Error: --folder is required\n\n")
printDetectAnomaliesUsage()
os.Exit(1)
}
if len(models) < 2 {
fmt.Fprintf(os.Stderr, "Error: at least 2 --model values required\n\n")
printDetectAnomaliesUsage()
os.Exit(1)
}
output, err := tools.DetectAnomalies(tools.DetectAnomaliesInput{
Folder: folder,
Models: models,
Species: species,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "Examined %d files, %d had all models\n",
output.FilesExamined, output.FilesWithAllModels)
fmt.Fprintf(os.Stderr, "Anomalies: %d total (%d label, %d certainty)\n",
output.AnomaliesTotal, output.LabelMismatches, output.CertaintyMismatches)
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(output); err != nil {
fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
os.Exit(1)
}
}