mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-09-26 23:09:28 +08:00
Merge pull request #93 from lorow/feature/config-rewrite-with-defualts-reset
Settings rewrite for easier data validation and resseting to defaults
This commit is contained in:
commit
0ee5404f5d
@ -1,540 +1,21 @@
|
||||
import PySimpleGUI as sg
|
||||
|
||||
from config import EyeTrackSettingsConfig
|
||||
from config import EyeTrackConfig
|
||||
from osc import EyeId
|
||||
from queue import Queue
|
||||
from threading import Event
|
||||
|
||||
from settings.BaseSettings import BaseSettingsWidget
|
||||
from settings.modules.AdvancedTrackingAlgoSettingsModule import (
|
||||
AdvancedTrackingAlgoSettingsModule,
|
||||
)
|
||||
from settings.modules.BlinkAlgoModule import BlinkAlgoSettingsModule
|
||||
from settings.modules.TrackingAlgorithmModule import TrackingAlgorithmModule
|
||||
|
||||
|
||||
class AlgoSettingsWidget:
|
||||
def __init__(
|
||||
self, widget_id: EyeId, main_config: EyeTrackSettingsConfig, osc_queue: Queue
|
||||
):
|
||||
|
||||
self.gui_flip_x_axis_left = f"-FLIPXAXISLEFT{widget_id}-"
|
||||
self.gui_flip_x_axis_right = f"-FLIPXAXISRIGHT{widget_id}-"
|
||||
self.gui_flip_y_axis = f"-FLIPYAXIS{widget_id}-"
|
||||
self.gui_general_settings_layout = f"-GENERALSETTINGSLAYOUT{widget_id}-"
|
||||
self.gui_osc_address = f"-OSCADDRESS{widget_id}-"
|
||||
self.gui_osc_port = f"-OSCPORT{widget_id}-"
|
||||
self.gui_osc_receiver_port = f"OSCRECEIVERPORT{widget_id}-"
|
||||
self.gui_osc_recenter_address = f"OSCRECENTERADDRESS{widget_id}-"
|
||||
self.gui_osc_recalibrate_address = f"OSCRECALIBRATEADDRESS{widget_id}-"
|
||||
self.gui_BLOB = f"-BLOBFALLBACK{widget_id}-"
|
||||
self.gui_HSF = f"-HSF{widget_id}-"
|
||||
self.gui_DADDY = f"-DADDY{widget_id}-"
|
||||
self.gui_DADDYP = f"-DADDYP{widget_id}-"
|
||||
self.gui_LEAPP = f"-LEAPP{widget_id}-"
|
||||
self.gui_LEAP = f"-LEAP{widget_id}-"
|
||||
self.gui_RANSAC3D = f"-RANSAC3D{widget_id}-"
|
||||
self.gui_BLINK = f"-BLINK{widget_id}-"
|
||||
self.gui_IBO = f"-IBO{widget_id}-"
|
||||
self.gui_HSRAC = f"-HSRAC{widget_id}-"
|
||||
self.gui_HSF_radius = f"-HSFRADIUS{widget_id}-"
|
||||
self.gui_blob_maxsize = f"-BLOBMAXSIZE{widget_id}-"
|
||||
self.gui_blob_minsize = f"-BLOBMINSIZE{widget_id}-"
|
||||
self.gui_speed_coefficient = f"-SPEEDCOEFFICIENT{widget_id}-"
|
||||
self.gui_min_cutoff = f"-MINCUTOFF{widget_id}-"
|
||||
self.gui_eye_falloff = f"-EYEFALLOFF{widget_id}-"
|
||||
self.gui_skip_autoradius = f"-SKIPAUTORADIUS{widget_id}-"
|
||||
self.gui_HSRACP = f"-HSRACP{widget_id}-"
|
||||
self.gui_RANSAC3DP = f"-RANSAC3DP{widget_id}-"
|
||||
self.gui_HSFP = f"-HSFP{widget_id}-"
|
||||
self.gui_BLOBP = f"-BLOBP{widget_id}-"
|
||||
self.gui_thresh_add = f"-THRESHADD{widget_id}-"
|
||||
self.gui_ROSC = f"-ROSC{widget_id}-"
|
||||
self.gui_RANSACBLINK = f"-RANSACBLINK{widget_id}-"
|
||||
self.gui_vrc_native = f"-VRCNATIVE{widget_id}-"
|
||||
self.gui_circular_crop_left = f"-CIRCLECROPLEFT{widget_id}-"
|
||||
self.gui_circular_crop_right = f"-CIRCLECROPRIGHT{widget_id}-"
|
||||
self.gui_update_check = f"-UPDATECHECK{widget_id}-"
|
||||
self.gui_threshold_slider = f"-BLOBTHRESHOLD{widget_id}-"
|
||||
self.gui_HSF_radius_left = f"-HSFRADIUSLEFT{widget_id}-"
|
||||
self.gui_HSF_radius_right = f"-HSFRADIUSRIGHT{widget_id}-"
|
||||
self.ibo_filter_samples = f"-IBOFILTERSAMPLE{widget_id}-"
|
||||
self.calibration_samples = f"-CALIBRATIONSAMPLES{widget_id}-"
|
||||
self.ibo_fully_close_eye_threshold = f"-CLOSETHRESH{widget_id}-"
|
||||
self.gui_legacy_ransac = f"-LEGACYRANSACTHRESH{widget_id}-"
|
||||
self.gui_legacy_ransac_thresh_right = f"-THRESHRIGHT{widget_id}-"
|
||||
self.gui_legacy_ransac_thresh_left = f"-THRESHLEFT{widget_id}-"
|
||||
self.gui_pupil_dilation = f"-EBPD{widget_id}-"
|
||||
self.gui_LEAP_lid = f"-LEAPLID{widget_id}-"
|
||||
self.main_config = main_config
|
||||
self.config = main_config.settings
|
||||
self.osc_queue = osc_queue
|
||||
|
||||
# Define the window's contents
|
||||
self.general_settings_layout = [
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_HSRAC,
|
||||
key=self.gui_HSRAC,
|
||||
background_color="#424042",
|
||||
tooltip="Our flagship algorithm, utilizing both HSF and RANSAC for best tracking quality and lighting resistance.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_HSRACP,
|
||||
key=self.gui_HSRACP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("HSRAC", background_color="#424042"),
|
||||
# ],
|
||||
# [
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_HSF,
|
||||
key=self.gui_HSF,
|
||||
background_color="#424042",
|
||||
tooltip="HSF Is a new, lower resolution tracking algorithim that provides excelent resilancy to lighting conditions and great speed.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_HSFP,
|
||||
key=self.gui_HSFP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithims.",
|
||||
),
|
||||
sg.Text("Haar Surround Feature", background_color="#424042"),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_DADDY,
|
||||
key=self.gui_DADDY,
|
||||
background_color="#424042",
|
||||
tooltip="DADDY Uses a Deep learning algorithm. This has a big CPU usage impact.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_DADDYP,
|
||||
key=self.gui_DADDYP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("DADDY", background_color="#424042"),
|
||||
# ],
|
||||
# [
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_RANSAC3D,
|
||||
key=self.gui_RANSAC3D,
|
||||
background_color="#424042",
|
||||
tooltip="RANSAC3D provides good tracking quality, however does not do well in bad lighting conditions.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_RANSAC3DP,
|
||||
key=self.gui_RANSAC3DP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("RANSAC 3D", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"Legacy RANSAC Thresh",
|
||||
default=self.config.gui_legacy_ransac,
|
||||
key=self.gui_legacy_ransac,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_LEAP,
|
||||
key=self.gui_LEAP,
|
||||
background_color="#424042",
|
||||
tooltip="LEAP Uses a lightweight deep learning algorithm.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_LEAPP,
|
||||
key=self.gui_LEAPP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("LEAP", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_BLOB,
|
||||
key=self.gui_BLOB,
|
||||
background_color="#424042",
|
||||
tooltip="Blob tracking is the oldest and worst tracking algorithm, it provides fast, though sometimes inaccurate tracking.",
|
||||
),
|
||||
sg.Combo(
|
||||
["1", "2", "3", "4", "5", "6"],
|
||||
default_value=self.config.gui_BLOBP,
|
||||
key=self.gui_BLOBP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("Blob", background_color="#424042"),
|
||||
],
|
||||
[sg.Text("Eyelid Algo Settings:", background_color="#242224")],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Intensity Based Openness",
|
||||
default=self.config.gui_IBO,
|
||||
key=self.gui_IBO,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"RANSAC Quick Blink Algo",
|
||||
default=self.config.gui_RANSACBLINK,
|
||||
key=self.gui_RANSACBLINK,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Binary Blink Algo",
|
||||
default=self.config.gui_BLINK,
|
||||
key=self.gui_BLINK,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"LEAP Lid",
|
||||
default=self.config.gui_LEAP_lid,
|
||||
key=self.gui_LEAP_lid,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("IBO Filter Sample Size", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.ibo_filter_samples,
|
||||
key=self.ibo_filter_samples,
|
||||
size=(0, 10),
|
||||
),
|
||||
sg.Text("Calibration Samples", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.calibration_samples,
|
||||
key=self.calibration_samples,
|
||||
size=(0, 10),
|
||||
),
|
||||
sg.Text("IBO Close Threshold", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.ibo_fully_close_eye_threshold,
|
||||
key=self.ibo_fully_close_eye_threshold,
|
||||
size=(0, 10),
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Left Eye Circle crop",
|
||||
default=self.config.gui_circular_crop_left,
|
||||
key=self.gui_circular_crop_left,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Right Eye Circle crop",
|
||||
default=self.config.gui_circular_crop_right,
|
||||
key=self.gui_circular_crop_right,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[sg.Text("Pupil Dilation Algo Settings:", background_color="#242224")],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Ellipse Based Pupil Dilation",
|
||||
default=self.config.gui_pupil_dilation,
|
||||
key=self.gui_pupil_dilation,
|
||||
background_color="#424042",
|
||||
)
|
||||
],
|
||||
[
|
||||
sg.Text(
|
||||
"Advanced Tracking Algorithim Settings:", background_color="#242224"
|
||||
)
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"HSF: Skip Auto Radius",
|
||||
default=self.config.gui_skip_autoradius,
|
||||
key=self.gui_skip_autoradius,
|
||||
background_color="#424042",
|
||||
tooltip="To gain more control and possibly better tracking quality of HSF, please disable auto radius to enable manual adjustment.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Left HSF Radius:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_HSF_radius_left,
|
||||
orientation="h",
|
||||
key=self.gui_HSF_radius_left,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.",
|
||||
),
|
||||
sg.Text("Right HSF Radius:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_HSF_radius_right,
|
||||
orientation="h",
|
||||
key=self.gui_HSF_radius_right,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("RANSAC Thresh Add", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_thresh_add,
|
||||
orientation="h",
|
||||
key=self.gui_thresh_add,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the amount of threshold to add to RANSAC. Useful for fine tuning your setup.",
|
||||
),
|
||||
sg.Text("Blob Threshold", background_color="#424042"),
|
||||
# TODO make this for right and left eyes? I dont know how vital that is..
|
||||
sg.Slider(
|
||||
range=(0, 110),
|
||||
default_value=self.config.gui_threshold,
|
||||
orientation="h",
|
||||
key=self.gui_threshold_slider,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the threshold for blob tracking.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Min Blob Size:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_blob_minsize,
|
||||
orientation="h",
|
||||
key=self.gui_blob_minsize,
|
||||
background_color="#424042",
|
||||
tooltip="Minimum size a blob has to be for blob tracking.",
|
||||
),
|
||||
sg.Text("Max Blob Size:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_blob_maxsize,
|
||||
orientation="h",
|
||||
key=self.gui_blob_maxsize,
|
||||
background_color="#424042",
|
||||
tooltip="Maximum size a blob can be for blob tracking.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Right Eye Thresh:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 120),
|
||||
default_value=self.config.gui_legacy_ransac_thresh_right,
|
||||
orientation="h",
|
||||
key=self.gui_legacy_ransac_thresh_right,
|
||||
background_color="#424042",
|
||||
tooltip="Threshold for right eye, legacy RANSAC only",
|
||||
),
|
||||
sg.Text("Left Eye Thresh:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 120),
|
||||
default_value=self.config.gui_legacy_ransac_thresh_left,
|
||||
orientation="h",
|
||||
key=self.gui_legacy_ransac_thresh_left,
|
||||
background_color="#424042",
|
||||
tooltip="Threshold for left eye, legacy RANSAC only",
|
||||
),
|
||||
],
|
||||
class AlgoSettingsWidget(BaseSettingsWidget):
|
||||
def __init__(self, widget_id: EyeId, main_config: EyeTrackConfig):
|
||||
settings_modules = [
|
||||
TrackingAlgorithmModule,
|
||||
BlinkAlgoSettingsModule,
|
||||
AdvancedTrackingAlgoSettingsModule,
|
||||
]
|
||||
|
||||
self.widget_layout = [
|
||||
[
|
||||
sg.Text(
|
||||
"Tracking Algorithm Order Settings:", background_color="#242224"
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Column(
|
||||
self.general_settings_layout,
|
||||
key=self.gui_general_settings_layout,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
]
|
||||
|
||||
self.cancellation_event = (
|
||||
Event()
|
||||
) # Set the event until start is called, otherwise we can block if shutdown is called.
|
||||
self.cancellation_event.set()
|
||||
self.image_queue = Queue()
|
||||
|
||||
def started(self):
|
||||
return not self.cancellation_event.is_set()
|
||||
|
||||
def start(self):
|
||||
# If we're already running, bail
|
||||
if not self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.clear()
|
||||
|
||||
def stop(self):
|
||||
# If we're not running yet, bail
|
||||
if self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.set()
|
||||
|
||||
def render(self, window, event, values):
|
||||
# If anything has changed in our configuration settings, change/update those.
|
||||
changed = False
|
||||
|
||||
if self.config.gui_HSFP != int(values[self.gui_HSFP]):
|
||||
self.config.gui_HSFP = int(values[self.gui_HSFP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_HSF != values[self.gui_HSF]:
|
||||
self.config.gui_HSF = values[self.gui_HSF]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_DADDYP != int(values[self.gui_DADDYP]):
|
||||
self.config.gui_DADDYP = int(values[self.gui_DADDYP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_DADDY != values[self.gui_DADDY]:
|
||||
self.config.gui_DADDY = values[self.gui_DADDY]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_RANSAC3DP != int(
|
||||
values[self.gui_RANSAC3DP]
|
||||
): # TODO check that priority order is unique/auto fix it.
|
||||
self.config.gui_RANSAC3DP = int(values[self.gui_RANSAC3DP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_RANSAC3D != values[self.gui_RANSAC3D]:
|
||||
self.config.gui_RANSAC3D = values[self.gui_RANSAC3D]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_legacy_ransac != values[self.gui_legacy_ransac]:
|
||||
self.config.gui_legacy_ransac = values[self.gui_legacy_ransac]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_HSRACP != int(values[self.gui_HSRACP]):
|
||||
self.config.gui_HSRACP = int(values[self.gui_HSRACP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_HSRAC != values[self.gui_HSRAC]:
|
||||
self.config.gui_HSRAC = values[self.gui_HSRAC]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_LEAPP != int(values[self.gui_LEAPP]):
|
||||
self.config.gui_LEAPP = int(values[self.gui_LEAPP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_LEAP != values[self.gui_LEAP]:
|
||||
self.config.gui_LEAP = values[self.gui_LEAP]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_skip_autoradius != values[self.gui_skip_autoradius]:
|
||||
self.config.gui_skip_autoradius = values[self.gui_skip_autoradius]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_BLINK != values[self.gui_BLINK]:
|
||||
self.config.gui_BLINK = values[self.gui_BLINK]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_IBO != values[self.gui_IBO]:
|
||||
self.config.gui_IBO = values[self.gui_IBO]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_pupil_dilation != values[self.gui_pupil_dilation]:
|
||||
self.config.gui_pupil_dilation = values[self.gui_pupil_dilation]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_RANSACBLINK != values[self.gui_RANSACBLINK]:
|
||||
self.config.gui_RANSACBLINK = values[self.gui_RANSACBLINK]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_LEAP_lid != values[self.gui_LEAP_lid]:
|
||||
self.config.gui_LEAP_lid = values[self.gui_LEAP_lid]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_circular_crop_left != values[self.gui_circular_crop_left]:
|
||||
self.config.gui_circular_crop_left = values[self.gui_circular_crop_left]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_circular_crop_right != values[self.gui_circular_crop_right]:
|
||||
self.config.gui_circular_crop_right = values[self.gui_circular_crop_right]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_HSF_radius_left != int(values[self.gui_HSF_radius_left]):
|
||||
self.config.gui_HSF_radius_left = int(values[self.gui_HSF_radius_left])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_HSF_radius_right != int(values[self.gui_HSF_radius_right]):
|
||||
self.config.gui_HSF_radius_right = int(values[self.gui_HSF_radius_right])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_BLOB != values[self.gui_BLOB]:
|
||||
self.config.gui_BLOB = values[self.gui_BLOB]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_BLOBP != int(values[self.gui_BLOBP]):
|
||||
self.config.gui_BLOBP = int(values[self.gui_BLOBP])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_threshold != values[self.gui_threshold_slider]:
|
||||
self.config.gui_threshold = int(values[self.gui_threshold_slider])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_thresh_add != values[self.gui_thresh_add]:
|
||||
self.config.gui_thresh_add = int(values[self.gui_thresh_add])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_blob_maxsize != values[self.gui_blob_maxsize]:
|
||||
self.config.gui_blob_maxsize = values[self.gui_blob_maxsize]
|
||||
changed = True
|
||||
|
||||
if self.config.ibo_filter_samples != int(values[self.ibo_filter_samples]):
|
||||
self.config.ibo_filter_samples = int(values[self.ibo_filter_samples])
|
||||
changed = True
|
||||
|
||||
if self.config.ibo_fully_close_eye_threshold != float(
|
||||
values[self.ibo_fully_close_eye_threshold]
|
||||
):
|
||||
self.config.ibo_fully_close_eye_threshold = float(
|
||||
values[self.ibo_fully_close_eye_threshold]
|
||||
)
|
||||
changed = True
|
||||
|
||||
if self.config.calibration_samples != int(values[self.calibration_samples]):
|
||||
self.config.calibration_samples = int(values[self.calibration_samples])
|
||||
changed = True
|
||||
|
||||
if self.config.gui_legacy_ransac_thresh_left != int(
|
||||
values[self.gui_legacy_ransac_thresh_left]
|
||||
):
|
||||
self.config.gui_legacy_ransac_thresh_left = int(
|
||||
values[self.gui_legacy_ransac_thresh_left]
|
||||
)
|
||||
changed = True
|
||||
|
||||
if self.config.gui_legacy_ransac_thresh_right != int(
|
||||
values[self.gui_legacy_ransac_thresh_right]
|
||||
):
|
||||
self.config.gui_legacy_ransac_thresh_right = int(
|
||||
values[self.gui_legacy_ransac_thresh_right]
|
||||
)
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
self.main_config.save()
|
||||
# print(self.main_config)
|
||||
self.osc_queue.put(EyeId.ALGOSETTINGS)
|
||||
super().__init__(widget_id, main_config, settings_modules)
|
||||
|
@ -91,8 +91,8 @@ class EyeTrackConfig(BaseModel):
|
||||
right_eye: EyeTrackCameraConfig = EyeTrackCameraConfig()
|
||||
left_eye: EyeTrackCameraConfig = EyeTrackCameraConfig()
|
||||
settings: EyeTrackSettingsConfig = EyeTrackSettingsConfig()
|
||||
# algo_settings: EyeTrackSettingsConfig = EyeTrackSettingsConfig()
|
||||
eye_display_id: EyeId = EyeId.RIGHT
|
||||
__listeners = []
|
||||
|
||||
@staticmethod
|
||||
def load():
|
||||
@ -117,6 +117,13 @@ class EyeTrackConfig(BaseModel):
|
||||
load_config = EyeTrackConfig()
|
||||
return load_config
|
||||
|
||||
def update(self, data, save=False):
|
||||
for field, value in data.items():
|
||||
setattr(self.settings, field, value)
|
||||
self.__notify_listeners()
|
||||
if save:
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
# make sure this is only called if there is a change
|
||||
if os.path.exists(CONFIG_FILE_NAME):
|
||||
@ -130,5 +137,13 @@ class EyeTrackConfig(BaseModel):
|
||||
# No backup because the saved settings file is broken.
|
||||
pass
|
||||
with open(CONFIG_FILE_NAME, "w") as settings_file:
|
||||
json.dump(obj=self.dict(), fp=settings_file)
|
||||
json.dump(obj=self.model_dump(warnings=False), fp=settings_file)
|
||||
print(f"\033[92m[INFO] Config Saved Successfully\033[0m")
|
||||
|
||||
def register_listener_callback(self, callback):
|
||||
print(f"[DEBUG] Registering listener {callback}")
|
||||
self.__listeners.append(callback)
|
||||
|
||||
def __notify_listeners(self):
|
||||
for listener in self.__listeners:
|
||||
listener()
|
||||
|
@ -281,12 +281,12 @@ class EyeProcessor:
|
||||
self.settings.ibo_average_output_samples,
|
||||
)
|
||||
if (
|
||||
self.eyeopen < self.settings.ibo_fully_close_eye_threshold
|
||||
self.eyeopen < float(self.settings.ibo_fully_close_eye_threshold)
|
||||
): # threshold so the eye fully closes
|
||||
self.eyeopen = 0.0
|
||||
|
||||
if self.bd_blink == True:
|
||||
prin("blinks")
|
||||
print("blinks")
|
||||
pass
|
||||
|
||||
if self.settings.gui_IBO and self.eyeopen != 0.0:
|
||||
|
@ -90,8 +90,8 @@ def main():
|
||||
]
|
||||
|
||||
settings = [
|
||||
SettingsWidget(EyeId.SETTINGS, config, osc_queue),
|
||||
AlgoSettingsWidget(EyeId.ALGOSETTINGS, config, osc_queue),
|
||||
SettingsWidget(EyeId.SETTINGS, config),
|
||||
AlgoSettingsWidget(EyeId.ALGOSETTINGS, config),
|
||||
]
|
||||
|
||||
layout = [
|
||||
@ -148,14 +148,14 @@ def main():
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Column(
|
||||
settings[0].widget_layout,
|
||||
settings[0].get_layout(),
|
||||
vertical_alignment="top",
|
||||
key=SETTINGS_NAME,
|
||||
visible=(config.eye_display_id in [EyeId.SETTINGS]),
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Column(
|
||||
settings[1].widget_layout,
|
||||
settings[1].get_layout(),
|
||||
vertical_alignment="top",
|
||||
key=ALGO_SETTINGS_NAME,
|
||||
visible=(config.eye_display_id in [EyeId.ALGOSETTINGS]),
|
||||
|
@ -1,340 +1,18 @@
|
||||
import PySimpleGUI as sg
|
||||
|
||||
from config import EyeTrackSettingsConfig
|
||||
from config import EyeTrackConfig
|
||||
from osc import EyeId
|
||||
from queue import Queue
|
||||
from threading import Event
|
||||
|
||||
from settings.BaseSettings import BaseSettingsWidget
|
||||
from settings.modules.GeneralSettingsModule import GeneralSettingsModule
|
||||
from settings.modules.OneEuroSettingsModule import OneEuroSettingsModule
|
||||
from settings.modules.OSCSettingsModule import OSCSettingsModule
|
||||
|
||||
|
||||
class SettingsWidget:
|
||||
def __init__(
|
||||
self, widget_id: EyeId, main_config: EyeTrackSettingsConfig, osc_queue: Queue
|
||||
):
|
||||
|
||||
self.gui_flip_x_axis_left = f"-FLIPXAXISLEFT{widget_id}-"
|
||||
self.gui_flip_x_axis_right = f"-FLIPXAXISRIGHT{widget_id}-"
|
||||
self.gui_flip_y_axis = f"-FLIPYAXIS{widget_id}-"
|
||||
self.gui_general_settings_layout = f"-GENERALSETTINGSLAYOUT{widget_id}-"
|
||||
self.gui_osc_address = f"-OSCADDRESS{widget_id}-"
|
||||
self.gui_osc_port = f"-OSCPORT{widget_id}-"
|
||||
self.gui_osc_receiver_port = f"OSCRECEIVERPORT{widget_id}-"
|
||||
self.gui_osc_recenter_address = f"OSCRECENTERADDRESS{widget_id}-"
|
||||
self.gui_osc_recalibrate_address = f"OSCRECALIBRATEADDRESS{widget_id}-"
|
||||
self.gui_BLOB = f"-BLOBFALLBACK{widget_id}-"
|
||||
self.gui_HSF = f"-HSF{widget_id}-"
|
||||
self.gui_DADDY = f"-DADDY{widget_id}-"
|
||||
self.gui_DADDYP = f"-DADDYP{widget_id}-"
|
||||
self.gui_RANSAC3D = f"-RANSAC3D{widget_id}-"
|
||||
self.gui_BLINK = f"-BLINK{widget_id}-"
|
||||
self.gui_IBO = f"-IBO{widget_id}-"
|
||||
self.gui_HSRAC = f"-HSRAC{widget_id}-"
|
||||
self.gui_HSF_radius = f"-HSFRADIUS{widget_id}-"
|
||||
self.gui_blob_maxsize = f"-BLOBMAXSIZE{widget_id}-"
|
||||
self.gui_blob_minsize = f"-BLOBMINSIZE{widget_id}-"
|
||||
self.gui_speed_coefficient = f"-SPEEDCOEFFICIENT{widget_id}-"
|
||||
self.gui_min_cutoff = f"-MINCUTOFF{widget_id}-"
|
||||
self.gui_eye_falloff = f"-EYEFALLOFF{widget_id}-"
|
||||
self.gui_skip_autoradius = f"-SKIPAUTORADIUS{widget_id}-"
|
||||
self.gui_HSRACP = f"-HSRACP{widget_id}-"
|
||||
self.gui_RANSAC3DP = f"-RANSAC3DP{widget_id}-"
|
||||
self.gui_HSFP = f"-HSFP{widget_id}-"
|
||||
self.gui_BLOBP = f"-BLOBP{widget_id}-"
|
||||
self.gui_thresh_add = f"-THRESHADD{widget_id}-"
|
||||
self.gui_ROSC = f"-ROSC{widget_id}-"
|
||||
self.gui_vrc_native = f"-VRCNATIVE{widget_id}-"
|
||||
self.gui_circular_crop_left = f"-CIRCLECROPLEFT{widget_id}-"
|
||||
self.gui_circular_crop_right = f"-CIRCLECROPRIGHT{widget_id}-"
|
||||
self.gui_update_check = f"-UPDATECHECK{widget_id}-"
|
||||
self.gui_threshold_slider = f"-BLOBTHRESHOLD{widget_id}-"
|
||||
self.gui_osc_vrcft_v1 = f"-OSCVRCFTV1{widget_id}-"
|
||||
self.gui_osc_vrcft_v2 = f"-OSCVRCFTV2{widget_id}-"
|
||||
self.main_config = main_config
|
||||
self.config = main_config.settings
|
||||
self.osc_queue = osc_queue
|
||||
|
||||
# Define the window's contents
|
||||
self.general_settings_layout = [
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Flip Left Eye X Axis",
|
||||
default=self.config.gui_flip_x_axis_left,
|
||||
key=self.gui_flip_x_axis_left,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the left eye's X axis.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Flip Right Eye X Axis",
|
||||
default=self.config.gui_flip_x_axis_right,
|
||||
key=self.gui_flip_x_axis_right,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the right eye's X axis.",
|
||||
),
|
||||
# ],
|
||||
# [
|
||||
sg.Checkbox(
|
||||
"Flip Y Axis",
|
||||
default=self.config.gui_flip_y_axis,
|
||||
key=self.gui_flip_y_axis,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the eye's Y axis.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Dual Eye Falloff",
|
||||
default=self.config.gui_eye_falloff,
|
||||
key=self.gui_eye_falloff,
|
||||
background_color="#424042",
|
||||
tooltip="If one eye stops tracking, we send tracking data from your other eye.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Check For Updates",
|
||||
default=self.config.gui_update_check,
|
||||
key=self.gui_update_check,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle update check on launch.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("One Euro Filter Paramaters:", background_color="#242224"),
|
||||
],
|
||||
[
|
||||
sg.Text("Min Frequency Cutoff", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_min_cutoff,
|
||||
key=self.gui_min_cutoff,
|
||||
size=(0, 10),
|
||||
),
|
||||
# ],
|
||||
# [
|
||||
sg.Text("Speed Coefficient", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_speed_coefficient,
|
||||
key=self.gui_speed_coefficient,
|
||||
size=(0, 10),
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("OSC Settings:", background_color="#242224"),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"VRC Native",
|
||||
default=self.config.gui_vrc_native,
|
||||
key=self.gui_vrc_native,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRC's Native Eyetracking format.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"VRCFT v1",
|
||||
default=self.config.gui_osc_vrcft_v1,
|
||||
key=self.gui_osc_vrcft_v1,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRCFT's v1 Eyetracking format.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"VRCFT v2 (UE)",
|
||||
default=self.config.gui_osc_vrcft_v2,
|
||||
key=self.gui_osc_vrcft_v2,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRCFT's v2 (UE) Eyetracking format.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Address:", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_address,
|
||||
key=self.gui_osc_address,
|
||||
size=(0, 20),
|
||||
tooltip="IP address we send OSC data to.",
|
||||
),
|
||||
# ],
|
||||
# [
|
||||
sg.Text("Port:", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_port,
|
||||
key=self.gui_osc_port,
|
||||
size=(0, 10),
|
||||
tooltip="OSC port we send data to.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Receive functions", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_ROSC,
|
||||
key=self.gui_ROSC,
|
||||
background_color="#424042",
|
||||
size=(0, 10),
|
||||
tooltip="Toggle OSC receive functions.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Receiver Port:", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_receiver_port,
|
||||
key=self.gui_osc_receiver_port,
|
||||
size=(0, 10),
|
||||
tooltip="Port we receive OSC data from (used to recalibrate or recenter app from within VRChat.",
|
||||
),
|
||||
# ],
|
||||
# [
|
||||
sg.Text("Recenter Address:", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_recenter_address,
|
||||
key=self.gui_osc_recenter_address,
|
||||
size=(0, 10),
|
||||
tooltip="OSC Address used for recentering your eye.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Recalibrate Address:", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_recalibrate_address,
|
||||
key=self.gui_osc_recalibrate_address,
|
||||
size=(0, 10),
|
||||
tooltip="OSC address we use for recalibrating your eye",
|
||||
),
|
||||
],
|
||||
class SettingsWidget(BaseSettingsWidget):
|
||||
def __init__(self, widget_id: EyeId, main_config: EyeTrackConfig):
|
||||
settings_modules = [
|
||||
GeneralSettingsModule,
|
||||
OneEuroSettingsModule,
|
||||
OSCSettingsModule,
|
||||
]
|
||||
super().__init__(widget_id, main_config, settings_modules)
|
||||
|
||||
self.widget_layout = [
|
||||
[
|
||||
sg.Text("General Settings:", background_color="#242224"),
|
||||
],
|
||||
[
|
||||
sg.Column(
|
||||
self.general_settings_layout,
|
||||
key=self.gui_general_settings_layout,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
]
|
||||
|
||||
self.cancellation_event = (
|
||||
Event()
|
||||
) # Set the event until start is called, otherwise we can block if shutdown is called.
|
||||
self.cancellation_event.set()
|
||||
self.image_queue = Queue()
|
||||
|
||||
def started(self):
|
||||
return not self.cancellation_event.is_set()
|
||||
|
||||
def start(self):
|
||||
# If we're already running, bail
|
||||
if not self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.clear()
|
||||
|
||||
def stop(self):
|
||||
# If we're not running yet, bail
|
||||
if self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.set()
|
||||
|
||||
def render(self, window, event, values):
|
||||
# If anything has changed in our configuration settings, change/update those.
|
||||
changed = False
|
||||
|
||||
if self.config.gui_osc_port != int(values[self.gui_osc_port]):
|
||||
print(self.config.gui_osc_port, values[self.gui_osc_port])
|
||||
try:
|
||||
int(values[self.gui_osc_port])
|
||||
if len(values[self.gui_osc_port]) <= 5:
|
||||
self.config.gui_osc_port = int(values[self.gui_osc_port])
|
||||
changed = True
|
||||
else:
|
||||
print(
|
||||
"\033[91m[ERROR] OSC port value must be an integer 0-65535\033[0m"
|
||||
)
|
||||
except:
|
||||
print(
|
||||
"\033[91m[ERROR] OSC port value must be an integer 0-65535\033[0m"
|
||||
)
|
||||
|
||||
if self.config.gui_osc_receiver_port != int(values[self.gui_osc_receiver_port]):
|
||||
try:
|
||||
int(values[self.gui_osc_receiver_port])
|
||||
if len(values[self.gui_osc_receiver_port]) <= 5:
|
||||
self.config.gui_osc_receiver_port = int(
|
||||
values[self.gui_osc_receiver_port]
|
||||
)
|
||||
changed = True
|
||||
else:
|
||||
print(
|
||||
"\033[91m[ERROR] OSC receive port value must be an integer 0-65535\033[0m"
|
||||
)
|
||||
except:
|
||||
print(
|
||||
"\033[91m[ERROR] OSC receive port value must be an integer 0-65535\033[0m"
|
||||
)
|
||||
|
||||
if self.config.gui_osc_address != values[self.gui_osc_address]:
|
||||
self.config.gui_osc_address = values[self.gui_osc_address]
|
||||
changed = True
|
||||
|
||||
if (
|
||||
self.config.gui_osc_recenter_address
|
||||
!= values[self.gui_osc_recenter_address]
|
||||
):
|
||||
self.config.gui_osc_recenter_address = values[self.gui_osc_recenter_address]
|
||||
changed = True
|
||||
|
||||
if (
|
||||
self.config.gui_osc_recalibrate_address
|
||||
!= values[self.gui_osc_recalibrate_address]
|
||||
):
|
||||
self.config.gui_osc_recalibrate_address = values[
|
||||
self.gui_osc_recalibrate_address
|
||||
]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_min_cutoff != values[self.gui_min_cutoff]:
|
||||
self.config.gui_min_cutoff = values[self.gui_min_cutoff]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_speed_coefficient != values[self.gui_speed_coefficient]:
|
||||
self.config.gui_speed_coefficient = values[self.gui_speed_coefficient]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_flip_x_axis_right != values[self.gui_flip_x_axis_right]:
|
||||
self.config.gui_flip_x_axis_right = values[self.gui_flip_x_axis_right]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_flip_x_axis_left != values[self.gui_flip_x_axis_left]:
|
||||
self.config.gui_flip_x_axis_left = values[self.gui_flip_x_axis_left]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_osc_vrcft_v1 != values[self.gui_osc_vrcft_v1]:
|
||||
self.config.gui_osc_vrcft_v1 = values[self.gui_osc_vrcft_v1]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_osc_vrcft_v2 != values[self.gui_osc_vrcft_v2]:
|
||||
self.config.gui_osc_vrcft_v2 = values[self.gui_osc_vrcft_v2]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_vrc_native != values[self.gui_vrc_native]:
|
||||
self.config.gui_vrc_native = values[self.gui_vrc_native]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_update_check != values[self.gui_update_check]:
|
||||
self.config.gui_update_check = values[self.gui_update_check]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_flip_y_axis != values[self.gui_flip_y_axis]:
|
||||
self.config.gui_flip_y_axis = values[self.gui_flip_y_axis]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_eye_falloff != values[self.gui_eye_falloff]:
|
||||
self.config.gui_eye_falloff = values[self.gui_eye_falloff]
|
||||
changed = True
|
||||
|
||||
if self.config.gui_ROSC != values[self.gui_ROSC]:
|
||||
self.config.gui_ROSC = values[self.gui_ROSC]
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
self.main_config.save()
|
||||
self.osc_queue.put((EyeId.SETTINGS))
|
||||
|
@ -1,6 +1,7 @@
|
||||
from pythonosc import udp_client
|
||||
from pythonosc import osc_server
|
||||
from pythonosc import dispatcher
|
||||
from config import EyeTrackConfig
|
||||
from utils.misc_utils import PlaySound, SND_FILENAME, SND_ASYNC
|
||||
import queue
|
||||
import threading
|
||||
@ -16,7 +17,6 @@ class EyeId(IntEnum):
|
||||
ALGOSETTINGS = 4
|
||||
|
||||
|
||||
from config import EyeTrackConfig
|
||||
|
||||
|
||||
def eyelid_transformer(self, eye_blink):
|
||||
|
138
EyeTrackApp/settings/BaseSettings.py
Normal file
138
EyeTrackApp/settings/BaseSettings.py
Normal file
@ -0,0 +1,138 @@
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Iterable
|
||||
|
||||
import PySimpleGUI as sg
|
||||
from colorama import Fore
|
||||
|
||||
from config import EyeTrackConfig, EyeTrackSettingsConfig
|
||||
from threading import Event
|
||||
from osc import EyeId # TODO this is bad, fix this
|
||||
|
||||
|
||||
class BaseSettingsWidget:
|
||||
def __init__(
|
||||
self,
|
||||
widget_id: EyeId,
|
||||
main_config: EyeTrackConfig,
|
||||
settings_modules: Iterable,
|
||||
):
|
||||
# we put the last time an error was printed in the past so whenever a newone appears
|
||||
self.last_error_printout = datetime.now() - timedelta(seconds=20)
|
||||
self.error_printout_timeout = 2
|
||||
self.gui_general_settings_layout = f"-GENERALSETTINGSLAYOUT{widget_id}-"
|
||||
self.reset_button_key = f"RESET_SETTINGS{widget_id}"
|
||||
self.is_saving = False
|
||||
self.main_config = main_config
|
||||
self.config = main_config.settings
|
||||
|
||||
self.initialized_modules = self._initialize_modules(
|
||||
settings_modules=settings_modules, widget_id=widget_id
|
||||
)
|
||||
|
||||
self.general_settings_layout = []
|
||||
for module in self.initialized_modules:
|
||||
self.general_settings_layout.extend(module.get_layout())
|
||||
|
||||
self.widget_layout = [
|
||||
[
|
||||
sg.Column(
|
||||
self.general_settings_layout,
|
||||
key=self.gui_general_settings_layout,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[sg.Text("", background_color="#424042"), ],
|
||||
[sg.Button("Reset settings to default", key=self.reset_button_key, button_color="#c40e23")],
|
||||
]
|
||||
|
||||
self.cancellation_event = (
|
||||
Event()
|
||||
) # Set the event until start is called, otherwise we can block if shutdown is called.
|
||||
self.cancellation_event.set()
|
||||
|
||||
def started(self):
|
||||
return not self.cancellation_event.is_set()
|
||||
|
||||
def start(self):
|
||||
# If we're already running, bail
|
||||
if not self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.clear()
|
||||
|
||||
def stop(self):
|
||||
# If we're not running yet, bail
|
||||
if self.cancellation_event.is_set():
|
||||
return
|
||||
self.cancellation_event.set()
|
||||
|
||||
def _update_and_save_config(self, validated_data: dict):
|
||||
self.main_config.update(validated_data, save=True)
|
||||
self.is_saving = False
|
||||
|
||||
def _handle_errors(self, errors):
|
||||
now = datetime.now()
|
||||
elapsed_seconds = (datetime.now() - self.last_error_printout).seconds
|
||||
if elapsed_seconds > self.error_printout_timeout:
|
||||
self.last_error_printout = now
|
||||
|
||||
messages = []
|
||||
for module_errors in errors:
|
||||
for error in module_errors:
|
||||
messages.append(f"{Fore.RED}[ERROR]{Fore.RESET} {error['msg']} \n")
|
||||
print("".join(messages))
|
||||
|
||||
def render(self, window, event, values):
|
||||
validated_data, errors = {}, []
|
||||
# we might want to think about event driven architecture here eventually, validate only
|
||||
# if anything changes instead of checking for changes
|
||||
for module in self.initialized_modules:
|
||||
module_validated_data = module.validate(values)
|
||||
if module_validated_data.changes:
|
||||
validated_data.update(module_validated_data.changes)
|
||||
if module_validated_data.errors:
|
||||
errors.append(module_validated_data.errors)
|
||||
|
||||
if not errors and validated_data and not self.is_saving:
|
||||
self.is_saving = True
|
||||
self._update_and_save_config(validated_data)
|
||||
|
||||
if errors:
|
||||
self._handle_errors(errors)
|
||||
|
||||
self.handle_events(event, window)
|
||||
|
||||
def _initialize_modules(self, settings_modules, widget_id):
|
||||
return [
|
||||
module(
|
||||
config=self.config,
|
||||
settings=self.main_config,
|
||||
widget_id=widget_id,
|
||||
)
|
||||
for module in settings_modules
|
||||
]
|
||||
|
||||
def get_layout(self) -> Iterable:
|
||||
return self.widget_layout
|
||||
|
||||
def handle_events(self, event, window):
|
||||
if event == "__TIMEOUT__":
|
||||
return
|
||||
|
||||
if event == self.reset_button_key:
|
||||
self.reset_config(window)
|
||||
|
||||
def reset_config(self, window):
|
||||
|
||||
default_values = {}
|
||||
base_settings = EyeTrackSettingsConfig()
|
||||
|
||||
print(f"\033[92m[INFO] Resetting config to defaults\033[0m")
|
||||
for module in self.initialized_modules:
|
||||
for key in module.get_key_for_panel_defaults():
|
||||
default_val = getattr(base_settings, key)
|
||||
widget_key = getattr(module, key)
|
||||
default_values[key] = default_val
|
||||
window[widget_key].update(default_val)
|
||||
print(f"\033[92m[INFO] Config reset, saving\033[0m")
|
||||
|
||||
self._update_and_save_config(default_values)
|
1
EyeTrackApp/settings/constants.py
Normal file
1
EyeTrackApp/settings/constants.py
Normal file
@ -0,0 +1 @@
|
||||
BACKGROUND_COLOR = "#424042"
|
@ -0,0 +1,137 @@
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
import PySimpleGUI as sg
|
||||
|
||||
|
||||
class AdvancedTrackingAlgoSettingsValidationModel(BaseValidationModel):
|
||||
gui_HSF_radius_left: int
|
||||
gui_HSF_radius_right: int
|
||||
gui_blob_maxsize: int
|
||||
gui_blob_minsize: int
|
||||
gui_legacy_ransac_thresh_left: int
|
||||
gui_legacy_ransac_thresh_right: int
|
||||
gui_skip_autoradius: bool
|
||||
gui_thresh_add: int
|
||||
gui_threshold: int
|
||||
gui_pupil_dilation: bool
|
||||
|
||||
|
||||
class AdvancedTrackingAlgoSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.validation_model = AdvancedTrackingAlgoSettingsValidationModel
|
||||
|
||||
self.gui_blob_maxsize = f"-BLOBMAXSIZE{widget_id}-"
|
||||
self.gui_blob_minsize = f"-BLOBMINSIZE{widget_id}-"
|
||||
self.gui_skip_autoradius = f"-SKIPAUTORADIUS{widget_id}-"
|
||||
self.gui_thresh_add = f"-THRESHADD{widget_id}-"
|
||||
self.gui_threshold = f"-BLOBTHRESHOLD{widget_id}-"
|
||||
self.gui_HSF_radius_left = f"-HSFRADIUSLEFT{widget_id}-"
|
||||
self.gui_HSF_radius_right = f"-HSFRADIUSRIGHT{widget_id}-"
|
||||
|
||||
self.gui_legacy_ransac_thresh_right = f"-THRESHRIGHT{widget_id}-"
|
||||
self.gui_legacy_ransac_thresh_left = f"-THRESHLEFT{widget_id}-"
|
||||
self.gui_pupil_dilation = f"-EBPD{widget_id}-"
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[sg.Text("Pupil Dilation Algo Settings:", background_color="#242224")],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Ellipse Based Pupil Dilation",
|
||||
default=self.config.gui_pupil_dilation,
|
||||
key=self.gui_pupil_dilation,
|
||||
background_color="#424042",
|
||||
)
|
||||
],
|
||||
[sg.Text("Advanced Tracking Algorithm Settings:", background_color="#242224")],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"HSF: Skip Auto Radius",
|
||||
default=self.config.gui_skip_autoradius,
|
||||
key=self.gui_skip_autoradius,
|
||||
background_color="#424042",
|
||||
tooltip="To gain more control and possibly better tracking quality of HSF, please disable auto radius to enable manual adjustment.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Left HSF Radius:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_HSF_radius_left,
|
||||
orientation="h",
|
||||
key=self.gui_HSF_radius_left,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.",
|
||||
),
|
||||
sg.Text("Right HSF Radius:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_HSF_radius_right,
|
||||
orientation="h",
|
||||
key=self.gui_HSF_radius_right,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the radius parameter for HSF. Only adjust if you are having tracking issues.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("RANSAC Thresh Add", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_thresh_add,
|
||||
orientation="h",
|
||||
key=self.gui_thresh_add,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the amount of threshold to add to RANSAC. Useful for fine tuning your setup.",
|
||||
),
|
||||
sg.Text("Blob Threshold", background_color="#424042"),
|
||||
# TODO make this for right and left eyes? I dont know how vital that is..
|
||||
sg.Slider(
|
||||
range=(0, 110),
|
||||
default_value=self.config.gui_threshold,
|
||||
orientation="h",
|
||||
key=self.gui_threshold,
|
||||
background_color="#424042",
|
||||
tooltip="Adjusts the threshold for blob tracking.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Min Blob Size:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_blob_minsize,
|
||||
orientation="h",
|
||||
key=self.gui_blob_minsize,
|
||||
background_color="#424042",
|
||||
tooltip="Minimum size a blob has to be for blob tracking.",
|
||||
),
|
||||
sg.Text("Max Blob Size:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 50),
|
||||
default_value=self.config.gui_blob_maxsize,
|
||||
orientation="h",
|
||||
key=self.gui_blob_maxsize,
|
||||
background_color="#424042",
|
||||
tooltip="Maximum size a blob can be for blob tracking.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Right Eye Thresh:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 120),
|
||||
default_value=self.config.gui_legacy_ransac_thresh_right,
|
||||
orientation="h",
|
||||
key=self.gui_legacy_ransac_thresh_right,
|
||||
background_color="#424042",
|
||||
tooltip="Threshold for right eye, legacy RANSAC only",
|
||||
),
|
||||
sg.Text("Left Eye Thresh:", background_color="#424042"),
|
||||
sg.Slider(
|
||||
range=(1, 120),
|
||||
default_value=self.config.gui_legacy_ransac_thresh_left,
|
||||
orientation="h",
|
||||
key=self.gui_legacy_ransac_thresh_left,
|
||||
background_color="#424042",
|
||||
tooltip="Threshold for left eye, legacy RANSAC only",
|
||||
),
|
||||
],
|
||||
]
|
68
EyeTrackApp/settings/modules/BaseModule.py
Normal file
68
EyeTrackApp/settings/modules/BaseModule.py
Normal file
@ -0,0 +1,68 @@
|
||||
from typing import Iterable, Optional, NamedTuple, Any
|
||||
|
||||
import pydantic
|
||||
from pydantic import BaseModel
|
||||
|
||||
from config import EyeTrackSettingsConfig
|
||||
|
||||
|
||||
class MissingValidationModelException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingValidationConfigException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseValidationModel(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
class ValidationResult(NamedTuple):
|
||||
changes: Optional[dict[str, str]]
|
||||
errors: list[Any] # ErrorDict but we cannot import it, it's not exposed
|
||||
|
||||
|
||||
class BaseSettingsModule:
|
||||
def __init__(self, config: EyeTrackSettingsConfig, widget_id, **kwargs):
|
||||
self.validation_model: BaseValidationModel = BaseValidationModel # noqa
|
||||
self.config = config
|
||||
self.widget_id = widget_id
|
||||
|
||||
def get_validation_model(self):
|
||||
"""Return validation model, can be overridden for custom behaviour"""
|
||||
return self.validation_model
|
||||
|
||||
def initialize_validation_model(self, values):
|
||||
validation_model = self.get_validation_model()
|
||||
if not validation_model:
|
||||
raise MissingValidationModelException()
|
||||
|
||||
field_mapping = {}
|
||||
for field in self.validation_model.model_fields.keys():
|
||||
field_mapping[field] = values[getattr(self, field)]
|
||||
|
||||
return validation_model(**field_mapping)
|
||||
|
||||
def validate(self, values, raise_exception=False) -> Optional[ValidationResult]:
|
||||
"""Return """
|
||||
if not self.config:
|
||||
raise MissingValidationConfigException()
|
||||
try:
|
||||
changes = {}
|
||||
validated_model = self.initialize_validation_model(values)
|
||||
for field, value in validated_model.model_dump().items():
|
||||
if getattr(self.config, field) != value:
|
||||
changes[field] = value
|
||||
|
||||
return ValidationResult(changes, [])
|
||||
except pydantic.ValidationError as e:
|
||||
if not raise_exception:
|
||||
return ValidationResult(None, e.errors())
|
||||
raise
|
||||
|
||||
def get_layout(self) -> Iterable:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_key_for_panel_defaults(self) -> dict:
|
||||
return self.validation_model.schema().get("properties").keys()
|
100
EyeTrackApp/settings/modules/BlinkAlgoModule.py
Normal file
100
EyeTrackApp/settings/modules/BlinkAlgoModule.py
Normal file
@ -0,0 +1,100 @@
|
||||
from pydantic import AfterValidator
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
import PySimpleGUI as sg
|
||||
|
||||
from settings.modules.CommonFieldValidators import check_is_float_convertible
|
||||
|
||||
|
||||
class BlinkAlgoSettingsValidationModel(BaseValidationModel):
|
||||
gui_IBO: bool
|
||||
gui_RANSACBLINK: bool
|
||||
gui_BLINK: bool
|
||||
gui_LEAP_lid: bool
|
||||
ibo_filter_samples: int
|
||||
calibration_samples: int
|
||||
ibo_fully_close_eye_threshold: Annotated[str, AfterValidator(check_is_float_convertible)]
|
||||
gui_circular_crop_left: bool
|
||||
gui_circular_crop_right: bool
|
||||
|
||||
|
||||
class BlinkAlgoSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.validation_model = BlinkAlgoSettingsValidationModel
|
||||
|
||||
self.gui_IBO = f"-IBO{widget_id}-"
|
||||
self.gui_RANSACBLINK = f"-RANSACBLINK{widget_id}-"
|
||||
self.gui_BLINK = f"-BLINK{widget_id}-"
|
||||
self.gui_LEAP_lid = f"-LEAPLID{widget_id}-"
|
||||
self.ibo_filter_samples = f"-IBOFILTERSAMPLE{widget_id}-"
|
||||
self.calibration_samples = f"-CALIBRATIONSAMPLES{widget_id}-"
|
||||
self.ibo_fully_close_eye_threshold = f"-CLOSETHRESH{widget_id}-"
|
||||
self.gui_circular_crop_left = f"-CIRCLECROPLEFT{widget_id}-"
|
||||
self.gui_circular_crop_right = f"-CIRCLECROPRIGHT{widget_id}-"
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[sg.Text("Blink Algo Settings:", background_color="#242224")],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Intensity Based Openness",
|
||||
default=self.config.gui_IBO,
|
||||
key=self.gui_IBO,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"RANSAC Quick Blink Algo",
|
||||
default=self.config.gui_RANSACBLINK,
|
||||
key=self.gui_RANSACBLINK,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Binary Blink Algo",
|
||||
default=self.config.gui_BLINK,
|
||||
key=self.gui_BLINK,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"LEAP Lid",
|
||||
default=self.config.gui_LEAP_lid,
|
||||
key=self.gui_LEAP_lid,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("IBO Filter Sample Size", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.ibo_filter_samples,
|
||||
key=self.ibo_filter_samples,
|
||||
size=(0, 10),
|
||||
),
|
||||
sg.Text("Calibration Samples", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.calibration_samples,
|
||||
key=self.calibration_samples,
|
||||
size=(0, 10),
|
||||
),
|
||||
sg.Text("IBO Close Threshold", background_color="#424042"),
|
||||
sg.InputText(
|
||||
self.config.ibo_fully_close_eye_threshold,
|
||||
key=self.ibo_fully_close_eye_threshold,
|
||||
size=(0, 10),
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Left Eye Circle crop",
|
||||
default=self.config.gui_circular_crop_left,
|
||||
key=self.gui_circular_crop_left,
|
||||
background_color="#424042",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Right Eye Circle crop",
|
||||
default=self.config.gui_circular_crop_right,
|
||||
key=self.gui_circular_crop_right,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
]
|
11
EyeTrackApp/settings/modules/CommonFieldValidators.py
Normal file
11
EyeTrackApp/settings/modules/CommonFieldValidators.py
Normal file
@ -0,0 +1,11 @@
|
||||
def check_is_float_convertible(v: str):
|
||||
"""Check if value provided can be converted to a float or double.
|
||||
|
||||
PySimpleGUI does not support floats or doubles in UI, so we have to make sure
|
||||
that what the user typed in is correct
|
||||
"""
|
||||
try:
|
||||
float(v)
|
||||
return v
|
||||
except ValueError:
|
||||
raise ValueError("Please provide a proper number")
|
70
EyeTrackApp/settings/modules/GeneralSettingsModule.py
Normal file
70
EyeTrackApp/settings/modules/GeneralSettingsModule.py
Normal file
@ -0,0 +1,70 @@
|
||||
from config import EyeTrackSettingsConfig
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
import PySimpleGUI as sg
|
||||
|
||||
|
||||
class GeneralSettingsValidationModel(BaseValidationModel):
|
||||
gui_flip_x_axis_left: bool
|
||||
gui_flip_x_axis_right: bool
|
||||
gui_flip_y_axis: bool
|
||||
gui_eye_falloff: bool
|
||||
gui_update_check: bool
|
||||
|
||||
|
||||
class GeneralSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.validation_model = GeneralSettingsValidationModel
|
||||
self.gui_flip_x_axis_left = f"-FLIPXAXISLEFT{widget_id}-"
|
||||
self.gui_flip_x_axis_right = f"-FLIPXAXISRIGHT{widget_id}-"
|
||||
self.gui_flip_y_axis = f"-FLIPYAXIS{widget_id}-"
|
||||
self.gui_eye_falloff = f"-EYEFALLOFF{widget_id}-"
|
||||
self.gui_update_check = f"-UPDATECHECK{widget_id}-"
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[
|
||||
sg.Text("General Settings:", background_color="#242224"),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Flip Left Eye X Axis",
|
||||
default=self.config.gui_flip_x_axis_left,
|
||||
key=self.gui_flip_x_axis_left,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the left eye's X axis.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Flip Right Eye X Axis",
|
||||
default=self.config.gui_flip_x_axis_right,
|
||||
key=self.gui_flip_x_axis_right,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the right eye's X axis.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"Flip Y Axis",
|
||||
default=self.config.gui_flip_y_axis,
|
||||
key=self.gui_flip_y_axis,
|
||||
background_color="#424042",
|
||||
tooltip="Flips the eye's Y axis.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Dual Eye Falloff",
|
||||
default=self.config.gui_eye_falloff,
|
||||
key=self.gui_eye_falloff,
|
||||
background_color="#424042",
|
||||
tooltip="If one eye stops tracking, we send tracking data from your other eye.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"Check For Updates",
|
||||
default=self.config.gui_update_check,
|
||||
key=self.gui_update_check,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle update check on launch.",
|
||||
),
|
||||
],
|
||||
]
|
126
EyeTrackApp/settings/modules/OSCSettingsModule.py
Normal file
126
EyeTrackApp/settings/modules/OSCSettingsModule.py
Normal file
@ -0,0 +1,126 @@
|
||||
from pydantic import model_validator
|
||||
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
from settings.constants import BACKGROUND_COLOR
|
||||
import PySimpleGUI as sg
|
||||
|
||||
|
||||
class OSCValidationModel(BaseValidationModel):
|
||||
gui_osc_port: int
|
||||
gui_osc_address: str
|
||||
gui_ROSC: bool
|
||||
gui_osc_receiver_port: int
|
||||
gui_osc_recenter_address: str
|
||||
gui_osc_recalibrate_address: str
|
||||
gui_vrc_native: bool
|
||||
gui_osc_vrcft_v1: bool
|
||||
gui_osc_vrcft_v2: bool
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_osc_vrcft_versions(self):
|
||||
if self.gui_osc_vrcft_v1 and self.gui_osc_vrcft_v2:
|
||||
raise ValueError("Only one version of VRCFT params can be turned on")
|
||||
return self
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_osc_output_mode(self):
|
||||
if self.gui_vrc_native and any([self.gui_osc_vrcft_v1, self.gui_osc_vrcft_v2]):
|
||||
raise ValueError("Either VRCNative or VRCFT output can be active at a time")
|
||||
return self
|
||||
|
||||
|
||||
class OSCSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.validation_model = OSCValidationModel
|
||||
self.gui_osc_address = f"-OSCADDRESS{widget_id}-"
|
||||
self.gui_osc_port = f"-OSCPORT{widget_id}-"
|
||||
self.gui_ROSC = f"-ROSC{widget_id}-"
|
||||
self.gui_osc_receiver_port = f"OSCRECEIVERPORT{widget_id}-"
|
||||
self.gui_osc_recenter_address = f"OSCRECENTERADDRESS{widget_id}-"
|
||||
self.gui_osc_recalibrate_address = f"OSCRECALIBRATEADDRESS{widget_id}-"
|
||||
self.gui_vrc_native = f"-VRCNATIVE{widget_id}-"
|
||||
self.gui_osc_vrcft_v1 = f"-OSCVRCFTV1{widget_id}-"
|
||||
self.gui_osc_vrcft_v2 = f"-OSCVRCFTV2{widget_id}-"
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[
|
||||
sg.Text("OSC Settings:", background_color="#242224"),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"VRC Native Eyetracking",
|
||||
default=self.config.gui_vrc_native,
|
||||
key=self.gui_vrc_native,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRCFT output or VRC native",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"VRCFT v1",
|
||||
default=self.config.gui_osc_vrcft_v1,
|
||||
key=self.gui_osc_vrcft_v1,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRCFT's v1 Eyetracking format.",
|
||||
),
|
||||
sg.Checkbox(
|
||||
"VRCFT v2 (UE)",
|
||||
default=self.config.gui_osc_vrcft_v2,
|
||||
key=self.gui_osc_vrcft_v2,
|
||||
background_color="#424042",
|
||||
tooltip="Toggle VRCFT's v2 (UE) Eyetracking format.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Address:", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_address,
|
||||
key=self.gui_osc_address,
|
||||
size=(0, 20),
|
||||
tooltip="IP address we send OSC data to.",
|
||||
),
|
||||
sg.Text("Port:", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_port,
|
||||
key=self.gui_osc_port,
|
||||
size=(0, 10),
|
||||
tooltip="OSC port we send data to.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Receive functions", background_color=BACKGROUND_COLOR),
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_ROSC,
|
||||
key=self.gui_ROSC,
|
||||
background_color=BACKGROUND_COLOR,
|
||||
size=(0, 10),
|
||||
tooltip="Toggle OSC receive functions.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Receiver Port:", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_receiver_port,
|
||||
key=self.gui_osc_receiver_port,
|
||||
size=(0, 10),
|
||||
tooltip="Port we receive OSC data from (used to recalibrate or recenter app from within VRChat.",
|
||||
),
|
||||
sg.Text("Recenter Address:", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_recenter_address,
|
||||
key=self.gui_osc_recenter_address,
|
||||
size=(0, 10),
|
||||
tooltip="OSC Address used for recentering your eye.",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Text("Recalibrate Address:", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_osc_recalibrate_address,
|
||||
key=self.gui_osc_recalibrate_address,
|
||||
size=(0, 10),
|
||||
tooltip="OSC address we use for recalibrating your eye",
|
||||
),
|
||||
],
|
||||
]
|
42
EyeTrackApp/settings/modules/OneEuroSettingsModule.py
Normal file
42
EyeTrackApp/settings/modules/OneEuroSettingsModule.py
Normal file
@ -0,0 +1,42 @@
|
||||
from pydantic import AfterValidator
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
from settings.constants import BACKGROUND_COLOR
|
||||
import PySimpleGUI as sg
|
||||
|
||||
from settings.modules.CommonFieldValidators import check_is_float_convertible
|
||||
|
||||
|
||||
class OneEuroFilterValidationModel(BaseValidationModel):
|
||||
gui_speed_coefficient: Annotated[str, AfterValidator(check_is_float_convertible)]
|
||||
gui_min_cutoff: Annotated[str, AfterValidator(check_is_float_convertible)]
|
||||
|
||||
|
||||
class OneEuroSettingsModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.gui_speed_coefficient = f"-SPEEDCOEFFICIENT{widget_id}-"
|
||||
self.gui_min_cutoff = f"-MINCUTOFF{widget_id}-"
|
||||
self.validation_model = OneEuroFilterValidationModel
|
||||
|
||||
def get_layout(self):
|
||||
return [
|
||||
[
|
||||
sg.Text("One Euro Filter Paramaters:", background_color='#242224'),
|
||||
],
|
||||
[
|
||||
sg.Text("Min Frequency Cutoff", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_min_cutoff,
|
||||
key=self.gui_min_cutoff,
|
||||
size=(0, 10),
|
||||
),
|
||||
sg.Text("Speed Coefficient", background_color=BACKGROUND_COLOR),
|
||||
sg.InputText(
|
||||
self.config.gui_speed_coefficient,
|
||||
key=self.gui_speed_coefficient,
|
||||
size=(0, 10),
|
||||
),
|
||||
],
|
||||
]
|
190
EyeTrackApp/settings/modules/TrackingAlgorithmModule.py
Normal file
190
EyeTrackApp/settings/modules/TrackingAlgorithmModule.py
Normal file
@ -0,0 +1,190 @@
|
||||
from pydantic import model_validator
|
||||
|
||||
from settings.modules.BaseModule import BaseSettingsModule, BaseValidationModel
|
||||
import PySimpleGUI as sg
|
||||
|
||||
|
||||
class TrackingAlgorithmValidationModel(BaseValidationModel):
|
||||
gui_BLOB: bool
|
||||
gui_DADDY: bool
|
||||
gui_HSF: bool
|
||||
gui_HSRAC: bool
|
||||
gui_LEAP: bool
|
||||
gui_RANSAC3D: bool
|
||||
gui_legacy_ransac: bool
|
||||
|
||||
gui_BLOBP: int
|
||||
gui_DADDYP: int
|
||||
gui_HSFP: int
|
||||
gui_HSRACP: int
|
||||
gui_LEAPP: int
|
||||
gui_RANSAC3DP: int
|
||||
|
||||
@model_validator(mode="after")
|
||||
def check_algorith_order(self):
|
||||
algos_list = [
|
||||
self.gui_BLOBP,
|
||||
self.gui_DADDYP,
|
||||
self.gui_HSFP,
|
||||
self.gui_HSRACP,
|
||||
self.gui_LEAPP,
|
||||
self.gui_RANSAC3DP,
|
||||
]
|
||||
algos_set = set(algos_list)
|
||||
if len(algos_set) != len(algos_list):
|
||||
raise ValueError("Please fixup the algorithm order, some algos are doubled")
|
||||
return self
|
||||
|
||||
|
||||
class TrackingAlgorithmModule(BaseSettingsModule):
|
||||
def __init__(self, config, widget_id, **kwargs):
|
||||
super().__init__(config=config, widget_id=widget_id, **kwargs)
|
||||
self.algo_count = ["1", "2", "3", "4", "5", "6"]
|
||||
self.validation_model = TrackingAlgorithmValidationModel
|
||||
self.gui_BLOB = f"-BLOBFALLBACK{widget_id}-"
|
||||
self.gui_DADDY = f"-DADDY{widget_id}-"
|
||||
self.gui_HSF = f"-HSF{widget_id}-"
|
||||
self.gui_HSRAC = f"-HSRAC{widget_id}-"
|
||||
self.gui_LEAP = f"-LEAP{widget_id}-"
|
||||
self.gui_RANSAC3D = f"-RANSAC3D{widget_id}-"
|
||||
self.gui_legacy_ransac = f"-LEGACYRANSACTHRESH{widget_id}-"
|
||||
|
||||
self.gui_BLOBP = f"-BLOBP{widget_id}-"
|
||||
self.gui_DADDYP = f"-DADDYP{widget_id}-"
|
||||
self.gui_HSFP = f"-HSFP{widget_id}-"
|
||||
self.gui_HSRACP = f"-HSRACP{widget_id}-"
|
||||
self.gui_LEAPP = f"-LEAPP{widget_id}-"
|
||||
self.gui_RANSAC3DP = f"-RANSAC3DP{widget_id}-"
|
||||
|
||||
# TODO custom validation, make a set of values, count if there's less than overall, if yeah we have a problem
|
||||
def get_layout(self):
|
||||
return [
|
||||
[
|
||||
sg.Text(
|
||||
"Tracking Algorithm Order Settings:",
|
||||
background_color="#242224",
|
||||
)
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_HSRAC,
|
||||
key=self.gui_HSRAC,
|
||||
background_color="#424042",
|
||||
tooltip="Our flagship algorithm, utilizing both HSF and RANSAC for best tracking quality and lighting resistance.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_HSRACP,
|
||||
key=self.gui_HSRACP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("HSRAC", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_HSF,
|
||||
key=self.gui_HSF,
|
||||
background_color="#424042",
|
||||
tooltip="HSF Is a new, lower resolution tracking algorithim that provides excelent resilancy to lighting conditions and great speed.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_HSFP,
|
||||
key=self.gui_HSFP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithims.",
|
||||
),
|
||||
sg.Text("Haar Surround Feature", background_color="#424042"),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_DADDY,
|
||||
key=self.gui_DADDY,
|
||||
background_color="#424042",
|
||||
tooltip="DADDY Uses a Deep learning algorithm. This has a big CPU usage impact.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_DADDYP,
|
||||
key=self.gui_DADDYP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("DADDY", background_color="#424042"),
|
||||
# ],
|
||||
# [
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_RANSAC3D,
|
||||
key=self.gui_RANSAC3D,
|
||||
background_color="#424042",
|
||||
tooltip="RANSAC3D provides good tracking quality, however does not do well in bad lighting conditions.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_RANSAC3DP,
|
||||
key=self.gui_RANSAC3DP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("RANSAC 3D", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"Legacy RANSAC Thresh",
|
||||
default=self.config.gui_legacy_ransac,
|
||||
key=self.gui_legacy_ransac,
|
||||
background_color="#424042",
|
||||
),
|
||||
],
|
||||
[
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_LEAP,
|
||||
key=self.gui_LEAP,
|
||||
background_color="#424042",
|
||||
tooltip="LEAP Uses a lightweight deep learning algorithm.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_LEAPP,
|
||||
key=self.gui_LEAPP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("LEAP", background_color="#424042"),
|
||||
sg.Checkbox(
|
||||
"",
|
||||
default=self.config.gui_BLOB,
|
||||
key=self.gui_BLOB,
|
||||
background_color="#424042",
|
||||
tooltip="Blob tracking is the oldest and worst tracking algorithm, it provides fast, though sometimes inaccurate tracking.",
|
||||
),
|
||||
sg.Combo(
|
||||
self.algo_count,
|
||||
default_value=self.config.gui_BLOBP,
|
||||
key=self.gui_BLOBP,
|
||||
background_color="#424042",
|
||||
text_color="white",
|
||||
button_arrow_color="black",
|
||||
button_background_color="#6f4ca1",
|
||||
tooltip="Select the priority of eyetracking algorithms.",
|
||||
),
|
||||
sg.Text("Blob", background_color="#424042"),
|
||||
],
|
||||
]
|
249
poetry.lock
generated
249
poetry.lock
generated
@ -1,10 +1,9 @@
|
||||
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "altgraph"
|
||||
version = "0.17.3"
|
||||
description = "Python graph (network) package"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -12,11 +11,21 @@ files = [
|
||||
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.6.0"
|
||||
description = "Reusable constraint types to use with typing.Annotated"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"},
|
||||
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "22.12.0"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -39,7 +48,6 @@ click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
@ -51,7 +59,6 @@ uvloop = ["uvloop (>=0.15.2)"]
|
||||
name = "certifi"
|
||||
version = "2023.5.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -63,7 +70,6 @@ files = [
|
||||
name = "charset-normalizer"
|
||||
version = "3.1.0"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
@ -148,7 +154,6 @@ files = [
|
||||
name = "click"
|
||||
version = "8.1.3"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -163,7 +168,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
@ -175,7 +179,6 @@ files = [
|
||||
name = "coloredlogs"
|
||||
version = "15.0.1"
|
||||
description = "Colored terminal output for Python's logging module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
@ -193,7 +196,6 @@ cron = ["capturer (>=2.4)"]
|
||||
name = "flake8"
|
||||
version = "5.0.4"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1"
|
||||
files = [
|
||||
@ -210,7 +212,6 @@ pyflakes = ">=2.5.0,<2.6.0"
|
||||
name = "flatbuffers"
|
||||
version = "23.5.26"
|
||||
description = "The FlatBuffers serialization format for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -222,7 +223,6 @@ files = [
|
||||
name = "humanfriendly"
|
||||
version = "10.0"
|
||||
description = "Human friendly output for text interfaces using Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
@ -237,7 +237,6 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -249,7 +248,6 @@ files = [
|
||||
name = "macholib"
|
||||
version = "1.16.2"
|
||||
description = "Mach-O header analysis and editing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -264,7 +262,6 @@ altgraph = ">=0.17"
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -276,7 +273,6 @@ files = [
|
||||
name = "mpmath"
|
||||
version = "1.3.0"
|
||||
description = "Python library for arbitrary-precision floating-point arithmetic"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -294,7 +290,6 @@ tests = ["pytest (>=4.6)"]
|
||||
name = "msgpack"
|
||||
version = "1.0.5"
|
||||
description = "MessagePack serializer"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -367,7 +362,6 @@ files = [
|
||||
name = "mslex"
|
||||
version = "0.3.0"
|
||||
description = "shlex for windows"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -379,7 +373,6 @@ files = [
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@ -391,7 +384,6 @@ files = [
|
||||
name = "numpy"
|
||||
version = "1.23.5"
|
||||
description = "NumPy is the fundamental package for array computing with Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -429,7 +421,6 @@ files = [
|
||||
name = "onnxruntime"
|
||||
version = "1.15.1"
|
||||
description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -471,7 +462,6 @@ sympy = "*"
|
||||
name = "opencv-python"
|
||||
version = "4.7.0.72"
|
||||
description = "Wrapper package for OpenCV python bindings."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -485,19 +475,12 @@ files = [
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = [
|
||||
{version = ">=1.21.2", markers = "python_version >= \"3.10\""},
|
||||
{version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""},
|
||||
{version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""},
|
||||
{version = ">=1.17.0", markers = "python_version >= \"3.7\""},
|
||||
{version = ">=1.17.3", markers = "python_version >= \"3.8\""},
|
||||
]
|
||||
numpy = {version = ">=1.22.0", markers = "python_version >= \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -509,7 +492,6 @@ files = [
|
||||
name = "pathspec"
|
||||
version = "0.11.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -521,7 +503,6 @@ files = [
|
||||
name = "pefile"
|
||||
version = "2023.2.7"
|
||||
description = "Python PE parsing module"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.0"
|
||||
files = [
|
||||
@ -533,7 +514,6 @@ files = [
|
||||
name = "platformdirs"
|
||||
version = "3.8.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -549,7 +529,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-
|
||||
name = "protobuf"
|
||||
version = "4.23.3"
|
||||
description = ""
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -572,7 +551,6 @@ files = [
|
||||
name = "psutil"
|
||||
version = "5.9.5"
|
||||
description = "Cross-platform lib for process and system monitoring in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@ -599,7 +577,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
|
||||
name = "pycodestyle"
|
||||
version = "2.9.1"
|
||||
description = "Python style guide checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -609,62 +586,145 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.9"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
category = "main"
|
||||
version = "2.4.2"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"},
|
||||
{file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"},
|
||||
{file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"},
|
||||
{file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"},
|
||||
{file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"},
|
||||
{file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"},
|
||||
{file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"},
|
||||
{file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"},
|
||||
{file = "pydantic-2.4.2-py3-none-any.whl", hash = "sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1"},
|
||||
{file = "pydantic-2.4.2.tar.gz", hash = "sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.2.0"
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.10.1"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
email = ["email-validator (>=1.0.3)"]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.10.1"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:d64728ee14e667ba27c66314b7d880b8eeb050e58ffc5fec3b7a109f8cddbd63"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:48525933fea744a3e7464c19bfede85df4aba79ce90c60b94d8b6e1eddd67096"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef337945bbd76cce390d1b2496ccf9f90b1c1242a3a7bc242ca4a9fc5993427a"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1392e0638af203cee360495fd2cfdd6054711f2db5175b6e9c3c461b76f5175"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0675ba5d22de54d07bccde38997e780044dcfa9a71aac9fd7d4d7a1d2e3e65f7"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:128552af70a64660f21cb0eb4876cbdadf1a1f9d5de820fed6421fa8de07c893"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f6e6aed5818c264412ac0598b581a002a9f050cb2637a84979859e70197aa9e"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ecaac27da855b8d73f92123e5f03612b04c5632fd0a476e469dfc47cd37d6b2e"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3c01c2fb081fced3bbb3da78510693dc7121bb893a1f0f5f4b48013201f362e"},
|
||||
{file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:92f675fefa977625105708492850bcbc1182bfc3e997f8eecb866d1927c98ae6"},
|
||||
{file = "pydantic_core-2.10.1-cp310-none-win32.whl", hash = "sha256:420a692b547736a8d8703c39ea935ab5d8f0d2573f8f123b0a294e49a73f214b"},
|
||||
{file = "pydantic_core-2.10.1-cp310-none-win_amd64.whl", hash = "sha256:0880e239827b4b5b3e2ce05e6b766a7414e5f5aedc4523be6b68cfbc7f61c5d0"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:073d4a470b195d2b2245d0343569aac7e979d3a0dcce6c7d2af6d8a920ad0bea"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:600d04a7b342363058b9190d4e929a8e2e715c5682a70cc37d5ded1e0dd370b4"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39215d809470f4c8d1881758575b2abfb80174a9e8daf8f33b1d4379357e417c"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eeb3d3d6b399ffe55f9a04e09e635554012f1980696d6b0aca3e6cf42a17a03b"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a7902bf75779bc12ccfc508bfb7a4c47063f748ea3de87135d433a4cca7a2f"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3625578b6010c65964d177626fde80cf60d7f2e297d56b925cb5cdeda6e9925a"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa48fc31fc7243e50188197b5f0c4228956f97b954f76da157aae7f67269ae8"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:07ec6d7d929ae9c68f716195ce15e745b3e8fa122fc67698ac6498d802ed0fa4"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6f31a17acede6a8cd1ae2d123ce04d8cca74056c9d456075f4f6f85de055607"},
|
||||
{file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f1ebca515a03e5654f88411420fea6380fc841d1bea08effb28184e3d4899f"},
|
||||
{file = "pydantic_core-2.10.1-cp311-none-win32.whl", hash = "sha256:6db2eb9654a85ada248afa5a6db5ff1cf0f7b16043a6b070adc4a5be68c716d6"},
|
||||
{file = "pydantic_core-2.10.1-cp311-none-win_amd64.whl", hash = "sha256:4a5be350f922430997f240d25f8219f93b0c81e15f7b30b868b2fddfc2d05f27"},
|
||||
{file = "pydantic_core-2.10.1-cp311-none-win_arm64.whl", hash = "sha256:5fdb39f67c779b183b0c853cd6b45f7db84b84e0571b3ef1c89cdb1dfc367325"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1f22a9ab44de5f082216270552aa54259db20189e68fc12484873d926426921"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8572cadbf4cfa95fb4187775b5ade2eaa93511f07947b38f4cd67cf10783b118"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9a28c063c7c00844ae42a80203eb6d2d6bbb97070cfa00194dff40e6f545ab"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e2a35baa428181cb2270a15864ec6286822d3576f2ed0f4cd7f0c1708472aff"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05560ab976012bf40f25d5225a58bfa649bb897b87192a36c6fef1ab132540d7"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6495008733c7521a89422d7a68efa0a0122c99a5861f06020ef5b1f51f9ba7c"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ac492c686defc8e6133e3a2d9eaf5261b3df26b8ae97450c1647286750b901"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8282bab177a9a3081fd3d0a0175a07a1e2bfb7fcbbd949519ea0980f8a07144d"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:aafdb89fdeb5fe165043896817eccd6434aee124d5ee9b354f92cd574ba5e78f"},
|
||||
{file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f6defd966ca3b187ec6c366604e9296f585021d922e666b99c47e78738b5666c"},
|
||||
{file = "pydantic_core-2.10.1-cp312-none-win32.whl", hash = "sha256:7c4d1894fe112b0864c1fa75dffa045720a194b227bed12f4be7f6045b25209f"},
|
||||
{file = "pydantic_core-2.10.1-cp312-none-win_amd64.whl", hash = "sha256:5994985da903d0b8a08e4935c46ed8daf5be1cf217489e673910951dc533d430"},
|
||||
{file = "pydantic_core-2.10.1-cp312-none-win_arm64.whl", hash = "sha256:0d8a8adef23d86d8eceed3e32e9cca8879c7481c183f84ed1a8edc7df073af94"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9badf8d45171d92387410b04639d73811b785b5161ecadabf056ea14d62d4ede"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:ebedb45b9feb7258fac0a268a3f6bec0a2ea4d9558f3d6f813f02ff3a6dc6698"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfe1090245c078720d250d19cb05d67e21a9cd7c257698ef139bc41cf6c27b4f"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e357571bb0efd65fd55f18db0a2fb0ed89d0bb1d41d906b138f088933ae618bb"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dcd587b69bbf54fc04ca157c2323b8911033e827fffaecf0cafa5a892a0904"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c120c9ce3b163b985a3b966bb701114beb1da4b0468b9b236fc754783d85aa3"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d6bca84ffc966cc9976b09a18cf9543ed4d4ecbd97e7086f9ce9327ea48891"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cabb9710f09d5d2e9e2748c3e3e20d991a4c5f96ed8f1132518f54ab2967221"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82f55187a5bebae7d81d35b1e9aaea5e169d44819789837cdd4720d768c55d15"},
|
||||
{file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1d40f55222b233e98e3921df7811c27567f0e1a4411b93d4c5c0f4ce131bc42f"},
|
||||
{file = "pydantic_core-2.10.1-cp37-none-win32.whl", hash = "sha256:14e09ff0b8fe6e46b93d36a878f6e4a3a98ba5303c76bb8e716f4878a3bee92c"},
|
||||
{file = "pydantic_core-2.10.1-cp37-none-win_amd64.whl", hash = "sha256:1396e81b83516b9d5c9e26a924fa69164156c148c717131f54f586485ac3c15e"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6835451b57c1b467b95ffb03a38bb75b52fb4dc2762bb1d9dbed8de31ea7d0fc"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b00bc4619f60c853556b35f83731bd817f989cba3e97dc792bb8c97941b8053a"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa467fd300a6f046bdb248d40cd015b21b7576c168a6bb20aa22e595c8ffcdd"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d99277877daf2efe074eae6338453a4ed54a2d93fb4678ddfe1209a0c93a2468"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa7db7558607afeccb33c0e4bf1c9a9a835e26599e76af6fe2fcea45904083a6"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aad7bd686363d1ce4ee930ad39f14e1673248373f4a9d74d2b9554f06199fb58"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:443fed67d33aa85357464f297e3d26e570267d1af6fef1c21ca50921d2976302"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:042462d8d6ba707fd3ce9649e7bf268633a41018d6a998fb5fbacb7e928a183e"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecdbde46235f3d560b18be0cb706c8e8ad1b965e5c13bbba7450c86064e96561"},
|
||||
{file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed550ed05540c03f0e69e6d74ad58d026de61b9eaebebbaaf8873e585cbb18de"},
|
||||
{file = "pydantic_core-2.10.1-cp38-none-win32.whl", hash = "sha256:8cdbbd92154db2fec4ec973d45c565e767ddc20aa6dbaf50142676484cbff8ee"},
|
||||
{file = "pydantic_core-2.10.1-cp38-none-win_amd64.whl", hash = "sha256:9f6f3e2598604956480f6c8aa24a3384dbf6509fe995d97f6ca6103bb8c2534e"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:655f8f4c8d6a5963c9a0687793da37b9b681d9ad06f29438a3b2326d4e6b7970"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e570ffeb2170e116a5b17e83f19911020ac79d19c96f320cbfa1fa96b470185b"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64322bfa13e44c6c30c518729ef08fda6026b96d5c0be724b3c4ae4da939f875"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:485a91abe3a07c3a8d1e082ba29254eea3e2bb13cbbd4351ea4e5a21912cc9b0"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7c2b8eb9fc872e68b46eeaf835e86bccc3a58ba57d0eedc109cbb14177be531"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5cb87bdc2e5f620693148b5f8f842d293cae46c5f15a1b1bf7ceeed324a740c"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25bd966103890ccfa028841a8f30cebcf5875eeac8c4bde4fe221364c92f0c9a"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f323306d0556351735b54acbf82904fe30a27b6a7147153cbe6e19aaaa2aa429"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c27f38dc4fbf07b358b2bc90edf35e82d1703e22ff2efa4af4ad5de1b3833e7"},
|
||||
{file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f1365e032a477c1430cfe0cf2856679529a2331426f8081172c4a74186f1d595"},
|
||||
{file = "pydantic_core-2.10.1-cp39-none-win32.whl", hash = "sha256:a1c311fd06ab3b10805abb72109f01a134019739bd3286b8ae1bc2fc4e50c07a"},
|
||||
{file = "pydantic_core-2.10.1-cp39-none-win_amd64.whl", hash = "sha256:ae8a8843b11dc0b03b57b52793e391f0122e740de3df1474814c700d2622950a"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d43002441932f9a9ea5d6f9efaa2e21458221a3a4b417a14027a1d530201ef1b"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fcb83175cc4936a5425dde3356f079ae03c0802bbdf8ff82c035f8a54b333521"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962ed72424bf1f72334e2f1e61b68f16c0e596f024ca7ac5daf229f7c26e4208"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cf5bb4dd67f20f3bbc1209ef572a259027c49e5ff694fa56bed62959b41e1f9"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e544246b859f17373bed915182ab841b80849ed9cf23f1f07b73b7c58baee5fb"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c0877239307b7e69d025b73774e88e86ce82f6ba6adf98f41069d5b0b78bd1bf"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:53df009d1e1ba40f696f8995683e067e3967101d4bb4ea6f667931b7d4a01357"},
|
||||
{file = "pydantic_core-2.10.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1254357f7e4c82e77c348dabf2d55f1d14d19d91ff025004775e70a6ef40ada"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:524ff0ca3baea164d6d93a32c58ac79eca9f6cf713586fdc0adb66a8cdeab96a"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f0ac9fb8608dbc6eaf17956bf623c9119b4db7dbb511650910a82e261e6600f"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:320f14bd4542a04ab23747ff2c8a778bde727158b606e2661349557f0770711e"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63974d168b6233b4ed6a0046296803cb13c56637a7b8106564ab575926572a55"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:417243bf599ba1f1fef2bb8c543ceb918676954734e2dcb82bf162ae9d7bd514"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dda81e5ec82485155a19d9624cfcca9be88a405e2857354e5b089c2a982144b2"},
|
||||
{file = "pydantic_core-2.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14cfbb00959259e15d684505263d5a21732b31248a5dd4941f73a3be233865b9"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:631cb7415225954fdcc2a024119101946793e5923f6c4d73a5914d27eb3d3a05"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec7dd208a4182e99c5b6c501ce0b1f49de2802448d4056091f8e630b28e9a52"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:149b8a07712f45b332faee1a2258d8ef1fb4a36f88c0c17cb687f205c5dc6e7d"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d966c47f9dd73c2d32a809d2be529112d509321c5310ebf54076812e6ecd884"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7eb037106f5c6b3b0b864ad226b0b7ab58157124161d48e4b30c4a43fef8bc4b"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:154ea7c52e32dce13065dbb20a4a6f0cc012b4f667ac90d648d36b12007fa9f7"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e562617a45b5a9da5be4abe72b971d4f00bf8555eb29bb91ec2ef2be348cd132"},
|
||||
{file = "pydantic_core-2.10.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f23b55eb5464468f9e0e9a9935ce3ed2a870608d5f534025cd5536bca25b1402"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e9121b4009339b0f751955baf4543a0bfd6bc3f8188f8056b1a25a2d45099934"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0523aeb76e03f753b58be33b26540880bac5aa54422e4462404c432230543f33"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0e2959ef5d5b8dc9ef21e1a305a21a36e254e6a34432d00c72a92fdc5ecda5"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da01bec0a26befab4898ed83b362993c844b9a607a86add78604186297eb047e"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2e9072d71c1f6cfc79a36d4484c82823c560e6f5599c43c1ca6b5cdbd54f881"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f36a3489d9e28fe4b67be9992a23029c3cec0babc3bd9afb39f49844a8c721c5"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f64f82cc3443149292b32387086d02a6c7fb39b8781563e0ca7b8d7d9cf72bd7"},
|
||||
{file = "pydantic_core-2.10.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b4a6db486ac8e99ae696e09efc8b2b9fea67b63c8f88ba7a1a16c24a057a0776"},
|
||||
{file = "pydantic_core-2.10.1.tar.gz", hash = "sha256:0f8682dbdd2f67f8e1edddcbffcc29f60a6182b4901c367fc8c1c40d30bb0a82"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pye3d"
|
||||
version = "0.3.2"
|
||||
description = "3D eye model"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -705,7 +765,6 @@ with-opencv = ["opencv-python"]
|
||||
name = "pyflakes"
|
||||
version = "2.5.0"
|
||||
description = "passive checker of Python programs"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -717,7 +776,6 @@ files = [
|
||||
name = "pyinstaller"
|
||||
version = "5.13.0"
|
||||
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "<3.13,>=3.7"
|
||||
files = [
|
||||
@ -751,7 +809,6 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2023.4"
|
||||
description = "Community maintained hooks for PyInstaller"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -763,7 +820,6 @@ files = [
|
||||
name = "pyreadline3"
|
||||
version = "3.4.1"
|
||||
description = "A python implementation of GNU readline."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -775,7 +831,6 @@ files = [
|
||||
name = "pyserial"
|
||||
version = "3.5"
|
||||
description = "Python Serial Port Extension"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -790,7 +845,6 @@ cp2110 = ["hidapi"]
|
||||
name = "pysimplegui"
|
||||
version = "4.60.5"
|
||||
description = "Python GUIs for Humans. Launched in 2018. It's 2022 & PySimpleGUI is an ACTIVE & supported project. Super-simple to create custom GUI's. 325+ Demo programs & Cookbook for rapid start. Extensive documentation. Main docs at www.PySimpleGUI.org. Fun & your success are the focus. Examples using Machine Learning (GUI, OpenCV Integration), Rainmeter Style Desktop Widgets, Matplotlib + Pyplot, PIL support, add GUI to command line scripts, PDF & Image Viewers. Great for beginners & advanced GUI programmers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -802,7 +856,6 @@ files = [
|
||||
name = "python-osc"
|
||||
version = "1.8.1"
|
||||
description = "Open Sound Control server and client implementations in pure Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -814,7 +867,6 @@ files = [
|
||||
name = "pywin32-ctypes"
|
||||
version = "0.2.2"
|
||||
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -826,7 +878,6 @@ files = [
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -848,7 +899,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
name = "setuptools"
|
||||
version = "68.0.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -865,7 +915,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
|
||||
name = "sortedcontainers"
|
||||
version = "2.4.0"
|
||||
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -877,7 +926,6 @@ files = [
|
||||
name = "sympy"
|
||||
version = "1.12"
|
||||
description = "Computer algebra system (CAS) in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -892,7 +940,6 @@ mpmath = ">=0.19"
|
||||
name = "taskipy"
|
||||
version = "1.11.0"
|
||||
description = "tasks runner for python projects"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4.0"
|
||||
files = [
|
||||
@ -910,7 +957,6 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version >= \"3.7\" and py
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -920,21 +966,19 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.7.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.7+"
|
||||
category = "main"
|
||||
version = "4.8.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.7.0-py3-none-any.whl", hash = "sha256:5d8c9dac95c27d20df12fb1d97b9793ab8b2af8a3a525e68c80e21060c161771"},
|
||||
{file = "typing_extensions-4.7.0.tar.gz", hash = "sha256:935ccf31549830cda708b42289d44b6f74084d616a00be651601a4f968e77c82"},
|
||||
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
|
||||
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.0.3"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -952,7 +996,6 @@ zstd = ["zstandard (>=0.18.0)"]
|
||||
name = "winotify"
|
||||
version = "1.1.0"
|
||||
description = "Show notification toast on Windows 10"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@ -962,5 +1005,5 @@ files = [
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "~3.10.0"
|
||||
content-hash = "e7ba1f268906e96f3e40127b34c43e8eaa2a2367bc3a2b471d7f6917a1edcc76"
|
||||
python-versions = "~3.11.0"
|
||||
content-hash = "0ba077e8a19c2fbfe87ee251c1b1ab26ff3a49e0072abd16f122c46c2db181a3"
|
||||
|
@ -14,7 +14,7 @@ opencv-python = "^4.6.0.66"
|
||||
numpy = "~1.23.5"
|
||||
pye3d = "^0.3.1.post1"
|
||||
pysimplegui = "^4.60.4"
|
||||
pydantic = "^1.10.2"
|
||||
pydantic = "^2.4.2"
|
||||
pyserial = "^3.5"
|
||||
winotify = [
|
||||
{ version = "^1.1.0", platform = 'win32' }
|
||||
|
Loading…
Reference in New Issue
Block a user