feat(hints): use the model's threshold when hint.threshold is unset
- commit
- 08d5eeba7e73280e545643475080f6abac9661bd
- author
- brice · · 2026-10-22 05:26 UTC
- parent
- 2fd66b7
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
8 files · +48 -15
M docs/config.md +1 -1
| @@ -62,7 +62,7 @@ See [examples/config](../examples/config) for every key with its default. | |||
| 62 | 62 | | `hint.enable` | `off` | Turn on the experimental [hint mode](#hint-mode) (restart required) | | |
| 63 | 63 | | `hint.detector` | `nefer-hints` | The [hint mode](#hint-mode) detector binary: a path, or a name looked up in `PATH` (restart required) | | |
| 64 | 64 | | `hint.model` | `$XDG_DATA_HOME/nefer-hints/models` | Directory of the detector's model files; `~/.local/share/nefer-hints/models` when `XDG_DATA_HOME` is unset; a leading `~/` is expanded (restart required) | | |
| 65 | - | | `hint.threshold` | `0.05` | Minimum detection score, 0.01 to 0.99; lower finds more targets and more false ones (restart required) | | |
| 65 | + | | `hint.threshold` | model default | Optional minimum detection score override, 0.01 to 0.99; unset or empty uses the model’s own threshold (`model.json`), else the runner default. Lower finds more targets and more false ones (restart required) | | |
| 66 | 66 | | `hint.capture` | `off` | Show hint labels in captures requested by Wayland clients (screenshots, screencasts); the compositor's own hint scans never see them; applies on reload | | |
| 67 | 67 | | `hint.size` | `auto` | Label text size in logical pixels (6 to 72), or `auto` for screen pixel density | | |
| 68 | 68 | | `hint.background` | empty | Label background (`#rrggbb`); empty uses `border.active` | | |
| @@ -62,7 +62,7 @@ See [examples/config](../examples/config) for every key with its default. | |||||
| 62 | | `hint.enable` | `off` | Turn on the experimental [hint mode](#hint-mode) (restart required) | | 62 | | `hint.enable` | `off` | Turn on the experimental [hint mode](#hint-mode) (restart required) | | ||
| 63 | | `hint.detector` | `nefer-hints` | The [hint mode](#hint-mode) detector binary: a path, or a name looked up in `PATH` (restart required) | | 63 | | `hint.detector` | `nefer-hints` | The [hint mode](#hint-mode) detector binary: a path, or a name looked up in `PATH` (restart required) | | ||
| 64 | | `hint.model` | `$XDG_DATA_HOME/nefer-hints/models` | Directory of the detector's model files; `~/.local/share/nefer-hints/models` when `XDG_DATA_HOME` is unset; a leading `~/` is expanded (restart required) | | 64 | | `hint.model` | `$XDG_DATA_HOME/nefer-hints/models` | Directory of the detector's model files; `~/.local/share/nefer-hints/models` when `XDG_DATA_HOME` is unset; a leading `~/` is expanded (restart required) | | ||
| 65 | - | | `hint.threshold` | `0.05` | Minimum detection score, 0.01 to 0.99; lower finds more targets and more false ones (restart required) | | 65 | + | | `hint.threshold` | model default | Optional minimum detection score override, 0.01 to 0.99; unset or empty uses the model’s own threshold (`model.json`), else the runner default. Lower finds more targets and more false ones (restart required) | |
| 66 | | `hint.capture` | `off` | Show hint labels in captures requested by Wayland clients (screenshots, screencasts); the compositor's own hint scans never see them; applies on reload | | 66 | | `hint.capture` | `off` | Show hint labels in captures requested by Wayland clients (screenshots, screencasts); the compositor's own hint scans never see them; applies on reload | | ||
| 67 | | `hint.size` | `auto` | Label text size in logical pixels (6 to 72), or `auto` for screen pixel density | | 67 | | `hint.size` | `auto` | Label text size in logical pixels (6 to 72), or `auto` for screen pixel density | | ||
| 68 | | `hint.background` | empty | Label background (`#rrggbb`); empty uses `border.active` | | 68 | | `hint.background` | empty | Label background (`#rrggbb`); empty uses `border.active` | | ||
M examples/config +3 -1
| @@ -101,7 +101,9 @@ focus.flash-color = | |||
| 101 | 101 | # Hint mode finds its targets with the nefer-hints detector (restart required). | |
| 102 | 102 | # hint.detector = nefer-hints | |
| 103 | 103 | # hint.model = ~/.local/share/nefer-hints/models | |
| 104 | - | # hint.threshold = 0.05 | |
| 104 | + | # Unset or empty uses the model threshold (model.json), else the runner default. | |
| 105 | + | # Set 0.01..0.99 to override it. | |
| 106 | + | # hint.threshold = | |
| 105 | 107 | # Show the labels in screenshots and screencasts taken by clients. | |
| 106 | 108 | # hint.capture = off | |
| 107 | 109 | ||
| @@ -101,7 +101,9 @@ focus.flash-color = | |||||
| 101 | # Hint mode finds its targets with the nefer-hints detector (restart required). | 101 | # Hint mode finds its targets with the nefer-hints detector (restart required). | ||
| 102 | # hint.detector = nefer-hints | 102 | # hint.detector = nefer-hints | ||
| 103 | # hint.model = ~/.local/share/nefer-hints/models | 103 | # hint.model = ~/.local/share/nefer-hints/models | ||
| 104 | - | # hint.threshold = 0.05 | 104 | + | # Unset or empty uses the model threshold (model.json), else the runner default. |
| 105 | + | # Set 0.01..0.99 to override it. | |||
| 106 | + | # hint.threshold = | |||
| 105 | # Show the labels in screenshots and screencasts taken by clients. | 107 | # Show the labels in screenshots and screencasts taken by clients. | ||
| 106 | # hint.capture = off | 108 | # hint.capture = off | ||
| 107 | 109 | ||||
M internal/adapters/config/config.go +5 -5
| @@ -168,7 +168,6 @@ func Defaults() ports.Config { | |||
| 168 | 168 | c.Hint.Enable = false | |
| 169 | 169 | c.Hint.Detector = defaultHintDetector | |
| 170 | 170 | c.Hint.Model = defaultHintModel() | |
| 171 | - | c.Hint.Threshold = defaultHintThreshold | |
| 172 | 171 | c.Xwayland = "xwayland-satellite" | |
| 173 | 172 | c.Background.Color = "#111111" | |
| 174 | 173 | c.Floating.Dim = 0.3 | |
| @@ -909,6 +908,10 @@ func set(c *ports.Config, key, v string) error { | |||
| 909 | 908 | } | |
| 910 | 909 | c.Hint.Model = expandHome(v) | |
| 911 | 910 | case "hint.threshold": | |
| 911 | + | if v == "" { | |
| 912 | + | c.Hint.Threshold = 0 | |
| 913 | + | break | |
| 914 | + | } | |
| 912 | 915 | n, err := strconv.ParseFloat(v, 64) | |
| 913 | 916 | if err != nil || math.IsNaN(n) || n < 0.01 || n > 0.99 { | |
| 914 | 917 | return fmt.Errorf("must be a number from 0.01 to 0.99") | |
| @@ -1337,10 +1340,7 @@ func checkAction(v string) error { | |||
| 1337 | 1340 | return nil | |
| 1338 | 1341 | } | |
| 1339 | 1342 | ||
| 1340 | - | const ( | |
| 1341 | - | defaultHintDetector = "nefer-hints" | |
| 1342 | - | defaultHintThreshold = 0.05 | |
| 1343 | - | ) | |
| 1343 | + | const defaultHintDetector = "nefer-hints" | |
| 1344 | 1344 | ||
| 1345 | 1345 | // defaultHintModel is $XDG_DATA_HOME/nefer-hints/models, or | |
| 1346 | 1346 | // ~/.local/share/nefer-hints/models when XDG_DATA_HOME is unset. | |
| @@ -168,7 +168,6 @@ func Defaults() ports.Config { | |||||
| 168 | c.Hint.Enable = false | 168 | c.Hint.Enable = false | ||
| 169 | c.Hint.Detector = defaultHintDetector | 169 | c.Hint.Detector = defaultHintDetector | ||
| 170 | c.Hint.Model = defaultHintModel() | 170 | c.Hint.Model = defaultHintModel() | ||
| 171 | - | c.Hint.Threshold = defaultHintThreshold | |||
| 172 | c.Xwayland = "xwayland-satellite" | 171 | c.Xwayland = "xwayland-satellite" | ||
| 173 | c.Background.Color = "#111111" | 172 | c.Background.Color = "#111111" | ||
| 174 | c.Floating.Dim = 0.3 | 173 | c.Floating.Dim = 0.3 | ||
| @@ -909,6 +908,10 @@ func set(c *ports.Config, key, v string) error { | |||||
| 909 | } | 908 | } | ||
| 910 | c.Hint.Model = expandHome(v) | 909 | c.Hint.Model = expandHome(v) | ||
| 911 | case "hint.threshold": | 910 | case "hint.threshold": | ||
| 911 | + | if v == "" { | |||
| 912 | + | c.Hint.Threshold = 0 | |||
| 913 | + | break | |||
| 914 | + | } | |||
| 912 | n, err := strconv.ParseFloat(v, 64) | 915 | n, err := strconv.ParseFloat(v, 64) | ||
| 913 | if err != nil || math.IsNaN(n) || n < 0.01 || n > 0.99 { | 916 | if err != nil || math.IsNaN(n) || n < 0.01 || n > 0.99 { | ||
| 914 | return fmt.Errorf("must be a number from 0.01 to 0.99") | 917 | return fmt.Errorf("must be a number from 0.01 to 0.99") | ||
| @@ -1337,10 +1340,7 @@ func checkAction(v string) error { | |||||
| 1337 | return nil | 1340 | return nil | ||
| 1338 | } | 1341 | } | ||
| 1339 | 1342 | ||||
| 1340 | - | const ( | 1343 | + | const defaultHintDetector = "nefer-hints" |
| 1341 | - | defaultHintDetector = "nefer-hints" | |||
| 1342 | - | defaultHintThreshold = 0.05 | |||
| 1343 | - | ) | |||
| 1344 | 1344 | ||||
| 1345 | // defaultHintModel is $XDG_DATA_HOME/nefer-hints/models, or | 1345 | // defaultHintModel is $XDG_DATA_HOME/nefer-hints/models, or | ||
| 1346 | // ~/.local/share/nefer-hints/models when XDG_DATA_HOME is unset. | 1346 | // ~/.local/share/nefer-hints/models when XDG_DATA_HOME is unset. | ||
M internal/adapters/config/config_test.go +14 -4
| @@ -974,7 +974,7 @@ func TestHintDetectorConfig(t *testing.T) { | |||
| 974 | 974 | t.Setenv("HOME", "/home/u") | |
| 975 | 975 | t.Setenv("XDG_DATA_HOME", "") | |
| 976 | 976 | d := Defaults().Hint | |
| 977 | - | if d.Detector != "nefer-hints" || d.Model != "/home/u/.local/share/nefer-hints/models" || d.Threshold != 0.05 { | |
| 977 | + | if d.Detector != "nefer-hints" || d.Model != "/home/u/.local/share/nefer-hints/models" || d.Threshold != 0 { | |
| 978 | 978 | t.Fatalf("defaults: %+v", d) | |
| 979 | 979 | } | |
| 980 | 980 | t.Setenv("XDG_DATA_HOME", "/data") | |
| @@ -989,14 +989,24 @@ func TestHintDetectorConfig(t *testing.T) { | |||
| 989 | 989 | if len(w) != 0 || c.Hint.Detector != "/opt/nh" || c.Hint.Model != "/opt/models" { | |
| 990 | 990 | t.Fatalf("%+v %v", c.Hint, w) | |
| 991 | 991 | } | |
| 992 | - | for _, v := range []string{"0", "0.009", "1", "0.995", "NaN", "high", "-1"} { | |
| 992 | + | for _, input := range []string{"", "hint.threshold =\n"} { | |
| 993 | + | c, w := parseString(t, input) | |
| 994 | + | if len(w) != 0 || c.Hint.Threshold != 0 { | |
| 995 | + | t.Errorf("unset threshold %q: %v %v", input, c.Hint.Threshold, w) | |
| 996 | + | } | |
| 997 | + | } | |
| 998 | + | c, w = parseString(t, "hint.threshold = 0.3\nhint.threshold =\n") | |
| 999 | + | if len(w) != 1 || c.Hint.Threshold != 0 { // duplicate-key warning only | |
| 1000 | + | t.Fatalf("cleared threshold: %v %v", c.Hint.Threshold, w) | |
| 1001 | + | } | |
| 1002 | + | for _, v := range []string{"0", "0.009", "1", "0.995", "NaN", "Inf", "-Inf", "high", "-1"} { | |
| 993 | 1003 | c, w := parseString(t, "hint.threshold = "+v+"\n") | |
| 994 | - | if len(w) != 1 || c.Hint.Threshold != 0.05 { | |
| 1004 | + | if len(w) != 1 || c.Hint.Threshold != 0 { | |
| 995 | 1005 | t.Errorf("hint.threshold = %s: %v %v", v, c.Hint.Threshold, w) | |
| 996 | 1006 | } | |
| 997 | 1007 | } | |
| 998 | 1008 | for _, v := range []string{"0.01", "0.99"} { | |
| 999 | - | if c, w := parseString(t, "hint.threshold = "+v+"\n"); len(w) != 0 || c.Hint.Threshold == 0.05 { | |
| 1009 | + | if c, w := parseString(t, "hint.threshold = "+v+"\n"); len(w) != 0 || c.Hint.Threshold == 0 { | |
| 1000 | 1010 | t.Errorf("hint.threshold = %s: %v", v, w) | |
| 1001 | 1011 | } | |
| 1002 | 1012 | } | |
| @@ -974,7 +974,7 @@ func TestHintDetectorConfig(t *testing.T) { | |||||
| 974 | t.Setenv("HOME", "/home/u") | 974 | t.Setenv("HOME", "/home/u") | ||
| 975 | t.Setenv("XDG_DATA_HOME", "") | 975 | t.Setenv("XDG_DATA_HOME", "") | ||
| 976 | d := Defaults().Hint | 976 | d := Defaults().Hint | ||
| 977 | - | if d.Detector != "nefer-hints" || d.Model != "/home/u/.local/share/nefer-hints/models" || d.Threshold != 0.05 { | 977 | + | if d.Detector != "nefer-hints" || d.Model != "/home/u/.local/share/nefer-hints/models" || d.Threshold != 0 { |
| 978 | t.Fatalf("defaults: %+v", d) | 978 | t.Fatalf("defaults: %+v", d) | ||
| 979 | } | 979 | } | ||
| 980 | t.Setenv("XDG_DATA_HOME", "/data") | 980 | t.Setenv("XDG_DATA_HOME", "/data") | ||
| @@ -989,14 +989,24 @@ func TestHintDetectorConfig(t *testing.T) { | |||||
| 989 | if len(w) != 0 || c.Hint.Detector != "/opt/nh" || c.Hint.Model != "/opt/models" { | 989 | if len(w) != 0 || c.Hint.Detector != "/opt/nh" || c.Hint.Model != "/opt/models" { | ||
| 990 | t.Fatalf("%+v %v", c.Hint, w) | 990 | t.Fatalf("%+v %v", c.Hint, w) | ||
| 991 | } | 991 | } | ||
| 992 | - | for _, v := range []string{"0", "0.009", "1", "0.995", "NaN", "high", "-1"} { | 992 | + | for _, input := range []string{"", "hint.threshold =\n"} { |
| 993 | + | c, w := parseString(t, input) | |||
| 994 | + | if len(w) != 0 || c.Hint.Threshold != 0 { | |||
| 995 | + | t.Errorf("unset threshold %q: %v %v", input, c.Hint.Threshold, w) | |||
| 996 | + | } | |||
| 997 | + | } | |||
| 998 | + | c, w = parseString(t, "hint.threshold = 0.3\nhint.threshold =\n") | |||
| 999 | + | if len(w) != 1 || c.Hint.Threshold != 0 { // duplicate-key warning only | |||
| 1000 | + | t.Fatalf("cleared threshold: %v %v", c.Hint.Threshold, w) | |||
| 1001 | + | } | |||
| 1002 | + | for _, v := range []string{"0", "0.009", "1", "0.995", "NaN", "Inf", "-Inf", "high", "-1"} { | |||
| 993 | c, w := parseString(t, "hint.threshold = "+v+"\n") | 1003 | c, w := parseString(t, "hint.threshold = "+v+"\n") | ||
| 994 | - | if len(w) != 1 || c.Hint.Threshold != 0.05 { | 1004 | + | if len(w) != 1 || c.Hint.Threshold != 0 { |
| 995 | t.Errorf("hint.threshold = %s: %v %v", v, c.Hint.Threshold, w) | 1005 | t.Errorf("hint.threshold = %s: %v %v", v, c.Hint.Threshold, w) | ||
| 996 | } | 1006 | } | ||
| 997 | } | 1007 | } | ||
| 998 | for _, v := range []string{"0.01", "0.99"} { | 1008 | for _, v := range []string{"0.01", "0.99"} { | ||
| 999 | - | if c, w := parseString(t, "hint.threshold = "+v+"\n"); len(w) != 0 || c.Hint.Threshold == 0.05 { | 1009 | + | if c, w := parseString(t, "hint.threshold = "+v+"\n"); len(w) != 0 || c.Hint.Threshold == 0 { |
| 1000 | t.Errorf("hint.threshold = %s: %v", v, w) | 1010 | t.Errorf("hint.threshold = %s: %v", v, w) | ||
| 1001 | } | 1011 | } | ||
| 1002 | } | 1012 | } | ||
M internal/adapters/hints/detector.go +10 -2
| @@ -274,10 +274,18 @@ func (p *process) wait() { | |||
| 274 | 274 | }) | |
| 275 | 275 | } | |
| 276 | 276 | ||
| 277 | + | // cmd leaves confidence selection to the runner unless explicitly configured. | |
| 278 | + | func (d *procDetector) cmd() *exec.Cmd { | |
| 279 | + | args := []string{"--model", d.model, "--imgsz", strconv.Itoa(imgsz), "--gpu", "auto"} | |
| 280 | + | if d.conf != 0 { | |
| 281 | + | args = append(args, "--conf", strconv.FormatFloat(d.conf, 'f', -1, 64)) | |
| 282 | + | } | |
| 283 | + | return exec.Command(d.command, args...) | |
| 284 | + | } | |
| 285 | + | ||
| 277 | 286 | func (d *procDetector) start(ctx context.Context) error { | |
| 278 | 287 | log := logging.For(ctx, "hints") | |
| 279 | - | cmd := exec.Command(d.command, "--model", d.model, "--imgsz", strconv.Itoa(imgsz), | |
| 280 | - | "--conf", strconv.FormatFloat(d.conf, 'f', -1, 64), "--gpu", "auto") | |
| 288 | + | cmd := d.cmd() | |
| 281 | 289 | cmd.Stderr = &lineLog{log: func(line string) { log.Debug().Str("detector", d.command).Msg(line) }} | |
| 282 | 290 | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |
| 283 | 291 | cmd.WaitDelay = waitDelay | |
| @@ -274,10 +274,18 @@ func (p *process) wait() { | |||||
| 274 | }) | 274 | }) | ||
| 275 | } | 275 | } | ||
| 276 | 276 | ||||
| 277 | + | // cmd leaves confidence selection to the runner unless explicitly configured. | |||
| 278 | + | func (d *procDetector) cmd() *exec.Cmd { | |||
| 279 | + | args := []string{"--model", d.model, "--imgsz", strconv.Itoa(imgsz), "--gpu", "auto"} | |||
| 280 | + | if d.conf != 0 { | |||
| 281 | + | args = append(args, "--conf", strconv.FormatFloat(d.conf, 'f', -1, 64)) | |||
| 282 | + | } | |||
| 283 | + | return exec.Command(d.command, args...) | |||
| 284 | + | } | |||
| 285 | + | ||||
| 277 | func (d *procDetector) start(ctx context.Context) error { | 286 | func (d *procDetector) start(ctx context.Context) error { | ||
| 278 | log := logging.For(ctx, "hints") | 287 | log := logging.For(ctx, "hints") | ||
| 279 | - | cmd := exec.Command(d.command, "--model", d.model, "--imgsz", strconv.Itoa(imgsz), | 288 | + | cmd := d.cmd() |
| 280 | - | "--conf", strconv.FormatFloat(d.conf, 'f', -1, 64), "--gpu", "auto") | |||
| 281 | cmd.Stderr = &lineLog{log: func(line string) { log.Debug().Str("detector", d.command).Msg(line) }} | 289 | cmd.Stderr = &lineLog{log: func(line string) { log.Debug().Str("detector", d.command).Msg(line) }} | ||
| 282 | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | 290 | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | ||
| 283 | cmd.WaitDelay = waitDelay | 291 | cmd.WaitDelay = waitDelay | ||
M internal/adapters/hints/detector_test.go +11 -0
| @@ -145,3 +145,14 @@ func TestProcDetectorMissingBinary(t *testing.T) { | |||
| 145 | 145 | require.Nil(t, d.proc) | |
| 146 | 146 | require.NoError(t, d.Close()) | |
| 147 | 147 | } | |
| 148 | + | ||
| 149 | + | func TestProcDetectorCommand(t *testing.T) { | |
| 150 | + | for _, threshold := range []float64{0, 0.3} { | |
| 151 | + | d := newProcDetector("nefer-hints", "/models", threshold) | |
| 152 | + | want := []string{"nefer-hints", "--model", "/models", "--imgsz", "1280", "--gpu", "auto"} | |
| 153 | + | if threshold != 0 { | |
| 154 | + | want = append(want, "--conf", "0.3") | |
| 155 | + | } | |
| 156 | + | require.Equal(t, want, d.cmd().Args) | |
| 157 | + | } | |
| 158 | + | } | |
| @@ -145,3 +145,14 @@ func TestProcDetectorMissingBinary(t *testing.T) { | |||||
| 145 | require.Nil(t, d.proc) | 145 | require.Nil(t, d.proc) | ||
| 146 | require.NoError(t, d.Close()) | 146 | require.NoError(t, d.Close()) | ||
| 147 | } | 147 | } | ||
| 148 | + | ||||
| 149 | + | func TestProcDetectorCommand(t *testing.T) { | |||
| 150 | + | for _, threshold := range []float64{0, 0.3} { | |||
| 151 | + | d := newProcDetector("nefer-hints", "/models", threshold) | |||
| 152 | + | want := []string{"nefer-hints", "--model", "/models", "--imgsz", "1280", "--gpu", "auto"} | |||
| 153 | + | if threshold != 0 { | |||
| 154 | + | want = append(want, "--conf", "0.3") | |||
| 155 | + | } | |||
| 156 | + | require.Equal(t, want, d.cmd().Args) | |||
| 157 | + | } | |||
| 158 | + | } | |||
M internal/adapters/hints/dump.go +2 -1
| @@ -30,7 +30,8 @@ type Options struct { | |||
| 30 | 30 | Command string | |
| 31 | 31 | // ModelDir is the directory of the detector's model files. | |
| 32 | 32 | ModelDir string | |
| 33 | - | // Threshold is the minimum detection score, 0.01 to 0.99. | |
| 33 | + | // Threshold overrides the minimum detection score, 0.01 to 0.99. | |
| 34 | + | // Zero uses model.json or, if absent, the runner default. | |
| 34 | 35 | Threshold float64 | |
| 35 | 36 | // DumpDir, when not empty, receives the scanned frames (PNG, annotated | |
| 36 | 37 | // PNG and JSON). They contain the screen in clear. | |
| @@ -30,7 +30,8 @@ type Options struct { | |||||
| 30 | Command string | 30 | Command string | ||
| 31 | // ModelDir is the directory of the detector's model files. | 31 | // ModelDir is the directory of the detector's model files. | ||
| 32 | ModelDir string | 32 | ModelDir string | ||
| 33 | - | // Threshold is the minimum detection score, 0.01 to 0.99. | 33 | + | // Threshold overrides the minimum detection score, 0.01 to 0.99. |
| 34 | + | // Zero uses model.json or, if absent, the runner default. | |||
| 34 | Threshold float64 | 35 | Threshold float64 | ||
| 35 | // DumpDir, when not empty, receives the scanned frames (PNG, annotated | 36 | // DumpDir, when not empty, receives the scanned frames (PNG, annotated | ||
| 36 | // PNG and JSON). They contain the screen in clear. | 37 | // PNG and JSON). They contain the screen in clear. | ||
M internal/ports/config.go +2 -1
| @@ -178,7 +178,8 @@ type Config struct { | |||
| 178 | 178 | // Detector is the nefer-hints binary (hint.detector): a path, or a | |
| 179 | 179 | // name looked up in PATH. Model is the directory of its model files | |
| 180 | 180 | // (hint.model), with a leading ~/ already expanded. Threshold is the | |
| 181 | - | // minimum detection score (hint.threshold, 0.01 to 0.99). All three | |
| 181 | + | // minimum detection score (hint.threshold, 0.01 to 0.99); zero leaves | |
| 182 | + | // it unset, using model.json or the runner default. All three | |
| 182 | 183 | // are read at startup. | |
| 183 | 184 | Detector, Model string | |
| 184 | 185 | Threshold float64 | |
| @@ -178,7 +178,8 @@ type Config struct { | |||||
| 178 | // Detector is the nefer-hints binary (hint.detector): a path, or a | 178 | // Detector is the nefer-hints binary (hint.detector): a path, or a | ||
| 179 | // name looked up in PATH. Model is the directory of its model files | 179 | // name looked up in PATH. Model is the directory of its model files | ||
| 180 | // (hint.model), with a leading ~/ already expanded. Threshold is the | 180 | // (hint.model), with a leading ~/ already expanded. Threshold is the | ||
| 181 | - | // minimum detection score (hint.threshold, 0.01 to 0.99). All three | 181 | + | // minimum detection score (hint.threshold, 0.01 to 0.99); zero leaves |
| 182 | + | // it unset, using model.json or the runner default. All three | |||
| 182 | // are read at startup. | 183 | // are read at startup. | ||
| 183 | Detector, Model string | 184 | Detector, Model string | ||
| 184 | Threshold float64 | 185 | Threshold float64 | ||