bead 0.1.0__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.
- bead/__init__.py +11 -0
- bead/__main__.py +11 -0
- bead/active_learning/__init__.py +15 -0
- bead/active_learning/config.py +231 -0
- bead/active_learning/loop.py +566 -0
- bead/active_learning/models/__init__.py +24 -0
- bead/active_learning/models/base.py +852 -0
- bead/active_learning/models/binary.py +910 -0
- bead/active_learning/models/categorical.py +943 -0
- bead/active_learning/models/cloze.py +862 -0
- bead/active_learning/models/forced_choice.py +956 -0
- bead/active_learning/models/free_text.py +773 -0
- bead/active_learning/models/lora.py +365 -0
- bead/active_learning/models/magnitude.py +835 -0
- bead/active_learning/models/multi_select.py +795 -0
- bead/active_learning/models/ordinal_scale.py +811 -0
- bead/active_learning/models/peft_adapter.py +155 -0
- bead/active_learning/models/random_effects.py +639 -0
- bead/active_learning/selection.py +354 -0
- bead/active_learning/strategies.py +391 -0
- bead/active_learning/trainers/__init__.py +26 -0
- bead/active_learning/trainers/base.py +210 -0
- bead/active_learning/trainers/data_collator.py +172 -0
- bead/active_learning/trainers/dataset_utils.py +261 -0
- bead/active_learning/trainers/huggingface.py +304 -0
- bead/active_learning/trainers/lightning.py +324 -0
- bead/active_learning/trainers/metrics.py +424 -0
- bead/active_learning/trainers/mixed_effects.py +551 -0
- bead/active_learning/trainers/model_wrapper.py +509 -0
- bead/active_learning/trainers/registry.py +104 -0
- bead/adapters/__init__.py +11 -0
- bead/adapters/huggingface.py +61 -0
- bead/behavioral/__init__.py +116 -0
- bead/behavioral/analytics.py +646 -0
- bead/behavioral/extraction.py +343 -0
- bead/behavioral/merging.py +343 -0
- bead/cli/__init__.py +11 -0
- bead/cli/active_learning.py +513 -0
- bead/cli/active_learning_commands.py +779 -0
- bead/cli/completion.py +359 -0
- bead/cli/config.py +624 -0
- bead/cli/constraint_builders.py +286 -0
- bead/cli/deployment.py +859 -0
- bead/cli/deployment_trials.py +493 -0
- bead/cli/deployment_ui.py +332 -0
- bead/cli/display.py +378 -0
- bead/cli/items.py +960 -0
- bead/cli/items_factories.py +776 -0
- bead/cli/list_constraints.py +714 -0
- bead/cli/lists.py +490 -0
- bead/cli/main.py +430 -0
- bead/cli/models.py +877 -0
- bead/cli/resource_loaders.py +621 -0
- bead/cli/resources.py +1036 -0
- bead/cli/shell.py +356 -0
- bead/cli/simulate.py +840 -0
- bead/cli/templates.py +1158 -0
- bead/cli/training.py +1080 -0
- bead/cli/utils.py +614 -0
- bead/cli/workflow.py +1273 -0
- bead/config/__init__.py +68 -0
- bead/config/active_learning.py +1009 -0
- bead/config/config.py +192 -0
- bead/config/defaults.py +118 -0
- bead/config/deployment.py +217 -0
- bead/config/env.py +147 -0
- bead/config/item.py +45 -0
- bead/config/list.py +193 -0
- bead/config/loader.py +149 -0
- bead/config/logging.py +42 -0
- bead/config/model.py +49 -0
- bead/config/paths.py +46 -0
- bead/config/profiles.py +320 -0
- bead/config/resources.py +47 -0
- bead/config/serialization.py +210 -0
- bead/config/simulation.py +206 -0
- bead/config/template.py +238 -0
- bead/config/validation.py +267 -0
- bead/data/__init__.py +65 -0
- bead/data/base.py +87 -0
- bead/data/identifiers.py +97 -0
- bead/data/language_codes.py +61 -0
- bead/data/metadata.py +270 -0
- bead/data/range.py +123 -0
- bead/data/repository.py +358 -0
- bead/data/serialization.py +249 -0
- bead/data/timestamps.py +89 -0
- bead/data/validation.py +349 -0
- bead/data_collection/__init__.py +11 -0
- bead/data_collection/jatos.py +223 -0
- bead/data_collection/merger.py +154 -0
- bead/data_collection/prolific.py +198 -0
- bead/deployment/__init__.py +5 -0
- bead/deployment/distribution.py +402 -0
- bead/deployment/jatos/__init__.py +1 -0
- bead/deployment/jatos/api.py +200 -0
- bead/deployment/jatos/exporter.py +210 -0
- bead/deployment/jspsych/__init__.py +9 -0
- bead/deployment/jspsych/biome.json +44 -0
- bead/deployment/jspsych/config.py +411 -0
- bead/deployment/jspsych/generator.py +598 -0
- bead/deployment/jspsych/package.json +51 -0
- bead/deployment/jspsych/pnpm-lock.yaml +2141 -0
- bead/deployment/jspsych/randomizer.py +299 -0
- bead/deployment/jspsych/src/lib/list-distributor.test.ts +327 -0
- bead/deployment/jspsych/src/lib/list-distributor.ts +1282 -0
- bead/deployment/jspsych/src/lib/randomizer.test.ts +232 -0
- bead/deployment/jspsych/src/lib/randomizer.ts +367 -0
- bead/deployment/jspsych/src/plugins/cloze-dropdown.ts +252 -0
- bead/deployment/jspsych/src/plugins/forced-choice.ts +265 -0
- bead/deployment/jspsych/src/plugins/plugins.test.ts +141 -0
- bead/deployment/jspsych/src/plugins/rating.ts +248 -0
- bead/deployment/jspsych/src/slopit/index.ts +9 -0
- bead/deployment/jspsych/src/types/jatos.d.ts +256 -0
- bead/deployment/jspsych/src/types/jspsych.d.ts +228 -0
- bead/deployment/jspsych/templates/experiment.css +1 -0
- bead/deployment/jspsych/templates/experiment.js.template +289 -0
- bead/deployment/jspsych/templates/index.html +51 -0
- bead/deployment/jspsych/templates/randomizer.js +241 -0
- bead/deployment/jspsych/templates/randomizer.js.template +313 -0
- bead/deployment/jspsych/trials.py +723 -0
- bead/deployment/jspsych/tsconfig.json +23 -0
- bead/deployment/jspsych/tsup.config.ts +30 -0
- bead/deployment/jspsych/ui/__init__.py +1 -0
- bead/deployment/jspsych/ui/components.py +383 -0
- bead/deployment/jspsych/ui/styles.py +411 -0
- bead/dsl/__init__.py +80 -0
- bead/dsl/ast.py +168 -0
- bead/dsl/context.py +178 -0
- bead/dsl/errors.py +71 -0
- bead/dsl/evaluator.py +570 -0
- bead/dsl/grammar.lark +81 -0
- bead/dsl/parser.py +231 -0
- bead/dsl/stdlib.py +929 -0
- bead/evaluation/__init__.py +13 -0
- bead/evaluation/convergence.py +485 -0
- bead/evaluation/interannotator.py +398 -0
- bead/items/__init__.py +40 -0
- bead/items/adapters/__init__.py +70 -0
- bead/items/adapters/anthropic.py +224 -0
- bead/items/adapters/api_utils.py +167 -0
- bead/items/adapters/base.py +216 -0
- bead/items/adapters/google.py +259 -0
- bead/items/adapters/huggingface.py +1074 -0
- bead/items/adapters/openai.py +323 -0
- bead/items/adapters/registry.py +202 -0
- bead/items/adapters/sentence_transformers.py +224 -0
- bead/items/adapters/togetherai.py +309 -0
- bead/items/binary.py +515 -0
- bead/items/cache.py +558 -0
- bead/items/categorical.py +593 -0
- bead/items/cloze.py +757 -0
- bead/items/constructor.py +784 -0
- bead/items/forced_choice.py +413 -0
- bead/items/free_text.py +681 -0
- bead/items/generation.py +432 -0
- bead/items/item.py +396 -0
- bead/items/item_template.py +787 -0
- bead/items/magnitude.py +573 -0
- bead/items/multi_select.py +621 -0
- bead/items/ordinal_scale.py +569 -0
- bead/items/scoring.py +448 -0
- bead/items/validation.py +723 -0
- bead/lists/__init__.py +30 -0
- bead/lists/balancer.py +263 -0
- bead/lists/constraints.py +1067 -0
- bead/lists/experiment_list.py +286 -0
- bead/lists/list_collection.py +378 -0
- bead/lists/partitioner.py +1141 -0
- bead/lists/stratification.py +254 -0
- bead/participants/__init__.py +73 -0
- bead/participants/collection.py +699 -0
- bead/participants/merging.py +312 -0
- bead/participants/metadata_spec.py +491 -0
- bead/participants/models.py +276 -0
- bead/resources/__init__.py +29 -0
- bead/resources/adapters/__init__.py +19 -0
- bead/resources/adapters/base.py +104 -0
- bead/resources/adapters/cache.py +128 -0
- bead/resources/adapters/glazing.py +508 -0
- bead/resources/adapters/registry.py +117 -0
- bead/resources/adapters/unimorph.py +796 -0
- bead/resources/classification.py +856 -0
- bead/resources/constraint_builders.py +329 -0
- bead/resources/constraints.py +165 -0
- bead/resources/lexical_item.py +223 -0
- bead/resources/lexicon.py +744 -0
- bead/resources/loaders.py +209 -0
- bead/resources/template.py +441 -0
- bead/resources/template_collection.py +707 -0
- bead/resources/template_generation.py +349 -0
- bead/simulation/__init__.py +29 -0
- bead/simulation/annotators/__init__.py +15 -0
- bead/simulation/annotators/base.py +175 -0
- bead/simulation/annotators/distance_based.py +135 -0
- bead/simulation/annotators/lm_based.py +114 -0
- bead/simulation/annotators/oracle.py +182 -0
- bead/simulation/annotators/random.py +181 -0
- bead/simulation/dsl_extension/__init__.py +3 -0
- bead/simulation/noise_models/__init__.py +13 -0
- bead/simulation/noise_models/base.py +42 -0
- bead/simulation/noise_models/random_noise.py +82 -0
- bead/simulation/noise_models/systematic.py +132 -0
- bead/simulation/noise_models/temperature.py +86 -0
- bead/simulation/runner.py +144 -0
- bead/simulation/strategies/__init__.py +23 -0
- bead/simulation/strategies/base.py +123 -0
- bead/simulation/strategies/binary.py +103 -0
- bead/simulation/strategies/categorical.py +123 -0
- bead/simulation/strategies/cloze.py +224 -0
- bead/simulation/strategies/forced_choice.py +127 -0
- bead/simulation/strategies/free_text.py +105 -0
- bead/simulation/strategies/magnitude.py +116 -0
- bead/simulation/strategies/multi_select.py +129 -0
- bead/simulation/strategies/ordinal_scale.py +131 -0
- bead/templates/__init__.py +27 -0
- bead/templates/adapters/__init__.py +17 -0
- bead/templates/adapters/base.py +128 -0
- bead/templates/adapters/cache.py +178 -0
- bead/templates/adapters/huggingface.py +312 -0
- bead/templates/combinatorics.py +103 -0
- bead/templates/filler.py +605 -0
- bead/templates/renderers.py +177 -0
- bead/templates/resolver.py +178 -0
- bead/templates/strategies.py +1806 -0
- bead/templates/streaming.py +195 -0
- bead-0.1.0.dist-info/METADATA +212 -0
- bead-0.1.0.dist-info/RECORD +231 -0
- bead-0.1.0.dist-info/WHEEL +4 -0
- bead-0.1.0.dist-info/entry_points.txt +2 -0
- bead-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bead-rating plugin
|
|
3
|
+
*
|
|
4
|
+
* jsPsych plugin for ordinal scale judgments (Likert scales, rating scales).
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Discrete scales (e.g., 1-7, 1-9)
|
|
8
|
+
* - Custom labels for scale points
|
|
9
|
+
* - Keyboard shortcuts (number keys 1-9)
|
|
10
|
+
* - Material Design styling
|
|
11
|
+
* - Required response validation
|
|
12
|
+
* - Preserves all item and template metadata
|
|
13
|
+
*
|
|
14
|
+
* @author Bead Project
|
|
15
|
+
* @version 0.1.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { JsPsych, JsPsychPlugin, KeyboardResponseInfo, PluginInfo } from "../types/jspsych.js";
|
|
19
|
+
|
|
20
|
+
/** Task specification from bead metadata */
|
|
21
|
+
interface TaskSpec {
|
|
22
|
+
scale_bounds?: [number, number];
|
|
23
|
+
scale_labels?: Record<number, string>;
|
|
24
|
+
prompt?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Bead item/template metadata */
|
|
28
|
+
interface BeadMetadata {
|
|
29
|
+
task_spec?: TaskSpec;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Rating trial parameters */
|
|
34
|
+
export interface RatingTrialParams {
|
|
35
|
+
/** The prompt to display above the rating scale */
|
|
36
|
+
prompt: string | null;
|
|
37
|
+
/** Minimum value of the scale */
|
|
38
|
+
scale_min: number;
|
|
39
|
+
/** Maximum value of the scale */
|
|
40
|
+
scale_max: number;
|
|
41
|
+
/** Labels for specific scale points (e.g., {1: "Strongly Disagree", 7: "Strongly Agree"}) */
|
|
42
|
+
scale_labels: Record<number, string>;
|
|
43
|
+
/** Whether to require a response before continuing */
|
|
44
|
+
require_response: boolean;
|
|
45
|
+
/** Text for the continue button */
|
|
46
|
+
button_label: string;
|
|
47
|
+
/** Complete item and template metadata (automatically populated from trial.data) */
|
|
48
|
+
metadata: BeadMetadata;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Rating response data */
|
|
52
|
+
interface RatingResponse {
|
|
53
|
+
rating: number | null;
|
|
54
|
+
rt: number | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Plugin info constant */
|
|
58
|
+
const info: PluginInfo = {
|
|
59
|
+
name: "bead-rating",
|
|
60
|
+
parameters: {
|
|
61
|
+
prompt: {
|
|
62
|
+
type: 8, // ParameterType.HTML_STRING
|
|
63
|
+
default: null,
|
|
64
|
+
},
|
|
65
|
+
scale_min: {
|
|
66
|
+
type: 2, // ParameterType.INT
|
|
67
|
+
default: 1,
|
|
68
|
+
},
|
|
69
|
+
scale_max: {
|
|
70
|
+
type: 2, // ParameterType.INT
|
|
71
|
+
default: 7,
|
|
72
|
+
},
|
|
73
|
+
scale_labels: {
|
|
74
|
+
type: 12, // ParameterType.OBJECT
|
|
75
|
+
default: {},
|
|
76
|
+
},
|
|
77
|
+
require_response: {
|
|
78
|
+
type: 0, // ParameterType.BOOL
|
|
79
|
+
default: true,
|
|
80
|
+
},
|
|
81
|
+
button_label: {
|
|
82
|
+
type: 1, // ParameterType.STRING
|
|
83
|
+
default: "Continue",
|
|
84
|
+
},
|
|
85
|
+
metadata: {
|
|
86
|
+
type: 12, // ParameterType.OBJECT
|
|
87
|
+
default: {},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* BeadRatingPlugin - jsPsych plugin for ordinal scale judgments
|
|
94
|
+
*/
|
|
95
|
+
class BeadRatingPlugin implements JsPsychPlugin<typeof info, RatingTrialParams> {
|
|
96
|
+
static info = info;
|
|
97
|
+
|
|
98
|
+
private jsPsych: JsPsych;
|
|
99
|
+
|
|
100
|
+
constructor(jsPsych: JsPsych) {
|
|
101
|
+
this.jsPsych = jsPsych;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
trial(display_element: HTMLElement, trial: RatingTrialParams): void {
|
|
105
|
+
const response: RatingResponse = {
|
|
106
|
+
rating: null,
|
|
107
|
+
rt: null,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const start_time = performance.now();
|
|
111
|
+
|
|
112
|
+
// Override scale bounds from metadata if available
|
|
113
|
+
if (trial.metadata.task_spec?.scale_bounds) {
|
|
114
|
+
trial.scale_min = trial.metadata.task_spec.scale_bounds[0];
|
|
115
|
+
trial.scale_max = trial.metadata.task_spec.scale_bounds[1];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Override scale labels from metadata if available
|
|
119
|
+
if (trial.metadata.task_spec?.scale_labels) {
|
|
120
|
+
trial.scale_labels = trial.metadata.task_spec.scale_labels;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Override prompt from metadata if available
|
|
124
|
+
if (trial.metadata.task_spec?.prompt && !trial.prompt) {
|
|
125
|
+
trial.prompt = trial.metadata.task_spec.prompt;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Create HTML
|
|
129
|
+
let html = '<div class="bead-rating-container">';
|
|
130
|
+
|
|
131
|
+
if (trial.prompt !== null) {
|
|
132
|
+
html += `<div class="bead-rating-prompt">${trial.prompt}</div>`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
html += '<div class="bead-rating-scale">';
|
|
136
|
+
|
|
137
|
+
// Create rating buttons
|
|
138
|
+
for (let i = trial.scale_min; i <= trial.scale_max; i++) {
|
|
139
|
+
const label = trial.scale_labels[i] ?? i;
|
|
140
|
+
html += `
|
|
141
|
+
<div class="bead-rating-option">
|
|
142
|
+
<button class="bead-rating-button" data-value="${i}">${i}</button>
|
|
143
|
+
<div class="bead-rating-label">${label}</div>
|
|
144
|
+
</div>
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
html += "</div>"; // Close scale
|
|
149
|
+
|
|
150
|
+
// Continue button
|
|
151
|
+
html += `
|
|
152
|
+
<div class="bead-rating-button-container">
|
|
153
|
+
<button class="bead-button bead-continue-button" id="bead-rating-continue" disabled>
|
|
154
|
+
${trial.button_label}
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
html += "</div>"; // Close container
|
|
160
|
+
|
|
161
|
+
display_element.innerHTML = html;
|
|
162
|
+
|
|
163
|
+
// Add event listeners for rating buttons
|
|
164
|
+
const rating_buttons =
|
|
165
|
+
display_element.querySelectorAll<HTMLButtonElement>(".bead-rating-button");
|
|
166
|
+
for (const button of rating_buttons) {
|
|
167
|
+
button.addEventListener("click", (e) => {
|
|
168
|
+
const target = e.target as HTMLButtonElement;
|
|
169
|
+
const valueAttr = target.getAttribute("data-value");
|
|
170
|
+
if (valueAttr !== null) {
|
|
171
|
+
const value = Number.parseInt(valueAttr, 10);
|
|
172
|
+
select_rating(value);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Keyboard listener
|
|
178
|
+
const keyboard_listener = this.jsPsych.pluginAPI.getKeyboardResponse({
|
|
179
|
+
callback_function: (info: KeyboardResponseInfo) => {
|
|
180
|
+
// Check if key is 1-9
|
|
181
|
+
const key = info.key;
|
|
182
|
+
const num = Number.parseInt(key, 10);
|
|
183
|
+
if (!Number.isNaN(num) && num >= trial.scale_min && num <= trial.scale_max) {
|
|
184
|
+
select_rating(num);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
valid_responses: "ALL_KEYS",
|
|
188
|
+
rt_method: "performance",
|
|
189
|
+
persist: true,
|
|
190
|
+
allow_held_key: false,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Continue button listener
|
|
194
|
+
const continue_button =
|
|
195
|
+
display_element.querySelector<HTMLButtonElement>("#bead-rating-continue");
|
|
196
|
+
if (continue_button) {
|
|
197
|
+
continue_button.addEventListener("click", () => {
|
|
198
|
+
if (response.rating !== null || !trial.require_response) {
|
|
199
|
+
end_trial();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const select_rating = (value: number): void => {
|
|
205
|
+
// Update response
|
|
206
|
+
response.rating = value;
|
|
207
|
+
response.rt = performance.now() - start_time;
|
|
208
|
+
|
|
209
|
+
// Update UI
|
|
210
|
+
for (const btn of rating_buttons) {
|
|
211
|
+
btn.classList.remove("selected");
|
|
212
|
+
}
|
|
213
|
+
const selected_button = display_element.querySelector<HTMLButtonElement>(
|
|
214
|
+
`[data-value="${value}"]`,
|
|
215
|
+
);
|
|
216
|
+
if (selected_button) {
|
|
217
|
+
selected_button.classList.add("selected");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Enable continue button
|
|
221
|
+
if (continue_button) {
|
|
222
|
+
continue_button.disabled = false;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const end_trial = (): void => {
|
|
227
|
+
// Kill keyboard listener
|
|
228
|
+
if (keyboard_listener) {
|
|
229
|
+
this.jsPsych.pluginAPI.cancelKeyboardResponse(keyboard_listener);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Preserve all metadata from trial.metadata and add response data
|
|
233
|
+
const trial_data: Record<string, unknown> = {
|
|
234
|
+
...trial.metadata, // Spread all metadata
|
|
235
|
+
rating: response.rating,
|
|
236
|
+
rt: response.rt,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Clear display
|
|
240
|
+
display_element.innerHTML = "";
|
|
241
|
+
|
|
242
|
+
// End trial
|
|
243
|
+
this.jsPsych.finishTrial(trial_data);
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export { BeadRatingPlugin };
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for JATOS (Just Another Tool for Online Studies) API.
|
|
3
|
+
*
|
|
4
|
+
* JATOS provides a server-side infrastructure for running online experiments
|
|
5
|
+
* with features like batch sessions, worker management, and data storage.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** JATOS URL query parameters (typically from Prolific/MTurk) */
|
|
9
|
+
export interface JatosUrlParams {
|
|
10
|
+
/** Prolific participant ID */
|
|
11
|
+
PROLIFIC_PID?: string;
|
|
12
|
+
/** Prolific study ID */
|
|
13
|
+
STUDY_ID?: string;
|
|
14
|
+
/** Prolific session ID */
|
|
15
|
+
SESSION_ID?: string;
|
|
16
|
+
/** Generic participant ID */
|
|
17
|
+
participant_id?: string;
|
|
18
|
+
/** Any other URL parameters */
|
|
19
|
+
[key: string]: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Batch session data stored in JATOS */
|
|
23
|
+
export interface BatchSessionData {
|
|
24
|
+
/** Assignment queue for random/sequential distribution */
|
|
25
|
+
assignment_queue?: number[];
|
|
26
|
+
/** Counts of participants assigned to each list */
|
|
27
|
+
assignment_counts?: Record<string, number>;
|
|
28
|
+
/** Latin square counter for counterbalancing */
|
|
29
|
+
latin_square_counter?: number;
|
|
30
|
+
/** Quota tracking per list */
|
|
31
|
+
quotas?: Record<string, number>;
|
|
32
|
+
/** Workers currently assigned (for completion tracking) */
|
|
33
|
+
active_workers?: Record<string, number>;
|
|
34
|
+
/** Workers who completed the study */
|
|
35
|
+
completed_workers?: string[];
|
|
36
|
+
/** Custom metadata for stratification */
|
|
37
|
+
stratification_state?: Record<string, unknown>;
|
|
38
|
+
/** Version for optimistic locking */
|
|
39
|
+
version?: number;
|
|
40
|
+
/** Any other batch session data */
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** JATOS batch session API */
|
|
45
|
+
export interface JatosBatchSession {
|
|
46
|
+
/**
|
|
47
|
+
* Get a value from the batch session by path.
|
|
48
|
+
* Uses dot notation (e.g., "assignment_counts.list_0").
|
|
49
|
+
*/
|
|
50
|
+
get<T = unknown>(path: string): T | undefined;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if a path is defined in the batch session.
|
|
54
|
+
*/
|
|
55
|
+
defined(path: string): boolean;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Set a value in the batch session.
|
|
59
|
+
* Returns a promise that resolves when the write is confirmed.
|
|
60
|
+
*/
|
|
61
|
+
set<T>(path: string, value: T): JatosPromise<void>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Replace the entire batch session data.
|
|
65
|
+
* Useful for atomic updates.
|
|
66
|
+
*/
|
|
67
|
+
replace(data: BatchSessionData): JatosPromise<void>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Remove a value from the batch session.
|
|
71
|
+
*/
|
|
72
|
+
remove(path: string): JatosPromise<void>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Find a value using JSON pointer or path.
|
|
76
|
+
*/
|
|
77
|
+
find(path: string): unknown;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get all batch session data.
|
|
81
|
+
*/
|
|
82
|
+
getAll(): BatchSessionData;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Clear all batch session data.
|
|
86
|
+
*/
|
|
87
|
+
clear(): JatosPromise<void>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** JATOS-style promise with .fail() for error handling */
|
|
91
|
+
export interface JatosPromise<T> extends Promise<T> {
|
|
92
|
+
/**
|
|
93
|
+
* Handle errors (JATOS uses .fail() instead of .catch()).
|
|
94
|
+
*/
|
|
95
|
+
fail(onRejected: (reason: Error) => void): JatosPromise<T>;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Chain operations (alias for .then()).
|
|
99
|
+
*/
|
|
100
|
+
then<TResult1 = T, TResult2 = never>(
|
|
101
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
102
|
+
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
|
|
103
|
+
): JatosPromise<TResult1 | TResult2>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Component result state */
|
|
107
|
+
export type ComponentResultState =
|
|
108
|
+
| "PRE"
|
|
109
|
+
| "STARTED"
|
|
110
|
+
| "DATA_RETRIEVED"
|
|
111
|
+
| "RESULTDATA_POSTED"
|
|
112
|
+
| "FINISHED"
|
|
113
|
+
| "RELOADED"
|
|
114
|
+
| "ABORTED"
|
|
115
|
+
| "FAIL";
|
|
116
|
+
|
|
117
|
+
/** Study result state */
|
|
118
|
+
export type StudyResultState =
|
|
119
|
+
| "PRE"
|
|
120
|
+
| "STARTED"
|
|
121
|
+
| "DATA_RETRIEVED"
|
|
122
|
+
| "FINISHED"
|
|
123
|
+
| "ABORTED"
|
|
124
|
+
| "FAIL";
|
|
125
|
+
|
|
126
|
+
/** Main JATOS API interface */
|
|
127
|
+
export interface JatosAPI {
|
|
128
|
+
/** Current JATOS version */
|
|
129
|
+
version: string;
|
|
130
|
+
|
|
131
|
+
/** Worker ID assigned by JATOS */
|
|
132
|
+
workerId: string;
|
|
133
|
+
|
|
134
|
+
/** Current study result ID */
|
|
135
|
+
studyResultId: string;
|
|
136
|
+
|
|
137
|
+
/** Current component result ID */
|
|
138
|
+
componentResultId: string;
|
|
139
|
+
|
|
140
|
+
/** Study ID */
|
|
141
|
+
studyId: string;
|
|
142
|
+
|
|
143
|
+
/** Component ID */
|
|
144
|
+
componentId: string;
|
|
145
|
+
|
|
146
|
+
/** Batch ID */
|
|
147
|
+
batchId: string;
|
|
148
|
+
|
|
149
|
+
/** Group result ID (if in group study) */
|
|
150
|
+
groupResultId?: string;
|
|
151
|
+
|
|
152
|
+
/** URL query parameters */
|
|
153
|
+
urlQueryParameters: JatosUrlParams;
|
|
154
|
+
|
|
155
|
+
/** Study properties set in JATOS GUI */
|
|
156
|
+
studyProperties: Record<string, unknown>;
|
|
157
|
+
|
|
158
|
+
/** Component properties set in JATOS GUI */
|
|
159
|
+
componentProperties: Record<string, unknown>;
|
|
160
|
+
|
|
161
|
+
/** Study session data (persists across components) */
|
|
162
|
+
studySessionData: Record<string, unknown>;
|
|
163
|
+
|
|
164
|
+
/** Batch session API */
|
|
165
|
+
batchSession: JatosBatchSession;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Called when JATOS is ready.
|
|
169
|
+
*/
|
|
170
|
+
onLoad(callback: () => void): void;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Submit result data to JATOS.
|
|
174
|
+
*/
|
|
175
|
+
submitResultData(data: string | object): JatosPromise<void>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Append to result data.
|
|
179
|
+
*/
|
|
180
|
+
appendResultData(data: string | object): JatosPromise<void>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* End the study successfully.
|
|
184
|
+
*/
|
|
185
|
+
endStudy(successful?: boolean, message?: string): void;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* End the study and redirect to a URL.
|
|
189
|
+
*/
|
|
190
|
+
endStudyAndRedirect(url: string, message?: string): void;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* End the current component and move to next.
|
|
194
|
+
*/
|
|
195
|
+
startNextComponent(): void;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* End the current component and move to a specific component.
|
|
199
|
+
*/
|
|
200
|
+
startComponent(componentId: number | string): void;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* End the current component and move to the last component.
|
|
204
|
+
*/
|
|
205
|
+
startLastComponent(): void;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Abort the study.
|
|
209
|
+
*/
|
|
210
|
+
abortStudy(message?: string): void;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Add an abort button to the page.
|
|
214
|
+
*/
|
|
215
|
+
addAbortButton(): void;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Remove the abort button.
|
|
219
|
+
*/
|
|
220
|
+
removeAbortButton(): void;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Log a message to the JATOS console.
|
|
224
|
+
*/
|
|
225
|
+
log(message: string): void;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set study session data.
|
|
229
|
+
*/
|
|
230
|
+
setStudySessionData(data: Record<string, unknown>): JatosPromise<void>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Upload a file to JATOS.
|
|
234
|
+
*/
|
|
235
|
+
uploadResultFile(file: File | Blob, filename: string): JatosPromise<{ url: string }>;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Download study assets.
|
|
239
|
+
*/
|
|
240
|
+
downloadAssetFile(filename: string): Promise<Blob>;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get the component result state.
|
|
244
|
+
*/
|
|
245
|
+
getComponentResultState(): ComponentResultState;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get the study result state.
|
|
249
|
+
*/
|
|
250
|
+
getStudyResultState(): StudyResultState;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Global JATOS instance */
|
|
254
|
+
declare global {
|
|
255
|
+
const jatos: JatosAPI;
|
|
256
|
+
}
|