Spaces:
Sleeping
Sleeping
File size: 24,878 Bytes
87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 87b4d1f 8134208 ffa503d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
import gradio as gr
import os
import json
import pandas as pd
from huggingface_hub import HfApi
# ==============================================================================
# 数据定义 (Data Definition)
# ==============================================================================
DIMENSIONS_DATA = [
{
"title": "语义和语用特征",
"audio": "audio/sample1.wav",
"desc": "这是“语义和语用特征”维度的文本描述示例。",
"sub_dims": [
"记忆一致性:回应者是否能够正确并正确并延续并记忆并延续对话信息?是否存在对上下文的误解或不自洽?", "逻辑连贯性:回应者在语义与对话结构上保持前后一致、合乎逻辑?是否存在前后矛盾的情况?",
"常见多音字处理:是否能再上下文中正确使用常见多音字?", "多语言混杂:是否存在自然的语言切换现象?如中英混杂、文化化表达。",
"语言不精确性:是否出现打断、自纠正等人类似语言行为?是否存在如“差不多”、“可能吧”这类表达不确定性的用法?", "填充词使用:如“呃”、“嗯”等自然语流中的停顿或过渡词,使用是否得体且自然?",
"隐喻与语用用意:是否展现出复杂的语用功能(如讽刺、劝阻、暗示等),以及对活在含义层次的理解能力?"
],
"reference":"""
<p>🔴 <strong>记忆一致性:</strong> 在说话人明确提出自己已经中年后,回应者仍做出了他是青少年的错误假定</p>
<p>🔴 <strong>逻辑连贯性:</strong> 回应者在第一轮对话中说他说的话并不重要,但在第二轮对话中说他说的话“能够改变你的一生”</p>
<p>🔴 <strong>常见多音字处理:</strong> 该条对话中未出现多音字</p>
<p>🟢 <strong>多语言混杂:</strong> 回应者在回复中夹杂了"I see",回复中存在多语言混杂</p>
<p>🔴 <strong>语言不精确性:</strong> 回应者使用的语言中未夹杂任何的不确定性</p>
<p>🟢 <strong>填充词使用:</strong> 回应者在回复中使用了“嗯”这个填充词</p>
<p>🔴 <strong>隐喻与语用用意:</strong> 回应者误将说话人的挖苦当成了真心的赞扬</p>
"""
},
{
"title": "非生理性副语言特征",
"audio": "audio/sample1.wav",
"desc": "这是“非生理性副语言特征”维度的文本描述示例。",
"sub_dims": [
"节奏:回应者是否存在自然的停顿?语速是否存在自然、流畅的变化?", "语调:在表达疑问、惊讶、强调时,回应者的音调是否会自然上扬或下降?是否表现出符合语境的变化?",
"重读:是否存在句中关键词上有意识地加重语气?", "辅助性发声:是否存在叹气、短哼、笑声等辅助情绪的非语言性发声?这些发声是否在语境中正确表达了情绪或意图?"
],
"reference": """
<p>🟢 <strong>节奏:</strong> 回应者的语速变化、停顿都较为自然</p>
<p>🔴 <strong>语调:</strong> 回应者的音调不存在显著变化</p>
<p>🔴 <strong>重读:</strong> 回应者语气不存在显著变化</p>
<p>🔴 <strong>辅助性发声:</strong> 尽管回应者发出了叹气的声音,但是该发声并未传递出语境下应有的失落情堵</p>
"""
},
{
"title": "生理性副语言特征",
"audio": "audio/sample1.wav",
"desc": "这是“生理性副语言特征”维度的文本描述示例。",
"sub_dims": [
"微生理杂音:回应中是否出现如呼吸声、口水音、气泡音等无意识发声?这些发声是否自然地穿插在恰当的语流节奏当中?",
"发音不稳定性:回应者是否出现连读、颤音、鼻音等不稳定发音?", "口音:(如果存在的话)回应者的口音是否自然?是否存在机械式的元辅音发音风格?"
],
"reference": """
<p>🔴 <strong>微生理杂音:</strong> 回应中不存在任何无意识发声</p>
<p>🔴 <strong>发音不稳定性:</strong> 回应者的咬字清晰、发音标准</p>
<p>🟢 <strong>口音:</strong> 回应者的口音自然</p>
"""
},
{
"title": "机械人格",
"audio": "audio/sample1.wav",
"desc": "这是“机械人格”维度的文本描述示例。",
"sub_dims": [
"谄媚现象:回应者是否频繁地赞同用户、重复用户的说法、不断表示感谢或道歉?是否存在“无论用户说什么都肯定或支持”的语气模式?",
"书面化表达:回应的内容是否缺乏口语化特征?句式是否整齐划一、结构完整却缺乏真实交流中的松散感或灵活性?是否使用抽象或泛泛的措辞来回避具体问题?"
],
"reference": """
<p>🟢 <strong>谄媚现象:</strong> 回应者并未明显表现出谄媚现象的特征</p>
<p>🔴 <strong>书面化表达:</strong> 回应的内容结构过于缜密,符合书面用语特征</p>
"""
},
{
"title": "情感表达",
"audio": "audio/sample1.wav",
"desc": "这是“情感表达”维度的文本描述示例。",
"sub_dims": [
"语义层面:回应者的语言内容是否体现出符合上下文的情绪反应?是否表达了人类对某些情境应有的情感态度?",
"声学层面:回应者的声音情绪是否与语义一致?语调是否有自然的高低起伏来表达情绪变化?是否出现回应内容与声音传达出的情绪不吻合的现象?"
],
"reference": """
<p>🔴 <strong>语义层面:</strong> 说话者阐述了一件伤心的事情,而回应者的语言内容中体现出了恰当的悲伤情绪</p>
<p>🟢 <strong>声学层面:</strong> 回应者的语音特征与情感表达不匹配。语言内容中表达出了悲伤的情感,但语音特征平淡、缺少变化</p>
"""
}
]
DIMENSION_TITLES = [d["title"] for d in DIMENSIONS_DATA]
QUESTION_SET = [
{"audio": "audio/Ses02F_impro01.wav", "desc": "这是第一个测试文件的描述",},
{"audio": "audio/Ses02F_impro02.wav", "desc": "这是第二个测试文件的描述",},
{"audio": "audio/Ses02F_impro03.wav", "desc": "这是第三个测试文件的描述",},
]
MAX_SUB_DIMS = max(len(d['sub_dims']) for d in DIMENSIONS_DATA)
# ==============================================================================
# 功能函数定义 (Function Definitions)
# ==============================================================================
def start_challenge():
return gr.update(visible=False), gr.update(visible=True)
def toggle_education_other(choice):
is_other = (choice == "其他(请注明)")
return gr.update(visible=is_other, interactive=is_other, value="")
def check_info_complete(age, gender, education, education_other):
if age and gender and education:
if education == "其他(请注明)" and not education_other.strip():
return gr.update(interactive=False)
return gr.update(interactive=True)
return gr.update(interactive=False)
def show_sample_page_and_init(age, gender, education, education_other, user_data):
final_edu = education_other if education == "其他(请注明)" else education
user_data.update({"age": age, "gender": gender, "education": final_edu})
first_dim_title = DIMENSION_TITLES[0]
return gr.update(visible=False), gr.update(visible=True), user_data, first_dim_title
def update_sample_view(dimension_title):
dim_data = next((d for d in DIMENSIONS_DATA if d["title"] == dimension_title), None)
if dim_data:
return (
gr.update(value=dim_data["audio"]),
gr.update(value=dim_data["desc"]),
gr.update(choices=dim_data["sub_dims"], value=[], interactive=True),
gr.update(value=dim_data["reference"])
)
return gr.update(), gr.update(), gr.update(), gr.update()
def update_test_dimension_view(d_idx, selections):
dimension = DIMENSIONS_DATA[d_idx]
progress_d = f"维度 {d_idx + 1} / {len(DIMENSIONS_DATA)}: **{dimension['title']}**"
existing_scores = selections.get(dimension['title'], {})
slider_updates = []
for i in range(MAX_SUB_DIMS):
if i < len(dimension['sub_dims']):
sub_dim_label = dimension['sub_dims'][i]
value = existing_scores.get(sub_dim_label, 0)
slider_updates.append(gr.update(visible=True, label=sub_dim_label, value=value))
else:
slider_updates.append(gr.update(visible=False, value=0))
prev_btn_update = gr.update(interactive=(d_idx > 0))
next_btn_update = gr.update(
value="进入最终判断" if d_idx == len(DIMENSIONS_DATA) - 1 else "下一维度",
interactive=True
)
return [gr.update(value=progress_d), prev_btn_update, next_btn_update] + slider_updates
def init_test_question(user_data, q_idx):
d_idx = 0
question = QUESTION_SET[q_idx]
progress_q = f"第 {q_idx + 1} / {len(QUESTION_SET)} 题"
initial_updates = update_test_dimension_view(d_idx, {})
dim_title_update, prev_btn_update, next_btn_update = initial_updates[:3]
slider_updates = initial_updates[3:]
return (
gr.update(visible=False),
gr.update(visible=True),
gr.update(visible=False),
gr.update(visible=False),
q_idx, d_idx, {},
gr.update(value=progress_q),
dim_title_update,
gr.update(value=question['audio']),
gr.update(value=question['desc']),
prev_btn_update,
next_btn_update,
gr.update(interactive=False),
gr.update(interactive=False),
) + tuple(slider_updates)
def navigate_dimensions(direction, q_idx, d_idx, selections, *slider_values):
current_dim_data = DIMENSIONS_DATA[d_idx]
current_sub_dims = current_dim_data['sub_dims']
scores = {sub_dim: slider_values[i] for i, sub_dim in enumerate(current_sub_dims)}
selections[current_dim_data['title']] = scores
new_d_idx = d_idx + (1 if direction == "next" else -1)
if direction == "next" and d_idx == len(DIMENSIONS_DATA) - 1:
return (
gr.update(visible=False),
gr.update(visible=True),
q_idx, d_idx, selections,
gr.update(),
gr.update(value=""),
gr.update(),
gr.update(),
gr.update(interactive=True),
gr.update(interactive=True),
gr.update(interactive=False),
gr.update(value="下一维度", interactive=False),
) + (gr.update(),) * MAX_SUB_DIMS
else:
view_updates = update_test_dimension_view(new_d_idx, selections)
dim_title_update, prev_btn_update, next_btn_update = view_updates[:3]
slider_updates = view_updates[3:]
return (
gr.update(), gr.update(),
q_idx, new_d_idx, selections,
gr.update(),
dim_title_update,
gr.update(),
gr.update(),
gr.update(interactive=False),
gr.update(interactive=False),
prev_btn_update,
next_btn_update,
) + tuple(slider_updates)
def submit_question_and_advance(q_idx, d_idx, selections, final_choice, all_results, user_data):
selections["final_choice"] = final_choice
final_question_result = {
"question_id": q_idx, "audio_file": QUESTION_SET[q_idx]['audio'],
"user_data": user_data, "selections": selections
}
all_results.append(final_question_result)
q_idx += 1
if q_idx < len(QUESTION_SET):
init_q_updates = init_test_question(user_data, q_idx)
return init_q_updates + (all_results, gr.update(value=""))
else:
result_str = "### 测试全部完成!\n\n你的提交结果概览:\n"
for res in all_results:
result_str += f"\n#### 题目: {res['audio_file']}\n"
result_str += f"##### 最终判断: **{res['selections'].get('final_choice', '未选择')}**\n"
for dim_title, dim_data in res['selections'].items():
if dim_title == 'final_choice': continue
result_str += f"- **{dim_title}**:\n"
for sub_dim, score in dim_data.items():
result_str += f" - *{sub_dim[:20]}...*: {score}/5\n"
# This function now handles the upload to Hugging Face
save_all_results_to_file(all_results, user_data)
return (
gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True),
q_idx, d_idx, {},
gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(),
gr.update(), gr.update(),
) + (gr.update(),) * MAX_SUB_DIMS + (all_results, result_str)
# MODIFIED FUNCTION TO SAVE TO HUGGING FACE DATASET
def save_all_results_to_file(all_results, user_data):
"""
Packages results and uploads them as a single JSON file to a Hugging Face Dataset.
"""
# IMPORTANT: Change this to your Hugging Face username and dataset repo name
repo_id = "Hu6ery/Turing-Test-Submissions"
# Create a unique filename for the submission
username = user_data.get("age", "user")
filename = f"submission_{username}_{pd.Timestamp.now().strftime('%Y%m%d_%H%M%S')}.json"
# Package all data into a single dictionary
final_data_package = {
"user_info": user_data,
"results": all_results
}
# Convert the dictionary to a JSON string in memory
json_string = json.dumps(final_data_package, ensure_ascii=False, indent=4)
# Get the Hugging Face token from the environment secrets
hf_token = os.getenv("HF_TOKEN")
if not hf_token:
print("HF_TOKEN not found. Cannot upload to the Hub. Please set it in Space secrets.")
return
try:
# Instantiate the HfApi client
api = HfApi()
# Upload the JSON string as a file to the specified dataset repository
api.upload_file(
path_or_fileobj=bytes(json_string, "utf-8"),
path_in_repo=f"data/{filename}", # We recommend saving to a subfolder
repo_id=repo_id,
repo_type="dataset",
token=hf_token,
commit_message=f"Add new submission from {username}"
)
print(f"Successfully uploaded results to dataset: {repo_id}")
except Exception as e:
print(f"Error uploading to Hugging Face Hub: {e}")
def toggle_reference_view(current):
if current == "参考": return gr.update(visible=False), gr.update(visible=True), gr.update(value="返回")
else: return gr.update(visible=True), gr.update(visible=False), gr.update(value="参考")
def back_to_welcome():
return (
gr.update(visible=True), {}, 0, 0, {}, [],
gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
)
# ==============================================================================
# Gradio 界面定义 (Gradio UI Definition)
# ==============================================================================
with gr.Blocks(theme=gr.themes.Soft(), css=".gradio-container {max-width: 960px !important}") as demo:
# --- 状态变量 (State Variables) ---
user_data_state = gr.State({})
current_question_index = gr.State(0)
current_test_dimension_index = gr.State(0)
current_question_selections = gr.State({})
test_results = gr.State([])
# --- 页面 (Pages) ---
welcome_page = gr.Column(visible=True)
info_page = gr.Column(visible=False)
sample_page = gr.Column(visible=False)
pretest_page = gr.Column(visible=False)
test_page = gr.Column(visible=False)
final_judgment_page = gr.Column(visible=False)
result_page = gr.Column(visible=False)
pages = {
"welcome": welcome_page, "info": info_page, "sample": sample_page,
"pretest": pretest_page, "test": test_page, "final_judgment": final_judgment_page,
"result": result_page
}
with welcome_page:
gr.Markdown("# AI 识破者\n你将听到一系列对话,请判断哪个回应者是 AI。")
start_btn = gr.Button("开始挑战", variant="primary")
with info_page:
gr.Markdown("## 请提供一些基本信息")
age_input = gr.Radio(["18岁以下", "18-25岁", "26-35岁", "36-50岁", "50岁以上"], label="年龄")
gender_input = gr.Radio(["男", "女", "其他"], label="性别")
education_input = gr.Radio(["高中及以下", "本科", "硕士", "博士", "其他(请注明)"], label="学历")
education_other_input = gr.Textbox(label="请填写你的学历", visible=False, interactive=False)
submit_info_btn = gr.Button("提交并开始学习样例", variant="primary", interactive=False)
with sample_page:
gr.Markdown("## 样例分析\n请选择一个维度进行学习。所有维度共用同一个样例音频。")
sample_dimension_selector = gr.Radio(DIMENSION_TITLES, label="选择学习维度", value=DIMENSION_TITLES[0])
with gr.Row():
with gr.Column(scale=1):
sample_audio = gr.Audio(label="样例音频", value=DIMENSIONS_DATA[0]["audio"])
sample_desc = gr.Textbox(label="文本描述", interactive=False, value=DIMENSIONS_DATA[0]["desc"])
with gr.Column(scale=2):
with gr.Column(visible=True) as interactive_view:
interactive_checkbox_group = gr.CheckboxGroup(label="维度特征", choices=DIMENSIONS_DATA[0]["sub_dims"], interactive=True)
with gr.Column(visible=False) as reference_view:
gr.Markdown("### 参考答案解析")
reference_text = gr.Markdown(value=DIMENSIONS_DATA[0]["reference"])
reference_btn = gr.Button("参考")
go_to_pretest_btn = gr.Button("我明白了,开始测试", variant="primary")
with pretest_page:
gr.Markdown("## 测试说明\n"
"- 对于每一道题,你都需要对全部 **5 个维度** 进行评估。\n"
"- 在每个维度下,请为出现的每个特征 **从0到5打分**。\n"
"- 完成5个维度的打分后,你将需要做出“人类”或“机器人”的 **最终判断**。\n"
"- 你可以使用“上一维度”和“下一维度”按钮在5个维度间自由切换和修改分数。")
go_to_test_btn = gr.Button("开始测试", variant="primary")
with test_page:
gr.Markdown("## 正式测试")
question_progress_text = gr.Markdown()
test_dimension_title = gr.Markdown()
test_audio = gr.Audio(label="测试音频")
test_desc = gr.Textbox(label="文本描述", interactive=False)
gr.Markdown("--- \n ### 请为以下特征打分 (0-5分)")
test_sliders = [gr.Slider(minimum=0, maximum=5, step=1, label=f"Sub-dim {i+1}", visible=False, interactive=True) for i in range(MAX_SUB_DIMS)]
with gr.Row():
prev_dim_btn = gr.Button("上一维度")
next_dim_btn = gr.Button("下一维度", variant="primary")
with final_judgment_page:
gr.Markdown("## 最终判断")
gr.Markdown("您已完成对所有维度的评分。请根据您的综合印象,做出最终判断。")
final_human_robot_radio = gr.Radio(["👤 人类", "🤖 机器人"], label="请判断回应者类型 (必填)", interactive=False)
submit_final_answer_btn = gr.Button("提交本题答案", variant="primary", interactive=False)
with result_page:
gr.Markdown("## 测试完成")
result_text = gr.Markdown()
back_to_welcome_btn = gr.Button("返回主界面", variant="primary")
# ==============================================================================
# 事件绑定 (Event Binding) & IO 列表定义
# ==============================================================================
test_init_outputs = [
pretest_page, test_page, final_judgment_page, result_page,
current_question_index, current_test_dimension_index, current_question_selections,
question_progress_text, test_dimension_title, test_audio, test_desc,
prev_dim_btn, next_dim_btn,
final_human_robot_radio, submit_final_answer_btn,
] + test_sliders
nav_inputs = [current_question_index, current_test_dimension_index, current_question_selections] + test_sliders
nav_outputs = [
test_page, final_judgment_page,
current_question_index, current_test_dimension_index, current_question_selections,
question_progress_text, test_dimension_title, test_audio, test_desc,
final_human_robot_radio, submit_final_answer_btn,
prev_dim_btn, next_dim_btn,
] + test_sliders
full_outputs_with_results = test_init_outputs + [test_results, result_text]
start_btn.click(fn=start_challenge, outputs=[welcome_page, info_page])
for comp in [age_input, gender_input, education_input, education_other_input]:
comp.change(fn=check_info_complete, inputs=[age_input, gender_input, education_input, education_other_input], outputs=submit_info_btn)
education_input.change(fn=toggle_education_other, inputs=education_input, outputs=education_other_input)
submit_info_btn.click(fn=show_sample_page_and_init, inputs=[age_input, gender_input, education_input, education_other_input, user_data_state], outputs=[info_page, sample_page, user_data_state, sample_dimension_selector])
sample_dimension_selector.change(fn=update_sample_view, inputs=sample_dimension_selector, outputs=[sample_audio, sample_desc, interactive_checkbox_group, reference_text])
reference_btn.click(fn=toggle_reference_view, inputs=reference_btn, outputs=[interactive_view, reference_view, reference_btn])
go_to_pretest_btn.click(lambda: (gr.update(visible=False), gr.update(visible=True)), outputs=[sample_page, pretest_page])
go_to_test_btn.click(
fn=lambda user: init_test_question(user, 0) + ([], gr.update()),
inputs=[user_data_state],
outputs=full_outputs_with_results
)
prev_dim_btn.click(
fn=lambda q,d,s, *sliders: navigate_dimensions("prev", q,d,s, *sliders),
inputs=nav_inputs, outputs=nav_outputs
)
next_dim_btn.click(
fn=lambda q,d,s, *sliders: navigate_dimensions("next", q,d,s, *sliders),
inputs=nav_inputs, outputs=nav_outputs
)
submit_final_answer_btn.click(
fn=submit_question_and_advance,
inputs=[current_question_index, current_test_dimension_index, current_question_selections, final_human_robot_radio, test_results, user_data_state],
outputs=full_outputs_with_results
)
back_to_welcome_btn.click(fn=back_to_welcome, outputs=list(pages.values()) + [user_data_state, current_question_index, current_test_dimension_index, current_question_selections, test_results])
# ==============================================================================
# 程序入口 (Entry Point)
# ==============================================================================
if __name__ == "__main__":
if not os.path.exists("audio"):
os.makedirs("audio")
# A quick check to see if we're in a deployed Space, to avoid local errors.
if "SPACE_ID" in os.environ:
print("Running in a Hugging Face Space, checking for audio files...")
# In a real deployment, you'd ensure the audio files are in the repo.
# This is just a placeholder check.
all_files = [q["audio"] for q in QUESTION_SET] + [d["audio"] for d in DIMENSIONS_DATA]
for audio_file in set(all_files):
if not os.path.exists(audio_file):
print(f"⚠️ Warning: Audio file not found: {audio_file}")
demo.launch(debug=True) |