HotshotGoku commited on
Commit
d87f99a
·
1 Parent(s): 5b8460a

Improved UI

Browse files
Files changed (1) hide show
  1. app.py +83 -108
app.py CHANGED
@@ -38,55 +38,55 @@ def click_timer(is_checked, state):
38
  state["timer_start"] = datetime.now().isoformat()
39
  return state
40
 
41
- def record_run(name, session_start, attempts, wrongs, total_time, familiarity):
42
- """Append one row per run to Google Sheets, including attempt count, time & familiarity."""
 
 
 
43
  ws.append_row([
44
  name,
45
- session_start, # when they clicked Start
46
- len(attempts), # number of Submit clicks
47
- total_time, # elapsed seconds
48
  familiarity, # slider value
49
- json.dumps(attempts), # full list of correct counts
50
- json.dumps(wrongs) # full list of wrong lists
51
  ])
52
 
53
  def get_new_grid(state=None):
54
- # # 1) Preserve or initialize timer & history
55
- # if state is None or "session_start" not in state:
56
- # session_start = datetime.now().isoformat()
 
 
 
 
 
 
57
  # attempts = []
58
  # wrongs = []
 
59
  # else:
60
- # session_start = state["session_start"]
61
- # attempts = state["attempts"]
62
- # wrongs = state["wrongs"]
63
-
64
-
65
- # 1) Initialize or preserve only attempts/wrongs and any existing timer
66
- if state is None or "attempts" not in state:
67
- attempts = []
68
- wrongs = []
69
- # do NOT set timer_start here—that only comes from the checkbox
70
- else:
71
- attempts = state["attempts"]
72
- wrongs = state["wrongs"]
73
- # preserve timer_start if previously set
74
- timer_start = state.get("timer_start") if state else None
75
-
76
-
77
- # 2) Pick & shuffle images
78
- ai_files = [os.path.join(folder_ai, f) for f in os.listdir(folder_ai)
79
- if f.lower().endswith(".png")]
80
- real_files = [os.path.join(folder_real, f) for f in os.listdir(folder_real)
81
- if f.lower().endswith(".png")]
82
- t = random.randint(4, 12)
83
- sel_ai = random.sample(ai_files, t)
84
- sel_real = random.sample(real_files, 16 - t)
85
- combined = [(p, False) for p in sel_ai] + [(p, True) for p in sel_real]
86
- random.shuffle(combined)
87
-
88
- paths = [p for p, _ in combined]
89
- truth = [lbl for _, lbl in combined]
90
  thumbs = [np.array(Image.open(p).convert("RGB")) for p in paths]
91
  resets = [False] * 16
92
 
@@ -100,87 +100,67 @@ def get_new_grid(state=None):
100
  # }
101
 
102
  new_state = {
103
- "attempts": attempts,
104
- "wrongs": wrongs,
105
  "paths": paths,
106
- "truth": truth
 
107
  }
108
- # carry over the timer only if they've clicked to start it
109
- if timer_start is not None:
110
- new_state["timer_start"] = timer_start
111
 
112
- # 4) Return images, resets, and the full state
113
  return (*thumbs, *resets, new_state)
 
114
  def evaluate(
115
  sel0, sel1, sel2, sel3,
116
  sel4, sel5, sel6, sel7,
117
  sel8, sel9, sel10, sel11,
118
  sel12, sel13, sel14, sel15,
119
- state
 
 
120
  ):
 
 
 
 
 
121
  sels = [sel0, sel1, sel2, sel3, sel4, sel5, sel6, sel7,
122
  sel8, sel9, sel10, sel11, sel12, sel13, sel14, sel15]
123
- paths = state["paths"]
124
- truth = state["truth"]
125
  bordered, wrong_list = [], []
126
  correct_count = 0
127
 
128
  for i, chosen in enumerate(sels):
129
- img = Image.open(paths[i]).convert("RGB")
130
- is_real = truth[i]
131
- if chosen == (not is_real):
132
- color = "green"
 
133
  correct_count += 1
134
  else:
135
- wrong_list.append(os.path.basename(paths[i]))
136
- color = "red"
137
  bordered.append(np.array(ImageOps.expand(img, border=5, fill=color)))
138
 
139
- # accumulate this attempt in state
140
-
141
- state["attempts"].append(correct_count)
142
- state["wrongs"].append(wrong_list)
143
-
144
- return (*bordered, state)
145
-
146
- def done_now(name, state, familiarity):
147
- # only use the timer_start from the box click; if missing, elapsed = 0
148
- timer_iso = state.get("timer_start")
149
- if timer_iso is None:
150
- elapsed = 0.0
151
- timer_iso = datetime.now().isoformat()
152
- else:
153
- start = datetime.fromisoformat(timer_iso)
154
- elapsed = (datetime.now() - start).total_seconds()
155
-
156
- # if they never clicked Start or Submit, elapsed = 0; else from first interaction
157
  timer_iso = state.get("timer_start")
158
- if timer_iso:
159
- elapsed = (datetime.now() - datetime.fromisoformat(timer_iso)).total_seconds()
160
- else:
161
- elapsed = 0.0
162
- timer_iso = datetime.now().isoformat()
163
 
164
- # record the whole run; if they never started timer, timestamp now
165
- record_run(
166
- name,
167
- state.get("timer_start", datetime.now().isoformat()),
168
- state["attempts"],
169
- state["wrongs"],
170
- elapsed,
171
- familiarity
172
- )
173
-
174
- minutes = int(elapsed // 60)
175
- seconds = int(elapsed % 60)
176
 
177
- return (
178
- f"Run recorded for '{name}'.\n"
179
- f"Familiarity: {familiarity}/10\n"
180
- f"Total time: {minutes}m {seconds}s\n"
181
- f"Thanks for playing ^_^!"
 
 
 
182
  )
 
 
 
183
 
 
184
 
185
 
186
  with gr.Blocks() as demo:
@@ -196,7 +176,7 @@ with gr.Blocks() as demo:
196
 
197
  user_name = gr.Textbox(label="Your name", placeholder="e.g. Can be anonymous ex: 'Trisolaris123'")
198
 
199
- gr.Markdown("# Instructions: Click the images you think are AI-generated. \nYou can submit multiple times per grid if you want to improve your score. \nClick 'Refresh Grid' to get a new set of images. \nWhen you are done, click 'I am done now' to record your results.")
200
  # Familiarity slider (1=first time, 10=expert)
201
  familiarity = gr.Slider(
202
  minimum=1, maximum=10, step=1, value=1,
@@ -227,30 +207,25 @@ with gr.Blocks() as demo:
227
  cb.change(fn=click_timer, inputs=[cb, state], outputs=[state])
228
 
229
  submit_btn = gr.Button("Submit")
230
- refresh_btn = gr.Button("Refresh Grid")
231
- done_btn = gr.Button("I am done now")
232
- done_out = gr.Textbox(interactive=False)
233
 
234
  demo.load(
235
  fn=get_new_grid,
236
  inputs=[state],
237
  outputs=[*image_components, *checkbox_components, state]
238
  )
239
- refresh_btn.click(
240
  fn=get_new_grid,
241
  inputs=[state],
242
  outputs=[*image_components, *checkbox_components, state]
243
  )
244
  submit_btn.click(
245
  fn=evaluate,
246
- inputs=[*checkbox_components, state],
247
- outputs=[*image_components, state]
248
- )
249
- done_btn.click(
250
- fn=done_now,
251
- inputs=[user_name, state, familiarity],
252
- outputs=[done_out]
253
  )
 
254
 
255
  # Reveal main UI only after agreeing to terms
256
  terms_cb.change(
 
38
  state["timer_start"] = datetime.now().isoformat()
39
  return state
40
 
41
+ def record_run(name, session_start, attempt_num, elapsed_sec, familiarity, correct_count, wrong_list):
42
+ """
43
+ Append one row with exactly:
44
+ Name | StartTime | #Attempt | ElapsedSec | Familiarity | AttemptsList | WrongsList
45
+ """
46
  ws.append_row([
47
  name,
48
+ session_start, # when that grid/timer started
49
+ attempt_num, # 1, 2, 3,
50
+ elapsed_sec, # seconds for this attempt
51
  familiarity, # slider value
52
+ json.dumps([correct_count]), # e.g. [9]
53
+ json.dumps(wrong_list) # e.g. ["217_1.png","243_2.png"]
54
  ])
55
 
56
  def get_new_grid(state=None):
57
+ """
58
+ Generate a fresh 4×4 grid:
59
+ - Preserve attempt_count
60
+ - **Reset** timer_start to "now" whenever the user hits Retry (i.e. state is not None)
61
+ - Leave timer_start unset on initial load (so they must click Start or first Fake?)
62
+ """
63
+
64
+ # # 1) Initialize or preserve only attempts/wrongs and any existing timer
65
+ # if state is None or "attempts" not in state:
66
  # attempts = []
67
  # wrongs = []
68
+ # # do NOT set timer_start here—that only comes from the checkbox
69
  # else:
70
+ # attempts = state["attempts"]
71
+ # wrongs = state["wrongs"]
72
+ # # preserve timer_start if previously set
73
+ # timer_start = state.get("timer_start") if state else None
74
+
75
+ # 1) Preserve attempt_count or start at 0
76
+ attempt_count = (state or {}).get("attempt_count", 0)
77
+
78
+
79
+ # 2) Sample & shuffle images as before
80
+ ai_files = [os.path.join(folder_ai, f) for f in os.listdir(folder_ai) if f.endswith(".png")]
81
+ real_files = [os.path.join(folder_real, f) for f in os.listdir(folder_real) if f.endswith(".png")]
82
+ t = random.randint(4, 12)
83
+ sel_ai = random.sample(ai_files, t)
84
+ sel_real = random.sample(real_files, 16 - t)
85
+ combo = [(p, False) for p in sel_ai] + [(p, True) for p in sel_real]
86
+ random.shuffle(combo)
87
+ paths, truth = zip(*combo)
88
+
89
+ # 3) Build thumbnails + reset flags
 
 
 
 
 
 
 
 
 
 
90
  thumbs = [np.array(Image.open(p).convert("RGB")) for p in paths]
91
  resets = [False] * 16
92
 
 
100
  # }
101
 
102
  new_state = {
 
 
103
  "paths": paths,
104
+ "truth": truth,
105
+ "attempt_count": attempt_count , # increment attempt count
106
  }
107
+ # Reset timer on Retry (state exists); leave unset on first load (state is None)
108
+ if state is not None:
109
+ new_state["timer_start"] = datetime.now().isoformat()
110
 
 
111
  return (*thumbs, *resets, new_state)
112
+
113
  def evaluate(
114
  sel0, sel1, sel2, sel3,
115
  sel4, sel5, sel6, sel7,
116
  sel8, sel9, sel10, sel11,
117
  sel12, sel13, sel14, sel15,
118
+ state,
119
+ user_name,
120
+ familiarity
121
  ):
122
+ # 1) Increment the simple count
123
+ attempt_count = state.get("attempt_count", 0) + 1
124
+ state["attempt_count"] = attempt_count
125
+
126
+ # 2) Border logic as before...
127
  sels = [sel0, sel1, sel2, sel3, sel4, sel5, sel6, sel7,
128
  sel8, sel9, sel10, sel11, sel12, sel13, sel14, sel15]
 
 
129
  bordered, wrong_list = [], []
130
  correct_count = 0
131
 
132
  for i, chosen in enumerate(sels):
133
+ img = Image.open(state["paths"][i]).convert("RGB")
134
+ is_real = state["truth"][i]
135
+ correct = chosen == (not is_real)
136
+ color = "green" if correct else "red"
137
+ if correct:
138
  correct_count += 1
139
  else:
140
+ wrong_list.append(os.path.basename(state["paths"][i]))
 
141
  bordered.append(np.array(ImageOps.expand(img, border=5, fill=color)))
142
 
143
+ # 3) Timer logic
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  timer_iso = state.get("timer_start")
145
+ elapsed = (datetime.now() - datetime.fromisoformat(timer_iso)).total_seconds() if timer_iso else 0.0
 
 
 
 
146
 
147
+ # incremented earlier in evaluate:
148
+ attempt_num = state["attempt_count"]
 
 
 
 
 
 
 
 
 
 
149
 
150
+ record_run(
151
+ user_name, # your textbox input
152
+ state["timer_start"], # ISO start time for this grid
153
+ attempt_num, # 1, 2, 3, ...
154
+ elapsed, # per‐attempt elapsed
155
+ familiarity, # slider input
156
+ correct_count, # how many correct this try
157
+ wrong_list # which files were wrong
158
  )
159
+ # 5) Summary text
160
+ pct = correct_count / 16 * 100
161
+ summary = f"Attempt {attempt_count}: {correct_count}/16 correct ({pct:.1f}%), time {elapsed:.1f}s. \n Retry to improve your score! (The grid of images will refresh )"
162
 
163
+ return (*bordered, state, summary)
164
 
165
 
166
  with gr.Blocks() as demo:
 
176
 
177
  user_name = gr.Textbox(label="Your name", placeholder="e.g. Can be anonymous ex: 'Trisolaris123'")
178
 
179
+ gr.Markdown("# Instructions: Click the images you think are AI-generated. \nWhen you are done, click 'Submit' to record your results.\nClick 'Retry' to get a new set of images and improve your score (infinite retries). ")
180
  # Familiarity slider (1=first time, 10=expert)
181
  familiarity = gr.Slider(
182
  minimum=1, maximum=10, step=1, value=1,
 
207
  cb.change(fn=click_timer, inputs=[cb, state], outputs=[state])
208
 
209
  submit_btn = gr.Button("Submit")
210
+ retry_btn = gr.Button("Retry")
211
+ score_out = gr.Textbox(label="Score & Time", interactive=False)
 
212
 
213
  demo.load(
214
  fn=get_new_grid,
215
  inputs=[state],
216
  outputs=[*image_components, *checkbox_components, state]
217
  )
218
+ retry_btn.click(
219
  fn=get_new_grid,
220
  inputs=[state],
221
  outputs=[*image_components, *checkbox_components, state]
222
  )
223
  submit_btn.click(
224
  fn=evaluate,
225
+ inputs=[*checkbox_components, state,user_name, familiarity],
226
+ outputs=[*image_components, state,score_out]
 
 
 
 
 
227
  )
228
+
229
 
230
  # Reveal main UI only after agreeing to terms
231
  terms_cb.change(