朱东升 commited on
Commit
32a0a99
·
1 Parent(s): 074639d
Files changed (1) hide show
  1. app.py +138 -40
app.py CHANGED
@@ -27,11 +27,13 @@ active_tasks = {}
27
  completed_tasks = []
28
  task_id_counter = 0
29
  task_lock = threading.Lock()
30
- update_event = threading.Event() # 通知UI需要刷新
31
 
32
  def trigger_ui_update():
33
  """触发UI更新事件"""
34
- update_event.set()
 
 
35
 
36
  def get_next_task_id():
37
  global task_id_counter
@@ -87,18 +89,27 @@ def estimate_completion_time(input_data):
87
  Returns:
88
  timedelta: 估计的完成时间
89
  """
90
- # 假设每个任务项平均需要2秒处理
91
- # 这个值可以根据实际情况调整或从历史数据中学习
92
- avg_time_per_item = 2
93
  total_items = len(input_data)
94
 
95
- # 考虑并行处理因素
96
- cpu_count = multiprocessing.cpu_count()
97
- parallel_factor = min(cpu_count, total_items)
 
 
 
 
 
 
 
98
 
99
  if parallel_factor > 0:
100
  estimated_seconds = (total_items * avg_time_per_item) / parallel_factor
101
- return timedelta(seconds=estimated_seconds)
 
 
102
  else:
103
  return timedelta(seconds=0)
104
 
@@ -152,27 +163,67 @@ def evaluate(input_data):
152
  Returns:
153
  list: 包含评估结果的列表
154
  """
 
 
 
 
155
  try:
156
  if not isinstance(input_data, list):
157
  return {"status": "Exception", "error": "Input must be a list"}
158
 
159
  results = []
160
- max_workers = multiprocessing.cpu_count()
 
 
 
 
 
 
 
161
  with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
162
- future_to_item = {executor.submit(evaluate_single_case, item): item for item in input_data}
163
- for future in concurrent.futures.as_completed(future_to_item):
164
- item = future_to_item[future]
165
- try:
166
- result = future.result()
167
- item.update(result)
168
- results.append(item)
169
- except Exception as e:
170
- item.update({"status": "Exception", "error": str(e)})
171
- results.append(item)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  return results
173
 
174
  except Exception as e:
175
- return {"status": "Exception", "error": str(e)}
176
 
177
  def evaluate_single_case(input_data):
178
  """评估单个代码用例
@@ -389,6 +440,7 @@ def render_queue_status():
389
 
390
  def refresh_ui():
391
  """定期刷新UI函数"""
 
392
  return render_queue_status()
393
 
394
  def submit_json_data(json_data):
@@ -429,32 +481,70 @@ with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
429
  # JavaScript-based auto-refresh solution
430
  gr.HTML("""
431
  <script>
432
- // 使用JavaScript作为自动刷新机制
433
  function setupAutoRefresh() {
434
- const refreshInterval = 2000; // 2秒刷新一次
 
 
 
435
 
436
  // 查找刷新按钮并模拟点击
437
  function autoRefresh() {
438
- // 获取所有按钮元素
439
- const buttons = document.querySelectorAll('button');
440
- // 查找刷新状态按钮
441
- for (const button of buttons) {
442
- if (button.textContent === '刷新状态') {
443
- button.click();
444
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
  }
 
 
446
  }
447
  }
448
 
449
- // 周期性检查刷新
450
- setInterval(autoRefresh, refreshInterval);
 
 
 
 
 
 
 
 
 
 
 
 
451
 
452
  // 设置首次加载时立即刷新一次
453
  setTimeout(autoRefresh, 100);
454
  }
455
 
456
- // 页面加载完成后设置自动刷新
457
- window.addEventListener('load', setupAutoRefresh);
 
 
 
 
458
  </script>
459
  """)
460
 
@@ -534,12 +624,20 @@ with gr.Blocks(title="代码评估服务", theme=gr.themes.Soft()) as demo:
534
  api_input.change(fn=evaluate, inputs=api_input, outputs=api_output)
535
 
536
  if __name__ == "__main__":
537
- # 打印Gradio版本,用于调试
538
- import gradio
539
- print(f"Gradio version: {gradio.__version__}")
540
-
541
  # 设置队列,并添加API支持
542
- demo.queue(api_open=True)
 
 
 
 
 
543
 
544
  # 启动应用
545
- demo.launch()
 
 
 
 
 
 
 
 
27
  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
 
89
  Returns:
90
  timedelta: 估计的完成时间
91
  """
92
+ # 在Hugging Face Spaces环境中,资源通常受限,调整处理时间预估
93
+ # 假设每个任务项平均需要5秒处理(HF环境中可能更慢)
94
+ avg_time_per_item = 5
95
  total_items = len(input_data)
96
 
97
+ # Hugging Face Spaces通常有限制的CPU资源
98
+ # 保守估计并行处理能力
99
+ try:
100
+ cpu_count = multiprocessing.cpu_count()
101
+ except:
102
+ # 如果获取失败,假设只有2个CPU
103
+ cpu_count = 2
104
+
105
+ # 在HF环境中,即使有多核也可能性能受限,降低并行因子
106
+ parallel_factor = min(2, total_items) # 限制最多2个并行任务
107
 
108
  if parallel_factor > 0:
109
  estimated_seconds = (total_items * avg_time_per_item) / parallel_factor
110
+ # 为了避免过于乐观的估计,增加30%的缓冲时间
111
+ estimated_seconds = estimated_seconds * 1.3
112
+ return timedelta(seconds=round(estimated_seconds))
113
  else:
114
  return timedelta(seconds=0)
115
 
 
163
  Returns:
164
  list: 包含评估结果的列表
165
  """
166
+ # 打印Gradio版本,用于调试
167
+ import gradio
168
+ print(f"Gradio version: {gradio.__version__}")
169
+
170
  try:
171
  if not isinstance(input_data, list):
172
  return {"status": "Exception", "error": "Input must be a list"}
173
 
174
  results = []
175
+
176
+ # 在HF Spaces环境中可能受限,降低并行数量
177
+ try:
178
+ max_workers = min(multiprocessing.cpu_count(), 2) # 最多2个并行任务
179
+ except:
180
+ max_workers = 2 # 如果无法获取,默认为2
181
+
182
+ # 增加超时处理
183
  with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
184
+ future_to_item = {}
185
+ # 分批处理,每批最多5个任务,避免资源耗尽
186
+ batch_size = 5
187
+ for i in range(0, len(input_data), batch_size):
188
+ batch = input_data[i:i+batch_size]
189
+ # 为每个任务提交并记录
190
+ for item in batch:
191
+ future = executor.submit(evaluate_single_case, item)
192
+ future_to_item[future] = item
193
+
194
+ # 等待当前批次完成
195
+ for future in concurrent.futures.as_completed(future_to_item):
196
+ item = future_to_item[future]
197
+ try:
198
+ # 设置较短的超时时间,避免任务卡死
199
+ result = future.result(timeout=60) # 60秒超时
200
+ item.update(result)
201
+ results.append(item)
202
+ except concurrent.futures.TimeoutError:
203
+ # 处理超时情况
204
+ item.update({
205
+ "status": "Timeout",
206
+ "error": "Task processing timed out in Hugging Face environment"
207
+ })
208
+ results.append(item)
209
+ except Exception as e:
210
+ # 处理其他异常
211
+ item.update({
212
+ "status": "Exception",
213
+ "error": f"Error in Hugging Face environment: {str(e)}"
214
+ })
215
+ results.append(item)
216
+
217
+ # 清空当前批次
218
+ future_to_item = {}
219
+
220
+ # 短暂休息,让系统喘息
221
+ time.sleep(0.5)
222
+
223
  return results
224
 
225
  except Exception as e:
226
+ return {"status": "Exception", "error": f"Evaluation error in Hugging Face environment: {str(e)}"}
227
 
228
  def evaluate_single_case(input_data):
229
  """评估单个代码用例
 
440
 
441
  def refresh_ui():
442
  """定期刷新UI函数"""
443
+ # 不再需要等待事件,直接返回最新状态
444
  return render_queue_status()
445
 
446
  def submit_json_data(json_data):
 
481
  # JavaScript-based auto-refresh solution
482
  gr.HTML("""
483
  <script>
484
+ // 为Hugging Face Spaces环境优化的自动刷新机制
485
  function setupAutoRefresh() {
486
+ // 在HF Spaces中更保守的刷新间隔,避免过多请求
487
+ const refreshInterval = 3000; // 3秒刷新一次
488
+ let lastTaskCount = 0;
489
+ let consecutiveNoChange = 0;
490
 
491
  // 查找刷新按钮并模拟点击
492
  function autoRefresh() {
493
+ try {
494
+ // 获取所有按钮元素
495
+ const buttons = document.querySelectorAll('button');
496
+ // 查找刷新状态按钮
497
+ for (const button of buttons) {
498
+ if (button.textContent === '刷新状态') {
499
+ button.click();
500
+
501
+ // 检查任务数量是否变化 (动态优化刷新频率的预留代码)
502
+ setTimeout(() => {
503
+ const activeTasks = document.querySelectorAll('table tbody tr');
504
+ const currentTaskCount = activeTasks.length;
505
+
506
+ if (currentTaskCount === lastTaskCount) {
507
+ consecutiveNoChange++;
508
+ } else {
509
+ consecutiveNoChange = 0;
510
+ }
511
+
512
+ lastTaskCount = currentTaskCount;
513
+ }, 500);
514
+
515
+ break;
516
+ }
517
  }
518
+ } catch (e) {
519
+ console.error("Auto-refresh error:", e);
520
  }
521
  }
522
 
523
+ // 周期性检查刷新,确保即使在HF Spaces资源受限情况下也能工作
524
+ let refreshTimer = setInterval(autoRefresh, refreshInterval);
525
+
526
+ // 确保页面可见性变化时刷新机制正常工作
527
+ document.addEventListener('visibilitychange', function() {
528
+ if (document.visibilityState === 'visible') {
529
+ // 页面变为可见时立即刷新一次
530
+ autoRefresh();
531
+ // 如果计时器被清除,重新创建
532
+ if (!refreshTimer) {
533
+ refreshTimer = setInterval(autoRefresh, refreshInterval);
534
+ }
535
+ }
536
+ });
537
 
538
  // 设置首次加载时立即刷新一次
539
  setTimeout(autoRefresh, 100);
540
  }
541
 
542
+ // 确保在DOM完全加载后运行
543
+ if (document.readyState === 'loading') {
544
+ document.addEventListener('DOMContentLoaded', setupAutoRefresh);
545
+ } else {
546
+ setupAutoRefresh();
547
+ }
548
  </script>
549
  """)
550
 
 
624
  api_input.change(fn=evaluate, inputs=api_input, outputs=api_output)
625
 
626
  if __name__ == "__main__":
 
 
 
 
627
  # 设置队列,并添加API支持
628
+ demo.queue(api_open=True, concurrency_count=2, max_size=30)
629
+
630
+ # 针对Hugging Face Spaces环境的优化配置
631
+ is_hf_space = os.environ.get("SPACE_ID") is not None
632
+ server_port = int(os.environ.get("PORT", 7860))
633
+ server_name = "0.0.0.0" if is_hf_space else "127.0.0.1"
634
 
635
  # 启动应用
636
+ demo.launch(
637
+ server_name=server_name,
638
+ server_port=server_port,
639
+ share=False, # 在HF Spaces环境中无需share
640
+ debug=False, # 在HF Spaces环境中关闭调试,提高稳定性
641
+ show_api=True,
642
+ max_threads=2 # 限制最大线程数,避免资源耗尽
643
+ )