Files
2025-08-26 13:24:53 -07:00

711 lines
28 KiB
Python

"""
Settings Dialog - Application settings and configuration
"""
from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QTabWidget,
QGroupBox, QLabel, QPushButton, QCheckBox,
QComboBox, QSpinBox, QSlider, QLineEdit,
QTextEdit, QFileDialog, QColorDialog, QFrame,
QGridLayout, QFormLayout, QListWidget,
QListWidgetItem, QSplitter, QScrollArea, QSpacerItem,
QSizePolicy, QWidget, QDialogButtonBox)
from PySide6.QtCore import Qt, Signal, QSettings, QSize
from PySide6.QtGui import QFont, QColor, QIcon, QPalette
import json
import os
class SettingsDialog(QDialog):
"""
Comprehensive settings dialog for the Smart Intersection Monitoring System
Sections:
- General: Application preferences
- Display: UI themes and display options
- Detection: AI model and detection settings
- IoT: Device connections and protocols
- Performance: System optimization settings
- Security: Authentication and access control
"""
# Signals
settings_changed = Signal(dict)
theme_changed = Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.settings = QSettings("SmartIntersection", "MonitoringSystem")
self.pending_changes = {}
self.setWindowTitle("Settings - Smart Intersection Monitoring")
self.setModal(True)
self.resize(800, 600)
self._setup_ui()
self._load_settings()
def _setup_ui(self):
"""Setup settings dialog UI"""
layout = QVBoxLayout(self)
# Header
header = self._create_header()
layout.addWidget(header)
# Main content
content_splitter = QSplitter(Qt.Horizontal)
layout.addWidget(content_splitter)
# Categories list
categories_list = self._create_categories_list()
content_splitter.addWidget(categories_list)
# Settings panels
self.settings_stack = QTabWidget()
self.settings_stack.setTabPosition(QTabWidget.North)
content_splitter.addWidget(self.settings_stack)
# Create settings tabs
self._create_general_tab()
self._create_display_tab()
self._create_detection_tab()
self._create_iot_tab()
self._create_performance_tab()
self._create_security_tab()
# Set splitter proportions
content_splitter.setSizes([200, 600])
# Dialog buttons
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Apply)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
button_box.button(QDialogButtonBox.Apply).clicked.connect(self._apply_settings)
layout.addWidget(button_box)
def _create_header(self):
"""Create settings dialog header"""
header = QFrame()
header.setFixedHeight(60)
header.setStyleSheet("""
QFrame {
background-color: #2c3e50;
border-bottom: 1px solid #34495e;
}
""")
layout = QHBoxLayout(header)
layout.setContentsMargins(20, 10, 20, 10)
# Title
title = QLabel("⚙️ System Settings")
title.setFont(QFont("Segoe UI", 14, QFont.Bold))
title.setStyleSheet("color: white;")
layout.addWidget(title)
# Subtitle
subtitle = QLabel("Configure your Smart Intersection Monitoring System")
subtitle.setFont(QFont("Segoe UI", 9))
subtitle.setStyleSheet("color: #ecf0f1;")
layout.addWidget(subtitle)
layout.addStretch()
return header
def _create_categories_list(self):
"""Create settings categories list"""
categories = QListWidget()
categories.setFixedWidth(180)
categories.setStyleSheet("""
QListWidget {
background-color: #34495e;
border: none;
outline: none;
font-size: 10pt;
}
QListWidget::item {
color: white;
padding: 12px;
border-bottom: 1px solid #2c3e50;
}
QListWidget::item:selected {
background-color: #3498db;
}
QListWidget::item:hover {
background-color: #495860;
}
""")
category_items = [
("⚙️ General", 0),
("🎨 Display", 1),
("🤖 Detection", 2),
("📡 IoT Devices", 3),
("⚡ Performance", 4),
("🔒 Security", 5),
]
for text, tab_index in category_items:
item = QListWidgetItem(text)
item.setData(Qt.UserRole, tab_index)
categories.addItem(item)
categories.currentItemChanged.connect(self._on_category_changed)
categories.setCurrentRow(0)
return categories
def _on_category_changed(self, current, previous):
"""Handle category selection change"""
if current:
tab_index = current.data(Qt.UserRole)
self.settings_stack.setCurrentIndex(tab_index)
def _create_general_tab(self):
"""Create general settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Application settings
app_group = QGroupBox("Application Settings")
app_layout = QFormLayout(app_group)
# Auto-start
self.auto_start_cb = QCheckBox("Start with system")
app_layout.addRow("Startup:", self.auto_start_cb)
# Language
self.language_combo = QComboBox()
self.language_combo.addItems(["English", "Spanish", "French", "German"])
app_layout.addRow("Language:", self.language_combo)
# Update check
self.auto_update_cb = QCheckBox("Check for updates automatically")
app_layout.addRow("Updates:", self.auto_update_cb)
# Data directory
data_layout = QHBoxLayout()
self.data_dir_edit = QLineEdit()
data_browse_btn = QPushButton("Browse")
data_browse_btn.clicked.connect(self._browse_data_directory)
data_layout.addWidget(self.data_dir_edit)
data_layout.addWidget(data_browse_btn)
app_layout.addRow("Data Directory:", data_layout)
layout.addWidget(app_group)
# Logging settings
log_group = QGroupBox("Logging Settings")
log_layout = QFormLayout(log_group)
# Log level
self.log_level_combo = QComboBox()
self.log_level_combo.addItems(["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])
log_layout.addRow("Log Level:", self.log_level_combo)
# Log retention
self.log_retention_spin = QSpinBox()
self.log_retention_spin.setRange(1, 365)
self.log_retention_spin.setSuffix(" days")
log_layout.addRow("Log Retention:", self.log_retention_spin)
layout.addWidget(log_group)
layout.addStretch()
self.settings_stack.addTab(tab, "General")
def _create_display_tab(self):
"""Create display settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Theme settings
theme_group = QGroupBox("Theme Settings")
theme_layout = QFormLayout(theme_group)
# Theme selection
self.theme_combo = QComboBox()
self.theme_combo.addItems(["Light", "Dark", "Auto (System)"])
self.theme_combo.currentTextChanged.connect(self._on_theme_changed)
theme_layout.addRow("Theme:", self.theme_combo)
# Color scheme
self.color_scheme_combo = QComboBox()
self.color_scheme_combo.addItems(["Default", "Blue", "Green", "Purple", "Orange"])
theme_layout.addRow("Color Scheme:", self.color_scheme_combo)
layout.addWidget(theme_group)
# Display options
display_group = QGroupBox("Display Options")
display_layout = QFormLayout(display_group)
# UI scaling
self.ui_scale_slider = QSlider(Qt.Horizontal)
self.ui_scale_slider.setRange(80, 150)
self.ui_scale_slider.setValue(100)
scale_layout = QHBoxLayout()
scale_layout.addWidget(self.ui_scale_slider)
self.scale_label = QLabel("100%")
scale_layout.addWidget(self.scale_label)
self.ui_scale_slider.valueChanged.connect(
lambda v: self.scale_label.setText(f"{v}%")
)
display_layout.addRow("UI Scale:", scale_layout)
# Font size
self.font_size_spin = QSpinBox()
self.font_size_spin.setRange(8, 20)
self.font_size_spin.setSuffix(" pt")
display_layout.addRow("Font Size:", self.font_size_spin)
# Show tooltips
self.tooltips_cb = QCheckBox("Show tooltips")
display_layout.addRow("Tooltips:", self.tooltips_cb)
# Animations
self.animations_cb = QCheckBox("Enable animations")
display_layout.addRow("Animations:", self.animations_cb)
layout.addWidget(display_group)
layout.addStretch()
self.settings_stack.addTab(tab, "Display")
def _create_detection_tab(self):
"""Create detection settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Model settings
model_group = QGroupBox("AI Model Settings")
model_layout = QFormLayout(model_group)
# Detection model
self.detection_model_combo = QComboBox()
self.detection_model_combo.addItems([
"YOLO11n (Fast)", "YOLO11s (Balanced)", "YOLO11m (Accurate)", "YOLO11x (Best)"
])
model_layout.addRow("Detection Model:", self.detection_model_combo)
# Device
self.device_combo = QComboBox()
self.device_combo.addItems(["AUTO", "CPU", "GPU"])
model_layout.addRow("Compute Device:", self.device_combo)
# Confidence threshold
conf_layout = QHBoxLayout()
self.conf_slider = QSlider(Qt.Horizontal)
self.conf_slider.setRange(10, 95)
self.conf_slider.setValue(50)
conf_layout.addWidget(self.conf_slider)
self.conf_label = QLabel("0.50")
conf_layout.addWidget(self.conf_label)
self.conf_slider.valueChanged.connect(
lambda v: self.conf_label.setText(f"{v/100:.2f}")
)
model_layout.addRow("Confidence Threshold:", conf_layout)
# NMS threshold
nms_layout = QHBoxLayout()
self.nms_slider = QSlider(Qt.Horizontal)
self.nms_slider.setRange(10, 80)
self.nms_slider.setValue(45)
nms_layout.addWidget(self.nms_slider)
self.nms_label = QLabel("0.45")
nms_layout.addWidget(self.nms_label)
self.nms_slider.valueChanged.connect(
lambda v: self.nms_label.setText(f"{v/100:.2f}")
)
model_layout.addRow("NMS Threshold:", nms_layout)
layout.addWidget(model_group)
# Detection classes
classes_group = QGroupBox("Detection Classes")
classes_layout = QVBoxLayout(classes_group)
# Class selection list
self.classes_list = QListWidget()
classes = [
"person", "bicycle", "car", "motorcycle", "bus", "truck",
"traffic light", "stop sign", "parking meter", "bench"
]
for class_name in classes:
item = QListWidgetItem(class_name)
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
item.setCheckState(Qt.Checked)
self.classes_list.addItem(item)
classes_layout.addWidget(self.classes_list)
# Class buttons
class_buttons = QHBoxLayout()
select_all_btn = QPushButton("Select All")
select_all_btn.clicked.connect(self._select_all_classes)
class_buttons.addWidget(select_all_btn)
deselect_all_btn = QPushButton("Deselect All")
deselect_all_btn.clicked.connect(self._deselect_all_classes)
class_buttons.addWidget(deselect_all_btn)
class_buttons.addStretch()
classes_layout.addLayout(class_buttons)
layout.addWidget(classes_group)
layout.addStretch()
self.settings_stack.addTab(tab, "Detection")
def _create_iot_tab(self):
"""Create IoT settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# MQTT settings
mqtt_group = QGroupBox("MQTT Configuration")
mqtt_layout = QFormLayout(mqtt_group)
# Broker settings
self.mqtt_host_edit = QLineEdit()
mqtt_layout.addRow("MQTT Broker:", self.mqtt_host_edit)
self.mqtt_port_spin = QSpinBox()
self.mqtt_port_spin.setRange(1, 65535)
self.mqtt_port_spin.setValue(1883)
mqtt_layout.addRow("Port:", self.mqtt_port_spin)
self.mqtt_username_edit = QLineEdit()
mqtt_layout.addRow("Username:", self.mqtt_username_edit)
self.mqtt_password_edit = QLineEdit()
self.mqtt_password_edit.setEchoMode(QLineEdit.Password)
mqtt_layout.addRow("Password:", self.mqtt_password_edit)
# Topics
self.mqtt_topic_edit = QLineEdit()
mqtt_layout.addRow("Base Topic:", self.mqtt_topic_edit)
layout.addWidget(mqtt_group)
# InfluxDB settings
influx_group = QGroupBox("InfluxDB Configuration")
influx_layout = QFormLayout(influx_group)
self.influx_url_edit = QLineEdit()
influx_layout.addRow("InfluxDB URL:", self.influx_url_edit)
self.influx_token_edit = QLineEdit()
self.influx_token_edit.setEchoMode(QLineEdit.Password)
influx_layout.addRow("Token:", self.influx_token_edit)
self.influx_org_edit = QLineEdit()
influx_layout.addRow("Organization:", self.influx_org_edit)
self.influx_bucket_edit = QLineEdit()
influx_layout.addRow("Bucket:", self.influx_bucket_edit)
layout.addWidget(influx_group)
# Device settings
device_group = QGroupBox("Device Settings")
device_layout = QFormLayout(device_group)
# Discovery
self.device_discovery_cb = QCheckBox("Enable device auto-discovery")
device_layout.addRow("Discovery:", self.device_discovery_cb)
# Heartbeat interval
self.heartbeat_spin = QSpinBox()
self.heartbeat_spin.setRange(5, 300)
self.heartbeat_spin.setSuffix(" seconds")
device_layout.addRow("Heartbeat Interval:", self.heartbeat_spin)
layout.addWidget(device_group)
layout.addStretch()
self.settings_stack.addTab(tab, "IoT Devices")
def _create_performance_tab(self):
"""Create performance settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Processing settings
processing_group = QGroupBox("Processing Settings")
processing_layout = QFormLayout(processing_group)
# Frame rate
self.fps_spin = QSpinBox()
self.fps_spin.setRange(1, 60)
self.fps_spin.setSuffix(" FPS")
processing_layout.addRow("Target Frame Rate:", self.fps_spin)
# Buffer size
self.buffer_spin = QSpinBox()
self.buffer_spin.setRange(1, 100)
self.buffer_spin.setSuffix(" frames")
processing_layout.addRow("Frame Buffer Size:", self.buffer_spin)
# Thread count
self.threads_spin = QSpinBox()
self.threads_spin.setRange(1, 16)
processing_layout.addRow("Processing Threads:", self.threads_spin)
layout.addWidget(processing_group)
# Memory settings
memory_group = QGroupBox("Memory Settings")
memory_layout = QFormLayout(memory_group)
# Cache size
self.cache_spin = QSpinBox()
self.cache_spin.setRange(100, 2000)
self.cache_spin.setSuffix(" MB")
memory_layout.addRow("Cache Size:", self.cache_spin)
# Cleanup interval
self.cleanup_spin = QSpinBox()
self.cleanup_spin.setRange(1, 60)
self.cleanup_spin.setSuffix(" minutes")
memory_layout.addRow("Cleanup Interval:", self.cleanup_spin)
layout.addWidget(memory_group)
# GPU settings
gpu_group = QGroupBox("GPU Settings")
gpu_layout = QFormLayout(gpu_group)
# GPU acceleration
self.gpu_acceleration_cb = QCheckBox("Enable GPU acceleration")
gpu_layout.addRow("Acceleration:", self.gpu_acceleration_cb)
# Memory fraction
gpu_mem_layout = QHBoxLayout()
self.gpu_memory_slider = QSlider(Qt.Horizontal)
self.gpu_memory_slider.setRange(10, 90)
self.gpu_memory_slider.setValue(70)
gpu_mem_layout.addWidget(self.gpu_memory_slider)
self.gpu_memory_label = QLabel("70%")
gpu_mem_layout.addWidget(self.gpu_memory_label)
self.gpu_memory_slider.valueChanged.connect(
lambda v: self.gpu_memory_label.setText(f"{v}%")
)
gpu_layout.addRow("GPU Memory Usage:", gpu_mem_layout)
layout.addWidget(gpu_group)
layout.addStretch()
self.settings_stack.addTab(tab, "Performance")
def _create_security_tab(self):
"""Create security settings tab"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Authentication
auth_group = QGroupBox("Authentication")
auth_layout = QFormLayout(auth_group)
# Enable authentication
self.auth_enabled_cb = QCheckBox("Enable user authentication")
auth_layout.addRow("Authentication:", self.auth_enabled_cb)
# Session timeout
self.session_timeout_spin = QSpinBox()
self.session_timeout_spin.setRange(5, 480)
self.session_timeout_spin.setSuffix(" minutes")
auth_layout.addRow("Session Timeout:", self.session_timeout_spin)
layout.addWidget(auth_group)
# Encryption
encryption_group = QGroupBox("Encryption")
encryption_layout = QFormLayout(encryption_group)
# Enable encryption
self.encryption_cb = QCheckBox("Enable data encryption")
encryption_layout.addRow("Encryption:", self.encryption_cb)
# SSL/TLS
self.ssl_cb = QCheckBox("Use SSL/TLS connections")
encryption_layout.addRow("SSL/TLS:", self.ssl_cb)
layout.addWidget(encryption_group)
# Audit logging
audit_group = QGroupBox("Audit & Compliance")
audit_layout = QFormLayout(audit_group)
# Enable audit log
self.audit_log_cb = QCheckBox("Enable audit logging")
audit_layout.addRow("Audit Logging:", self.audit_log_cb)
# Compliance mode
self.compliance_combo = QComboBox()
self.compliance_combo.addItems(["None", "GDPR", "HIPAA", "SOX"])
audit_layout.addRow("Compliance Mode:", self.compliance_combo)
layout.addWidget(audit_group)
layout.addStretch()
self.settings_stack.addTab(tab, "Security")
def _browse_data_directory(self):
"""Browse for data directory"""
directory = QFileDialog.getExistingDirectory(self, "Select Data Directory")
if directory:
self.data_dir_edit.setText(directory)
def _on_theme_changed(self, theme):
"""Handle theme change"""
self.theme_changed.emit(theme.lower())
def _select_all_classes(self):
"""Select all detection classes"""
for i in range(self.classes_list.count()):
item = self.classes_list.item(i)
item.setCheckState(Qt.Checked)
def _deselect_all_classes(self):
"""Deselect all detection classes"""
for i in range(self.classes_list.count()):
item = self.classes_list.item(i)
item.setCheckState(Qt.Unchecked)
def _load_settings(self):
"""Load settings from QSettings"""
# General settings
self.auto_start_cb.setChecked(self.settings.value("general/auto_start", False, type=bool))
self.language_combo.setCurrentText(self.settings.value("general/language", "English"))
self.auto_update_cb.setChecked(self.settings.value("general/auto_update", True, type=bool))
self.data_dir_edit.setText(self.settings.value("general/data_dir", "./data"))
# Logging
self.log_level_combo.setCurrentText(self.settings.value("logging/level", "INFO"))
self.log_retention_spin.setValue(self.settings.value("logging/retention", 30, type=int))
# Display
self.theme_combo.setCurrentText(self.settings.value("display/theme", "Light"))
self.color_scheme_combo.setCurrentText(self.settings.value("display/color_scheme", "Default"))
self.ui_scale_slider.setValue(self.settings.value("display/ui_scale", 100, type=int))
self.font_size_spin.setValue(self.settings.value("display/font_size", 9, type=int))
self.tooltips_cb.setChecked(self.settings.value("display/tooltips", True, type=bool))
self.animations_cb.setChecked(self.settings.value("display/animations", True, type=bool))
# Detection
self.detection_model_combo.setCurrentText(self.settings.value("detection/model", "YOLO11n (Fast)"))
self.device_combo.setCurrentText(self.settings.value("detection/device", "AUTO"))
self.conf_slider.setValue(int(self.settings.value("detection/confidence", 0.5, type=float) * 100))
self.nms_slider.setValue(int(self.settings.value("detection/nms", 0.45, type=float) * 100))
# IoT
self.mqtt_host_edit.setText(self.settings.value("iot/mqtt_host", "localhost"))
self.mqtt_port_spin.setValue(self.settings.value("iot/mqtt_port", 1883, type=int))
self.mqtt_username_edit.setText(self.settings.value("iot/mqtt_username", ""))
self.mqtt_topic_edit.setText(self.settings.value("iot/mqtt_topic", "smart_intersection"))
# Performance
self.fps_spin.setValue(self.settings.value("performance/fps", 30, type=int))
self.buffer_spin.setValue(self.settings.value("performance/buffer_size", 10, type=int))
self.threads_spin.setValue(self.settings.value("performance/threads", 4, type=int))
self.cache_spin.setValue(self.settings.value("performance/cache_size", 500, type=int))
self.cleanup_spin.setValue(self.settings.value("performance/cleanup_interval", 5, type=int))
self.gpu_acceleration_cb.setChecked(self.settings.value("performance/gpu_acceleration", True, type=bool))
self.gpu_memory_slider.setValue(self.settings.value("performance/gpu_memory", 70, type=int))
# Security
self.auth_enabled_cb.setChecked(self.settings.value("security/auth_enabled", False, type=bool))
self.session_timeout_spin.setValue(self.settings.value("security/session_timeout", 60, type=int))
self.encryption_cb.setChecked(self.settings.value("security/encryption", True, type=bool))
self.ssl_cb.setChecked(self.settings.value("security/ssl", True, type=bool))
self.audit_log_cb.setChecked(self.settings.value("security/audit_log", True, type=bool))
self.compliance_combo.setCurrentText(self.settings.value("security/compliance", "None"))
def _apply_settings(self):
"""Apply settings without closing dialog"""
self._save_settings()
self.settings_changed.emit(self.pending_changes)
self.pending_changes.clear()
def _save_settings(self):
"""Save settings to QSettings"""
# General settings
self.settings.setValue("general/auto_start", self.auto_start_cb.isChecked())
self.settings.setValue("general/language", self.language_combo.currentText())
self.settings.setValue("general/auto_update", self.auto_update_cb.isChecked())
self.settings.setValue("general/data_dir", self.data_dir_edit.text())
# Logging
self.settings.setValue("logging/level", self.log_level_combo.currentText())
self.settings.setValue("logging/retention", self.log_retention_spin.value())
# Display
self.settings.setValue("display/theme", self.theme_combo.currentText())
self.settings.setValue("display/color_scheme", self.color_scheme_combo.currentText())
self.settings.setValue("display/ui_scale", self.ui_scale_slider.value())
self.settings.setValue("display/font_size", self.font_size_spin.value())
self.settings.setValue("display/tooltips", self.tooltips_cb.isChecked())
self.settings.setValue("display/animations", self.animations_cb.isChecked())
# Detection
self.settings.setValue("detection/model", self.detection_model_combo.currentText())
self.settings.setValue("detection/device", self.device_combo.currentText())
self.settings.setValue("detection/confidence", self.conf_slider.value() / 100.0)
self.settings.setValue("detection/nms", self.nms_slider.value() / 100.0)
# IoT
self.settings.setValue("iot/mqtt_host", self.mqtt_host_edit.text())
self.settings.setValue("iot/mqtt_port", self.mqtt_port_spin.value())
self.settings.setValue("iot/mqtt_username", self.mqtt_username_edit.text())
self.settings.setValue("iot/mqtt_topic", self.mqtt_topic_edit.text())
# Performance
self.settings.setValue("performance/fps", self.fps_spin.value())
self.settings.setValue("performance/buffer_size", self.buffer_spin.value())
self.settings.setValue("performance/threads", self.threads_spin.value())
self.settings.setValue("performance/cache_size", self.cache_spin.value())
self.settings.setValue("performance/cleanup_interval", self.cleanup_spin.value())
self.settings.setValue("performance/gpu_acceleration", self.gpu_acceleration_cb.isChecked())
self.settings.setValue("performance/gpu_memory", self.gpu_memory_slider.value())
# Security
self.settings.setValue("security/auth_enabled", self.auth_enabled_cb.isChecked())
self.settings.setValue("security/session_timeout", self.session_timeout_spin.value())
self.settings.setValue("security/encryption", self.encryption_cb.isChecked())
self.settings.setValue("security/ssl", self.ssl_cb.isChecked())
self.settings.setValue("security/audit_log", self.audit_log_cb.isChecked())
self.settings.setValue("security/compliance", self.compliance_combo.currentText())
print("⚙️ Settings saved successfully")
def accept(self):
"""Accept dialog and save settings"""
self._save_settings()
self.settings_changed.emit(self.pending_changes)
super().accept()
def get_current_settings(self):
"""Get current settings as dictionary"""
return {
'general': {
'auto_start': self.auto_start_cb.isChecked(),
'language': self.language_combo.currentText(),
'auto_update': self.auto_update_cb.isChecked(),
'data_dir': self.data_dir_edit.text()
},
'display': {
'theme': self.theme_combo.currentText(),
'ui_scale': self.ui_scale_slider.value(),
'font_size': self.font_size_spin.value()
},
'detection': {
'model': self.detection_model_combo.currentText(),
'device': self.device_combo.currentText(),
'confidence': self.conf_slider.value() / 100.0,
'nms': self.nms_slider.value() / 100.0
}
}