You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
40 lines
2.9 KiB
40 lines
2.9 KiB
"""Validation and override conversion for GUI experiment fields."""
|
|
from __future__ import annotations
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from .gui_models import GuiExperimentRequest, GuiValidationResult
|
|
|
|
def validate_experiment_request(request: GuiExperimentRequest) -> GuiValidationResult:
|
|
errors: list[str] = []; warnings: list[str] = []
|
|
if request.input_type not in {"camera", "video"}: errors.append("Input type must be camera or video")
|
|
if request.camera_index < 0: errors.append("Camera index must be zero or greater")
|
|
if request.input_type == "video" and (not request.video_path or not Path(request.video_path).is_file()): errors.append("Select an existing video file")
|
|
if request.voice_mode not in {"prompt", "control", "disabled"}: errors.append("Voice mode is invalid")
|
|
if not 0.0 <= request.voice_volume <= 1.0: errors.append("Volume must be between 0.0 and 1.0")
|
|
if request.face_every is not None and request.face_every < 1: errors.append("Face interval must be at least 1")
|
|
if request.max_face_persons is not None and request.max_face_persons < 1: errors.append("Maximum face persons must be at least 1")
|
|
if request.signage_yaw_direction not in {None, "positive", "negative"}: errors.append("Signage yaw direction is invalid")
|
|
if request.voice_mode == "prompt" and (not request.audio_file or not Path(request.audio_file).is_file()): warnings.append("Prompt mode has no existing audio file")
|
|
if not Path(request.config_path).is_file(): errors.append("Configuration file does not exist")
|
|
return GuiValidationResult(tuple(errors), tuple(warnings))
|
|
|
|
def experiment_overrides(request: GuiExperimentRequest) -> dict[str, Any]:
|
|
values: dict[str, Any] = {
|
|
"input": {"type": request.input_type, "camera_id": request.camera_index,
|
|
"video_path": request.video_path if request.input_type == "video" else None},
|
|
"display": {"enabled": request.show_opencv_window},
|
|
"voice_prompt": {"enabled": request.voice_mode != "disabled", "mode": request.voice_mode},
|
|
"audio": {"volume": request.voice_volume},
|
|
"unified_logging": {"enabled": request.enable_unified_logging,
|
|
"camera_position_note": request.camera_position_note},
|
|
}
|
|
if request.audio_file: values["audio"]["file_path"] = request.audio_file
|
|
if request.face_every is not None: values.setdefault("face", {})["process_every_n_frames"] = request.face_every
|
|
if request.max_face_persons is not None: values.setdefault("face", {})["max_persons_per_frame"] = request.max_face_persons
|
|
if request.signage_yaw_direction: values.setdefault("turn_detection", {})["signage_yaw_direction"] = request.signage_yaw_direction
|
|
return values
|
|
|
|
class ConfigPanelLogic:
|
|
"""Compatibility facade used by tests and a future richer config editor."""
|
|
validate = staticmethod(validate_experiment_request)
|
|
to_overrides = staticmethod(experiment_overrides)
|
|
|