qiuyiding commited on
Commit
e6d7d30
·
0 Parent(s):

Initial commit: Sound Generation Survey

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +41 -0
  2. README.md +22 -0
  3. __pycache__/app.cpython-312.pyc +0 -0
  4. app.py +384 -0
  5. packages.txt +1 -0
  6. questions/question1/1chainsaw_04_019898_to_saxophone_t0.99_cfg3.5_g0.0_method_z0_hat_mixed.wav +3 -0
  7. questions/question1/2chainsaw_04_019898_to_saxophone_t0.99_cfg3.5_g3.0_method_z0_hat_mixed.wav +3 -0
  8. questions/question1/chainsaw.jpeg +3 -0
  9. questions/question1/chainsaw_04_019898.wav +3 -0
  10. questions/question10/1alarm_to_crickets_alpha0.50_ngs0.50_mix1.00_mixed.wav +3 -0
  11. questions/question10/2alarm_to_crickets_alpha0.50_ngs0.60_mix0.60_mixed.wav +3 -0
  12. questions/question10/alarm.jpg +3 -0
  13. questions/question10/alarm.wav +3 -0
  14. questions/question11/1reverse_beeper_02_012441_to_rain_alpha0.60_ngs0.50_mix1.00_mixed.wav +3 -0
  15. questions/question11/2reverse_beeper_02_012441_to_rain_alpha0.60_ngs0.50_mix0.60_mixed.wav +3 -0
  16. questions/question11/reverse beeper.jpeg +3 -0
  17. questions/question11/reverse_beeper_02_012441.wav +3 -0
  18. questions/question12/1reverse_beeper_02_012441_to_saxophone_alpha0.50_ngs0.50_mix0.60_mixed.wav +3 -0
  19. questions/question12/2reverse_beeper_02_012441_to_saxophone_alpha1.00_ngs0.50_mix1.00_mixed.wav +3 -0
  20. questions/question12/reverse beeper.jpeg +3 -0
  21. questions/question12/reverse_beeper_02_012441.wav +3 -0
  22. questions/question13/1engine_siren_05_016551_to_xylophone_alpha0.50_ngs0.50_mix0.60_mixed.wav +3 -0
  23. questions/question13/2engine_siren_05_016551_to_xylophone_alpha0.50_ngs0.50_mix1.00_mixed.wav +3 -0
  24. questions/question13/engine_siren.jpeg +3 -0
  25. questions/question13/engine_siren_05_016551.wav +3 -0
  26. questions/question14/1people_talking_06_018164_to_bubbling_stream_alpha0.50_ngs0.50_mix0.60_mixed.wav +3 -0
  27. questions/question14/2people_talking_06_018164_to_bubbling_stream_alpha0.50_ngs0.50_mix1.00_mixed.wav +3 -0
  28. questions/question14/people_talking_06_018164.wav +3 -0
  29. questions/question14/peopletalking.jpg +3 -0
  30. questions/question15/1people_talking_06_018164_to_rain_alpha0.50_ngs0.50_mix1.00_mixed.wav +3 -0
  31. questions/question15/2people_talking_06_018164_to_rain_alpha0.50_ngs0.50_mix0.60_mixed.wav +3 -0
  32. questions/question15/people_talking_06_018164.wav +3 -0
  33. questions/question15/peopletalking.jpg +3 -0
  34. questions/question16/1chainsaw_04_019898_to_rain_alpha0.50_ngs0.50_mix0.60_mixed.wav +3 -0
  35. questions/question16/2chainsaw_04_019898_to_rain_alpha0.50_ngs0.50_mix1.00_mixed.wav +3 -0
  36. questions/question16/chainsaw.jpeg +3 -0
  37. questions/question16/chainsaw_04_019898.wav +3 -0
  38. questions/question2/1chainsaw_04_019898_to_violin_t0.99_cfg3.5_g0.0_method_z0_hat_mixed.wav +3 -0
  39. questions/question2/2chainsaw_04_019898_to_violin_t0.90_cfg3.5_g2.0_method_z0_hat_mixed.wav +3 -0
  40. questions/question2/chainsaw.jpeg +3 -0
  41. questions/question2/chainsaw_04_019898.wav +3 -0
  42. questions/question3/1engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g0.0_method_direct_mixed.wav +3 -0
  43. questions/question3/2engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g2.0_method_z0_hat_mixed.wav +3 -0
  44. questions/question3/engine.JPG +3 -0
  45. questions/question3/engine_medium_05_010898.wav +3 -0
  46. questions/question4/1engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g2.0_method_z0_hat_mixed.wav +3 -0
  47. questions/question4/2engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g0.0_method_direct_mixed.wav +3 -0
  48. questions/question4/engine.JPG +3 -0
  49. questions/question4/engine_siren_05_016551.wav +3 -0
  50. questions/question5/1people_talking_06_018164_to_bubbling_stream_t0.99_cfg3.5_g0.0_method_direct_mixed.wav +3 -0
.gitattributes ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.wav filter=lfs diff=lfs merge=lfs -text
37
+ *.png filter=lfs diff=lfs merge=lfs -text
38
+ *.jpg filter=lfs diff=lfs merge=lfs -text
39
+ *.jpeg filter=lfs diff=lfs merge=lfs -text
40
+ *.JPG filter=lfs diff=lfs merge=lfs -text
41
+ *.JPEG filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Subjective Noise Reduction Survey
3
+ emoji: 🎧
4
+ colorFrom: indigo
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.47.1
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ This Space serves a single-page scrollable survey for subjective evaluation of noise reduction quality.
13
+
14
+ Instructions:
15
+ - Each question has a Noise Reference (if available), plus two anonymized audios: Audio A (1‑prefixed) and Audio B (2‑prefixed).
16
+ - Task: select which audio contains less of the original noise.
17
+ - Click "Submit All" to export a CSV with your results.
18
+
19
+ Scoring note: any audio filename containing `t0.99` is treated as the wrong option; the other one is counted as correct.
20
+
21
+ Build/runtime:
22
+ - `requirements.txt` pins `gradio>=4.44.1` to avoid schema issues.
__pycache__/app.cpython-312.pyc ADDED
Binary file (14.2 kB). View file
 
app.py ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from datetime import datetime
5
+ import uuid
6
+ import re
7
+ from typing import List, Dict, Tuple, Optional
8
+
9
+ # =========================
10
+ # Configuration
11
+ # =========================
12
+
13
+ # Root directory containing question subfolders: question1, question2, ...
14
+ QUESTIONS_ROOT = os.path.join(os.path.dirname(__file__), "questions")
15
+ # How many question folders to scan (question1 ... questionN)
16
+ NUM_QUESTIONS = 16
17
+
18
+ # Regex to detect g values in filenames, e.g., "_g0_", "-g0.3-", "g1.0"
19
+ G_VALUE_PATTERN = re.compile(r"(?:^|[_-])g([0-9]+(?:\.[0-9]+)?)", re.IGNORECASE)
20
+ # Exact g==0 detection (g0, g0.0, g0.00, ...)
21
+ G0_PATTERN = re.compile(r"(?:^|[_-])g0(?:\.0+)?(?:[_-]|$)", re.IGNORECASE)
22
+ # Regex to detect mix value, e.g., "_mix1.00_", "-mix0.60-"
23
+ MIX_VALUE_PATTERN = re.compile(r"(?:^|[_-])mix([0-9]+(?:\.[0-9]+)?)", re.IGNORECASE)
24
+
25
+
26
+ # =========================
27
+ # Data discovery
28
+ # =========================
29
+
30
+ def discover_questions() -> List[Dict]:
31
+ """
32
+ Scan QUESTIONS_ROOT/question1..questionN and build a question list.
33
+
34
+ Rules:
35
+ - Noise reference: any .wav not starting with '1' or '2' (optional).
36
+ - Audio A: .wav starting with '1'
37
+ - Audio B: .wav starting with '2'
38
+ - Image (optional): first *.jpg/*.jpeg/*.png/*.gif in the folder
39
+ - Correctness heuristic:
40
+ * Prefer 'g' rule: if exactly one side has g==0, that side is WRONG.
41
+ * Fallback 'mix' rule when no 'g' param on either: if exactly one side has mix==1.0, that side is WRONG.
42
+ We store which side is WRONG in field 't099_is' for backward compatibility.
43
+ """
44
+ questions = []
45
+ print(f"[disc] Scanning: {QUESTIONS_ROOT}")
46
+
47
+ for i in range(1, NUM_QUESTIONS + 1):
48
+ qdir = os.path.join(QUESTIONS_ROOT, f"question{i}")
49
+ if not os.path.isdir(qdir):
50
+ print(f"[disc] Skip missing dir: {qdir}")
51
+ continue
52
+
53
+ # Collect files
54
+ all_files = [f for f in os.listdir(qdir) if f.lower().endswith(".wav")]
55
+ noise_candidates = [f for f in all_files if not (f.startswith("1") or f.startswith("2"))]
56
+ one_candidates = sorted([f for f in all_files if f.startswith("1")])
57
+ two_candidates = sorted([f for f in all_files if f.startswith("2")])
58
+
59
+ image_candidates = [f for f in os.listdir(qdir)
60
+ if f.lower().endswith(('.jpg', '.jpeg', '.png', '.gif'))]
61
+
62
+ # Resolve absolute paths
63
+ noise_path = os.path.join(qdir, noise_candidates[0]) if noise_candidates else None
64
+ a_path = os.path.join(qdir, one_candidates[0]) if one_candidates else None
65
+ b_path = os.path.join(qdir, two_candidates[0]) if two_candidates else None
66
+ image_path = os.path.join(qdir, image_candidates[0]) if image_candidates else None
67
+
68
+ if not (a_path and b_path):
69
+ print(f"[disc] Missing A/B in {qdir}: A={a_path}, B={b_path}")
70
+ continue
71
+
72
+ # Sanity checks (non-fatal)
73
+ for p in [a_path, b_path, noise_path, image_path]:
74
+ if p and not os.path.exists(p):
75
+ print(f"[disc] File not found (non-fatal): {p}")
76
+
77
+ # Correctness heuristic
78
+ fname_a = os.path.basename(a_path)
79
+ fname_b = os.path.basename(b_path)
80
+
81
+ a_has_g = bool(G_VALUE_PATTERN.search(fname_a))
82
+ b_has_g = bool(G_VALUE_PATTERN.search(fname_b))
83
+ a_is_g0 = bool(G0_PATTERN.search(fname_a))
84
+ b_is_g0 = bool(G0_PATTERN.search(fname_b))
85
+
86
+ a_is_mix1 = False
87
+ b_is_mix1 = False
88
+ if not (a_has_g or b_has_g):
89
+ ma = MIX_VALUE_PATTERN.search(fname_a)
90
+ mb = MIX_VALUE_PATTERN.search(fname_b)
91
+ try:
92
+ a_is_mix1 = (abs(float(ma.group(1)) - 1.0) < 1e-9) if ma else False
93
+ except Exception:
94
+ a_is_mix1 = False
95
+ try:
96
+ b_is_mix1 = (abs(float(mb.group(1)) - 1.0) < 1e-9) if mb else False
97
+ except Exception:
98
+ b_is_mix1 = False
99
+
100
+ wrong_label = None
101
+ if a_has_g or b_has_g:
102
+ if a_is_g0 and not b_is_g0:
103
+ wrong_label = "A"
104
+ elif b_is_g0 and not a_is_g0:
105
+ wrong_label = "B"
106
+ else:
107
+ if a_is_mix1 and not b_is_mix1:
108
+ wrong_label = "A"
109
+ elif b_is_mix1 and not a_is_mix1:
110
+ wrong_label = "B"
111
+
112
+ if wrong_label == "A":
113
+ correct_label = "B"
114
+ elif wrong_label == "B":
115
+ correct_label = "A"
116
+ else:
117
+ correct_label = None
118
+
119
+ questions.append({
120
+ "id": f"question{i}",
121
+ "index": i,
122
+ "noise": noise_path,
123
+ "A": a_path,
124
+ "B": b_path,
125
+ "image": image_path,
126
+ "correct": correct_label,
127
+ # For compatibility: which option is considered "wrong" by heuristic
128
+ "t099_is": wrong_label,
129
+ })
130
+
131
+ print(f"[disc] Found {len(questions)} valid questions.")
132
+ return questions
133
+
134
+
135
+ # =========================
136
+ # Upload to RESULTS dataset (no Space restart)
137
+ # =========================
138
+ def upload_to_results_dataset(local_path: str, dest_dir: str = "submissions") -> str:
139
+ """
140
+ Upload a local file into a dedicated dataset repo.
141
+ Unlike committing to the Space repo, this does NOT trigger rebuilds/restarts.
142
+
143
+ Requires Space secrets:
144
+ - HF_TOKEN: with write permissions
145
+ - RESULTS_REPO: dataset repo id (e.g., 'qiuyiding/sound-survey-results')
146
+ """
147
+ from huggingface_hub import upload_file, create_repo
148
+
149
+ repo_id = os.environ.get("RESULTS_REPO", "qiuyiding/sound-survey-results")
150
+ hf_token = os.environ.get("HF_TOKEN")
151
+ if not hf_token:
152
+ raise RuntimeError("Missing HF_TOKEN. Set it in Settings → Repository secrets.")
153
+
154
+ if "/" not in repo_id:
155
+ raise ValueError(f"RESULTS_REPO looks invalid: {repo_id!r}. Expected 'owner/dataset-name'.")
156
+
157
+ create_repo(repo_id, repo_type="dataset", exist_ok=True, token=hf_token)
158
+
159
+ remote_path = f"{dest_dir}/{os.path.basename(local_path)}"
160
+ upload_file(
161
+ path_or_fileobj=local_path,
162
+ path_in_repo=remote_path,
163
+ repo_id=repo_id,
164
+ repo_type="dataset",
165
+ token=hf_token,
166
+ commit_message=f"Add survey result {os.path.basename(local_path)}",
167
+ )
168
+ return f"{repo_id}:{remote_path}"
169
+
170
+ # =========================
171
+ # Export + Summary
172
+ # =========================
173
+
174
+ def finish_and_export_json(questions: List[Dict], responses: List[Dict]) -> Tuple[str, Optional[str]]:
175
+ """
176
+ Build a JSON payload, save to a local path (for front-end download),
177
+ then also upload it to the RESULTS dataset repo (so you can view results on the Hub).
178
+ Returns (summary_text, local_file_path_for_download).
179
+ """
180
+ total = len(questions)
181
+ answered = len(responses)
182
+ num_correct = sum(1 for r in responses if r.get("is_correct") is True)
183
+ num_incorrect = sum(1 for r in responses if r.get("is_correct") is False)
184
+ num_undetermined = answered - num_correct - num_incorrect
185
+
186
+ payload = {
187
+ "meta": {
188
+ "timestamp": datetime.now().isoformat(timespec="seconds"),
189
+ "total_questions": total,
190
+ "answered": answered,
191
+ "correct": num_correct,
192
+ "wrong": num_incorrect,
193
+ "undetermined": num_undetermined,
194
+ },
195
+ "results": sorted(responses, key=lambda x: x["index"]),
196
+ }
197
+
198
+ # Prefer /tmp as it is always writable in Spaces runtime
199
+ out_name = f"survey_results_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}.json"
200
+ save_attempts = [
201
+ os.path.join("/tmp", out_name),
202
+ os.path.join(os.path.dirname(__file__), out_name),
203
+ os.path.join(os.getcwd(), out_name),
204
+ ]
205
+ local_path = None
206
+ for save_path in save_attempts:
207
+ try:
208
+ with open(save_path, "w", encoding="utf-8") as f:
209
+ json.dump(payload, f, ensure_ascii=False, indent=2)
210
+ local_path = save_path
211
+ print(f"[export] Saved JSON: {save_path}")
212
+ break
213
+ except Exception as e:
214
+ print(f"[export] Save failed at {save_path}: {e}")
215
+
216
+ if local_path is None:
217
+ # Last resort: create a temp file
218
+ import tempfile
219
+ tf = tempfile.NamedTemporaryFile(delete=False, suffix=".json", mode="w", encoding="utf-8")
220
+ json.dump(payload, tf, ensure_ascii=False, indent=2)
221
+ tf.close()
222
+ local_path = tf.name
223
+ print(f"[export] Saved JSON to temp: {local_path}")
224
+
225
+ # Upload to results dataset (does NOT restart Space)
226
+ hub_loc = None
227
+ hub_err = None
228
+ try:
229
+ hub_loc = upload_to_results_dataset(local_path, dest_dir="submissions")
230
+ print(f"[export] Uploaded to dataset: {hub_loc}")
231
+ except Exception as e:
232
+ hub_err = str(e)
233
+ print(f"[export] Upload to dataset failed: {hub_err}")
234
+
235
+ # Human-readable summary shown in the textbox
236
+ lines = [
237
+ f"Total: {total} questions, Answered: {answered}",
238
+ f"Correct: {num_correct}, Wrong: {num_incorrect}, Undetermined: {num_undetermined}",
239
+ f"Saved locally (for download): {local_path}",
240
+ (f"Uploaded to results dataset as: {hub_loc}" if hub_loc else f"Upload to results dataset failed: {hub_err or 'see Logs'}"),
241
+ "\nPer-question results:",
242
+ ]
243
+ for r in payload["results"]:
244
+ correctness = (
245
+ "Correct" if r.get("is_correct") is True else
246
+ ("Wrong" if r.get("is_correct") is False else "Undetermined")
247
+ )
248
+ lines.append(
249
+ f"- {r['question_id']}: Selected {r['choice']}, Result: {correctness} (wrong-side heuristic: {r.get('t099_is')})"
250
+ )
251
+ return "\n".join(lines), local_path
252
+
253
+
254
+ # =========================
255
+ # UI App
256
+ # =========================
257
+
258
+ def create_survey_interface():
259
+ questions = discover_questions()
260
+ n = len(questions)
261
+
262
+ with gr.Blocks(title="Sound Generation Survey") as demo:
263
+ # Top instructions (combined and dynamic count)
264
+ gr.Markdown(
265
+ f"""
266
+ # Sound Generation Survey
267
+
268
+ Below are {n} pairs of audios processed with different noise reduction methods.
269
+ Please listen carefully and select **which audio sounds cleaner and contains less of the original noise**.
270
+
271
+ It may take some time to load all the audios.
272
+ If any loading error occurs, please refresh the webpage and try again.
273
+ We truly appreciate your time and patience in participating in this study!
274
+
275
+ ---
276
+
277
+ ## Instructions
278
+ - Each question shows a **Noise Reference** (if available) and two anonymized audios: **Audio A** and **Audio B**.
279
+ - **Task:** Select which audio has **less** of the original noise.
280
+ - **Tip:** First play the Noise Reference to memorize noise characteristics, then compare A and B.
281
+ - If the two audios sound the same, please choose the one that sounds more pleasant and has less noise.
282
+ """
283
+ )
284
+
285
+ radios = []
286
+
287
+ # Render questions
288
+ for idx, q in enumerate(questions):
289
+ with gr.Accordion(label=f"Question {idx+1}: {q['id']}", open=True):
290
+ # Optional noise reference + optional image
291
+ with gr.Row():
292
+ if q["noise"] and q["image"]:
293
+ with gr.Column(scale=1):
294
+ gr.Image(
295
+ value=q["image"], label="",
296
+ height=200, width=200, show_download_button=False
297
+ )
298
+ with gr.Column(scale=2):
299
+ gr.Audio(value=q["noise"], label="Noise Reference", interactive=False)
300
+ elif q["noise"]:
301
+ gr.Audio(value=q["noise"], label="Noise Reference", interactive=False)
302
+ elif q["image"]:
303
+ gr.Image(
304
+ value=q["image"], label="",
305
+ height=200, width=200, show_download_button=False
306
+ )
307
+ else:
308
+ gr.Markdown("*No noise reference or image available*")
309
+
310
+ # Audio A and B
311
+ with gr.Row():
312
+ with gr.Column():
313
+ gr.Audio(value=q["A"], label="Audio A", interactive=False)
314
+ with gr.Column():
315
+ gr.Audio(value=q["B"], label="Audio B", interactive=False)
316
+
317
+ # Single radio selection for A/B
318
+ r = gr.Radio(["A", "B"], label="Select which audio has LESS noise", value=None)
319
+ radios.append(r)
320
+
321
+ # Submit / Reset
322
+ with gr.Row():
323
+ submit_btn = gr.Button("Submit All", variant="primary")
324
+ reset_btn = gr.Button("Reset All")
325
+
326
+ summary = gr.Textbox(label="Results (summary)", interactive=False, lines=12)
327
+ download = gr.File(label="Download JSON", interactive=False)
328
+
329
+ # Submit callback
330
+ def submit_all(*choices):
331
+ try:
332
+ responses = []
333
+ for i, q in enumerate(questions):
334
+ choice_label = choices[i] if i < len(choices) else None
335
+ if choice_label not in ("A", "B"):
336
+ continue
337
+
338
+ timestamp = datetime.now().isoformat(timespec="seconds")
339
+ is_wrong = q.get("t099_is") == choice_label if q.get("t099_is") else None
340
+
341
+ entry = {
342
+ "timestamp": timestamp,
343
+ "question_id": q["id"],
344
+ "index": q["index"],
345
+ "choice": choice_label,
346
+ "is_correct": None if is_wrong is None else (not is_wrong),
347
+ "correct_label": q.get("correct"),
348
+ "t099_is": q.get("t099_is"),
349
+ "noise": q["noise"],
350
+ "A": q["A"],
351
+ "B": q["B"],
352
+ "chosen_path": q.get(choice_label),
353
+ "chosen_has_g0_or_mix1": bool(q.get("t099_is") == choice_label),
354
+ }
355
+ responses.append(entry)
356
+
357
+ if not responses:
358
+ return "Please make at least one selection before submitting.", None
359
+
360
+ summary_text, path = finish_and_export_json(questions, responses)
361
+ return summary_text, path
362
+ except Exception as e:
363
+ import traceback
364
+ traceback.print_exc()
365
+ return f"Error occurred: {str(e)}", None
366
+
367
+ # Reset callback: set all radios back to None
368
+ def reset_all():
369
+ return [None] * len(radios)
370
+
371
+ submit_btn.click(fn=submit_all, inputs=radios, outputs=[summary, download])
372
+ reset_btn.click(fn=reset_all, inputs=None, outputs=radios)
373
+
374
+ # Use queue for multi-user safety; avoid unsupported args (no concurrency_count here)
375
+ demo.queue()
376
+ return demo
377
+
378
+
379
+ # Expose a module-level `demo` so Spaces can find and launch it
380
+ demo = create_survey_interface()
381
+
382
+ # Local dev entry
383
+ if __name__ == "__main__":
384
+ demo.launch()
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ffmpeg
questions/question1/1chainsaw_04_019898_to_saxophone_t0.99_cfg3.5_g0.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f7b01f4a254763a19244da210c1beac7c9535a2400fa144e96badb217f206baf
3
+ size 320044
questions/question1/2chainsaw_04_019898_to_saxophone_t0.99_cfg3.5_g3.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0cc89da95e344512d34d4295357c68166e37850402a8ea6aaa1cbeb9053696d6
3
+ size 320044
questions/question1/chainsaw.jpeg ADDED

Git LFS Details

  • SHA256: 56de9e0809963bc5d22d25353c85a36a480ee6382b4ff9e312ca798a45984902
  • Pointer size: 130 Bytes
  • Size of remote file: 10.5 kB
questions/question1/chainsaw_04_019898.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7aa4210470f1b562853e4f64f90d559f6db3a0c7a5b8936c208bda1111cc9c70
3
+ size 960044
questions/question10/1alarm_to_crickets_alpha0.50_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2be009208095aba52551515129efbe0cdb33edf5b801b2af59aea6c5c76c6830
3
+ size 235052
questions/question10/2alarm_to_crickets_alpha0.50_ngs0.60_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7c45ab6346414ad9ac1ccf9f4ed135ba2e6d298638775af6308298f06796488b
3
+ size 235052
questions/question10/alarm.jpg ADDED

Git LFS Details

  • SHA256: 2329213f94dec228c1d7af91060aad7e4bf8031ddfd4b0f76cf90acb98064ab8
  • Pointer size: 131 Bytes
  • Size of remote file: 104 kB
questions/question10/alarm.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:14b6f8eee6a18b921d7e9821448c35b6f0584325dd486fb29bf8bea98fb8ead2
3
+ size 235008
questions/question11/1reverse_beeper_02_012441_to_rain_alpha0.60_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:93693942b40685b877dbe9663e80ebf6e911e3e0a85f7d3ebef9fbd342edf2c9
3
+ size 327724
questions/question11/2reverse_beeper_02_012441_to_rain_alpha0.60_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9bfd0f3c40c106bd14ba22d8f3f2fac1a2ec3dfa174ec7fdff63293964e88b97
3
+ size 327724
questions/question11/reverse beeper.jpeg ADDED

Git LFS Details

  • SHA256: c53dc7523ef1ef763bc19b12dbd3bd4af2669dfc23c24bc38da8d86ba1b0d71a
  • Pointer size: 129 Bytes
  • Size of remote file: 5.08 kB
questions/question11/reverse_beeper_02_012441.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efd67bf42142782760882825ffeb6f580e9b5489772e6d09e9d9c7d8d222d431
3
+ size 327724
questions/question12/1reverse_beeper_02_012441_to_saxophone_alpha0.50_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:017c2b645d64b0db1cdc3e3dbff43a017a338406ed7552e02f6e2ca9a55ca5a2
3
+ size 327724
questions/question12/2reverse_beeper_02_012441_to_saxophone_alpha1.00_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:915af5e250943b6abc47a11dfd19973b89947bafc1fa79ffd9a7f735b24cc335
3
+ size 327724
questions/question12/reverse beeper.jpeg ADDED

Git LFS Details

  • SHA256: c53dc7523ef1ef763bc19b12dbd3bd4af2669dfc23c24bc38da8d86ba1b0d71a
  • Pointer size: 129 Bytes
  • Size of remote file: 5.08 kB
questions/question12/reverse_beeper_02_012441.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efd67bf42142782760882825ffeb6f580e9b5489772e6d09e9d9c7d8d222d431
3
+ size 327724
questions/question13/1engine_siren_05_016551_to_xylophone_alpha0.50_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:76552006e86f22cec80a8fb4fe8373f1c2248a420a35040f9e719aa1c3526685
3
+ size 320044
questions/question13/2engine_siren_05_016551_to_xylophone_alpha0.50_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4b47c384c4a8f19e2d944677dc2e8501feb9a62c90a13c9fae09f8cc7c527e55
3
+ size 320044
questions/question13/engine_siren.jpeg ADDED

Git LFS Details

  • SHA256: 2b420a51231cde4ff33ff6e4054d9c499b16f20f6de44c15e0a4dea5014dd5d5
  • Pointer size: 131 Bytes
  • Size of remote file: 172 kB
questions/question13/engine_siren_05_016551.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e28dbd7c2a68d207ba620c691e85d71a9964f81e415acb8b47690bc2e6a4c880
3
+ size 320044
questions/question14/1people_talking_06_018164_to_bubbling_stream_alpha0.50_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be81c96a3117933aa025dcf92ee920421716fc02ab8040d1ff410a0833dc7182
3
+ size 327724
questions/question14/2people_talking_06_018164_to_bubbling_stream_alpha0.50_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a3a39b067f48adabb4e2d66d2b3a63e2128cc6a1f8000a9f4469e3702eded20d
3
+ size 327724
questions/question14/people_talking_06_018164.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efe0ef53ee7ddd0c6e455f6c103edf3a5ed431d0d362faf9c9d4681753e2e082
3
+ size 327724
questions/question14/peopletalking.jpg ADDED

Git LFS Details

  • SHA256: b095dfdd4adbe01e0ddabef91e4f4e6b31bd6d7daac6b5541fc4d049726aab0c
  • Pointer size: 131 Bytes
  • Size of remote file: 769 kB
questions/question15/1people_talking_06_018164_to_rain_alpha0.50_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:afc231b7c33e9faafac0ab626cb2be54fad10336e4e310954b603154313beb4b
3
+ size 327724
questions/question15/2people_talking_06_018164_to_rain_alpha0.50_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e13bf5562390ada2328c031086baa4d4fe6e9bbf1c8e4d46a4b7689fdf169b12
3
+ size 327724
questions/question15/people_talking_06_018164.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:efe0ef53ee7ddd0c6e455f6c103edf3a5ed431d0d362faf9c9d4681753e2e082
3
+ size 327724
questions/question15/peopletalking.jpg ADDED

Git LFS Details

  • SHA256: b095dfdd4adbe01e0ddabef91e4f4e6b31bd6d7daac6b5541fc4d049726aab0c
  • Pointer size: 131 Bytes
  • Size of remote file: 769 kB
questions/question16/1chainsaw_04_019898_to_rain_alpha0.50_ngs0.50_mix0.60_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b26ed2c1c94ee350c32fce45483b60be6528fb3d789e3ce3d29f4c7ba31718f6
3
+ size 320044
questions/question16/2chainsaw_04_019898_to_rain_alpha0.50_ngs0.50_mix1.00_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:77a7cf8ee3d993042188218cd4e55505decd095ab9a167402137ecf055c65d87
3
+ size 320044
questions/question16/chainsaw.jpeg ADDED

Git LFS Details

  • SHA256: 56de9e0809963bc5d22d25353c85a36a480ee6382b4ff9e312ca798a45984902
  • Pointer size: 130 Bytes
  • Size of remote file: 10.5 kB
questions/question16/chainsaw_04_019898.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7aa4210470f1b562853e4f64f90d559f6db3a0c7a5b8936c208bda1111cc9c70
3
+ size 960044
questions/question2/1chainsaw_04_019898_to_violin_t0.99_cfg3.5_g0.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0de5640c9b8773873f70033a38f08201bd0125eff8de377f19e1abc70f5ee470
3
+ size 320044
questions/question2/2chainsaw_04_019898_to_violin_t0.90_cfg3.5_g2.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:683d9b2983a695839ec21003be0a17ee2db16757201e09451519e61f401e2540
3
+ size 320044
questions/question2/chainsaw.jpeg ADDED

Git LFS Details

  • SHA256: 56de9e0809963bc5d22d25353c85a36a480ee6382b4ff9e312ca798a45984902
  • Pointer size: 130 Bytes
  • Size of remote file: 10.5 kB
questions/question2/chainsaw_04_019898.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7aa4210470f1b562853e4f64f90d559f6db3a0c7a5b8936c208bda1111cc9c70
3
+ size 960044
questions/question3/1engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g0.0_method_direct_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f9d36c04473ddbbcaa47d1eaa3ff2d917efded0df863f1a5cf5ae6f238947ad4
3
+ size 320044
questions/question3/2engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g2.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bf4d9c8453fa0b25a575d826aaf14c60244aade75c4ae9fbadc647ecd53acbfb
3
+ size 320044
questions/question3/engine.JPG ADDED

Git LFS Details

  • SHA256: ef256d5a4e98362d680ab602d4c7700900cb9faa98a6591f5265fe003799a7eb
  • Pointer size: 131 Bytes
  • Size of remote file: 127 kB
questions/question3/engine_medium_05_010898.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:89aed898fa3d9c63a01499009e6b5efd7e159d33cc095831a8584f2b6eefff6a
3
+ size 960044
questions/question4/1engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g2.0_method_z0_hat_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bf4d9c8453fa0b25a575d826aaf14c60244aade75c4ae9fbadc647ecd53acbfb
3
+ size 320044
questions/question4/2engine_medium_05_010898_to_saxophone_t0.99_cfg3.5_g0.0_method_direct_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f9d36c04473ddbbcaa47d1eaa3ff2d917efded0df863f1a5cf5ae6f238947ad4
3
+ size 320044
questions/question4/engine.JPG ADDED

Git LFS Details

  • SHA256: ef256d5a4e98362d680ab602d4c7700900cb9faa98a6591f5265fe003799a7eb
  • Pointer size: 131 Bytes
  • Size of remote file: 127 kB
questions/question4/engine_siren_05_016551.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e28dbd7c2a68d207ba620c691e85d71a9964f81e415acb8b47690bc2e6a4c880
3
+ size 320044
questions/question5/1people_talking_06_018164_to_bubbling_stream_t0.99_cfg3.5_g0.0_method_direct_mixed.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:76d2c21068cd929605fd648d5f0821f43d1a42f67a7c1ae967c2a370710b2384
3
+ size 327724