mxbiflow 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. mxbiflow/__init__.py +3 -0
  2. mxbiflow/assets/__init__.py +5 -0
  3. mxbiflow/assets/clicker.wav +0 -0
  4. mxbiflow/config_store.py +68 -0
  5. mxbiflow/data_logger.py +114 -0
  6. mxbiflow/default/__init__.py +4 -0
  7. mxbiflow/default/idle/assets/apple_v1.png +0 -0
  8. mxbiflow/default/idle/idle.py +57 -0
  9. mxbiflow/detector_bridge.py +87 -0
  10. mxbiflow/game.py +84 -0
  11. mxbiflow/infra/eventbus.py +31 -0
  12. mxbiflow/main.py +106 -0
  13. mxbiflow/models/animal.py +130 -0
  14. mxbiflow/models/reward.py +7 -0
  15. mxbiflow/models/session.py +145 -0
  16. mxbiflow/mxbiflow.py +43 -0
  17. mxbiflow/path.py +41 -0
  18. mxbiflow/scene/__init__.py +8 -0
  19. mxbiflow/scene/scene_manager.py +64 -0
  20. mxbiflow/scene/scene_protocol.py +22 -0
  21. mxbiflow/scheduler.py +90 -0
  22. mxbiflow/tasks/GNGSiD/models.py +70 -0
  23. mxbiflow/tasks/GNGSiD/stages/detect_stage/config.json +116 -0
  24. mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage.py +161 -0
  25. mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage_models.py +65 -0
  26. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/config.json +70 -0
  27. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage.py +173 -0
  28. mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage_models.py +80 -0
  29. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/config.json +83 -0
  30. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_models.py +58 -0
  31. mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_stage.py +149 -0
  32. mxbiflow/tasks/GNGSiD/tasks/artifacts.py +13 -0
  33. mxbiflow/tasks/GNGSiD/tasks/detect/models.py +21 -0
  34. mxbiflow/tasks/GNGSiD/tasks/detect/scene.py +271 -0
  35. mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_models.py +31 -0
  36. mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_scene.py +336 -0
  37. mxbiflow/tasks/GNGSiD/tasks/touch/touch_models.py +17 -0
  38. mxbiflow/tasks/GNGSiD/tasks/touch/touch_scene.py +256 -0
  39. mxbiflow/tasks/GNGSiD/tasks/utils/targets.py +57 -0
  40. mxbiflow/tasks/cross_modal/bundle_dir.py +553 -0
  41. mxbiflow/tasks/cross_modal/config.py +41 -0
  42. mxbiflow/tasks/cross_modal/media.py +61 -0
  43. mxbiflow/tasks/cross_modal/models.py +57 -0
  44. mxbiflow/tasks/cross_modal/scene.py +252 -0
  45. mxbiflow/tasks/cross_modal/stage.py +218 -0
  46. mxbiflow/tasks/cross_modal/trial_io.py +23 -0
  47. mxbiflow/tasks/cross_modal/trial_schema.py +113 -0
  48. mxbiflow/tasks/default/error_task/error_scene.py +53 -0
  49. mxbiflow/tasks/default/idle_task/assets/apple_v1.png +0 -0
  50. mxbiflow/tasks/default/idle_task/idle_scene.py +85 -0
  51. mxbiflow/tasks/default/initial_habituation_training/README.md +188 -0
  52. mxbiflow/tasks/default/initial_habituation_training/stages/config.csv +7 -0
  53. mxbiflow/tasks/default/initial_habituation_training/stages/config.json +67 -0
  54. mxbiflow/tasks/default/initial_habituation_training/stages/initial_habituation_training_stage.py +172 -0
  55. mxbiflow/tasks/default/initial_habituation_training/stages/models.py +56 -0
  56. mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward.py +244 -0
  57. mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward_models.py +50 -0
  58. mxbiflow/tasks/task_protocol.py +26 -0
  59. mxbiflow/tasks/task_table.py +29 -0
  60. mxbiflow/tasks/two_alternative_choice/assets/starter.py +27 -0
  61. mxbiflow/tasks/two_alternative_choice/models.py +68 -0
  62. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/config.json +118 -0
  63. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_models.py +41 -0
  64. mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_stage.py +122 -0
  65. mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_models.py +19 -0
  66. mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_scene.py +249 -0
  67. mxbiflow/timer/__init__.py +3 -0
  68. mxbiflow/timer/frame_timer.py +47 -0
  69. mxbiflow/timer/realtime_timer.py +0 -0
  70. mxbiflow/tmp_email.py +13 -0
  71. mxbiflow/ui/components/animal.py +87 -0
  72. mxbiflow/ui/components/baseconfig.py +68 -0
  73. mxbiflow/ui/components/card.py +18 -0
  74. mxbiflow/ui/components/device_card/__init__.py +17 -0
  75. mxbiflow/ui/components/device_card/detector/beambreak_detector_card.py +29 -0
  76. mxbiflow/ui/components/device_card/detector/fusion_detector.py +45 -0
  77. mxbiflow/ui/components/device_card/detector/mock_detector_card.py +20 -0
  78. mxbiflow/ui/components/device_card/detector/rfid_detector.py +40 -0
  79. mxbiflow/ui/components/device_card/device_card.py +67 -0
  80. mxbiflow/ui/components/device_card/rewarder/mock_rewarder_card.py +20 -0
  81. mxbiflow/ui/components/device_card/rewarder/rpi_gpio_rewarder.py +33 -0
  82. mxbiflow/ui/components/devices.py +183 -0
  83. mxbiflow/ui/components/dialog/__init__.py +3 -0
  84. mxbiflow/ui/components/dialog/add_devices_dialog.py +64 -0
  85. mxbiflow/ui/components/experiment_groups.py +122 -0
  86. mxbiflow/ui/experiment_panel.py +91 -0
  87. mxbiflow/ui/mxbi_panel.py +152 -0
  88. mxbiflow/utils/logger.py +19 -0
  89. mxbiflow/utils/serial.py +10 -0
  90. mxbiflow-0.1.1.dist-info/METADATA +168 -0
  91. mxbiflow-0.1.1.dist-info/RECORD +93 -0
  92. mxbiflow-0.1.1.dist-info/WHEEL +4 -0
  93. mxbiflow-0.1.1.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,7 @@
1
+ from enum import StrEnum, auto
2
+
3
+
4
+ class RewardEnum(StrEnum):
5
+ AGUM_ONE_FIFTH = auto()
6
+ AGUM_TWO_FIFTHS = auto()
7
+ M_JUICE = auto()
@@ -0,0 +1,145 @@
1
+ import os
2
+ import tempfile
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timezone
5
+ from pathlib import Path
6
+
7
+ from pydantic import BaseModel, Field, PrivateAttr, ValidationError
8
+
9
+ from .animal import Animal, AnimalConfig
10
+ from .reward import RewardEnum
11
+
12
+
13
+ class SessionConfig(BaseModel):
14
+ experimenter: str = Field(default="auto", frozen=True)
15
+ reward_type: RewardEnum = Field(default=RewardEnum.AGUM_ONE_FIFTH, frozen=True)
16
+ send_email: bool = Field(default=False, frozen=True)
17
+ sync_data: bool = Field(default=False, frozen=True)
18
+ note: str = Field(default="", max_length=1000)
19
+
20
+ animals: list[AnimalConfig] = Field(default_factory=list)
21
+
22
+
23
+ class DailySessionCounter(BaseModel):
24
+ day: str = Field(
25
+ default_factory=lambda: datetime.now(timezone.utc).date().isoformat()
26
+ )
27
+ last_session_id: int = Field(default=0, ge=0)
28
+
29
+
30
+ @dataclass
31
+ class DailySessionIdStore:
32
+ path: Path
33
+
34
+ def _today_utc(self):
35
+ return datetime.now(timezone.utc).date().isoformat()
36
+
37
+ def _load(self) -> DailySessionCounter:
38
+ if not self.path.exists():
39
+ return DailySessionCounter()
40
+
41
+ text = self.path.read_text()
42
+
43
+ try:
44
+ return DailySessionCounter.model_validate_json(text)
45
+ except ValueError, ValidationError:
46
+ return DailySessionCounter()
47
+
48
+ def _atomic_write(self, data: DailySessionCounter) -> None:
49
+ self.path.parent.mkdir(parents=True, exist_ok=True)
50
+ fd, tmp = tempfile.mkstemp(
51
+ dir=str(self.path.parent),
52
+ prefix=self.path.name,
53
+ suffix=".tmp",
54
+ )
55
+
56
+ try:
57
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
58
+ f.write(data.model_dump_json())
59
+ f.flush()
60
+ os.fsync(f.fileno())
61
+
62
+ os.replace(tmp, self.path)
63
+ finally:
64
+ try:
65
+ os.remove(tmp)
66
+ except FileNotFoundError:
67
+ pass
68
+
69
+ @property
70
+ def session_id(self) -> int:
71
+ today = self._today_utc()
72
+ data = self._load()
73
+
74
+ if data.day != today:
75
+ data.day = today
76
+ data.last_session_id = 0
77
+
78
+ data.last_session_id += 1
79
+ self._atomic_write(data)
80
+
81
+ return data.last_session_id
82
+
83
+
84
+ class Session(BaseModel):
85
+ experimenter: str = Field(default="auto", frozen=True)
86
+ reward_type: RewardEnum = Field(default=RewardEnum.AGUM_ONE_FIFTH, frozen=True)
87
+ send_email: bool = Field(default=False, frozen=True)
88
+ sync_data: bool = Field(default=False, frozen=True)
89
+
90
+ session_id: int = Field(default=0, ge=0)
91
+ start_at: float = Field(default=0, ge=0)
92
+ end_at: float = Field(default=0, ge=0)
93
+ note: str = Field(frozen=True)
94
+
95
+ _current_animal: str | None = PrivateAttr(default=None)
96
+ animals: dict[str, Animal] = Field(default_factory=dict, frozen=True)
97
+
98
+ def start(self):
99
+ self.start_at = datetime.now(timezone.utc).timestamp()
100
+
101
+ def end(self):
102
+ self.end_at = datetime.now(timezone.utc).timestamp()
103
+
104
+ @property
105
+ def current_animal(self) -> Animal | None:
106
+ key = self._current_animal
107
+ if key is None:
108
+ return None
109
+
110
+ return self.animals[key]
111
+
112
+ @property
113
+ def require_current_animal(self) -> Animal:
114
+ key = self._current_animal
115
+ if key is None:
116
+ raise RuntimeError(
117
+ f"Animal: {key} is not set. Please call set_current_animal() first"
118
+ )
119
+
120
+ return self.animals[key]
121
+
122
+ def clear_current_animal(self):
123
+ a = self.current_animal
124
+ if a is None:
125
+ return
126
+
127
+ a.end_animal_session()
128
+ self._current_animal = None
129
+
130
+ def set_current_animal(self, animal: str):
131
+ self.clear_current_animal()
132
+
133
+ try:
134
+ a = self.animals[animal]
135
+ except KeyError:
136
+ raise ValueError(f"animal {animal} not found")
137
+
138
+ self._current_animal = animal
139
+ a.start_animal_session()
140
+
141
+
142
+ class Options(BaseModel):
143
+ mxbis: list[str] = Field(default_factory=list, frozen=True)
144
+ experimenter: list[str] = Field(default_factory=list, frozen=True)
145
+ animals: dict[str, str] = Field(default_factory=dict, frozen=True)
mxbiflow/mxbiflow.py ADDED
@@ -0,0 +1,43 @@
1
+ from pymxbi import MXBI
2
+
3
+ from .models.session import Session
4
+ from .timer import FrameTimer
5
+
6
+
7
+ class MXBIFlow:
8
+ def __init__(self, session: Session, mxbi: MXBI) -> None:
9
+ self._session = session
10
+ self._timer = FrameTimer()
11
+ self._mxbi = mxbi
12
+
13
+ @property
14
+ def session(self) -> Session:
15
+ return self._session
16
+
17
+ @property
18
+ def timer(self) -> FrameTimer:
19
+ return self._timer
20
+
21
+ @property
22
+ def mxbi(self) -> MXBI:
23
+ return self._mxbi
24
+
25
+ def update(self) -> None:
26
+ self._timer.update()
27
+
28
+
29
+ _current_mxbiflow: MXBIFlow | None = None
30
+
31
+
32
+ def get_mxbiflow() -> MXBIFlow:
33
+ global _current_mxbiflow
34
+ if _current_mxbiflow is None:
35
+ raise RuntimeError("MXBIFlow not initialized")
36
+ return _current_mxbiflow
37
+
38
+
39
+ def set_mxbiflow(mxbiflow: MXBIFlow) -> None:
40
+ global _current_mxbiflow
41
+ if _current_mxbiflow is not None:
42
+ raise RuntimeError("MXBIFlow already initialized")
43
+ _current_mxbiflow = mxbiflow
mxbiflow/path.py ADDED
@@ -0,0 +1,41 @@
1
+ from pathlib import Path
2
+
3
+ # TODO: XDG Base Directory Specification
4
+ ROOT_DIR_PATH = Path(__file__).parents[2]
5
+
6
+ CONFIG_DIR_PATH = ROOT_DIR_PATH / "config"
7
+ CONFIG_SESSION_FILENAME = "config_session.json"
8
+ CONFIG_SESSION_PATH = CONFIG_DIR_PATH / CONFIG_SESSION_FILENAME
9
+
10
+ OPTIONS_SESSION_FILENAME = "options_session.json"
11
+ OPTIONS_SESSION_PATH = CONFIG_DIR_PATH / OPTIONS_SESSION_FILENAME
12
+
13
+ ANIMAL_DB_FILENAME = "animal_db.json"
14
+ ANIMAL_DB_PATH = CONFIG_DIR_PATH / ANIMAL_DB_FILENAME
15
+
16
+ CROSS_MODAL_CONFIG_FILENAME = "config_cross_modal.json"
17
+ CROSS_MODAL_CONFIG_PATH = CONFIG_DIR_PATH / CROSS_MODAL_CONFIG_FILENAME
18
+
19
+ DATA_DIR_PATH = ROOT_DIR_PATH / "data"
20
+
21
+ LOG_PATH = ROOT_DIR_PATH / "log"
22
+
23
+ SAMBA_MOUNT_PATH = ROOT_DIR_PATH / "samba_mount"
24
+ SAMBA_BACKUP_DIR_NAME = "backup"
25
+ SAMBA_BACKUP_DIR_PATH = SAMBA_MOUNT_PATH / SAMBA_BACKUP_DIR_NAME
26
+
27
+ SERVICE_DIR_NAME = "services"
28
+ SERVICE_DIR_PATH = ROOT_DIR_PATH / SERVICE_DIR_NAME
29
+ MOUNT_SERVICE_NAME = "mount.service"
30
+ MOUNT_SERVICE_PATH = SERVICE_DIR_PATH / MOUNT_SERVICE_NAME
31
+ SYNC_SERVICE_NAME = "sync.service"
32
+ SYNC_SERVICE_PATH = SERVICE_DIR_PATH / SYNC_SERVICE_NAME
33
+
34
+ MXBI_CONFIG_PATH = CONFIG_DIR_PATH / "mxbi.json"
35
+ SESSION_CONFIG_PATH = CONFIG_DIR_PATH / "session.json"
36
+ OPTIONS_PATH = CONFIG_DIR_PATH / "options.json"
37
+ STAGE_PATH = CONFIG_DIR_PATH / "stage.json"
38
+ SESSION_COUNTER_PATH = CONFIG_DIR_PATH / "session_counter.json"
39
+
40
+ ASSETS_DIR_PATH = ROOT_DIR_PATH / "assets"
41
+ ASSET_CLICKER_PATH = ASSETS_DIR_PATH / "clicker.wav"
@@ -0,0 +1,8 @@
1
+ from .scene_manager import SceneManager, Scenes
2
+ from .scene_protocol import SceneProtocol
3
+
4
+ __all__ = [
5
+ "SceneManager",
6
+ "Scenes",
7
+ "SceneProtocol",
8
+ ]
@@ -0,0 +1,64 @@
1
+ from pathlib import Path
2
+
3
+ from pydantic import RootModel
4
+ from pygame import Event, Surface
5
+
6
+ from .scene_protocol import SceneProtocol
7
+
8
+
9
+ class Scenes(RootModel):
10
+ root: list[str]
11
+
12
+
13
+ class SceneManager:
14
+ scenes: dict[str, type[SceneProtocol]] = {}
15
+
16
+ def __init__(self) -> None:
17
+ self.current: SceneProtocol | None = None
18
+ self._pending: SceneProtocol | None = None
19
+
20
+ def persist(self, path: Path) -> None:
21
+ scenes = Scenes(root=list(self.scenes.keys()))
22
+ json_data = scenes.model_dump_json()
23
+
24
+ with path.open("w") as f:
25
+ f.write(json_data)
26
+
27
+ def register(self, scene: type[SceneProtocol], name: str | None = None) -> None:
28
+ if name is None:
29
+ name = scene.__name__.lower()
30
+
31
+ self.scenes[name] = scene
32
+
33
+ def switch(self, scene: type[SceneProtocol], defer: bool = True) -> None:
34
+ if defer:
35
+ self._pending = scene()
36
+ else:
37
+ self._switch(scene())
38
+
39
+ def _switch(self, next_scene: SceneProtocol) -> None:
40
+ prev = self.current
41
+ if prev is not None and prev.running:
42
+ prev.quit()
43
+
44
+ self.current = next_scene
45
+ next_scene.start()
46
+
47
+ def apply_pending(self) -> None:
48
+ if self._pending is None:
49
+ return
50
+ next_scene = self._pending
51
+ self._pending = None
52
+ self._switch(next_scene)
53
+
54
+ def handle_event(self, event: Event) -> None:
55
+ if self.current:
56
+ self.current.handle_event(event)
57
+
58
+ def update(self, dt_s: float) -> None:
59
+ if self.current:
60
+ self.current.update(dt_s)
61
+
62
+ def draw(self, screen: Surface) -> None:
63
+ if self.current:
64
+ self.current.draw(screen)
@@ -0,0 +1,22 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ from pygame.event import Event
4
+ from pygame.surface import Surface
5
+
6
+
7
+ @runtime_checkable
8
+ class SceneProtocol(Protocol):
9
+ _running: bool
10
+
11
+ def start(self) -> None: ...
12
+
13
+ def quit(self) -> None: ...
14
+
15
+ @property
16
+ def running(self) -> bool: ...
17
+
18
+ def handle_event(self, event: Event) -> None: ...
19
+
20
+ def update(self, dt_s: float) -> None: ...
21
+
22
+ def draw(self, screen: Surface) -> None: ...
mxbiflow/scheduler.py ADDED
@@ -0,0 +1,90 @@
1
+ from pygame import Event
2
+ from pymxbi.detector.detector import DetectorEvent
3
+
4
+ from .default import IDLE
5
+ from .detector_bridge import EVT_DETECTOR, DetectorMsg
6
+ from .models.session import Session
7
+ from .scene import SceneManager
8
+
9
+
10
+ class Scheduler:
11
+ def __init__(
12
+ self,
13
+ session: Session,
14
+ scene_manager: SceneManager,
15
+ ) -> None:
16
+ self._session = session
17
+ self._scene_manager = scene_manager
18
+ self._scenes = self._scene_manager.scenes
19
+
20
+ self._need_refresh = False
21
+
22
+ def _mark_refresh(self) -> None:
23
+ self._need_refresh = True
24
+
25
+ def _set_current_animal(self, animal: str) -> None:
26
+ self._session.set_current_animal(animal)
27
+ self._need_refresh = True
28
+
29
+ def _clear_current_animal(self) -> None:
30
+ if self._session.current_animal is None:
31
+ return
32
+
33
+ self._session.clear_current_animal()
34
+ self._mark_refresh()
35
+
36
+ def _set_next_stage(self, stage: str) -> None:
37
+ if self._session.current_animal is None:
38
+ return
39
+
40
+ self._session.current_animal.set_current_stage(stage)
41
+ self._need_refresh = True
42
+
43
+ def _handle_fault_event(self) -> None: ...
44
+
45
+ def handle_event(self, event: Event) -> None:
46
+ if event.type != EVT_DETECTOR:
47
+ return
48
+
49
+ msg: DetectorMsg = event.msg
50
+
51
+ match msg.kind:
52
+ case DetectorEvent.FAULT_DETECTED:
53
+ self._handle_fault_event()
54
+
55
+ case DetectorEvent.ANIMAL_ENTERED:
56
+ if msg.animal is None:
57
+ return
58
+ self._set_current_animal(msg.animal)
59
+
60
+ case DetectorEvent.ANIMAL_LEFT:
61
+ self._clear_current_animal()
62
+
63
+ def _shoud_refresh(self) -> bool:
64
+ current = self._scene_manager.current
65
+ return (
66
+ current is not None
67
+ and not isinstance(current, IDLE)
68
+ and not current.running
69
+ )
70
+
71
+ def update(self) -> None:
72
+ if self._shoud_refresh():
73
+ self._mark_refresh()
74
+
75
+ if not self._need_refresh:
76
+ return
77
+
78
+ self._need_refresh = False
79
+ self._refresh_by_state()
80
+
81
+ def _refresh_by_state(self) -> None:
82
+ animal = self._session.current_animal
83
+
84
+ if animal is None:
85
+ if not isinstance(self._scene_manager.current, IDLE):
86
+ self._scene_manager.switch(self._scenes[IDLE.__name__.lower()])
87
+ return
88
+
89
+ stage = animal.current_stage.stage_name
90
+ self._scene_manager.switch(self._scenes[stage])
@@ -0,0 +1,70 @@
1
+ from enum import StrEnum, auto
2
+ from typing import TypeAlias
3
+
4
+ from pydantic import BaseModel, ConfigDict
5
+
6
+ LevelID: TypeAlias = int
7
+ MonkeyName: TypeAlias = str
8
+
9
+
10
+ class Result(StrEnum):
11
+ CORRECT = auto()
12
+ INCORRECT = auto()
13
+ TIMEOUT = auto()
14
+ CANCEL = auto()
15
+
16
+
17
+ class TouchEvent(BaseModel):
18
+ time: float
19
+ x: int
20
+ y: int
21
+
22
+
23
+ class BaseTrialConfig(BaseModel):
24
+ model_config = ConfigDict(frozen=True)
25
+
26
+ # basic config
27
+ level: int
28
+
29
+ # visual stimulation config
30
+ stimulation_size: int
31
+
32
+ # audio stimulation config
33
+ stimulus_duration: int
34
+
35
+ # trial lifecycle
36
+ time_out: int
37
+ inter_trial_interval: int
38
+
39
+ # reward config
40
+ reward_duration: int
41
+ reward_delay: int
42
+
43
+
44
+ class BaseTrialData(BaseModel):
45
+ animal: str
46
+ trial_id: int
47
+ current_level_trial_id: int
48
+ trial_start_time: float
49
+ trial_end_time: float
50
+ result: Result
51
+ correct_rate: float
52
+ touch_events: list[TouchEvent]
53
+
54
+
55
+ class BaseDataToShow(BaseModel):
56
+ name: str
57
+ id: int
58
+ level_id: int
59
+ level: int
60
+ rewards: int
61
+ correct: int
62
+ incorrect: int
63
+ timeout: int
64
+
65
+
66
+ class PersistentData(BaseModel):
67
+ rewards: int
68
+ correct: int
69
+ incorrect: int
70
+ timeout: int
@@ -0,0 +1,116 @@
1
+ {
2
+ "default": {
3
+ "condition": {
4
+ "config": {
5
+ "evaluation_interval": 2,
6
+ "difficulty_increase_threshold": 0.8,
7
+ "difficulty_decrease_threshold": 0.45,
8
+ "next_task": "gngsid_discriminate_stage"
9
+ }
10
+ },
11
+ "params": {
12
+ "stimulation_size": 250,
13
+ "visual_stimulus_delay": 500,
14
+ "stimulus_freq": 2000,
15
+ "stimulus_freq_duration": 100,
16
+ "stimulus_interval": 130,
17
+ "time_out": 10000,
18
+ "inter_trial_interval": 2000,
19
+ "reward_duration": 1000,
20
+ "reward_delay": 500
21
+ },
22
+ "levels_table": {
23
+ "0": {
24
+ "level": 0,
25
+ "min_stimulus_duration": 2500,
26
+ "max_stimulus_duration": 6500,
27
+ "go_task_prob": 0.8,
28
+ "nogo_task_prob": 0.2
29
+ },
30
+ "1": {
31
+ "level": 1,
32
+ "min_stimulus_duration": 1000,
33
+ "max_stimulus_duration": 2500,
34
+ "go_task_prob": 0.8,
35
+ "nogo_task_prob": 0.2
36
+ },
37
+ "2": {
38
+ "level": 2,
39
+ "min_stimulus_duration": 3500,
40
+ "max_stimulus_duration": 6500,
41
+ "go_task_prob": 0.8,
42
+ "nogo_task_prob": 0.2
43
+ },
44
+ "3": {
45
+ "level": 3,
46
+ "min_stimulus_duration": 1000,
47
+ "max_stimulus_duration": 2500,
48
+ "go_task_prob": 0.8,
49
+ "nogo_task_prob": 0.2
50
+ },
51
+ "4": {
52
+ "level": 4,
53
+ "min_stimulus_duration": 3500,
54
+ "max_stimulus_duration": 6500,
55
+ "go_task_prob": 0.8,
56
+ "nogo_task_prob": 0.2
57
+ },
58
+ "5": {
59
+ "level": 5,
60
+ "min_stimulus_duration": 1000,
61
+ "max_stimulus_duration": 2500,
62
+ "go_task_prob": 0.8,
63
+ "nogo_task_prob": 0.2
64
+ },
65
+ "6": {
66
+ "level": 6,
67
+ "min_stimulus_duration": 3500,
68
+ "max_stimulus_duration": 6500,
69
+ "go_task_prob": 0.8,
70
+ "nogo_task_prob": 0.2
71
+ },
72
+ "7": {
73
+ "level": 7,
74
+ "min_stimulus_duration": 1000,
75
+ "max_stimulus_duration": 3500,
76
+ "go_task_prob": 0.8,
77
+ "nogo_task_prob": 0.2
78
+ },
79
+ "8": {
80
+ "level": 8,
81
+ "min_stimulus_duration": 3500,
82
+ "max_stimulus_duration": 6500,
83
+ "go_task_prob": 0.8,
84
+ "nogo_task_prob": 0.2
85
+ },
86
+ "9": {
87
+ "level": 9,
88
+ "min_stimulus_duration": 1000,
89
+ "max_stimulus_duration": 2500,
90
+ "go_task_prob": 0.8,
91
+ "nogo_task_prob": 0.2
92
+ },
93
+ "10": {
94
+ "level": 10,
95
+ "min_stimulus_duration": 3500,
96
+ "max_stimulus_duration": 6500,
97
+ "go_task_prob": 0.8,
98
+ "nogo_task_prob": 0.2
99
+ },
100
+ "11": {
101
+ "level": 11,
102
+ "min_stimulus_duration": 1000,
103
+ "max_stimulus_duration": 2500,
104
+ "go_task_prob": 0.8,
105
+ "nogo_task_prob": 0.2
106
+ },
107
+ "12": {
108
+ "level": 12,
109
+ "min_stimulus_duration": 3000,
110
+ "max_stimulus_duration": 5000,
111
+ "go_task_prob": 0.5,
112
+ "nogo_task_prob": 0.5
113
+ }
114
+ }
115
+ }
116
+ }