Wenjiawang0312 commited on
Commit
d1d5132
·
1 Parent(s): 1c13596
Files changed (5) hide show
  1. .gitattributes +1 -0
  2. app_backup.py +313 -0
  3. app_fixed.py +334 -0
  4. requirements.txt +4 -0
  5. upload_to_hf.py +55 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* 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
 
 
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
+ *.mp4 filter=lfs diff=lfs merge=lfs -text
app_backup.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from datetime import datetime
5
+ from datasets import load_dataset
6
+ import tempfile
7
+
8
+ # 从Hugging Face dataset加载视频 / Load videos from Hugging Face dataset
9
+ def load_videos_from_huggingface():
10
+ try:
11
+ dataset = load_dataset("WenjiaWang/videoforuser")
12
+ print("成功加载数据集: WenjiaWang/videoforuser / Successfully loaded dataset")
13
+
14
+ # 获取数据集中的文件夹列表
15
+ question_folders = set()
16
+ all_videos = {} # 存储所有视频路径 {folder: {method: video_path}}
17
+
18
+ # 假设数据集包含file_path字段,或者使用标准的数据集结构
19
+ if 'train' in dataset:
20
+ for item in dataset['train']:
21
+ # 根据数据集的实际结构调整字段名
22
+ if 'file_path' in item:
23
+ file_path = item['file_path']
24
+ elif 'path' in item:
25
+ file_path = item['path']
26
+ elif 'video_path' in item:
27
+ file_path = item['video_path']
28
+ else:
29
+ continue
30
+
31
+ # 从路径提取文件夹名和文件名
32
+ folder_name = os.path.basename(os.path.dirname(file_path))
33
+ file_name = os.path.basename(file_path)
34
+
35
+ question_folders.add(folder_name)
36
+
37
+ if folder_name not in all_videos:
38
+ all_videos[folder_name] = {}
39
+
40
+ # 确定方法名并映射到匿名显示名
41
+ display_name = f"Method {len(all_videos[folder_name]) + 1}"
42
+ all_videos[folder_name][display_name] = item
43
+
44
+ return list(sorted(question_folders)), all_videos
45
+
46
+ except Exception as e:
47
+ print(f"Hugging Face数据集加载失败: {e} / Hugging Face dataset loading failed")
48
+ print("回退到本地videos文件夹 / Falling back to local videos folder")
49
+ return None, None
50
+
51
+ # 获取所有问题文件夹 / Get all question folders
52
+ def get_question_folders():
53
+ # 优先使用Hugging Face数据集
54
+ hf_folders, hf_videos = load_videos_from_huggingface()
55
+ if hf_folders and hf_videos:
56
+ return hf_folders
57
+
58
+ # 回退到本地文件夹
59
+ video_dir = "videos"
60
+ if not os.path.exists(video_dir):
61
+ print(f"视频目录不存在: {video_dir} / Video directory not found")
62
+ return []
63
+
64
+ folders = [f for f in os.listdir(video_dir) if os.path.isdir(os.path.join(video_dir, f))]
65
+ return sorted(folders)
66
+
67
+ # 获取问题文件夹中的所有视频 / Get all videos in the question folder
68
+ def get_videos_for_question(question_folder):
69
+ # 优先使用Hugging Face数据集
70
+ hf_folders, hf_videos = load_videos_from_huggingface()
71
+ if hf_folders and hf_videos and question_folder in hf_videos:
72
+ videos = {}
73
+ method_mapping = {}
74
+
75
+ for display_name, item in hf_videos[question_folder].items():
76
+ # 从item中获取视频路径或内容
77
+ if 'file_content' in item:
78
+ # 如果视频内容直接存储在数据集中
79
+ import tempfile
80
+ with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp:
81
+ tmp.write(item['file_content'])
82
+ videos[display_name] = tmp.name
83
+ elif 'file_path' in item:
84
+ # 如果存储的是路径
85
+ videos[display_name] = item['file_path']
86
+ elif 'path' in item:
87
+ videos[display_name] = item['path']
88
+
89
+ # 创建方法映射(假设能从路径推断真实方法名)
90
+ if 'file_path' in item:
91
+ file_path = item['file_path']
92
+ if 'stage12_new' in file_path:
93
+ method_mapping[display_name] = "Ours (stage12_new)"
94
+ elif 'gen3c' in file_path:
95
+ method_mapping[display_name] = "Gen3c"
96
+ elif 'svc' in file_path:
97
+ method_mapping[display_name] = "SVC"
98
+ elif 'trajattn' in file_path:
99
+ method_mapping[display_name] = "TrajAttn"
100
+
101
+ return videos, method_mapping
102
+
103
+ # 回退到本地文件夹
104
+ video_dir = os.path.join("videos", question_folder)
105
+ videos = {}
106
+ method_mapping = {} # 显示名称映射到真实方法名 / Map display names to real method names
107
+
108
+ if os.path.exists(video_dir):
109
+ for file in os.listdir(video_dir):
110
+ if file.endswith('.mp4'):
111
+ video_path = os.path.join(video_dir, file)
112
+ # 确定方法名称 / Determine method name
113
+ if file.startswith('stage12_new'):
114
+ real_method_name = "Ours (stage12_new)"
115
+ elif file.startswith('gen3c'):
116
+ real_method_name = "Gen3c"
117
+ elif file.startswith('svc'):
118
+ real_method_name = "SVC"
119
+ elif file.startswith('trajattn'):
120
+ real_method_name = "TrajAttn"
121
+ else:
122
+ real_method_name = file.replace('.mp4', '')
123
+
124
+ # 使用匿名显示名称 / Use anonymous display names
125
+ display_name = f"Method {len(videos) + 1}"
126
+ videos[display_name] = video_path
127
+ method_mapping[display_name] = real_method_name
128
+
129
+ return videos, method_mapping
130
+
131
+ # 保存评分数据 / Save rating data
132
+ def save_ratings(current_question, ratings_data, method_mapping):
133
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
134
+ filename = f"ratings_{timestamp}.json"
135
+
136
+ # 将显示名称映射到真实方法名 / Map display names to real method names
137
+ mapped_ratings = {}
138
+ for display_name, ratings in ratings_data.items():
139
+ real_method = method_mapping.get(display_name, display_name)
140
+ mapped_ratings[real_method] = ratings
141
+
142
+ # 读取现有数据 / Read existing data
143
+ all_data = []
144
+ if os.path.exists("ratings_data.json"):
145
+ try:
146
+ with open("ratings_data.json", "r", encoding="utf-8") as f:
147
+ all_data = json.load(f)
148
+ except:
149
+ all_data = []
150
+
151
+ # 添加新数据 / Add new data
152
+ entry = {
153
+ "timestamp": timestamp,
154
+ "question": current_question,
155
+ "ratings": mapped_ratings
156
+ }
157
+ all_data.append(entry)
158
+
159
+ # 保存数据 / Save data
160
+ with open("ratings_data.json", "w", encoding="utf-8") as f:
161
+ json.dump(all_data, f, ensure_ascii=False, indent=2)
162
+
163
+ return f"评分已保存到 {filename}"
164
+
165
+ # 创建Gradio界面 / Create Gradio interface
166
+ def create_video_survey_app():
167
+ question_folders = get_question_folders()
168
+ current_question_idx = gr.State(0)
169
+ all_ratings = gr.State({})
170
+ current_method_mapping = gr.State({})
171
+
172
+ with gr.Blocks(title="视频生成质量用户研究") as demo:
173
+ gr.Markdown("# 视频生成质量用户研究 / Video Generation Quality User Study")
174
+ gr.Markdown("Please rate each video based on dynamic generation quality, static consistency, and overall quality. 对每个视频从动态生成能力、静态物体的一致性、整体质量三方面进行1~5的评分")
175
+ gr.Markdown("Rating scale: 1-5 (5 = Best) 评分等级:1-5分(5分为最好)")
176
+
177
+ with gr.Row():
178
+ prev_btn = gr.Button("上一题 / Previous", visible=False)
179
+ question_text = gr.Markdown(f"问题 1 / {len(question_folders)} / Question 1 / {len(question_folders)}")
180
+ next_btn = gr.Button("下一题 / Next")
181
+
182
+ # 视频显示区域 / Video display area
183
+ with gr.Row():
184
+ video_cols = []
185
+ method_display_names = ["Method 1", "Method 2", "Method 3", "Method 4"]
186
+
187
+ for i, method in enumerate(method_display_names):
188
+ with gr.Column():
189
+ gr.Markdown(f"### {method}")
190
+ video = gr.Video(visible=False)
191
+ video_cols.append(video)
192
+
193
+ # 评分区域 / Rating area
194
+ with gr.Row():
195
+ ratings_cols = []
196
+
197
+ for i, method in enumerate(method_display_names):
198
+ with gr.Column():
199
+ gr.Markdown(f"#### {method} 评分 / Rating")
200
+
201
+ dynamic_quality = gr.Slider(
202
+ minimum=1, maximum=5, step=1, value=3,
203
+ label="Dynamic Generation Quality / 动态生成能力"
204
+ )
205
+ static_consistency = gr.Slider(
206
+ minimum=1, maximum=5, step=1, value=3,
207
+ label="Static Consistency / 静态一致性"
208
+ )
209
+ overall_quality = gr.Slider(
210
+ minimum=1, maximum=5, step=1, value=3,
211
+ label="Overall Quality / 整体质量"
212
+ )
213
+
214
+ ratings_cols.append({
215
+ "dynamic_quality": dynamic_quality,
216
+ "static_consistency": static_consistency,
217
+ "overall_quality": overall_quality
218
+ })
219
+
220
+ status_text = gr.Textbox(label="状态 / Status", interactive=False)
221
+
222
+ # 更新问题显示的函数 / Function to update question display
223
+ def update_question(question_idx):
224
+ if question_idx < 0 or question_idx >= len(question_folders):
225
+ return []
226
+
227
+ question_folder = question_folders[question_idx]
228
+ videos, method_mapping = get_videos_for_question(question_folder)
229
+
230
+ video_outputs = []
231
+ method_display_names = ["Method 1", "Method 2", "Method 3", "Method 4"]
232
+
233
+ for method_display in method_display_names:
234
+ if method_display in videos:
235
+ video_outputs.append(gr.Video(value=videos[method_display], visible=True))
236
+ else:
237
+ video_outputs.append(gr.Video(visible=False))
238
+
239
+ question_markdown = f"问题 {question_idx + 1} / {len(question_folders)}: {question_folder} / Question {question_idx + 1} / {len(question_folders)}: {question_folder}"
240
+
241
+ return video_outputs + [gr.Markdown(question_markdown)] + [gr.State(value=method_mapping)]
242
+
243
+ # 保存当前评分的函数 / Function to save current ratings
244
+ def save_current_ratings(question_idx, method_mapping, *rating_values):
245
+ if question_idx >= len(question_folders):
246
+ return "没有更多问题了 / No more questions"
247
+
248
+ question_folder = question_folders[question_idx]
249
+ method_display_names = ["Method 1", "Method 2", "Method 3", "Method 4"]
250
+
251
+ ratings = {}
252
+ for i, method_display in enumerate(method_display_names):
253
+ base_idx = i * 3
254
+ ratings[method_display] = {
255
+ "dynamic_quality": rating_values[base_idx],
256
+ "static_consistency": rating_values[base_idx + 1],
257
+ "overall_quality": rating_values[base_idx + 2]
258
+ }
259
+
260
+ return save_ratings(question_folder, ratings, method_mapping)
261
+
262
+ # 事件处理 / Event handling
263
+ def on_next_click(question_idx, method_mapping, *rating_values):
264
+ # 先保存当前评分 / First save current ratings
265
+ save_message = save_current_ratings(question_idx, method_mapping, *rating_values)
266
+
267
+ # 移动到下一题 / Move to next question
268
+ new_idx = question_idx + 1
269
+ if new_idx >= len(question_folders):
270
+ return [save_message + "\n所有问题已完成!/ All questions completed!"] + [gr.Button(visible=False)] * 3
271
+
272
+ # 更新显示 / Update display
273
+ video_updates = update_question(new_idx)
274
+
275
+ return [save_message + f"\n当前问题: {question_folders[new_idx]}/ Current question: {question_folders[new_idx]}"] + video_updates
276
+
277
+ def on_prev_click(question_idx):
278
+ new_idx = question_idx - 1
279
+ if new_idx < 0:
280
+ return []
281
+
282
+ return update_question(new_idx)
283
+
284
+ # 收集所有评分组件
285
+ all_rating_components = []
286
+ for col in ratings_cols:
287
+ all_rating_components.extend([
288
+ col["dynamic_quality"],
289
+ col["static_consistency"],
290
+ col["overall_quality"]
291
+ ])
292
+
293
+ # 初始化第一个问题
294
+ initial_videos = update_question(0)
295
+
296
+ # 绑定事件 / Bind events
297
+ next_btn.click(
298
+ on_next_click,
299
+ inputs=[current_question_idx, current_method_mapping] + all_rating_components,
300
+ outputs=[status_text] + video_cols + [question_text] + [current_method_mapping]
301
+ )
302
+
303
+ prev_btn.click(
304
+ on_prev_click,
305
+ inputs=[current_question_idx],
306
+ outputs=video_cols + [question_text] + [current_method_mapping]
307
+ )
308
+
309
+ return demo
310
+
311
+ if __name__ == "__main__":
312
+ app = create_video_survey_app()
313
+ app.launch(share=True)
app_fixed.py ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from datetime import datetime
5
+ from datasets import load_dataset
6
+ import random
7
+
8
+ # 全局变量存储数据集
9
+ DATASET = None
10
+ VIDEO_DATA = None
11
+
12
+ # 从Hugging Face dataset加载视频
13
+ def load_videos_from_huggingface():
14
+ global DATASET, VIDEO_DATA
15
+
16
+ try:
17
+ print("正在加载数据集: WenjiaWang/videoforuser...")
18
+ DATASET = load_dataset("WenjiaWang/videoforuser", split="train")
19
+ print(f"成功加载数据集,共 {len(DATASET)} 个视频")
20
+
21
+ # 组织视频数据:按场景分组
22
+ VIDEO_DATA = {}
23
+
24
+ for idx, item in enumerate(DATASET):
25
+ # 获取视频路径信息
26
+ if 'video' in item:
27
+ video_path = item['video']
28
+ elif 'path' in item:
29
+ video_path = item['path']
30
+ else:
31
+ print(f"警告: 第 {idx} 项没有视频路径字段")
32
+ continue
33
+
34
+ # 从路径中提取场景名和方法名
35
+ # 假设路径格式类似: "videos/scene_name/method.mp4"
36
+ path_parts = video_path.split('/')
37
+ if len(path_parts) >= 2:
38
+ scene_name = path_parts[-2] # 倒数第二部分是场景名
39
+ file_name = path_parts[-1] # 最后部分是文件名
40
+
41
+ # 提取方法名
42
+ method_name = file_name.replace('.mp4', '')
43
+
44
+ if scene_name not in VIDEO_DATA:
45
+ VIDEO_DATA[scene_name] = {}
46
+
47
+ # 存储视频信息(包括在dataset中的索引)
48
+ VIDEO_DATA[scene_name][method_name] = {
49
+ 'index': idx,
50
+ 'path': video_path,
51
+ 'item': item
52
+ }
53
+
54
+ print(f"组织完成,共 {len(VIDEO_DATA)} 个场景")
55
+ return True
56
+
57
+ except Exception as e:
58
+ print(f"加载数据集失败: {e}")
59
+ import traceback
60
+ traceback.print_exc()
61
+ return False
62
+
63
+ # 获取所有场景列表
64
+ def get_question_folders():
65
+ if VIDEO_DATA is None:
66
+ success = load_videos_from_huggingface()
67
+ if not success:
68
+ return []
69
+
70
+ return sorted(list(VIDEO_DATA.keys()))
71
+
72
+ # 获取某个场景的所有视频
73
+ def get_videos_for_question(scene_name):
74
+ if VIDEO_DATA is None or scene_name not in VIDEO_DATA:
75
+ return {}, {}
76
+
77
+ scene_videos = VIDEO_DATA[scene_name]
78
+
79
+ # 创建方法名到真实名称的映射
80
+ method_names = list(scene_videos.keys())
81
+
82
+ # 随机打乱顺序以匿名化
83
+ shuffled_methods = method_names.copy()
84
+ random.shuffle(shuffled_methods)
85
+
86
+ videos = {}
87
+ method_mapping = {}
88
+
89
+ for i, method_name in enumerate(shuffled_methods):
90
+ display_name = f"Method {chr(65+i)}" # Method A, B, C, D
91
+
92
+ # 获取视频数据
93
+ video_info = scene_videos[method_name]
94
+ video_item = video_info['item']
95
+
96
+ # 从dataset item中获取视频文件
97
+ if 'video' in video_item:
98
+ videos[display_name] = video_item['video'] # 这应该是视频文件路径或对象
99
+
100
+ method_mapping[display_name] = method_name
101
+
102
+ return videos, method_mapping
103
+
104
+ # 保存评分数据
105
+ def save_ratings(scene_name, ratings_data, method_mapping):
106
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
107
+
108
+ # 将显示名称映射到真实方法名
109
+ mapped_ratings = {}
110
+ for display_name, ratings in ratings_data.items():
111
+ real_method = method_mapping.get(display_name, display_name)
112
+ mapped_ratings[real_method] = ratings
113
+
114
+ # 读取现有数据
115
+ all_data = []
116
+ if os.path.exists("ratings_data.json"):
117
+ try:
118
+ with open("ratings_data.json", "r", encoding="utf-8") as f:
119
+ all_data = json.load(f)
120
+ except:
121
+ all_data = []
122
+
123
+ # 添加新数据
124
+ entry = {
125
+ "timestamp": timestamp,
126
+ "scene": scene_name,
127
+ "ratings": mapped_ratings
128
+ }
129
+ all_data.append(entry)
130
+
131
+ # 保存数据
132
+ with open("ratings_data.json", "w", encoding="utf-8") as f:
133
+ json.dump(all_data, f, ensure_ascii=False, indent=2)
134
+
135
+ return f"✓ 评分已保存 / Ratings saved"
136
+
137
+ # 创建Gradio界面
138
+ def create_video_survey_app():
139
+ # 预加载数据集
140
+ print("初始化应用...")
141
+ load_videos_from_huggingface()
142
+ question_folders = get_question_folders()
143
+
144
+ if not question_folders:
145
+ print("错误: 没有找到任何场景数据")
146
+ return None
147
+
148
+ print(f"找到 {len(question_folders)} 个场景")
149
+
150
+ with gr.Blocks(title="视频生成质量用户研究", theme=gr.themes.Soft()) as demo:
151
+ gr.Markdown("# 🎬 视频生成质量用户研究 / Video Generation Quality User Study")
152
+ gr.Markdown("""
153
+ ### 说明 / Instructions:
154
+ - ��观看每个视频并进行评分 / Please watch each video and rate them
155
+ - 评分标准 / Rating criteria:
156
+ - **动态生成质量** / Dynamic Generation Quality: 视频中物体运动的流畅性和真实性
157
+ - **静态一致性** / Static Consistency: 视频中静态物体的稳定性和一致性
158
+ - **整体质量** / Overall Quality: 视频的整体观感
159
+ - 评分范围:1-5分(5分最好)/ Rating scale: 1-5 (5 = Best)
160
+ """)
161
+
162
+ # 状态变量
163
+ current_question_idx = gr.State(0)
164
+ current_method_mapping = gr.State({})
165
+
166
+ # 进度显示
167
+ with gr.Row():
168
+ prev_btn = gr.Button("⬅️ 上一题 / Previous", size="sm")
169
+ question_text = gr.Markdown(f"**场景 1 / {len(question_folders)}**")
170
+ next_btn = gr.Button("下一题 / Next ➡️", size="sm", variant="primary")
171
+
172
+ status_text = gr.Textbox(label="状态 / Status", interactive=False, visible=False)
173
+
174
+ # 视频显示区域(4个视频)
175
+ video_components = []
176
+ rating_components = []
177
+
178
+ for i in range(4):
179
+ method_name = f"Method {chr(65+i)}"
180
+
181
+ with gr.Group():
182
+ gr.Markdown(f"### 🎥 {method_name}")
183
+
184
+ video = gr.Video(label="", height=300)
185
+ video_components.append(video)
186
+
187
+ with gr.Row():
188
+ dynamic = gr.Slider(
189
+ minimum=1, maximum=5, step=1, value=3,
190
+ label="动态质量 / Dynamic Quality",
191
+ info="1=差 / Poor, 5=优秀 / Excellent"
192
+ )
193
+ static = gr.Slider(
194
+ minimum=1, maximum=5, step=1, value=3,
195
+ label="静态一致性 / Static Consistency",
196
+ info="1=差 / Poor, 5=优秀 / Excellent"
197
+ )
198
+ overall = gr.Slider(
199
+ minimum=1, maximum=5, step=1, value=3,
200
+ label="整体质量 / Overall Quality",
201
+ info="1=差 / Poor, 5=优秀 / Excellent"
202
+ )
203
+
204
+ rating_components.append({
205
+ "dynamic": dynamic,
206
+ "static": static,
207
+ "overall": overall
208
+ })
209
+
210
+ # 更新问题显示
211
+ def update_question(question_idx, save_previous=False, prev_ratings=None, prev_mapping=None):
212
+ if question_idx < 0:
213
+ question_idx = 0
214
+ if question_idx >= len(question_folders):
215
+ question_idx = len(question_folders) - 1
216
+
217
+ # 如果需要,保存上一题的评分
218
+ save_msg = ""
219
+ if save_previous and prev_ratings and prev_mapping:
220
+ prev_scene = question_folders[question_idx - 1] if question_idx > 0 else None
221
+ if prev_scene:
222
+ save_msg = save_ratings(prev_scene, prev_ratings, prev_mapping)
223
+
224
+ scene_name = question_folders[question_idx]
225
+ videos, method_mapping = get_videos_for_question(scene_name)
226
+
227
+ # 更新视频显示
228
+ video_updates = []
229
+ for i in range(4):
230
+ method_name = f"Method {chr(65+i)}"
231
+ if method_name in videos:
232
+ video_updates.append(gr.Video(value=videos[method_name], visible=True))
233
+ else:
234
+ video_updates.append(gr.Video(value=None, visible=False))
235
+
236
+ # 重置评分
237
+ rating_updates = [gr.Slider(value=3) for _ in range(12)] # 4个视频 x 3个评分
238
+
239
+ question_markdown = f"**场景 {question_idx + 1} / {len(question_folders)}**: `{scene_name}`"
240
+
241
+ return (
242
+ [question_idx, method_mapping, question_markdown, save_msg] +
243
+ video_updates +
244
+ rating_updates
245
+ )
246
+
247
+ # 收集当前评分
248
+ def collect_ratings(*rating_values):
249
+ ratings = {}
250
+ for i in range(4):
251
+ method_name = f"Method {chr(65+i)}"
252
+ base_idx = i * 3
253
+ ratings[method_name] = {
254
+ "dynamic_quality": rating_values[base_idx],
255
+ "static_consistency": rating_values[base_idx + 1],
256
+ "overall_quality": rating_values[base_idx + 2]
257
+ }
258
+ return ratings
259
+
260
+ # 下一题按钮
261
+ def on_next(question_idx, method_mapping, *rating_values):
262
+ # 收集当前评分
263
+ current_ratings = collect_ratings(*rating_values)
264
+
265
+ # 保存当前评分
266
+ scene_name = question_folders[question_idx]
267
+ save_msg = save_ratings(scene_name, current_ratings, method_mapping)
268
+
269
+ # 移动到下一题
270
+ new_idx = question_idx + 1
271
+ if new_idx >= len(question_folders):
272
+ return [
273
+ question_idx,
274
+ method_mapping,
275
+ f"**✅ 所有场景已完成!/ All scenes completed!**",
276
+ save_msg + "\n🎉 感谢参与!/ Thank you for participating!"
277
+ ] + [gr.Video()] * 4 + [gr.Slider(value=3)] * 12
278
+
279
+ return update_question(new_idx)
280
+
281
+ # 上一题按钮
282
+ def on_prev(question_idx, *args):
283
+ new_idx = question_idx - 1
284
+ if new_idx < 0:
285
+ new_idx = 0
286
+ return update_question(new_idx)
287
+
288
+ # 收集所有评分组件
289
+ all_rating_inputs = []
290
+ for comp in rating_components:
291
+ all_rating_inputs.extend([comp["dynamic"], comp["static"], comp["overall"]])
292
+
293
+ # 绑定事件
294
+ next_btn.click(
295
+ on_next,
296
+ inputs=[current_question_idx, current_method_mapping] + all_rating_inputs,
297
+ outputs=[
298
+ current_question_idx,
299
+ current_method_mapping,
300
+ question_text,
301
+ status_text
302
+ ] + video_components + all_rating_inputs
303
+ )
304
+
305
+ prev_btn.click(
306
+ on_prev,
307
+ inputs=[current_question_idx] + all_rating_inputs,
308
+ outputs=[
309
+ current_question_idx,
310
+ current_method_mapping,
311
+ question_text,
312
+ status_text
313
+ ] + video_components + all_rating_inputs
314
+ )
315
+
316
+ # 初始化第一个问题
317
+ demo.load(
318
+ lambda: update_question(0),
319
+ outputs=[
320
+ current_question_idx,
321
+ current_method_mapping,
322
+ question_text,
323
+ status_text
324
+ ] + video_components + all_rating_inputs
325
+ )
326
+
327
+ return demo
328
+
329
+ if __name__ == "__main__":
330
+ app = create_video_survey_app()
331
+ if app:
332
+ app.launch(server_name="0.0.0.0", server_port=7860, share=False)
333
+ else:
334
+ print("应用初始化失败 / App initialization failed")
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ datasets>=2.14.0
3
+ huggingface_hub>=0.19.0
4
+ torchcodec
upload_to_hf.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ 上传文件到 Hugging Face Space
4
+ """
5
+ from huggingface_hub import HfApi, login
6
+ import os
7
+
8
+ # 你需要在这里输入你的 Hugging Face token
9
+ # 获取 token: https://huggingface.co/settings/tokens
10
+ TOKEN = input("请输入你的 Hugging Face token: ").strip()
11
+
12
+ if not TOKEN:
13
+ print("❌ 错误: 需要提供 token")
14
+ print("请访问 https://huggingface.co/settings/tokens 获取 token")
15
+ exit(1)
16
+
17
+ # 登录
18
+ print("正在登录...")
19
+ login(token=TOKEN)
20
+
21
+ # 初始化 API
22
+ api = HfApi()
23
+
24
+ # Space 信息
25
+ repo_id = "WenjiaWang/userstudy"
26
+ repo_type = "space"
27
+
28
+ print(f"\n📤 准备上传文件到 {repo_id}...")
29
+
30
+ # 要上传的文件
31
+ files_to_upload = [
32
+ "app.py",
33
+ "requirements.txt",
34
+ ]
35
+
36
+ # 上传每个文件
37
+ for file_name in files_to_upload:
38
+ if os.path.exists(file_name):
39
+ print(f" ⬆️ 上传 {file_name}...")
40
+ try:
41
+ api.upload_file(
42
+ path_or_fileobj=file_name,
43
+ path_in_repo=file_name,
44
+ repo_id=repo_id,
45
+ repo_type=repo_type,
46
+ commit_message=f"Upload {file_name}"
47
+ )
48
+ print(f" ✅ {file_name} 上传成功")
49
+ except Exception as e:
50
+ print(f" ❌ {file_name} 上传失败: {e}")
51
+ else:
52
+ print(f" ⚠️ 文件不存在: {file_name}")
53
+
54
+ print(f"\n🎉 完成!请访问: https://huggingface.co/spaces/{repo_id}")
55
+ print("Space 会自动构建和启动,可能需要几分钟时间。")