Emilyxml commited on
Commit
1cd259c
·
verified ·
1 Parent(s): ba063cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -47
app.py CHANGED
@@ -5,6 +5,7 @@ import uuid
5
  import csv
6
  from datetime import datetime
7
  from pathlib import Path
 
8
  from huggingface_hub import CommitScheduler, snapshot_download
9
 
10
  # --- 1. 配置区域 ---
@@ -14,7 +15,7 @@ LOG_FOLDER = Path("logs")
14
  LOG_FOLDER.mkdir(parents=True, exist_ok=True)
15
  TOKEN = os.environ.get("HF_TOKEN")
16
 
17
- # --- 2. 自动下载数据 (保证不为空) ---
18
  if not os.path.exists(DATA_FOLDER) or not os.listdir(DATA_FOLDER):
19
  try:
20
  print("🚀 正在从 Dataset 下载数据...")
@@ -27,7 +28,7 @@ if not os.path.exists(DATA_FOLDER) or not os.listdir(DATA_FOLDER):
27
  )
28
  print("✅ 数据下载完成!")
29
  except Exception as e:
30
- print(f"⚠️ 下载失败 (请检查 Token 或网络): {e}")
31
 
32
  # --- 3. 启动同步调度器 ---
33
  scheduler = CommitScheduler(
@@ -78,54 +79,75 @@ def load_data():
78
 
79
  ALL_GROUPS, ALL_GROUP_IDS = load_data()
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  # --- 5. 核心逻辑 ---
82
 
83
  def get_next_question(user_state):
84
  """准备下一题的数据"""
85
  idx = user_state["index"]
86
 
87
- # 1. 结束判断
88
  if idx >= len(ALL_GROUP_IDS):
89
  return (
90
- gr.update(visible=False), # Origin
91
- gr.update(visible=False), # Gallery
92
- gr.update(visible=False), # Checkbox
93
- gr.update(visible=False), # Instruction
94
- gr.update(visible=False), # Submit Btn
95
- gr.update(visible=False), # None Btn
96
  gr.update(value="## 🎉 测试结束!感谢您的参与。", visible=True),
97
  user_state,
98
- [] # current_candidates_info
99
  )
100
 
101
- # 2. 获取数据
102
  group_id = ALL_GROUP_IDS[idx]
103
  group_data = ALL_GROUPS[group_id]
104
 
105
- # 3. 准备原图
106
- origin_path = group_data["origin"]
107
 
108
- # 4. 准备候选图(打乱)
109
  candidates = group_data["candidates"].copy()
110
  random.shuffle(candidates)
111
 
112
- # 构造 Gallery 数据 [(path, label), ...] 和 选项列表 ["Option A", ...]
113
  gallery_items = []
114
  choices = []
115
- candidates_info = [] # 用于存储真实路径,方便后续查找
116
 
117
  for i, path in enumerate(candidates):
118
- label = f"Option {chr(65+i)}" # Option A, Option B...
119
- gallery_items.append((path, label))
 
 
 
 
120
  choices.append(label)
121
  candidates_info.append({"label": label, "path": path})
122
 
123
  instruction = f"### 任务 ({idx + 1} / {len(ALL_GROUP_IDS)})\n\n{group_data['instruction']}"
124
 
125
  return (
126
- gr.update(value=origin_path, visible=True if origin_path else False),
127
  gr.update(value=gallery_items, visible=True),
128
- gr.update(choices=choices, value=[], visible=True), # 重置多选框
129
  gr.update(value=instruction, visible=True),
130
  gr.update(visible=True),
131
  gr.update(visible=True),
@@ -135,38 +157,30 @@ def get_next_question(user_state):
135
  )
136
 
137
  def save_and_next(user_state, candidates_info, selected_options, is_none=False):
138
- """保存并进入下一题"""
139
  current_idx = user_state["index"]
140
  group_id = ALL_GROUP_IDS[current_idx]
141
 
142
- # --- 保存逻辑 ---
143
  if is_none:
144
  choice_str = "Rejected All"
145
  method_str = "None_Satisfied"
146
  else:
147
- # 检查是否未选
148
  if not selected_options:
149
  raise gr.Error("请至少勾选一个选项,或点击“都不满意”")
150
 
151
  choice_str = "; ".join(selected_options)
152
-
153
- # 查找对应的方法名
154
  selected_methods = []
155
- for opt in selected_options: # opt is "Option A"
156
- # 找到对应的文件路径
157
  for info in candidates_info:
158
  if info["label"] == opt:
159
  path = info["path"]
160
  filename = os.path.basename(path)
161
  name = os.path.splitext(filename)[0]
162
- # 简单清洗文件名拿到方法名
163
  parts = name.split('_', 1)
164
  method = parts[1] if len(parts) > 1 else name
165
  selected_methods.append(method)
166
  break
167
  method_str = "; ".join(selected_methods)
168
 
169
- # 写入 CSV
170
  user_file = LOG_FOLDER / f"user_{user_state['user_id']}.csv"
171
  with scheduler.lock:
172
  exists = user_file.exists()
@@ -182,42 +196,35 @@ def save_and_next(user_state, candidates_info, selected_options, is_none=False):
182
  method_str
183
  ])
184
 
185
- # --- 状态更新 ---
186
  user_state["index"] += 1
187
-
188
- # --- 加载下一题 ---
189
  return get_next_question(user_state)
190
 
191
  # --- 6. 界面构建 ---
192
  with gr.Blocks(title="User Study") as demo:
193
 
194
- # 状态变量
195
- state_user = gr.State({"user_id": str(uuid.uuid4())[:8], "index": 0})
196
- state_candidates_info = gr.State([]) # 存当前页面的候选图信息,用于把 Option A 映射回文件名
197
 
198
- # 布局
199
  with gr.Row():
200
  md_instruction = gr.Markdown("Loading...")
201
 
202
  with gr.Row():
203
- # 左侧:原图
204
  with gr.Column(scale=1):
205
- img_origin = gr.Image(label="Reference (参考原图)", interactive=False, height=400)
 
206
 
207
- # 右侧:候选图 + 选择区
208
  with gr.Column(scale=2):
209
- # 1. Gallery 显示所有选项
210
  gallery_candidates = gr.Gallery(
211
  label="Candidates (候选结果)",
212
  columns=[2],
213
  height="auto",
214
  object_fit="contain",
215
- interactive=False # 禁止 Gallery 自身的点击选择,用下面的 Checkbox 替代
 
216
  )
217
 
218
  gr.Markdown("👇 **请在下方勾选您认为最好的结果(可多选):**")
219
 
220
- # 2. 多选框 (核心交互)
221
  checkbox_options = gr.CheckboxGroup(
222
  choices=[],
223
  label="您的选择",
@@ -230,23 +237,18 @@ with gr.Blocks(title="User Study") as demo:
230
 
231
  md_end = gr.Markdown(visible=False)
232
 
233
- # --- 事件绑定 ---
234
-
235
- # 1. 页面加载时,加载第一题
236
  demo.load(
237
  fn=get_next_question,
238
  inputs=[state_user],
239
  outputs=[img_origin, gallery_candidates, checkbox_options, md_instruction, btn_submit, btn_none, md_end, state_user, state_candidates_info]
240
  )
241
 
242
- # 2. 提交按钮
243
  btn_submit.click(
244
  fn=lambda s, c, o: save_and_next(s, c, o, is_none=False),
245
  inputs=[state_user, state_candidates_info, checkbox_options],
246
  outputs=[img_origin, gallery_candidates, checkbox_options, md_instruction, btn_submit, btn_none, md_end, state_user, state_candidates_info]
247
  )
248
 
249
- # 3. 都不满意按钮
250
  btn_none.click(
251
  fn=lambda s, c, o: save_and_next(s, c, o, is_none=True),
252
  inputs=[state_user, state_candidates_info, checkbox_options],
 
5
  import csv
6
  from datetime import datetime
7
  from pathlib import Path
8
+ from PIL import Image # 引入 PIL 用于处理图片
9
  from huggingface_hub import CommitScheduler, snapshot_download
10
 
11
  # --- 1. 配置区域 ---
 
15
  LOG_FOLDER.mkdir(parents=True, exist_ok=True)
16
  TOKEN = os.environ.get("HF_TOKEN")
17
 
18
+ # --- 2. 自动下载数据 ---
19
  if not os.path.exists(DATA_FOLDER) or not os.listdir(DATA_FOLDER):
20
  try:
21
  print("🚀 正在从 Dataset 下载数据...")
 
28
  )
29
  print("✅ 数据下载完成!")
30
  except Exception as e:
31
+ print(f"⚠️ 下载失败: {e}")
32
 
33
  # --- 3. 启动同步调度器 ---
34
  scheduler = CommitScheduler(
 
79
 
80
  ALL_GROUPS, ALL_GROUP_IDS = load_data()
81
 
82
+ # --- NEW: 图片优化函数 (提速关键) ---
83
+ def optimize_image(image_path, max_width=800):
84
+ """
85
+ 读取图片并调整大小,减少传输时间。
86
+ max_width: 限制最大宽度为 800px (足够人眼评估)
87
+ """
88
+ if not image_path:
89
+ return None
90
+ try:
91
+ img = Image.open(image_path)
92
+ # 如果图片太大,就缩小
93
+ if img.width > max_width:
94
+ ratio = max_width / img.width
95
+ new_height = int(img.height * ratio)
96
+ img = img.resize((max_width, new_height), Image.LANCZOS)
97
+ return img
98
+ except Exception as e:
99
+ print(f"Error loading image {image_path}: {e}")
100
+ return None
101
+
102
  # --- 5. 核心逻辑 ---
103
 
104
  def get_next_question(user_state):
105
  """准备下一题的数据"""
106
  idx = user_state["index"]
107
 
 
108
  if idx >= len(ALL_GROUP_IDS):
109
  return (
110
+ gr.update(visible=False),
111
+ gr.update(visible=False),
112
+ gr.update(visible=False),
113
+ gr.update(visible=False),
114
+ gr.update(visible=False),
115
+ gr.update(visible=False),
116
  gr.update(value="## 🎉 测试结束!感谢您的参与。", visible=True),
117
  user_state,
118
+ []
119
  )
120
 
 
121
  group_id = ALL_GROUP_IDS[idx]
122
  group_data = ALL_GROUPS[group_id]
123
 
124
+ # 1. 优化原图 (返回 PIL 对象而不是路径)
125
+ origin_img = optimize_image(group_data["origin"], max_width=600)
126
 
127
+ # 2. 优化候选图
128
  candidates = group_data["candidates"].copy()
129
  random.shuffle(candidates)
130
 
 
131
  gallery_items = []
132
  choices = []
133
+ candidates_info = []
134
 
135
  for i, path in enumerate(candidates):
136
+ label = f"Option {chr(65+i)}"
137
+
138
+ # 优化每张候选图
139
+ optimized_img = optimize_image(path, max_width=600)
140
+
141
+ gallery_items.append((optimized_img, label))
142
  choices.append(label)
143
  candidates_info.append({"label": label, "path": path})
144
 
145
  instruction = f"### 任务 ({idx + 1} / {len(ALL_GROUP_IDS)})\n\n{group_data['instruction']}"
146
 
147
  return (
148
+ gr.update(value=origin_img, visible=True if origin_img else False),
149
  gr.update(value=gallery_items, visible=True),
150
+ gr.update(choices=choices, value=[], visible=True),
151
  gr.update(value=instruction, visible=True),
152
  gr.update(visible=True),
153
  gr.update(visible=True),
 
157
  )
158
 
159
  def save_and_next(user_state, candidates_info, selected_options, is_none=False):
 
160
  current_idx = user_state["index"]
161
  group_id = ALL_GROUP_IDS[current_idx]
162
 
 
163
  if is_none:
164
  choice_str = "Rejected All"
165
  method_str = "None_Satisfied"
166
  else:
 
167
  if not selected_options:
168
  raise gr.Error("请至少勾选一个选项,或点击“都不满意”")
169
 
170
  choice_str = "; ".join(selected_options)
 
 
171
  selected_methods = []
172
+ for opt in selected_options:
 
173
  for info in candidates_info:
174
  if info["label"] == opt:
175
  path = info["path"]
176
  filename = os.path.basename(path)
177
  name = os.path.splitext(filename)[0]
 
178
  parts = name.split('_', 1)
179
  method = parts[1] if len(parts) > 1 else name
180
  selected_methods.append(method)
181
  break
182
  method_str = "; ".join(selected_methods)
183
 
 
184
  user_file = LOG_FOLDER / f"user_{user_state['user_id']}.csv"
185
  with scheduler.lock:
186
  exists = user_file.exists()
 
196
  method_str
197
  ])
198
 
 
199
  user_state["index"] += 1
 
 
200
  return get_next_question(user_state)
201
 
202
  # --- 6. 界面构建 ---
203
  with gr.Blocks(title="User Study") as demo:
204
 
205
+ state_user = gr.State(lambda: {"user_id": str(uuid.uuid4())[:8], "index": 0})
206
+ state_candidates_info = gr.State([])
 
207
 
 
208
  with gr.Row():
209
  md_instruction = gr.Markdown("Loading...")
210
 
211
  with gr.Row():
 
212
  with gr.Column(scale=1):
213
+ # format 设置为 jpeg 进一步减小体积
214
+ img_origin = gr.Image(label="Reference (参考原图)", interactive=False, height=400, format="jpeg")
215
 
 
216
  with gr.Column(scale=2):
 
217
  gallery_candidates = gr.Gallery(
218
  label="Candidates (候选结果)",
219
  columns=[2],
220
  height="auto",
221
  object_fit="contain",
222
+ interactive=False,
223
+ format="jpeg" # 强制输出 JPEG 格式
224
  )
225
 
226
  gr.Markdown("👇 **请在下方勾选您认为最好的结果(可多选):**")
227
 
 
228
  checkbox_options = gr.CheckboxGroup(
229
  choices=[],
230
  label="您的选择",
 
237
 
238
  md_end = gr.Markdown(visible=False)
239
 
 
 
 
240
  demo.load(
241
  fn=get_next_question,
242
  inputs=[state_user],
243
  outputs=[img_origin, gallery_candidates, checkbox_options, md_instruction, btn_submit, btn_none, md_end, state_user, state_candidates_info]
244
  )
245
 
 
246
  btn_submit.click(
247
  fn=lambda s, c, o: save_and_next(s, c, o, is_none=False),
248
  inputs=[state_user, state_candidates_info, checkbox_options],
249
  outputs=[img_origin, gallery_candidates, checkbox_options, md_instruction, btn_submit, btn_none, md_end, state_user, state_candidates_info]
250
  )
251
 
 
252
  btn_none.click(
253
  fn=lambda s, c, o: save_and_next(s, c, o, is_none=True),
254
  inputs=[state_user, state_candidates_info, checkbox_options],