Spaces:
Sleeping
Sleeping
朱东升
commited on
Commit
·
ccdd995
1
Parent(s):
d4652ff
update15
Browse files
app.py
CHANGED
@@ -10,7 +10,9 @@ import time
|
|
10 |
import threading
|
11 |
import queue
|
12 |
import uuid
|
|
|
13 |
from datetime import datetime
|
|
|
14 |
from src.containerized_eval import eval_string_script
|
15 |
|
16 |
# 添加当前目录和src目录到模块搜索路径
|
@@ -25,7 +27,7 @@ if src_dir not in sys.path:
|
|
25 |
task_queue = queue.Queue()
|
26 |
# 存储任务状态的字典
|
27 |
task_status = {}
|
28 |
-
# 存储任务历史的列表,最多保存最近
|
29 |
task_history = []
|
30 |
# 用于保护共享资源的锁
|
31 |
lock = threading.Lock()
|
@@ -33,6 +35,8 @@ lock = threading.Lock()
|
|
33 |
worker_threads = multiprocessing.cpu_count()
|
34 |
# 后台线程是否运行的标志
|
35 |
running = True
|
|
|
|
|
36 |
|
37 |
def queue_processor():
|
38 |
"""处理队列中的任务"""
|
@@ -44,6 +48,21 @@ def queue_processor():
|
|
44 |
task_status[task_id]['status'] = 'processing'
|
45 |
task_status[task_id]['start_time'] = time.time()
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
# 处理任务
|
48 |
result = evaluate(input_data)
|
49 |
|
@@ -57,15 +76,30 @@ def queue_processor():
|
|
57 |
task_status[task_id]['end_time'] = end_time
|
58 |
task_status[task_id]['process_time'] = process_time
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
# 更新任务历史
|
61 |
task_history.append({
|
62 |
'task_id': task_id,
|
63 |
'request_time': request_time,
|
64 |
'process_time': process_time,
|
65 |
-
'status': 'completed'
|
|
|
66 |
})
|
67 |
-
# 只保留最近
|
68 |
-
while len(task_history) >
|
69 |
task_history.pop(0)
|
70 |
|
71 |
# 标记任务完成
|
@@ -82,6 +116,44 @@ def queue_processor():
|
|
82 |
task_status[task_id]['end_time'] = time.time()
|
83 |
task_queue.task_done()
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
def evaluate(input_data):
|
86 |
"""评估代码的主函数
|
87 |
|
@@ -174,6 +246,21 @@ def synchronous_evaluate(input_data):
|
|
174 |
Returns:
|
175 |
dict: 评估结果
|
176 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
# 获取队列当前状态
|
178 |
queue_info = get_queue_status()
|
179 |
waiting_tasks = queue_info['waiting_tasks']
|
@@ -188,7 +275,13 @@ def synchronous_evaluate(input_data):
|
|
188 |
'status': 'queued',
|
189 |
'queued_time': request_time,
|
190 |
'queue_position': task_queue.qsize() + 1,
|
191 |
-
'synchronous': True # 标记为同步任务
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
}
|
193 |
|
194 |
# 将任务添加到队列
|
@@ -213,6 +306,30 @@ def synchronous_evaluate(input_data):
|
|
213 |
# 短暂睡眠避免CPU占用过高
|
214 |
time.sleep(0.1)
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
def enqueue_task(input_data):
|
217 |
"""将任务添加到队列
|
218 |
|
@@ -222,6 +339,20 @@ def enqueue_task(input_data):
|
|
222 |
Returns:
|
223 |
dict: 包含任务ID和状态的字典
|
224 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
task_id = str(uuid.uuid4())
|
226 |
request_time = time.time()
|
227 |
|
@@ -230,9 +361,19 @@ def enqueue_task(input_data):
|
|
230 |
task_status[task_id] = {
|
231 |
'status': 'queued',
|
232 |
'queued_time': request_time,
|
233 |
-
'queue_position': task_queue.qsize() + 1
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
}
|
235 |
|
|
|
|
|
|
|
|
|
236 |
# 将任务添加到队列
|
237 |
task_queue.put((task_id, input_data, request_time))
|
238 |
|
@@ -240,7 +381,8 @@ def enqueue_task(input_data):
|
|
240 |
'task_id': task_id,
|
241 |
'status': 'queued',
|
242 |
'queue_position': task_status[task_id]['queue_position'],
|
243 |
-
'estimated_wait':
|
|
|
244 |
}
|
245 |
|
246 |
def check_status(task_id):
|
@@ -271,32 +413,70 @@ def get_queue_status():
|
|
271 |
dict: 包含队列状态的字典
|
272 |
"""
|
273 |
with lock:
|
|
|
|
|
|
|
|
|
274 |
queue_size = task_queue.qsize()
|
275 |
-
active_tasks =
|
276 |
-
waiting_tasks =
|
277 |
|
278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
|
280 |
-
#
|
281 |
-
if
|
282 |
-
|
283 |
-
# 确保平均时间至少为1秒
|
284 |
-
avg_time = max(avg_time, 1.0)
|
285 |
-
else:
|
286 |
-
# 没有历史数据时的默认平均处理时间(秒)
|
287 |
-
avg_time = 5.0
|
288 |
|
289 |
-
#
|
290 |
-
|
291 |
-
active_time = (active_tasks * avg_time) / 2 if active_tasks > 0 else 0
|
292 |
-
# 排队任务的总时间
|
293 |
-
queue_time = waiting_tasks * avg_time
|
294 |
-
# 总预计等待时间
|
295 |
-
estimated_wait = active_time + queue_time
|
296 |
|
297 |
-
#
|
298 |
-
if
|
299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
|
301 |
return {
|
302 |
'queue_size': queue_size,
|
@@ -304,7 +484,6 @@ def get_queue_status():
|
|
304 |
'waiting_tasks': waiting_tasks,
|
305 |
'worker_threads': worker_threads,
|
306 |
'estimated_wait': estimated_wait,
|
307 |
-
'avg_process_time': avg_time,
|
308 |
'recent_tasks': recent_tasks
|
309 |
}
|
310 |
|
@@ -328,113 +507,6 @@ def format_time(seconds):
|
|
328 |
minutes = int((seconds % 3600) / 60)
|
329 |
return f"{hours}小时{minutes}分钟"
|
330 |
|
331 |
-
def ui_submit(input_json):
|
332 |
-
"""提交任务到队列的UI函数
|
333 |
-
|
334 |
-
Args:
|
335 |
-
input_json: JSON格式的输入数据
|
336 |
-
|
337 |
-
Returns:
|
338 |
-
tuple: 任务ID和初始状态信息
|
339 |
-
"""
|
340 |
-
try:
|
341 |
-
input_data = json.loads(input_json) if isinstance(input_json, str) else input_json
|
342 |
-
response = enqueue_task(input_data)
|
343 |
-
task_id = response['task_id']
|
344 |
-
|
345 |
-
status_html = f"""
|
346 |
-
<div class="status-card">
|
347 |
-
<h3>任务状态</h3>
|
348 |
-
<p><b>任务ID:</b> {task_id}</p>
|
349 |
-
<p><b>状态:</b> 已入队</p>
|
350 |
-
<p><b>队列位置:</b> {response['queue_position']}</p>
|
351 |
-
<p><b>预计等待时间:</b> {format_time(response['estimated_wait'])}</p>
|
352 |
-
</div>
|
353 |
-
"""
|
354 |
-
|
355 |
-
return task_id, status_html
|
356 |
-
except Exception as e:
|
357 |
-
return None, f"<div class='error-message'>提交失败: {str(e)}</div>"
|
358 |
-
|
359 |
-
def ui_check_status(task_id):
|
360 |
-
"""检查任务状态的UI函数
|
361 |
-
|
362 |
-
Args:
|
363 |
-
task_id: 任务ID
|
364 |
-
|
365 |
-
Returns:
|
366 |
-
str: 包含任务状态的HTML
|
367 |
-
"""
|
368 |
-
if not task_id:
|
369 |
-
return "<div class='notice'>请提供任务ID</div>"
|
370 |
-
|
371 |
-
status = check_status(task_id)
|
372 |
-
|
373 |
-
if status['status'] == 'not_found':
|
374 |
-
return "<div class='error-message'>任务未找到</div>"
|
375 |
-
|
376 |
-
if status['status'] == 'queued':
|
377 |
-
queue_info = get_queue_status()
|
378 |
-
|
379 |
-
# 计算这个特定任务的等待时间
|
380 |
-
avg_time = queue_info.get('avg_process_time', 5.0)
|
381 |
-
active_time = (queue_info['active_tasks'] * avg_time) / 2 if queue_info['active_tasks'] > 0 else 0
|
382 |
-
|
383 |
-
# 计算此任务前面的任务数
|
384 |
-
tasks_ahead = status['queue_position'] - 1
|
385 |
-
|
386 |
-
# 此任务的估计等待时间 = 活跃任务完成时间 + 前面排队任务时间
|
387 |
-
est_wait = active_time + (tasks_ahead * avg_time)
|
388 |
-
|
389 |
-
return f"""
|
390 |
-
<div class="status-card">
|
391 |
-
<h3>任务状态</h3>
|
392 |
-
<p><b>任务ID:</b> {task_id}</p>
|
393 |
-
<p><b>状态:</b> 等待中</p>
|
394 |
-
<p><b>队列位置:</b> {status['queue_position']}</p>
|
395 |
-
<p><b>入队时间:</b> {datetime.fromtimestamp(status['queued_time']).strftime('%H:%M:%S')}</p>
|
396 |
-
<p><b>预计等待时间:</b> {format_time(est_wait)}</p>
|
397 |
-
</div>
|
398 |
-
"""
|
399 |
-
|
400 |
-
if status['status'] == 'processing':
|
401 |
-
process_time = time.time() - status['start_time']
|
402 |
-
|
403 |
-
return f"""
|
404 |
-
<div class="status-card">
|
405 |
-
<h3>任务状态</h3>
|
406 |
-
<p><b>任务ID:</b> {task_id}</p>
|
407 |
-
<p><b>状态:</b> 处理中</p>
|
408 |
-
<p><b>已处理时间:</b> {format_time(process_time)}</p>
|
409 |
-
<p><b>入队时间:</b> {datetime.fromtimestamp(status['queued_time']).strftime('%H:%M:%S')}</p>
|
410 |
-
</div>
|
411 |
-
"""
|
412 |
-
|
413 |
-
if status['status'] == 'completed':
|
414 |
-
result = status.get('result', {})
|
415 |
-
|
416 |
-
return f"""
|
417 |
-
<div class="status-card success">
|
418 |
-
<h3>任务状态</h3>
|
419 |
-
<p><b>任务ID:</b> {task_id}</p>
|
420 |
-
<p><b>状态:</b> 已完成</p>
|
421 |
-
<p><b>处理时间:</b> {format_time(status['process_time'])}</p>
|
422 |
-
<p><b>完成时间:</b> {datetime.fromtimestamp(status['end_time']).strftime('%H:%M:%S')}</p>
|
423 |
-
</div>
|
424 |
-
"""
|
425 |
-
|
426 |
-
if status['status'] == 'error':
|
427 |
-
return f"""
|
428 |
-
<div class="status-card error">
|
429 |
-
<h3>任务状态</h3>
|
430 |
-
<p><b>任务ID:</b> {task_id}</p>
|
431 |
-
<p><b>状态:</b> 错误</p>
|
432 |
-
<p><b>错误信息:</b> {status.get('error', '未知错误')}</p>
|
433 |
-
</div>
|
434 |
-
"""
|
435 |
-
|
436 |
-
return "<div class='error-message'>未知状态</div>"
|
437 |
-
|
438 |
def ui_get_queue_info():
|
439 |
"""获取队列信息的UI函数
|
440 |
|
@@ -461,9 +533,6 @@ def ui_get_queue_info():
|
|
461 |
</tr>
|
462 |
"""
|
463 |
|
464 |
-
# 添加平均处理时间显示
|
465 |
-
avg_time_html = f"""<p><b>平均处理时间:</b> {format_time(queue_info.get('avg_process_time', 0))}</p>"""
|
466 |
-
|
467 |
return f"""
|
468 |
<div class="dashboard">
|
469 |
<div class="queue-info-card main-card">
|
@@ -484,7 +553,6 @@ def ui_get_queue_info():
|
|
484 |
</div>
|
485 |
|
486 |
<div class="wait-time">
|
487 |
-
{avg_time_html}
|
488 |
<p><b>当前预计等待时间:</b> {format_time(queue_info['estimated_wait'])}</p>
|
489 |
<p class="last-update"><small>最后更新: {datetime.now().strftime('%H:%M:%S')}</small></p>
|
490 |
</div>
|
@@ -508,36 +576,6 @@ def ui_get_queue_info():
|
|
508 |
</div>
|
509 |
"""
|
510 |
|
511 |
-
def ui_get_result(task_id):
|
512 |
-
"""获取任务结果的UI函数
|
513 |
-
|
514 |
-
Args:
|
515 |
-
task_id: 任务ID
|
516 |
-
|
517 |
-
Returns:
|
518 |
-
任务结果
|
519 |
-
"""
|
520 |
-
if not task_id:
|
521 |
-
return None
|
522 |
-
|
523 |
-
status = check_status(task_id)
|
524 |
-
|
525 |
-
if status['status'] == 'completed':
|
526 |
-
return status.get('result', None)
|
527 |
-
|
528 |
-
return None
|
529 |
-
|
530 |
-
def launch_workers():
|
531 |
-
"""启动工作线程"""
|
532 |
-
global running
|
533 |
-
running = True
|
534 |
-
|
535 |
-
# 创建工作线程
|
536 |
-
for _ in range(worker_threads):
|
537 |
-
worker = threading.Thread(target=queue_processor)
|
538 |
-
worker.daemon = True
|
539 |
-
worker.start()
|
540 |
-
|
541 |
# 自定义CSS
|
542 |
custom_css = """
|
543 |
.container {
|
|
|
10 |
import threading
|
11 |
import queue
|
12 |
import uuid
|
13 |
+
import numpy as np
|
14 |
from datetime import datetime
|
15 |
+
from tqdm.auto import tqdm
|
16 |
from src.containerized_eval import eval_string_script
|
17 |
|
18 |
# 添加当前目录和src目录到模块搜索路径
|
|
|
27 |
task_queue = queue.Queue()
|
28 |
# 存储任务状态的字典
|
29 |
task_status = {}
|
30 |
+
# 存储任务历史的列表,最多保存最近20个任务
|
31 |
task_history = []
|
32 |
# 用于保护共享资源的锁
|
33 |
lock = threading.Lock()
|
|
|
35 |
worker_threads = multiprocessing.cpu_count()
|
36 |
# 后台线程是否运行的标志
|
37 |
running = True
|
38 |
+
# 任务类型到处理时间的映射
|
39 |
+
task_type_times = {}
|
40 |
|
41 |
def queue_processor():
|
42 |
"""处理队列中的任务"""
|
|
|
48 |
task_status[task_id]['status'] = 'processing'
|
49 |
task_status[task_id]['start_time'] = time.time()
|
50 |
|
51 |
+
# 识别任务特征以估计完成时间
|
52 |
+
# 例如:语言类型、代码大小等
|
53 |
+
if isinstance(input_data, list) and len(input_data) > 0:
|
54 |
+
sample_task = input_data[0]
|
55 |
+
language = sample_task.get('language', 'unknown') if isinstance(sample_task, dict) else 'unknown'
|
56 |
+
task_size = len(input_data)
|
57 |
+
task_complexity = _estimate_task_complexity(input_data)
|
58 |
+
|
59 |
+
with lock:
|
60 |
+
task_status[task_id]['estimated_factors'] = {
|
61 |
+
'language': language,
|
62 |
+
'size': task_size,
|
63 |
+
'complexity': task_complexity
|
64 |
+
}
|
65 |
+
|
66 |
# 处理任务
|
67 |
result = evaluate(input_data)
|
68 |
|
|
|
76 |
task_status[task_id]['end_time'] = end_time
|
77 |
task_status[task_id]['process_time'] = process_time
|
78 |
|
79 |
+
# 更新任务类型到处理时间的映射
|
80 |
+
if 'estimated_factors' in task_status[task_id]:
|
81 |
+
factors = task_status[task_id]['estimated_factors']
|
82 |
+
key = f"{factors['language']}_{factors['complexity']}"
|
83 |
+
|
84 |
+
if key not in task_type_times:
|
85 |
+
task_type_times[key] = []
|
86 |
+
|
87 |
+
# 记录此类型任务的处理时间
|
88 |
+
task_type_times[key].append(process_time / factors['size'])
|
89 |
+
# 只保留最近的10个记录
|
90 |
+
if len(task_type_times[key]) > 10:
|
91 |
+
task_type_times[key] = task_type_times[key][-10:]
|
92 |
+
|
93 |
# 更新任务历史
|
94 |
task_history.append({
|
95 |
'task_id': task_id,
|
96 |
'request_time': request_time,
|
97 |
'process_time': process_time,
|
98 |
+
'status': 'completed',
|
99 |
+
'factors': task_status[task_id].get('estimated_factors', {})
|
100 |
})
|
101 |
+
# 只保留最近20个任务
|
102 |
+
while len(task_history) > 20:
|
103 |
task_history.pop(0)
|
104 |
|
105 |
# 标记任务完成
|
|
|
116 |
task_status[task_id]['end_time'] = time.time()
|
117 |
task_queue.task_done()
|
118 |
|
119 |
+
def _estimate_task_complexity(tasks):
|
120 |
+
"""估计任务复杂度
|
121 |
+
|
122 |
+
Args:
|
123 |
+
tasks: 任务列表
|
124 |
+
|
125 |
+
Returns:
|
126 |
+
str: 复杂度评级 ('simple', 'medium', 'complex')
|
127 |
+
"""
|
128 |
+
# 基于代码和测试的长度评估复杂度
|
129 |
+
total_code_length = 0
|
130 |
+
count = 0
|
131 |
+
|
132 |
+
for task in tasks:
|
133 |
+
if isinstance(task, dict):
|
134 |
+
prompt = task.get('prompt', '')
|
135 |
+
tests = task.get('tests', '')
|
136 |
+
completions = task.get('processed_completions', [])
|
137 |
+
|
138 |
+
code_length = len(prompt) + len(tests)
|
139 |
+
if completions:
|
140 |
+
code_length += sum(len(comp) for comp in completions)
|
141 |
+
|
142 |
+
total_code_length += code_length
|
143 |
+
count += 1
|
144 |
+
|
145 |
+
if count == 0:
|
146 |
+
return 'medium' # 默认中等复杂度
|
147 |
+
|
148 |
+
avg_length = total_code_length / count
|
149 |
+
|
150 |
+
if avg_length < 1000:
|
151 |
+
return 'simple'
|
152 |
+
elif avg_length < 5000:
|
153 |
+
return 'medium'
|
154 |
+
else:
|
155 |
+
return 'complex'
|
156 |
+
|
157 |
def evaluate(input_data):
|
158 |
"""评估代码的主函数
|
159 |
|
|
|
246 |
Returns:
|
247 |
dict: 评估结果
|
248 |
"""
|
249 |
+
# a) 估计此任务的特征
|
250 |
+
if isinstance(input_data, list) and len(input_data) > 0:
|
251 |
+
sample_task = input_data[0]
|
252 |
+
language = sample_task.get('language', 'unknown') if isinstance(sample_task, dict) else 'unknown'
|
253 |
+
task_size = len(input_data)
|
254 |
+
task_complexity = _estimate_task_complexity(input_data)
|
255 |
+
else:
|
256 |
+
language = 'unknown'
|
257 |
+
task_size = 1
|
258 |
+
task_complexity = 'medium'
|
259 |
+
|
260 |
+
# b) 估计完成时间用于前端显示
|
261 |
+
estimated_time_per_task = _get_estimated_time_for_task(language, task_complexity)
|
262 |
+
estimated_total_time = estimated_time_per_task * task_size
|
263 |
+
|
264 |
# 获取队列当前状态
|
265 |
queue_info = get_queue_status()
|
266 |
waiting_tasks = queue_info['waiting_tasks']
|
|
|
275 |
'status': 'queued',
|
276 |
'queued_time': request_time,
|
277 |
'queue_position': task_queue.qsize() + 1,
|
278 |
+
'synchronous': True, # 标记为同步任务
|
279 |
+
'estimated_factors': {
|
280 |
+
'language': language,
|
281 |
+
'size': task_size,
|
282 |
+
'complexity': task_complexity
|
283 |
+
},
|
284 |
+
'estimated_time': estimated_total_time
|
285 |
}
|
286 |
|
287 |
# 将任务添加到队列
|
|
|
306 |
# 短暂睡眠避免CPU占用过高
|
307 |
time.sleep(0.1)
|
308 |
|
309 |
+
def _get_estimated_time_for_task(language, complexity):
|
310 |
+
"""获取特定类型任务的估计处理时间
|
311 |
+
|
312 |
+
Args:
|
313 |
+
language: 编程语言
|
314 |
+
complexity: 任务复杂度
|
315 |
+
|
316 |
+
Returns:
|
317 |
+
float: 估计的处理时间(秒)
|
318 |
+
"""
|
319 |
+
key = f"{language}_{complexity}"
|
320 |
+
|
321 |
+
# 如果有历史数据,使用中位数作为估计值
|
322 |
+
if key in task_type_times and len(task_type_times[key]) > 0:
|
323 |
+
return np.median(task_type_times[key])
|
324 |
+
|
325 |
+
# 否则使用基于复杂度的默认估计值
|
326 |
+
if complexity == 'simple':
|
327 |
+
return 1.0
|
328 |
+
elif complexity == 'medium':
|
329 |
+
return 3.0
|
330 |
+
else: # complex
|
331 |
+
return 8.0
|
332 |
+
|
333 |
def enqueue_task(input_data):
|
334 |
"""将任务添加到队列
|
335 |
|
|
|
339 |
Returns:
|
340 |
dict: 包含任务ID和状态的字典
|
341 |
"""
|
342 |
+
# 估计任务特征和处理时间
|
343 |
+
if isinstance(input_data, list) and len(input_data) > 0:
|
344 |
+
sample_task = input_data[0]
|
345 |
+
language = sample_task.get('language', 'unknown') if isinstance(sample_task, dict) else 'unknown'
|
346 |
+
task_size = len(input_data)
|
347 |
+
task_complexity = _estimate_task_complexity(input_data)
|
348 |
+
else:
|
349 |
+
language = 'unknown'
|
350 |
+
task_size = 1
|
351 |
+
task_complexity = 'medium'
|
352 |
+
|
353 |
+
estimated_time_per_task = _get_estimated_time_for_task(language, task_complexity)
|
354 |
+
estimated_total_time = estimated_time_per_task * task_size
|
355 |
+
|
356 |
task_id = str(uuid.uuid4())
|
357 |
request_time = time.time()
|
358 |
|
|
|
361 |
task_status[task_id] = {
|
362 |
'status': 'queued',
|
363 |
'queued_time': request_time,
|
364 |
+
'queue_position': task_queue.qsize() + 1,
|
365 |
+
'estimated_factors': {
|
366 |
+
'language': language,
|
367 |
+
'size': task_size,
|
368 |
+
'complexity': task_complexity
|
369 |
+
},
|
370 |
+
'estimated_time': estimated_total_time
|
371 |
}
|
372 |
|
373 |
+
# 获取队列状态以计算等待时间
|
374 |
+
queue_info = get_queue_status()
|
375 |
+
est_wait = queue_info['estimated_wait']
|
376 |
+
|
377 |
# 将任务添加到队列
|
378 |
task_queue.put((task_id, input_data, request_time))
|
379 |
|
|
|
381 |
'task_id': task_id,
|
382 |
'status': 'queued',
|
383 |
'queue_position': task_status[task_id]['queue_position'],
|
384 |
+
'estimated_wait': est_wait,
|
385 |
+
'estimated_processing': estimated_total_time
|
386 |
}
|
387 |
|
388 |
def check_status(task_id):
|
|
|
413 |
dict: 包含队列状态的字典
|
414 |
"""
|
415 |
with lock:
|
416 |
+
# 获取队列中的所有任务
|
417 |
+
queued_tasks = [t for t in task_status.values() if t['status'] == 'queued']
|
418 |
+
processing_tasks = [t for t in task_status.values() if t['status'] == 'processing']
|
419 |
+
|
420 |
queue_size = task_queue.qsize()
|
421 |
+
active_tasks = len(processing_tasks)
|
422 |
+
waiting_tasks = len(queued_tasks)
|
423 |
|
424 |
+
# 更准确地估计等待时间
|
425 |
+
# 1. 计算当前处理中任务的剩余时间
|
426 |
+
remaining_processing_time = 0
|
427 |
+
for task in processing_tasks:
|
428 |
+
# 如果任务有开始时间和估计总时间
|
429 |
+
if 'start_time' in task and 'estimated_time' in task:
|
430 |
+
elapsed = time.time() - task['start_time']
|
431 |
+
# 剩余时间 = 估计总时间 - 已经过去的时间
|
432 |
+
remaining = max(0, task['estimated_time'] - elapsed)
|
433 |
+
remaining_processing_time += remaining
|
434 |
+
else:
|
435 |
+
# 默认假设还需要2秒
|
436 |
+
remaining_processing_time += 2
|
437 |
+
|
438 |
+
# 使用动态均衡:根据工作线程数量平衡负载
|
439 |
+
if active_tasks > 0:
|
440 |
+
remaining_processing_time = remaining_processing_time / min(active_tasks, worker_threads)
|
441 |
+
|
442 |
+
# 2. 计算排队中任务的估计处理时间
|
443 |
+
queued_processing_time = 0
|
444 |
+
for task in queued_tasks:
|
445 |
+
if 'estimated_time' in task:
|
446 |
+
queued_processing_time += task['estimated_time']
|
447 |
+
else:
|
448 |
+
# 默认假设每个任务5秒
|
449 |
+
queued_processing_time += 5
|
450 |
|
451 |
+
# 考虑并行处理:分摊到可用工作线程
|
452 |
+
if worker_threads > 0 and queued_processing_time > 0:
|
453 |
+
queued_processing_time = queued_processing_time / worker_threads
|
|
|
|
|
|
|
|
|
|
|
454 |
|
455 |
+
# 总估计等待时间
|
456 |
+
estimated_wait = remaining_processing_time + queued_processing_time
|
|
|
|
|
|
|
|
|
|
|
457 |
|
458 |
+
# 应用统计校正:使用历史数据调整预测
|
459 |
+
if task_history:
|
460 |
+
# 计算历史预测与实际处理时间的比例
|
461 |
+
prediction_ratios = []
|
462 |
+
for task in task_history:
|
463 |
+
if 'factors' in task and 'estimated_time' in task:
|
464 |
+
prediction_ratios.append(task['process_time'] / task['estimated_time'])
|
465 |
+
|
466 |
+
# 如果有足够数据,使用中位数比例调整当前预测
|
467 |
+
if prediction_ratios:
|
468 |
+
correction_factor = np.median(prediction_ratios)
|
469 |
+
# 应用校正因子,但限制在合理范围内
|
470 |
+
correction_factor = max(0.5, min(2.0, correction_factor))
|
471 |
+
estimated_wait *= correction_factor
|
472 |
+
|
473 |
+
# 确保等待时间有意义
|
474 |
+
estimated_wait = max(0.1, estimated_wait)
|
475 |
+
if waiting_tasks == 0 and active_tasks == 0:
|
476 |
+
estimated_wait = 0
|
477 |
+
|
478 |
+
# 获取最近处理的任务
|
479 |
+
recent_tasks = task_history[-5:] if task_history else []
|
480 |
|
481 |
return {
|
482 |
'queue_size': queue_size,
|
|
|
484 |
'waiting_tasks': waiting_tasks,
|
485 |
'worker_threads': worker_threads,
|
486 |
'estimated_wait': estimated_wait,
|
|
|
487 |
'recent_tasks': recent_tasks
|
488 |
}
|
489 |
|
|
|
507 |
minutes = int((seconds % 3600) / 60)
|
508 |
return f"{hours}小时{minutes}分钟"
|
509 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
def ui_get_queue_info():
|
511 |
"""获取队列信息的UI函数
|
512 |
|
|
|
533 |
</tr>
|
534 |
"""
|
535 |
|
|
|
|
|
|
|
536 |
return f"""
|
537 |
<div class="dashboard">
|
538 |
<div class="queue-info-card main-card">
|
|
|
553 |
</div>
|
554 |
|
555 |
<div class="wait-time">
|
|
|
556 |
<p><b>当前预计等待时间:</b> {format_time(queue_info['estimated_wait'])}</p>
|
557 |
<p class="last-update"><small>最后更新: {datetime.now().strftime('%H:%M:%S')}</small></p>
|
558 |
</div>
|
|
|
576 |
</div>
|
577 |
"""
|
578 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
# 自定义CSS
|
580 |
custom_css = """
|
581 |
.container {
|