Fix model switching crash and improve error handling
**Model Reload Fixes:** - Properly disconnect signals before reconnecting to prevent duplicate connections - Wait for previous model loader thread to finish before starting new one - Add garbage collection after unloading model to free memory - Improve error handling in model reload callback **Settings Dialog:** - Remove duplicate success message (callback handles it) - Only show message if no callback is defined **Transcription Engine:** - Explicitly delete model reference before setting to None - Force garbage collection to ensure memory is freed This prevents crashes when switching models, especially when done multiple times in succession or while the app is under load. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -221,9 +221,16 @@ class TranscriptionEngine:
|
|||||||
def unload_model(self):
|
def unload_model(self):
|
||||||
"""Unload the model from memory."""
|
"""Unload the model from memory."""
|
||||||
with self.model_lock:
|
with self.model_lock:
|
||||||
|
if self.model is not None:
|
||||||
|
# Delete the model reference
|
||||||
|
del self.model
|
||||||
self.model = None
|
self.model = None
|
||||||
self.is_loaded = False
|
self.is_loaded = False
|
||||||
|
|
||||||
|
# Force garbage collection to free memory
|
||||||
|
import gc
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"TranscriptionEngine(model={self.model_size}, device={self.device}, loaded={self.is_loaded})"
|
return f"TranscriptionEngine(model={self.model_size}, device={self.device}, loaded={self.is_loaded})"
|
||||||
|
|
||||||
|
|||||||
@@ -571,6 +571,18 @@ class MainWindow(QMainWindow):
|
|||||||
self.status_label.setText("⚙ Reloading model...")
|
self.status_label.setText("⚙ Reloading model...")
|
||||||
self.start_button.setEnabled(False)
|
self.start_button.setEnabled(False)
|
||||||
|
|
||||||
|
# Wait for any existing model loader thread to finish and disconnect
|
||||||
|
if self.model_loader_thread and self.model_loader_thread.isRunning():
|
||||||
|
print("Waiting for previous model loader to finish...")
|
||||||
|
self.model_loader_thread.wait()
|
||||||
|
|
||||||
|
# Disconnect any existing signals to prevent duplicate connections
|
||||||
|
if self.model_loader_thread:
|
||||||
|
try:
|
||||||
|
self.model_loader_thread.finished.disconnect()
|
||||||
|
except:
|
||||||
|
pass # Already disconnected or never connected
|
||||||
|
|
||||||
# Unload current model
|
# Unload current model
|
||||||
if self.transcription_engine:
|
if self.transcription_engine:
|
||||||
try:
|
try:
|
||||||
@@ -600,10 +612,7 @@ class MainWindow(QMainWindow):
|
|||||||
min_confidence=self.config.get('processing.min_confidence', 0.5)
|
min_confidence=self.config.get('processing.min_confidence', 0.5)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Load model in background thread
|
# Create new model loader thread
|
||||||
if self.model_loader_thread and self.model_loader_thread.isRunning():
|
|
||||||
self.model_loader_thread.wait()
|
|
||||||
|
|
||||||
self.model_loader_thread = ModelLoaderThread(self.transcription_engine)
|
self.model_loader_thread = ModelLoaderThread(self.transcription_engine)
|
||||||
self.model_loader_thread.finished.connect(self._on_model_reloaded)
|
self.model_loader_thread.finished.connect(self._on_model_reloaded)
|
||||||
self.model_loader_thread.start()
|
self.model_loader_thread.start()
|
||||||
@@ -619,6 +628,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def _on_model_reloaded(self, success: bool, message: str):
|
def _on_model_reloaded(self, success: bool, message: str):
|
||||||
"""Handle model reloading completion."""
|
"""Handle model reloading completion."""
|
||||||
|
try:
|
||||||
if success:
|
if success:
|
||||||
# Update device label with actual device used
|
# Update device label with actual device used
|
||||||
if self.transcription_engine:
|
if self.transcription_engine:
|
||||||
@@ -636,6 +646,10 @@ class MainWindow(QMainWindow):
|
|||||||
self.status_label.setText("❌ Model loading failed")
|
self.status_label.setText("❌ Model loading failed")
|
||||||
QMessageBox.critical(self, "Error", f"Failed to reload model:\n{message}")
|
QMessageBox.critical(self, "Error", f"Failed to reload model:\n{message}")
|
||||||
self.start_button.setEnabled(False)
|
self.start_button.setEnabled(False)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in _on_model_reloaded: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
def _start_server_sync(self):
|
def _start_server_sync(self):
|
||||||
"""Start server sync client."""
|
"""Start server sync client."""
|
||||||
|
|||||||
@@ -283,11 +283,13 @@ class SettingsDialog(QDialog):
|
|||||||
self.config.set('server_sync.room', self.server_room_input.text())
|
self.config.set('server_sync.room', self.server_room_input.text())
|
||||||
self.config.set('server_sync.passphrase', self.server_passphrase_input.text())
|
self.config.set('server_sync.passphrase', self.server_passphrase_input.text())
|
||||||
|
|
||||||
# Call save callback
|
# Call save callback (which will show the success message)
|
||||||
if self.on_save:
|
if self.on_save:
|
||||||
self.on_save()
|
self.on_save()
|
||||||
|
else:
|
||||||
|
# Only show message if no callback
|
||||||
QMessageBox.information(self, "Settings Saved", "Settings have been saved successfully!")
|
QMessageBox.information(self, "Settings Saved", "Settings have been saved successfully!")
|
||||||
|
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user