朱东升 commited on
Commit
edf1ecb
·
1 Parent(s): 890be77
Files changed (1) hide show
  1. app.py +300 -182
app.py CHANGED
@@ -28,12 +28,18 @@ completed_tasks = []
28
  task_id_counter = 0
29
  task_lock = threading.Lock()
30
  last_update_time = datetime.now() # 替换update_event为时间戳跟踪
 
 
 
31
 
32
  def trigger_ui_update():
33
  """触发UI更新事件"""
34
- global last_update_time
35
  with task_lock:
36
- last_update_time = datetime.now() # 更新时间戳而不是使用Event
 
 
 
37
 
38
  def get_next_task_id():
39
  global task_id_counter
@@ -126,32 +132,53 @@ def process_task_queue():
126
 
127
  # 更新任务状态
128
  with task_lock:
129
- active_tasks[task_id]["status"] = "processing"
130
- trigger_ui_update() # 状态变更为处理中时更新UI
 
 
 
 
 
 
131
 
132
  # 处理任务
 
133
  result = evaluate(task_info["data"])
 
134
 
135
  # 更新任务结果
136
  with task_lock:
137
- active_tasks[task_id]["status"] = "completed"
138
- active_tasks[task_id]["completed_at"] = datetime.now()
139
- active_tasks[task_id]["result"] = result
140
-
141
- # 将任务移至已完成列表
142
- completed_tasks.append(active_tasks[task_id])
143
- del active_tasks[task_id]
144
-
145
- # 保留最近的20个已完成任务
146
- if len(completed_tasks) > 20:
147
- completed_tasks.pop(0)
148
-
149
- trigger_ui_update() # 任务完成时更新UI
 
 
 
 
 
 
 
 
 
 
 
150
 
151
  task_queue.task_done()
152
 
153
  except Exception as e:
154
- print(f"Error processing task queue: {str(e)}")
 
 
155
  time.sleep(1)
156
 
157
  def evaluate(input_data):
@@ -317,7 +344,9 @@ def get_queue_status():
317
  "completed_at": task["completed_at"].strftime("%Y-%m-%d %H:%M:%S") if "completed_at" in task else "",
318
  "duration": str(task["completed_at"] - task["submitted_at"]) if "completed_at" in task else ""
319
  } for task in completed_tasks[-5:] # 只显示最近5个完成的任务
320
- ]
 
 
321
  }
322
 
323
  def render_queue_status():
@@ -439,9 +468,20 @@ def render_queue_status():
439
  return html
440
 
441
  def refresh_ui():
442
- """定期刷新UI函数"""
443
- # 不再需要等待事件,直接返回最新状态
444
- return render_queue_status()
 
 
 
 
 
 
 
 
 
 
 
445
 
446
  def submit_json_data(json_data):
447
  """提交JSON数据处理接口"""
@@ -452,14 +492,63 @@ def submit_json_data(json_data):
452
  else:
453
  data = json_data
454
 
 
 
 
 
455
  result = submit_task(data)
456
  response = json.dumps(result, ensure_ascii=False, indent=2)
457
 
 
 
 
 
 
458
  # 返回任务提交结果和最新的队列状态
459
- return response, render_queue_status()
 
460
  except Exception as e:
 
461
  return json.dumps({"status": "error", "message": str(e)}, ensure_ascii=False, indent=2), render_queue_status()
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  # 创建Gradio接口
464
  with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
465
  gr.Markdown("""
@@ -467,9 +556,31 @@ with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
467
  ### 支持多种编程语言的代码评估服务
468
  """)
469
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  with gr.Tab("任务队列状态"):
471
  status_html = gr.HTML(render_queue_status)
 
472
  refresh_button = gr.Button("刷新状态")
 
473
 
474
  # 根据Gradio版本使用不同的事件注册方法
475
  if 'gradio_version' not in locals():
@@ -478,129 +589,116 @@ with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
478
 
479
  if gradio_version.startswith("3."):
480
  # Gradio 3.x 方式
481
- refresh_button.click(fn=refresh_ui, outputs=status_html, concurrency_limit=2)
482
  else:
483
  # Gradio 4.x 方式 (不使用concurrency_limit参数)
484
- refresh_button.click(fn=refresh_ui, outputs=status_html)
485
-
486
- # 使用正确的轮询方式替代
487
- dummy_input = gr.Textbox(value="", visible=False)
488
-
489
- # We'll rely on the JavaScript solution below for auto-refresh
490
- # The refresh button still works for manual refresh
491
-
492
- # JavaScript-based auto-refresh solution
493
- gr.HTML("""
 
 
 
 
 
 
 
 
494
  <script>
495
- // 兼容Gradio 3.x和4.x的自动刷新机制
496
- function setupAutoRefresh() {
497
- // 在HF Spaces中更保守的刷新间隔,避免过多请求
498
- const refreshInterval = 3000; // 3秒刷新一次
499
- let lastTaskCount = 0;
500
- let consecutiveNoChange = 0;
 
501
 
502
- // 查找刷新按钮并模拟点击
503
- function autoRefresh() {
504
- try {
505
- // 兼容Gradio 3.x和4.x的按钮查找方法
506
- const buttons = document.querySelectorAll('button');
507
- let refreshButton = null;
508
-
509
- // 尝试通过文本查找按钮
510
- for (const button of buttons) {
511
- if (button.textContent === '刷新状态' ||
512
- button.textContent.includes('刷新') ||
513
- button.innerHTML.includes('刷新状态')) {
514
- refreshButton = button;
515
- break;
516
- }
517
- }
518
 
519
- // 如果没找到,尝试查找第一个标签页中的第一个按钮
520
- if (!refreshButton) {
521
- const firstTab = document.querySelector('.tabitem');
522
- if (firstTab) {
523
- const firstTabButton = firstTab.querySelector('button');
524
- if (firstTabButton) {
525
- refreshButton = firstTabButton;
526
- }
527
- }
528
- }
529
-
530
- // 如果找到按钮,模拟点击
531
  if (refreshButton) {
532
  refreshButton.click();
533
- console.log("自动刷新已触发");
534
- } else {
535
- console.warn("未找到刷新按钮");
536
- // 如果找不到按钮,尝试重新加载整个页面
537
- // 但要限制频率,避免无限刷新
538
- if (consecutiveNoChange > 10) {
539
- console.log("长时间未找到刷新按钮,刷新页面");
540
- location.reload();
541
- return;
542
- }
543
  }
544
-
545
- // Gradio 3.x和4.x中检查任务数量变化
546
- setTimeout(() => {
547
- // 尝试不同的选择器来适配不同版本
548
- const tables = document.querySelectorAll('table');
549
- let activeTasks = [];
550
 
551
- if (tables.length > 0) {
552
- // 在所有表格中查找行
553
- for (const table of tables) {
554
- const rows = table.querySelectorAll('tbody tr');
555
- if (rows.length > 0) {
556
- activeTasks = rows;
557
- break;
558
- }
559
- }
560
- }
561
-
562
- const currentTaskCount = activeTasks.length || 0;
563
 
564
- if (currentTaskCount === lastTaskCount) {
565
- consecutiveNoChange++;
566
- } else {
567
- consecutiveNoChange = 0;
 
 
 
 
 
 
 
 
568
  }
569
-
570
- lastTaskCount = currentTaskCount;
571
- }, 500);
572
- } catch (e) {
573
- console.error("自动刷新错误:", e);
574
- }
575
- }
576
-
577
- // 周期性检查刷新,确保即使在HF Spaces资源受限情况下也能工作
578
- let refreshTimer = setInterval(autoRefresh, refreshInterval);
579
-
580
- // 确保页面可见性变化时刷新机制正常工作
581
- document.addEventListener('visibilitychange', function() {
582
- if (document.visibilityState === 'visible') {
583
- // 页面变为可见时立即刷新一次
584
- autoRefresh();
585
- // 如果计时器被清除,重新创建
586
- if (!refreshTimer) {
587
- refreshTimer = setInterval(autoRefresh, refreshInterval);
588
  }
589
  }
590
- });
 
 
591
 
592
- // 设置首次加载时立即刷新一次,但稍微延迟确保DOM已加载
593
- setTimeout(autoRefresh, 500);
594
  }
595
 
596
- // 确保在DOM完全加载后运行
597
  if (document.readyState === 'loading') {
598
- document.addEventListener('DOMContentLoaded', setupAutoRefresh);
599
  } else {
600
- setupAutoRefresh();
601
  }
 
 
 
 
 
 
 
 
 
602
  </script>
603
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
604
 
605
  with gr.Tab("提交新任务"):
606
  with gr.Row():
@@ -677,18 +775,8 @@ with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
677
  ```
678
  """)
679
 
680
- # 添加API端点
681
- with gr.Row(visible=False):
682
- api_input = gr.JSON()
683
- api_output = gr.JSON()
684
-
685
- # 根据Gradio版本使用不同的事件注册方法
686
- if gradio_version.startswith("3."):
687
- # Gradio 3.x 方式
688
- api_input.change(fn=evaluate, inputs=api_input, outputs=api_output, concurrency_limit=2)
689
- else:
690
- # Gradio 4.x 方式
691
- api_input.change(fn=evaluate, inputs=api_input, outputs=api_output)
692
 
693
  if __name__ == "__main__":
694
  # 检测Gradio版本以适配不同版本的API
@@ -696,78 +784,108 @@ if __name__ == "__main__":
696
  gradio_version = getattr(gradio, "__version__", "unknown")
697
  print(f"当前Gradio版本: {gradio_version}")
698
 
 
 
 
 
 
699
  try:
700
- # 设置队列,并添加API支持
701
- try:
702
- # 根据Gradio版本使用不同的队列配置
703
- if gradio_version.startswith("3."):
704
- # Gradio 3.x 版本
705
- demo.queue(api_open=True, max_size=30)
706
- else:
707
- # Gradio 4.x 或更高版本可能有不同的队列API
708
- try:
709
- # 尝试新版本的queue方法
710
- demo.queue(api_name="/api", max_size=30)
711
- except:
712
- # 如果失败,尝试不带参数的queue方法
713
- demo.queue()
714
- except Exception as e:
715
- # 任何队列配置错误,记录后继续
716
- print(f"配置队列时出错: {e}")
717
- print("继续启动应用,但队列功能可能不可用")
718
-
719
- # 针对Hugging Face Spaces环境的优化配置
720
- is_hf_space = os.environ.get("SPACE_ID") is not None
721
- server_port = int(os.environ.get("PORT", 7860))
722
- server_name = "0.0.0.0" if is_hf_space else "127.0.0.1"
723
 
724
  # 尝试使用兼容所有版本的参数启动
725
  launch_kwargs = {
726
- "server_name": server_name,
727
- "server_port": server_port,
728
  "share": False,
729
  }
730
 
731
- # 对于Gradio 3.x添加额外参数
732
- if gradio_version.startswith("3."):
733
- launch_kwargs.update({
734
- "debug": False,
735
- "show_api": True,
736
- "max_threads": 5,
737
- "concurrency_limit": 2
738
- })
739
-
740
- # 启动应用
741
- demo.launch(**launch_kwargs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
742
  except Exception as e:
743
- # 记录错误并使用最简配置重试
744
  print(f"启动时发生错误: {e}")
745
- print("使用最小配置重试...")
 
 
 
746
  try:
747
- # 最小配置,确保应用能启动
748
  demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
749
  except Exception as e2:
750
  print(f"最小配置启动也失败: {e2}")
 
751
 
752
  # 终极回退方案:创建最简单的接口并启动
753
- print("尝试创建备用界面...")
754
  try:
755
- import gradio as gr
756
 
 
757
  def simple_evaluate(json_data):
758
  try:
759
- return evaluate(json.loads(json_data) if isinstance(json_data, str) else json_data)
 
 
 
760
  except Exception as e:
761
  return {"error": str(e)}
762
 
763
  backup_demo = gr.Interface(
764
  fn=simple_evaluate,
765
  inputs=gr.Textbox(label="JSON输入"),
766
- outputs=gr.JSON(label="结果"),
767
  title="代码评估服务 (备用界面)",
768
- description="原界面启动失败,这是简化版本"
769
  )
770
 
771
  backup_demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
772
  except Exception as e3:
773
  print(f"备用界面也启动失败: {e3}")
 
 
28
  task_id_counter = 0
29
  task_lock = threading.Lock()
30
  last_update_time = datetime.now() # 替换update_event为时间戳跟踪
31
+ # 持久化的状态用于API访问和轮询更新
32
+ status_poll_counter = 0 # 用于强制更新UI,即使状态没有变化
33
+ last_background_update = datetime.now() # 最后一次后台更新时间
34
 
35
  def trigger_ui_update():
36
  """触发UI更新事件"""
37
+ global last_update_time, status_poll_counter, last_background_update
38
  with task_lock:
39
+ last_update_time = datetime.now() # 更新时间戳
40
+ status_poll_counter += 1 # 递增计数器,确保每次更新都被捕获
41
+ last_background_update = last_update_time # 更新后台状态
42
+ print(f"UI更新被触发: {datetime.now().strftime('%H:%M:%S')} [计数: {status_poll_counter}]")
43
 
44
  def get_next_task_id():
45
  global task_id_counter
 
132
 
133
  # 更新任务状态
134
  with task_lock:
135
+ if task_id in active_tasks: # 确保任务仍存在
136
+ active_tasks[task_id]["status"] = "processing"
137
+ print(f"任务 {task_id} 开始处理,当前时间: {datetime.now().strftime('%H:%M:%S')}")
138
+ trigger_ui_update() # 状态变更为处理中时更新UI
139
+ else:
140
+ print(f"警告: 任务 {task_id} 不在活跃任务列表中")
141
+ task_queue.task_done()
142
+ continue
143
 
144
  # 处理任务
145
+ print(f"开始评估任务 {task_id},数据项数: {len(task_info['data'])}")
146
  result = evaluate(task_info["data"])
147
+ print(f"任务 {task_id} 评估完成,结果数: {len(result) if isinstance(result, list) else 'Not a list'}")
148
 
149
  # 更新任务结果
150
  with task_lock:
151
+ if task_id in active_tasks: # 再次确保任务仍存在
152
+ completed_time = datetime.now()
153
+ active_tasks[task_id]["status"] = "completed"
154
+ active_tasks[task_id]["completed_at"] = completed_time
155
+ active_tasks[task_id]["result"] = result
156
+
157
+ # 计算处理持续时间
158
+ start_time = active_tasks[task_id]["submitted_at"]
159
+ duration = completed_time - start_time
160
+ print(f"任务 {task_id} 已完成,耗时: {duration},当前时间: {completed_time.strftime('%H:%M:%S')}")
161
+
162
+ # 将任务移至已完成列表
163
+ completed_tasks.append(active_tasks[task_id])
164
+ del active_tasks[task_id]
165
+
166
+ # 保留最近的20个已完成任务
167
+ if len(completed_tasks) > 20:
168
+ completed_tasks.pop(0)
169
+
170
+ # 状态更新后强制触发UI更新
171
+ trigger_ui_update()
172
+ print(f"任务 {task_id} 完成后触发UI更新: {last_update_time}")
173
+ else:
174
+ print(f"警告: 任务 {task_id} 在处理完成后不在活跃任务列表中")
175
 
176
  task_queue.task_done()
177
 
178
  except Exception as e:
179
+ print(f"处理任务队列出错: {str(e)}")
180
+ import traceback
181
+ traceback.print_exc()
182
  time.sleep(1)
183
 
184
  def evaluate(input_data):
 
344
  "completed_at": task["completed_at"].strftime("%Y-%m-%d %H:%M:%S") if "completed_at" in task else "",
345
  "duration": str(task["completed_at"] - task["submitted_at"]) if "completed_at" in task else ""
346
  } for task in completed_tasks[-5:] # 只显示最近5个完成的任务
347
+ ],
348
+ "poll_counter": status_poll_counter, # 添加轮询计数器
349
+ "timestamp": datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
350
  }
351
 
352
  def render_queue_status():
 
468
  return html
469
 
470
  def refresh_ui():
471
+ """定期刷新UI函数,确保显示最新状态"""
472
+ global status_poll_counter
473
+ print(f"UI刷新被调用: {datetime.now().strftime('%H:%M:%S')} [状态计数: {status_poll_counter}]")
474
+ return render_queue_status(), status_poll_counter
475
+
476
+ def get_status_for_polling():
477
+ """为AJAX轮询提供的状态获取函数,简化返回数据量"""
478
+ global status_poll_counter
479
+ # 返回最新状态和计数器值,用于客户端判断是否有更新
480
+ return {
481
+ "status_html": render_queue_status(),
482
+ "poll_counter": status_poll_counter,
483
+ "timestamp": datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
484
+ }
485
 
486
  def submit_json_data(json_data):
487
  """提交JSON数据处理接口"""
 
492
  else:
493
  data = json_data
494
 
495
+ # 为调试记录提交来源
496
+ print(f"接收到任务提交: {len(data) if isinstance(data, list) else 'Not a list'} 项")
497
+ print(f"当前队列状态 (提交前): 活跃任务 {len(active_tasks)}, 已完成任务 {len(completed_tasks)}")
498
+
499
  result = submit_task(data)
500
  response = json.dumps(result, ensure_ascii=False, indent=2)
501
 
502
+ # 强制触发UI更新
503
+ trigger_ui_update()
504
+ print(f"任务提交后触发UI更新: {last_update_time}")
505
+ print(f"当前队列状态 (提交后): 活跃任务 {len(active_tasks)}, 已完成任务 {len(completed_tasks)}")
506
+
507
  # 返回任务提交结果和最新的队列状态
508
+ status_html = render_queue_status()
509
+ return response, status_html
510
  except Exception as e:
511
+ print(f"提交任务出错: {str(e)}")
512
  return json.dumps({"status": "error", "message": str(e)}, ensure_ascii=False, indent=2), render_queue_status()
513
 
514
+ # API端点函数,用于获取最新队列状态
515
+ def api_get_queue_status():
516
+ """API端点,获取最新队列状态"""
517
+ status = get_queue_status()
518
+ status["html"] = render_queue_status() # 添加HTML渲染版本
519
+ return status
520
+
521
+ # 后台UI更新线程
522
+ def background_ui_updater():
523
+ """每隔一段时间检查任务状态,如有变化则触发更新"""
524
+ global last_background_update
525
+ print("后台UI更新线程已启动")
526
+
527
+ while True:
528
+ try:
529
+ # 检查队列状态
530
+ current_time = datetime.now()
531
+ time_since_last_update = (current_time - last_background_update).total_seconds()
532
+
533
+ # 如果30秒内没有更新,且有活跃任务,触发更新
534
+ with task_lock:
535
+ has_active_tasks = len(active_tasks) > 0
536
+
537
+ if time_since_last_update > 30 and has_active_tasks:
538
+ print(f"后台更新: 有{len(active_tasks)}个活跃任务,{time_since_last_update:.1f}秒未更新")
539
+ trigger_ui_update()
540
+
541
+ # 如果2分钟内没有更新,无论如何都触发一次更新保持UI活跃
542
+ if time_since_last_update > 120:
543
+ print(f"后台更新: 保活触发,{time_since_last_update:.1f}秒未更新")
544
+ trigger_ui_update()
545
+
546
+ except Exception as e:
547
+ print(f"后台更新出错: {str(e)}")
548
+
549
+ # 每5秒检查一次
550
+ time.sleep(5)
551
+
552
  # 创建Gradio接口
553
  with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
554
  gr.Markdown("""
 
556
  ### 支持多种编程语言的代码评估服务
557
  """)
558
 
559
+ # 添加隐藏的API处理组件
560
+ with gr.Row(visible=False):
561
+ api_input = gr.JSON()
562
+ api_output = gr.JSON()
563
+
564
+ # 设置API触发器
565
+ def api_trigger(data):
566
+ """处理API请求的函数"""
567
+ print(f"通过API接收到请求: {len(data) if isinstance(data, list) else 'Not a list'}")
568
+ try:
569
+ result = submit_task(data)
570
+ # 强制触发UI更新
571
+ trigger_ui_update()
572
+ return result
573
+ except Exception as e:
574
+ print(f"API处理出错: {str(e)}")
575
+ return {"status": "error", "message": str(e)}
576
+
577
+ api_input.change(fn=api_trigger, inputs=api_input, outputs=api_output)
578
+
579
  with gr.Tab("任务队列状态"):
580
  status_html = gr.HTML(render_queue_status)
581
+ poll_counter = gr.Number(value=0, visible=False) # 隐藏的计数器,用于触发更新
582
  refresh_button = gr.Button("刷新状态")
583
+ status_text = gr.Markdown("上次更新时间: 未更新")
584
 
585
  # 根据Gradio版本使用不同的事件注册方法
586
  if 'gradio_version' not in locals():
 
589
 
590
  if gradio_version.startswith("3."):
591
  # Gradio 3.x 方式
592
+ refresh_button.click(fn=refresh_ui, outputs=[status_html, poll_counter], concurrency_limit=2)
593
  else:
594
  # Gradio 4.x 方式 (不使用concurrency_limit参数)
595
+ refresh_button.click(
596
+ fn=refresh_ui,
597
+ outputs=[status_html, poll_counter],
598
+ every=10 # 每10秒自动刷新一次
599
+ )
600
+
601
+ # API断点,用于轮询最新状态
602
+ status_polling_input = gr.Number(value=0, visible=False, label="轮询触发器")
603
+ status_polling_output = gr.JSON(visible=False, label="轮询结果")
604
+
605
+ status_polling_input.change(
606
+ fn=get_status_for_polling,
607
+ inputs=[],
608
+ outputs=status_polling_output
609
+ )
610
+
611
+ # 使用JavaScript实现自动轮询
612
+ polling_js = """
613
  <script>
614
+ // 初始化轮询计数器
615
+ let lastPollCounter = 0;
616
+ let pollingActive = true;
617
+
618
+ // 轮询函数
619
+ async function pollStatus() {
620
+ if (!pollingActive) return;
621
 
622
+ try {
623
+ // 查找JSON输出元素 (在Gradio 4.x中,元素ID可能不同)
624
+ const jsonElements = document.querySelectorAll('[data-testid="json"]');
625
+ const statusElements = document.querySelectorAll('[id*="status_html"]');
626
+
627
+ // 如果找不到元素,使用普通AJAX请求
628
+ if (!jsonElements.length) {
629
+ // 通过已有的刷新按钮点击来刷新
630
+ const refreshButton = [...document.querySelectorAll('button')].find(btn =>
631
+ btn.textContent.includes('刷新状态'));
 
 
 
 
 
 
632
 
 
 
 
 
 
 
 
 
 
 
 
 
633
  if (refreshButton) {
634
  refreshButton.click();
635
+ console.log("刷新按钮被触发");
 
 
 
 
 
 
 
 
 
636
  }
637
+ } else {
638
+ // 使用Gradio API调用来获取最新状态
639
+ // 构建API请求的路径
640
+ const apiBase = window.location.pathname.endsWith('/')
641
+ ? window.location.pathname
642
+ : window.location.pathname + '/';
643
 
644
+ const response = await fetch(apiBase + 'api/queue/status');
645
+ if (response.ok) {
646
+ const data = await response.json();
647
+ const statusHtml = statusElements[0];
 
 
 
 
 
 
 
 
648
 
649
+ // 如果有状态更新,更新UI
650
+ if (statusHtml && data.status) {
651
+ // 根据API返回更新页面状态
652
+ console.log("服务器状态已更新");
653
+
654
+ // 触发刷新按钮
655
+ const refreshButton = [...document.querySelectorAll('button')].find(btn =>
656
+ btn.textContent.includes('刷新状态'));
657
+
658
+ if (refreshButton) {
659
+ refreshButton.click();
660
+ }
661
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
662
  }
663
  }
664
+ } catch (err) {
665
+ console.error("轮询错误:", err);
666
+ }
667
 
668
+ // 继续轮询
669
+ setTimeout(pollStatus, 5000); // 每5秒轮询一次
670
  }
671
 
672
+ // 页面加载完成后开始轮询
673
  if (document.readyState === 'loading') {
674
+ document.addEventListener('DOMContentLoaded', () => setTimeout(pollStatus, 1000));
675
  } else {
676
+ setTimeout(pollStatus, 1000);
677
  }
678
+
679
+ // 页面可见性变化时管理轮询
680
+ document.addEventListener('visibilitychange', function() {
681
+ pollingActive = document.visibilityState === 'visible';
682
+ if (pollingActive) {
683
+ // 页面变为可见时立即轮询一次
684
+ pollStatus();
685
+ }
686
+ });
687
  </script>
688
+ """
689
+
690
+ gr.HTML(polling_js)
691
+
692
+ # 以下是原来的自动刷新脚本,保留但不使用
693
+ auto_refresh_js = """
694
+ <script>
695
+ // 兼容Gradio 3.x和4.x的自动刷新机制 - 仅作为备用
696
+ console.log('自动刷新机制已加载,但已被新的轮询系统替代');
697
+ </script>
698
+ """
699
+
700
+ # 不显示旧的自动刷新脚本
701
+ # gr.HTML(auto_refresh_js)
702
 
703
  with gr.Tab("提交新任务"):
704
  with gr.Row():
 
775
  ```
776
  """)
777
 
778
+ # 这里不再添加状态API端点,避免与FastAPI冲突
779
+ # demo.queue(api_open=True).add_api_route("/api/queue/status", api_get_queue_status, methods=["GET"])
 
 
 
 
 
 
 
 
 
 
780
 
781
  if __name__ == "__main__":
782
  # 检测Gradio版本以适配不同版本的API
 
784
  gradio_version = getattr(gradio, "__version__", "unknown")
785
  print(f"当前Gradio版本: {gradio_version}")
786
 
787
+ # 启动后台UI更新线程
788
+ bg_thread = threading.Thread(target=background_ui_updater, daemon=True)
789
+ bg_thread.start()
790
+ print("后台UI更新线程已启动")
791
+
792
  try:
793
+ # 设置标准日志记录,确保足够的调试信息
794
+ import logging
795
+ logging.basicConfig(level=logging.INFO,
796
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
797
+ logger = logging.getLogger("CodeEvalService")
798
+ logger.info(f"启动代码评估服务,Gradio版本: {gradio_version}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
 
800
  # 尝试使用兼容所有版本的参数启动
801
  launch_kwargs = {
802
+ "server_name": "0.0.0.0",
803
+ "server_port": int(os.environ.get("PORT", 7860)),
804
  "share": False,
805
  }
806
 
807
+ # Gradio 4.x专用的FastAPI初始化
808
+ if not gradio_version.startswith("3."):
809
+ # 针对Gradio 4的API配置
810
+ import fastapi
811
+ from fastapi import FastAPI
812
+
813
+ # 创建FastAPI应用
814
+ app = FastAPI(title="代码评估服务API")
815
+
816
+ # 添加队列状态API端点
817
+ @app.get("/api/queue/status")
818
+ def get_queue_status_api():
819
+ return api_get_queue_status()
820
+
821
+ # 添加任务提交API端点
822
+ @app.post("/api/submit_task")
823
+ async def submit_task_api(data: list):
824
+ try:
825
+ result = submit_task(data)
826
+ return result
827
+ except Exception as e:
828
+ return {"status": "error", "message": str(e)}
829
+
830
+ # 启动应用到FastAPI
831
+ demo.launch(
832
+ **launch_kwargs,
833
+ app=app,
834
+ max_threads=5,
835
+ )
836
+ else:
837
+ # Gradio 3.x的方式
838
+ # 设置队列,并添加API支持
839
+ try:
840
+ demo.queue(api_open=True, max_size=30)
841
+ except Exception as e:
842
+ logger.warning(f"配置队列时出错: {e}")
843
+
844
+ # 启动应用
845
+ demo.launch(
846
+ **launch_kwargs,
847
+ debug=False,
848
+ show_api=True,
849
+ max_threads=5,
850
+ concurrency_limit=2
851
+ )
852
+
853
  except Exception as e:
 
854
  print(f"启动时发生错误: {e}")
855
+ import traceback
856
+ traceback.print_exc()
857
+
858
+ # 尝试最简配置启动
859
  try:
860
+ print("使用最小配置重试...")
861
  demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
862
  except Exception as e2:
863
  print(f"最小配置启动也失败: {e2}")
864
+ traceback.print_exc()
865
 
866
  # 终极回退方案:创建最简单的接口并启动
 
867
  try:
868
+ print("尝试创建备用界面...")
869
 
870
+ import gradio as gr
871
  def simple_evaluate(json_data):
872
  try:
873
+ print(f"备用界面收到请求: {json_data[:100] if isinstance(json_data, str) else 'Not a string'}")
874
+ data = json.loads(json_data) if isinstance(json_data, str) else json_data
875
+ result = submit_task(data)
876
+ return json.dumps(result, ensure_ascii=False)
877
  except Exception as e:
878
  return {"error": str(e)}
879
 
880
  backup_demo = gr.Interface(
881
  fn=simple_evaluate,
882
  inputs=gr.Textbox(label="JSON输入"),
883
+ outputs=gr.Textbox(label="结果"),
884
  title="代码评估服务 (备用界面)",
885
+ description="原界面启动失败,这是简化版本。提交格式: [{\"language\": \"python\", \"prompt\": \"def add(a, b):\\n\", \"processed_completions\": [\" return a + b\"], \"tests\": \"assert add(1, 2) == 3\"}]"
886
  )
887
 
888
  backup_demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
889
  except Exception as e3:
890
  print(f"备用界面也启动失败: {e3}")
891
+ traceback.print_exc()