dehezhang2 commited on
Commit
f92a088
·
verified ·
1 Parent(s): 479db49

deploy v2 study (40-runs baselines) at /v2/: dual-study backend + static/v2 rater UI; v1 study untouched

Browse files
Files changed (1) hide show
  1. static/v2/mobile.html +35 -11
static/v2/mobile.html CHANGED
@@ -841,11 +841,16 @@ function rowSlotOrder(caseId, qKey, slotCount){
841
  return Array.from({length:slotCount},(_,i)=>i);
842
  }
843
 
844
- /* ----- Ratings ----- */
 
 
 
 
 
845
  function getCaseR(cid){ if(!RATINGS[cid]) RATINGS[cid]={}; return RATINGS[cid]; }
846
- function getSlotR(cid, s){ const m = getCaseR(cid); if(!m[s]) m[s]={}; return m[s]; }
847
- function setRating(cid, sIdx, qk, score){
848
- getSlotR(cid, sIdx)[qk] = score;
849
  saveState();
850
  updateProgress();
851
  if (RATER.submitted_at){
@@ -861,7 +866,7 @@ function studyCompleteness(){
861
  for (const c of CASES){
862
  const slots = SHUFFLE[c.id] || c.videos.map((_,i)=>i);
863
  for (let s=0; s<slots.length; s++){
864
- const r = (RATINGS[c.id]||{})[s] || {};
865
  for (const qk of qkeys){
866
  expected++;
867
  if (typeof r[qk]==="number" && r[qk]>=1 && r[qk]<=5) done++;
@@ -876,7 +881,7 @@ function caseProgress(c){
876
  const expected = slots.length * TOTAL_QUESTIONS;
877
  let done=0;
878
  for (let s=0;s<slots.length;s++){
879
- const r = (RATINGS[c.id]||{})[s] || {};
880
  done += Object.keys(r).filter(k=>typeof r[k]==="number"&&r[k]>=1&&r[k]<=5).length;
881
  }
882
  return { done, expected };
@@ -920,7 +925,7 @@ function buildProgressPayload(){
920
  slot: String.fromCharCode(65+slotIdx), slot_index: slotIdx,
921
  original_index: origIdx, model: c.videos[origIdx].model,
922
  path: c.videos[origIdx].path,
923
- ratings: (RATINGS[c.id]||{})[slotIdx] || {},
924
  })),
925
  };
926
  }),
@@ -1007,7 +1012,7 @@ function exportJSON(){
1007
  videos: slots.map((oi,si)=>({
1008
  slot:String.fromCharCode(65+si), slot_index:si, original_index:oi,
1009
  model:c.videos[oi].model, path:c.videos[oi].path,
1010
- ratings:(RATINGS[c.id]||{})[si]||{},
1011
  })),
1012
  };
1013
  }),
@@ -1216,14 +1221,14 @@ function renderQuestionCard(c, q){
1216
  row.appendChild(chip);
1217
  const group = document.createElement("div");
1218
  group.className = "likert";
1219
- const cur = getSlotR(c.id, slotIdx)[q.key];
1220
  for (let s=1; s<=5; s++){
1221
  const b = document.createElement("button");
1222
  b.dataset.score = String(s);
1223
  b.textContent = String(s);
1224
  if (cur===s) b.classList.add("selected");
1225
  b.onclick = () => {
1226
- setRating(c.id, slotIdx, q.key, s);
1227
  Array.from(group.children).forEach((bb,i)=>bb.classList.toggle("selected", (i+1)===s));
1228
  };
1229
  group.appendChild(b);
@@ -1454,7 +1459,26 @@ function hideSubmittedOverlay(){ document.getElementById("submittedOverlay").cla
1454
  if (!isAdmin()) anonymize = true;
1455
  // Admins see all cases; everyone else gets a deterministic 10-case subset.
1456
  CASES = selectCasesForRater(ALL_CASES);
1457
- buildShuffle(CASES); saveState();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1458
 
1459
  // wire DOM events
1460
  document.getElementById("drawerBtn").onclick = openDrawer;
 
841
  return Array.from({length:slotCount},(_,i)=>i);
842
  }
843
 
844
+ /* ----- Ratings -----
845
+ * RATINGS is keyed RATINGS[case_id][model][q_key] — by MODEL NAME, exactly
846
+ * like desktop index.html, so the shared localStorage blob and the
847
+ * server-recovered state read identically on both pages. (Older mobile code
848
+ * keyed by slot index; see migrateSlotKeyedRatings for the one-shot fix-up.)
849
+ */
850
  function getCaseR(cid){ if(!RATINGS[cid]) RATINGS[cid]={}; return RATINGS[cid]; }
851
+ function getModelR(cid, model){ const m = getCaseR(cid); if(!m[model]) m[model]={}; return m[model]; }
852
+ function setRating(cid, model, qk, score){
853
+ getModelR(cid, model)[qk] = score;
854
  saveState();
855
  updateProgress();
856
  if (RATER.submitted_at){
 
866
  for (const c of CASES){
867
  const slots = SHUFFLE[c.id] || c.videos.map((_,i)=>i);
868
  for (let s=0; s<slots.length; s++){
869
+ const r = (RATINGS[c.id]||{})[c.videos[slots[s]].model] || {};
870
  for (const qk of qkeys){
871
  expected++;
872
  if (typeof r[qk]==="number" && r[qk]>=1 && r[qk]<=5) done++;
 
881
  const expected = slots.length * TOTAL_QUESTIONS;
882
  let done=0;
883
  for (let s=0;s<slots.length;s++){
884
+ const r = (RATINGS[c.id]||{})[c.videos[slots[s]].model] || {};
885
  done += Object.keys(r).filter(k=>typeof r[k]==="number"&&r[k]>=1&&r[k]<=5).length;
886
  }
887
  return { done, expected };
 
925
  slot: String.fromCharCode(65+slotIdx), slot_index: slotIdx,
926
  original_index: origIdx, model: c.videos[origIdx].model,
927
  path: c.videos[origIdx].path,
928
+ ratings: (RATINGS[c.id]||{})[c.videos[origIdx].model] || {},
929
  })),
930
  };
931
  }),
 
1012
  videos: slots.map((oi,si)=>({
1013
  slot:String.fromCharCode(65+si), slot_index:si, original_index:oi,
1014
  model:c.videos[oi].model, path:c.videos[oi].path,
1015
+ ratings:(RATINGS[c.id]||{})[c.videos[oi].model]||{},
1016
  })),
1017
  };
1018
  }),
 
1221
  row.appendChild(chip);
1222
  const group = document.createElement("div");
1223
  group.className = "likert";
1224
+ const cur = getModelR(c.id, v.model)[q.key];
1225
  for (let s=1; s<=5; s++){
1226
  const b = document.createElement("button");
1227
  b.dataset.score = String(s);
1228
  b.textContent = String(s);
1229
  if (cur===s) b.classList.add("selected");
1230
  b.onclick = () => {
1231
+ setRating(c.id, v.model, q.key, s);
1232
  Array.from(group.children).forEach((bb,i)=>bb.classList.toggle("selected", (i+1)===s));
1233
  };
1234
  group.appendChild(b);
 
1459
  if (!isAdmin()) anonymize = true;
1460
  // Admins see all cases; everyone else gets a deterministic 10-case subset.
1461
  CASES = selectCasesForRater(ALL_CASES);
1462
+ buildShuffle(CASES);
1463
+ // One-shot migration: older mobile builds keyed RATINGS by slot index
1464
+ // instead of model name. SHUFFLE is deterministic per (rater, case), so a
1465
+ // numeric slot key maps back to the exact model the rater saw and scored.
1466
+ {
1467
+ let moved = 0;
1468
+ for (const c of CASES) {
1469
+ const m = RATINGS[c.id];
1470
+ if (!m) continue;
1471
+ const slots = SHUFFLE[c.id] || c.videos.map((_,i)=>i);
1472
+ for (const k of Object.keys(m)) {
1473
+ if (!/^\d+$/.test(k)) continue;
1474
+ const model = (c.videos[slots[Number(k)]] || {}).model;
1475
+ if (model && !m[model]) { m[model] = m[k]; moved++; }
1476
+ delete m[k];
1477
+ }
1478
+ }
1479
+ if (moved) console.info(`[user-study] migrated ${moved} slot-keyed rating group(s) to model keys`);
1480
+ }
1481
+ saveState();
1482
 
1483
  // wire DOM events
1484
  document.getElementById("drawerBtn").onclick = openDrawer;