-
-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve configuration reload #378
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ import ( | |
"github.com/tphakala/birdnet-go/internal/datastore" | ||
"github.com/tphakala/birdnet-go/internal/diskmanager" | ||
"github.com/tphakala/birdnet-go/internal/httpcontroller" | ||
"github.com/tphakala/birdnet-go/internal/httpcontroller/handlers" | ||
"github.com/tphakala/birdnet-go/internal/myaudio" | ||
"github.com/tphakala/birdnet-go/internal/telemetry" | ||
"github.com/tphakala/birdnet-go/internal/weather" | ||
|
@@ -28,7 +29,7 @@ import ( | |
var audioLevelChan = make(chan myaudio.AudioLevelData, 100) | ||
|
||
// RealtimeAnalysis initiates the BirdNET Analyzer in real-time mode and waits for a termination signal. | ||
func RealtimeAnalysis(settings *conf.Settings) error { | ||
func RealtimeAnalysis(settings *conf.Settings, notificationChan chan handlers.Notification) error { | ||
// Initialize BirdNET interpreter | ||
if err := initializeBirdNET(settings); err != nil { | ||
return err | ||
|
@@ -153,7 +154,7 @@ func RealtimeAnalysis(settings *conf.Settings) error { | |
startTelemetryEndpoint(&wg, settings, metrics, quitChan) | ||
|
||
// start control monitor for hot reloads | ||
startControlMonitor(&wg, controlChan, quitChan) | ||
startControlMonitor(&wg, controlChan, quitChan, notificationChan) | ||
|
||
// start quit signal monitor | ||
monitorCtrlC(quitChan) | ||
|
@@ -327,7 +328,7 @@ func initBirdImageCache(ds datastore.Interface, metrics *telemetry.Metrics) *ima | |
} | ||
|
||
// startControlMonitor handles various control signals for realtime analysis mode | ||
func startControlMonitor(wg *sync.WaitGroup, controlChan chan string, quitChan chan struct{}) { | ||
func startControlMonitor(wg *sync.WaitGroup, controlChan chan string, quitChan chan struct{}, notificationChan chan handlers.Notification) { | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
|
@@ -338,8 +339,44 @@ func startControlMonitor(wg *sync.WaitGroup, controlChan chan string, quitChan c | |
case "rebuild_range_filter": | ||
if err := birdnet.BuildRangeFilter(bn); err != nil { | ||
log.Printf("\033[31m❌ Error handling range filter rebuild: %v\033[0m", err) | ||
notificationChan <- handlers.Notification{ | ||
Message: fmt.Sprintf("Failed to rebuild range filter: %v", err), | ||
Type: "error", | ||
} | ||
} else { | ||
log.Printf("\033[32m🔄 Range filter rebuilt successfully\033[0m") | ||
notificationChan <- handlers.Notification{ | ||
Message: "Range filter rebuilt successfully", | ||
Type: "success", | ||
} | ||
} | ||
case "reload_birdnet": | ||
if err := bn.ReloadModel(); err != nil { | ||
log.Printf("\033[31m❌ Error reloading BirdNET model: %v\033[0m", err) | ||
notificationChan <- handlers.Notification{ | ||
Message: fmt.Sprintf("Failed to reload BirdNET model: %v", err), | ||
Type: "error", | ||
} | ||
} else { | ||
log.Printf("\033[32m✅ BirdNET model reloaded successfully\033[0m") | ||
notificationChan <- handlers.Notification{ | ||
Message: "BirdNET model reloaded successfully", | ||
Type: "success", | ||
} | ||
// Rebuild range filter after model reload | ||
Comment on lines
+354
to
+366
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add timeout handling for model reload operation. The model reload operation could potentially be time-consuming. Consider adding a timeout to prevent blocking. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer cancel()
+
+ errChan := make(chan error, 1)
+ go func() {
+ errChan <- bn.ReloadModel()
+ }()
+
+ select {
+ case err := <-errChan:
if err != nil {
// ... error handling ...
} else {
// ... success handling ...
}
+ case <-ctx.Done():
+ notificationChan <- handlers.Notification{
+ Message: "Model reload timed out after 30 seconds",
+ Type: "error",
+ }
+ }
|
||
if err := birdnet.BuildRangeFilter(bn); err != nil { | ||
log.Printf("\033[31m❌ Error rebuilding range filter after model reload: %v\033[0m", err) | ||
notificationChan <- handlers.Notification{ | ||
Message: fmt.Sprintf("Failed to rebuild range filter: %v", err), | ||
Type: "error", | ||
} | ||
} else { | ||
log.Printf("\033[32m✅ Range filter rebuilt successfully\033[0m") | ||
notificationChan <- handlers.Notification{ | ||
Message: "Range filter rebuilt successfully", | ||
Type: "success", | ||
} | ||
} | ||
} | ||
default: | ||
log.Printf("Received unknown control signal: %v", signal) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -12,7 +12,6 @@ import ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"runtime" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"strings" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"sync" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"time" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/tphakala/birdnet-go/internal/conf" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"github.com/tphakala/go-tflite" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -45,7 +44,6 @@ type BirdNET struct { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
AnalysisInterpreter *tflite.Interpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RangeInterpreter *tflite.Interpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Settings *conf.Settings | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SpeciesListUpdated time.Time // Timestamp for the last update of the species list. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mu sync.Mutex | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -301,11 +299,105 @@ func (bn *BirdNET) loadModel() ([]byte, error) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modelPath := bn.Settings.BirdNET.ModelPath | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data, err := os.ReadFile(modelPath) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("failed to read custom model file: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil, fmt.Errorf("failed to read model file: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return data, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// validateModelAndLabels checks if the number of labels matches the model's output size | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (bn *BirdNET) validateModelAndLabels() error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get the output tensor to check its dimensions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
outputTensor := bn.AnalysisInterpreter.GetOutputTensor(0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if outputTensor == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("cannot get output tensor") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Get the number of classes from the model's output tensor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modelOutputSize := outputTensor.Dim(outputTensor.NumDims() - 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Compare with the number of labels | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if len(bn.Settings.BirdNET.Labels) != modelOutputSize { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("\033[31m❌ label count mismatch: model expects %d classes but label file has %d labels\033[0m", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modelOutputSize, len(bn.Settings.BirdNET.Labels)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+320
to
+322
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid including ANSI color codes and emojis in error messages Including ANSI color codes and emojis in error messages can lead to unreadable logs or issues in environments that do not support ANSI escape sequences. It is recommended to keep error messages plain to ensure they are properly displayed and logged across different systems. Apply this diff to remove color codes and emojis from error messages: - return fmt.Errorf("\033[31m❌ label count mismatch: model expects %d classes but label file has %d labels\033[0m",
+ return fmt.Errorf("label count mismatch: model expects %d classes but label file has %d labels",
modelOutputSize, len(bn.Settings.BirdNET.Labels))
...
- return fmt.Errorf("\033[31m❌ failed to reload model: %w\033[0m", err)
+ return fmt.Errorf("failed to reload model: %w", err)
...
- return fmt.Errorf("\033[31m❌ failed to reload meta model: %w\033[0m", err)
+ return fmt.Errorf("failed to reload meta model: %w", err)
...
- return fmt.Errorf("\033[31m❌ failed to reload labels: %w\033[0m", err)
+ return fmt.Errorf("failed to reload labels: %w", err)
...
- return fmt.Errorf("\033[31m❌ model validation failed: %w\033[0m", err)
+ return fmt.Errorf("model validation failed: %w", err) Also applies to: 341-341, 354-354, 370-370, 386-386 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Model validation successful: %d labels match model output size\033[0m", modelOutputSize) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+308
to
+326
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure In the Apply this diff to fix the issue: func (bn *BirdNET) validateModelAndLabels() error {
// Get the output tensor to check its dimensions
outputTensor := bn.AnalysisInterpreter.GetOutputTensor(0)
if outputTensor == nil {
return fmt.Errorf("cannot get output tensor")
}
+ if outputTensor.NumDims() == 0 {
+ return fmt.Errorf("output tensor has no dimensions")
+ }
// Get the number of classes from the model's output tensor
modelOutputSize := outputTensor.Dim(outputTensor.NumDims() - 1)
// Compare with the number of labels
if len(bn.Settings.BirdNET.Labels) != modelOutputSize {
return fmt.Errorf("\033[31m❌ label count mismatch: model expects %d classes but label file has %d labels\033[0m",
modelOutputSize, len(bn.Settings.BirdNET.Labels))
}
bn.Debug("\033[32m✅ Model validation successful: %d labels match model output size\033[0m", modelOutputSize)
return nil
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// ReloadModel safely reloads the BirdNET model and labels while handling ongoing analysis | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (bn *BirdNET) ReloadModel() error { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[33m🔒 Acquiring mutex for model reload\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.mu.Lock() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
defer bn.mu.Unlock() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Acquired mutex for model reload\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Store old interpreters to clean up after successful reload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
oldAnalysisInterpreter := bn.AnalysisInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
oldRangeInterpreter := bn.RangeInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Initialize new model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err := bn.initializeModel(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("\033[31m❌ failed to reload model: %w\033[0m", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Model initialized successfully\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Initialize new meta model | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err := bn.initializeMetaModel(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Clean up the newly created analysis interpreter if meta model fails | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.AnalysisInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Restore the old interpreters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter = oldAnalysisInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.RangeInterpreter = oldRangeInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("\033[31m❌ failed to reload meta model: %w\033[0m", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Meta model initialized successfully\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Reload labels | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err := bn.loadLabels(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Clean up the newly created interpreters if label loading fails | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.AnalysisInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.RangeInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.RangeInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Restore the old interpreters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter = oldAnalysisInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.RangeInterpreter = oldRangeInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("\033[31m❌ failed to reload labels: %w\033[0m", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Labels loaded successfully\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Validate that the model and labels match | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err := bn.validateModelAndLabels(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Clean up the newly created interpreters if validation fails | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.AnalysisInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.RangeInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.RangeInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Restore the old interpreters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.AnalysisInterpreter = oldAnalysisInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.RangeInterpreter = oldRangeInterpreter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return fmt.Errorf("\033[31m❌ model validation failed: %w\033[0m", err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Clean up old interpreters after successful reload | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if oldAnalysisInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
oldAnalysisInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if oldRangeInterpreter != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
oldRangeInterpreter.Delete() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bn.Debug("\033[32m✅ Model reload completed successfully\033[0m") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Debug prints debug messages if debug mode is enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func (bn *BirdNET) Debug(format string, v ...interface{}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if bn.Settings.BirdNET.Debug { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider error handling for channel operations.
The notification channel writes could block if the channel is full. Consider adding a select statement with a timeout.
Also applies to: 348-351