hellokawei commited on
Commit
c760938
·
verified ·
1 Parent(s): 42d2955

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -300
app.py CHANGED
@@ -1,18 +1,18 @@
1
- # app.py
2
-
3
  import gradio as gr
4
  from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
5
  import pandas as pd
6
  from apscheduler.schedulers.background import BackgroundScheduler
7
  from huggingface_hub import snapshot_download
8
  import os
9
- import json # 导入 json 和 os 库,用于处理文件
 
 
10
 
11
  # 从现有的 src 导入,这些我们无法修改,但需要继续使用其提供的功能
12
  from src.about import (
13
  CITATION_BUTTON_LABEL,
14
  CITATION_BUTTON_TEXT,
15
- EVALUATION_QUEUE_TEXT,
16
  INTRODUCTION_TEXT,
17
  LLM_BENCHMARKS_TEXT,
18
  TITLE,
@@ -21,14 +21,11 @@ from src.display.css_html_js import custom_css
21
 
22
  # =====================================================================
23
  # **重要修改开始:直接在 app.py 中定义 GRACE 相关的类和函数**
24
- # 我们无法修改 src/display/utils.py 和 src/populate.py
25
- # 所以在这里重新定义或覆盖部分功能,以添加 GRACE 维度。
26
  # =====================================================================
27
 
28
  from enum import Enum
29
  from typing import NamedTuple, List
30
 
31
- # 重新定义 Column 类(如果 src/display/utils 中有,这里的定义将优先被 app.py 使用)
32
  class Column(NamedTuple):
33
  name: str
34
  type: str
@@ -37,22 +34,13 @@ class Column(NamedTuple):
37
  hidden: bool = False
38
  filterable: bool = True
39
 
40
- # 重新定义 AutoEvalColumn,加入 GRACE 维度
41
  class AutoEvalColumn(Enum):
42
- # 尽可能复制 src/display/utils.py 中已有的 AutoEvalColumn 定义
43
- # 但请注意,如果您不知道原始的精确定义,这可能会导致不一致。
44
- # 这里我将使用一个合理的通用版本,并加入 GRACE 维度。
45
- # 您需要确保这些列名与您评估结果数据中的列名匹配。
46
  model = Column("Model", "str", displayed_by_default=True, never_hidden=True)
47
  model_type = Column("Model type", "str", displayed_by_default=True)
48
  precision = Column("Precision", "str", displayed_by_default=False)
49
  params = Column("Params (B)", "number", displayed_by_default=True)
50
  license = Column("License", "str", displayed_by_default=False)
51
  still_on_hub = Column("On Hub", "boolean", displayed_by_default=True, hidden=True)
52
- # ... 您可以尝试从已运行的 Leaderboard 检查元素,推断出其他默认列 ...
53
- # 例如:
54
- # dataset = Column("Dataset", "str", displayed_by_default=False)
55
- # average_score = Column("Average Score", "number", displayed_by_default=True) # 假设有一个总分
56
 
57
  # GRACE 框架新增列
58
  generalization_score = Column("G: 泛化性", "number", displayed_by_default=True, filterable=True)
@@ -61,39 +49,27 @@ class AutoEvalColumn(Enum):
61
  consistency_score = Column("C: 一致性", "number", displayed_by_default=True, filterable=True)
62
  efficiency_score = Column("E: 效率性", "number", displayed_by_default=True, filterable=True)
63
 
64
- # 重新定义 fields() 函数
65
  def fields(cls: type) -> List[Column]:
66
  return [c.value for c in cls if isinstance(c.value, Column)]
67
 
68
- # 重新定义 ModelType 枚举(选择一个作为焦点,例如 LanguageModeling)
69
  class ModelType(Enum):
70
  LanguageModeling = "语言生成模型"
71
  ImageGeneration = "图像生成模型"
72
- AudioSynthesis = "音频模型"
73
- # ... 根据您实际的 src/display/utils.py 或项目需求添加其他类型
74
- Unknown = "未知" # 保持 Unknown,防止意外
75
 
76
  def to_str(self, sep: str = " : ") -> str:
77
  return f"{self.name}{sep}{self.value}"
78
 
79
- # 重新定义 WeightType 和 Precision 枚举
80
  class WeightType(Enum):
81
  Original = NamedTuple("Original", [("name", str)])("Original")
82
  Lora = NamedTuple("Lora", [("name", str)])("Lora")
83
- # Add other types if necessary from your original src/display/utils.py
84
- # Example:
85
- # Adapter = NamedTuple("Adapter", [("name", str)])("Adapter")
86
 
87
  class Precision(Enum):
88
  float16 = NamedTuple("float16", [("name", str)])("float16")
89
  bfloat16 = NamedTuple("bfloat16", [("name", str)])("bfloat16")
90
- # Add other types if necessary
91
  Unknown = NamedTuple("Unknown", [("name", str)])("Unknown")
92
 
93
-
94
- # 重新定义 COLS, BENCHMARK_COLS, EVAL_COLS, EVAL_TYPES
95
- # 这些列表现在将使用我们在 app.py 中定义的 AutoEvalColumn
96
- COLS = fields(AutoEvalColumn) # 所有列,包括 GRACE
97
  BENCHMARK_COLS = [
98
  AutoEvalColumn.model.value,
99
  AutoEvalColumn.params.value,
@@ -102,193 +78,191 @@ BENCHMARK_COLS = [
102
  AutoEvalColumn.artistry_score.value,
103
  AutoEvalColumn.consistency_score.value,
104
  AutoEvalColumn.efficiency_score.value,
105
- # ... 其他你想在基准测试中默认显示的列
106
  ]
107
- EVAL_COLS = [c.name for c in fields(AutoEvalColumn)] # 评估队列的列名
108
- EVAL_TYPES = [c.type for c in fields(AutoEvalColumn)] # 评估队列的列类型
109
-
110
-
111
- # 重新定义 get_leaderboard_df 和 get_evaluation_queue_df 函数
112
- # 这两个函数现在将直接在 app.py 中处理数据加载和 GRACE 维度的添加。
113
- # 由于您无法修改 src/populate.py,我们需要在这里实现其功能。
114
 
 
 
115
  def get_leaderboard_df(eval_results_path: str, eval_requests_path: str, cols: list, benchmark_cols: list) -> pd.DataFrame:
116
- """
117
- 加载评估结果并构建排行榜 DataFrame。
118
- 此函数现在在 app.py 中定义,以包含 GRACE 分数。
119
- """
120
- all_results = []
121
-
122
- # ============== **重点修改区域:GRACE 分数的数据来源** ==============
123
- # 您需要根据您实际的评估结果文件格式来读取数据并包含 GRACE 分数。
124
- # 假设您的评估结果是在 EVAL_RESULTS_PATH 目录下,每个模型的 JSON 文件。
125
- # 示例路径:EVAL_RESULTS_PATH/model_name/results.json
126
- if os.path.exists(eval_results_path) and os.path.isdir(eval_results_path):
127
- for model_dir in os.listdir(eval_results_path):
128
- model_path = os.path.join(eval_results_path, model_dir)
129
- if os.path.isdir(model_path):
130
- # 尝试读取 results.json 或其他命名约定
131
- results_file = os.path.join(model_path, "results.json")
132
- if os.path.exists(results_file):
133
- try:
134
- with open(results_file, "r", encoding="utf-8") as f:
135
- data = json.load(f)
136
- # 确保 data 字典中包含 'generalization_score', 'relevance_score' 等键
137
- # 如果您的原始结果没有这些键,您需要在外部评估过程生成它们,或在这里进行计算。
138
- # 这里假设结果文件中直接有这些字段。
139
- all_results.append(data)
140
- except json.JSONDecodeError as e:
141
- print(f"解析 {results_file} 失败: {e}")
142
- except Exception as e:
143
- print(f"读取 {results_file} 发生未知错误: {e}")
144
- else:
145
- print(f"在 {model_path} 中未找到 results.json。")
146
- else:
147
- print(f"评估结果路径不存在或不是目录: {eval_results_path}")
148
-
149
- # 如果没有实际结果,提供一些模拟数据以便测试和展示 GRACE 维度
150
- if not all_results:
151
- print("未找到评估结果,使用模拟数据填充排行榜。")
152
- all_results = [
153
- {
154
- "model": "模拟模型_A",
155
- "model_type": ModelType.LanguageModeling.to_str(),
156
- "precision": Precision.float16.value.name,
157
- "params": 7.0,
158
- "license": "apache-2.0",
159
- "still_on_hub": True,
160
- "generalization_score": 0.85,
161
- "relevance_score": 0.92,
162
- "artistry_score": 0.78,
163
- "consistency_score": 0.88,
164
- "efficiency_score": 0.95,
165
- # ... 其他您希望展示的列,确保与 AutoEvalColumn 定义匹配
166
- },
167
- {
168
- "model": "模拟模型_B",
169
- "model_type": ModelType.LanguageModeling.to_str(),
170
- "precision": Precision.float16.value.name,
171
- "params": 13.0,
172
- "license": "mit",
173
- "still_on_hub": True,
174
- "generalization_score": 0.90,
175
- "relevance_score": 0.88,
176
- "artistry_score": 0.85,
177
- "consistency_score": 0.91,
178
- "efficiency_score": 0.90,
179
- # ...
180
- },
181
- {
182
- "model": "模拟模型_C_图像",
183
- "model_type": ModelType.ImageGeneration.to_str(),
184
- "precision": Precision.bfloat16.value.name,
185
- "params": 3.0,
186
- "license": "gpl-3.0",
187
- "still_on_hub": True,
188
- "generalization_score": 0.70,
189
- "relevance_score": 0.75,
190
- "artistry_score": 0.90,
191
- "consistency_score": None, # 图像模型可能没有一致性得分
192
- "efficiency_score": 0.80,
193
- # ...
194
- }
195
- ]
196
- # =====================================================================
197
-
198
- if all_results:
199
- df = pd.DataFrame(all_results)
200
- else:
201
- df = pd.DataFrame(columns=[c.name for c in fields(AutoEvalColumn)])
202
-
203
- # 确保所有期望的列都存在,如果缺失则填充 None
204
- expected_cols_names = [c.name for c in cols]
205
- for col_name in expected_cols_names:
206
- if col_name not in df.columns:
207
- df[col_name] = None
208
-
209
- # 对 DataFrame 进行必要的处理,例如排序
210
- if AutoEvalColumn.generalization_score.value.name in df.columns and not df[AutoEvalColumn.generalization_score.value.name].isnull().all():
211
- df = df.sort_values(by=AutoEvalColumn.generalization_score.value.name, ascending=False).reset_index(drop=True)
212
-
213
  return df
214
 
215
  def get_evaluation_queue_df(eval_requests_path: str, eval_cols: list):
216
- """
217
- 加载评估请求队列数据。此函数现在在 app.py 中定义。
218
- """
219
- pending_requests = []
220
- running_requests = []
221
- finished_requests = []
222
-
223
- # 示例:假设请求文件是位于 eval_requests_path 的 jsonl 文件
224
- if os.path.exists(eval_requests_path) and os.path.isdir(eval_requests_path):
225
- for filename in os.listdir(eval_requests_path):
226
- if filename.endswith(".jsonl"): # 或者其他你存储请求的文件格式
227
- filepath = os.path.join(eval_requests_path, filename)
228
- try:
229
- with open(filepath, "r", encoding="utf-8") as f:
230
- for line in f:
231
- try:
232
- request_data = json.loads(line)
233
- status = request_data.get('status', 'pending') # 假设请求数据中有 'status' 字段
234
- if status == 'finished':
235
- finished_requests.append(request_data)
236
- elif status == 'running':
237
- running_requests.append(request_data)
238
- else: # 默认或其他状态归为 pending
239
- pending_requests.append(request_data)
240
- except json.JSONDecodeError as e:
241
- print(f"解析 JSONL 行失败: {line.strip()}, 错误: {e}")
242
- except Exception as e:
243
- print(f"读取 {filepath} 失败: {e}")
244
- else:
245
- print(f"评估请求路径不存在或不是目录: {eval_requests_path}")
246
-
247
- # 将列表转换为 DataFrame,并确保列与 eval_cols 匹配
248
- finished_df = pd.DataFrame(finished_requests, columns=eval_cols) if finished_requests else pd.DataFrame(columns=eval_cols)
249
- running_df = pd.DataFrame(running_requests, columns=eval_cols) if running_requests else pd.DataFrame(columns=eval_cols)
250
- pending_df = pd.DataFrame(pending_requests, columns=eval_cols) if pending_requests else pd.DataFrame(columns=eval_cols)
251
-
252
- return finished_df, running_df, pending_df
253
 
254
  # =====================================================================
255
- # **重要修改结束:直接在 app.py 中定义 GRACE 相关的类和函数**
256
  # =====================================================================
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- # 继续使用 src.envs 中的 API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN
260
- # 这里我们假设这些环境变量或常量是可以通过某种方式加载的,或者在 Space 设置中配置的。
261
- # 如果 src.envs 也是无法修改的,且您无法通过环境变量设置这些值,那可能会有问题。
262
- # 通常在 Hugging Face Space 中,这些值是从环境变量或 Space Secrets 中加载的。
263
- # 这里我不会重定义它们,假设它们是可用的。
264
- from src.envs import API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN
265
- from src.submission.submit import add_new_eval # 假设 add_new_eval 也是从 src 导入的
266
-
267
- def restart_space():
268
- API.restart_space(repo_id=REPO_ID)
269
-
270
- ### Space initialisation
271
- try:
272
- print(f"下载评估请求到: {EVAL_REQUESTS_PATH}")
273
- snapshot_download(
274
- repo_id=QUEUE_REPO, local_dir=EVAL_REQUESTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
275
- )
276
- except Exception as e:
277
- print(f"下载评估请求失败: {e}")
278
- restart_space()
279
- try:
280
- print(f"下载评估结果到: {EVAL_RESULTS_PATH}")
281
- snapshot_download(
282
- repo_id=RESULTS_REPO, local_dir=EVAL_RESULTS_PATH, repo_type="dataset", tqdm_class=None, etag_timeout=30, token=TOKEN
283
- )
284
- except Exception as e:
285
- print(f"下载评估结果失败: {e}")
286
- restart_space()
287
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
 
289
- # 现在,这些函数调用将使用我们刚刚在 app.py 中定义的版本
290
  LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)
291
-
292
  (
293
  finished_eval_queue_df,
294
  running_eval_queue_df,
@@ -299,7 +273,7 @@ def init_leaderboard(dataframe):
299
  if dataframe is None or dataframe.empty:
300
  print("Leaderboard DataFrame 为空或 None,初始化空排行榜。")
301
  return Leaderboard(
302
- value=pd.DataFrame(columns=[c.name for c in fields(AutoEvalColumn)]), # 提供空但带列名的DataFrame
303
  datatype=[c.type for c in fields(AutoEvalColumn)],
304
  select_columns=SelectColumns(
305
  default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
@@ -308,7 +282,7 @@ def init_leaderboard(dataframe):
308
  ),
309
  search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
310
  hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
311
- filter_columns=[], # 如果是空 DataFrame,这里不添加具体的过滤器,避免错误
312
  bool_checkboxgroup_label="隐藏模型",
313
  interactive=False,
314
  )
@@ -337,13 +311,13 @@ def init_leaderboard(dataframe):
337
  AutoEvalColumn.still_on_hub.name, type="boolean", label="已删除/不完整", default=True
338
  ),
339
  # 为 GRACE 分数添加筛选器 (滑块)
340
- # 假设分数在 0.0 到 1.0 之间
341
  ColumnFilter(
342
  AutoEvalColumn.generalization_score.value.name,
343
  type="slider",
344
  min=0.0,
345
  max=1.0,
346
  label="G: 泛化性得分",
 
347
  ),
348
  ColumnFilter(
349
  AutoEvalColumn.relevance_score.value.name,
@@ -351,6 +325,7 @@ def init_leaderboard(dataframe):
351
  min=0.0,
352
  max=1.0,
353
  label="R: 相关性得分",
 
354
  ),
355
  ColumnFilter(
356
  AutoEvalColumn.artistry_score.value.name,
@@ -358,6 +333,7 @@ def init_leaderboard(dataframe):
358
  min=0.0,
359
  max=1.0,
360
  label="A: 创新表现力得分",
 
361
  ),
362
  ColumnFilter(
363
  AutoEvalColumn.consistency_score.value.name,
@@ -365,6 +341,7 @@ def init_leaderboard(dataframe):
365
  min=0.0,
366
  max=1.0,
367
  label="C: 一致性得���",
 
368
  ),
369
  ColumnFilter(
370
  AutoEvalColumn.efficiency_score.value.name,
@@ -372,6 +349,7 @@ def init_leaderboard(dataframe):
372
  min=0.0,
373
  max=1.0,
374
  label="E: 效率性得分",
 
375
  ),
376
  ],
377
  bool_checkboxgroup_label="隐藏模型",
@@ -385,102 +363,74 @@ with demo:
385
  gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
386
 
387
  with gr.Tabs(elem_classes="tab-buttons") as tabs:
388
- with gr.TabItem("🏅 LLM Benchmark", elem_id="llm-benchmark-tab-table", id=0):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  leaderboard = init_leaderboard(LEADERBOARD_DF)
390
 
391
  with gr.TabItem("📝 关于", elem_id="llm-benchmark-tab-table", id=2):
392
  gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
393
 
394
- with gr.TabItem("🚀 在此提交!", elem_id="llm-benchmark-tab-table", id=3):
395
- with gr.Column():
396
- with gr.Row():
397
- gr.Markdown(EVALUATION_QUEUE_TEXT, elem_classes="markdown-text")
398
-
399
- with gr.Column():
400
- with gr.Accordion(
401
- f"✅ 已完成评估 ({len(finished_eval_queue_df)})",
402
- open=False,
403
- ):
404
- with gr.Row():
405
- finished_eval_table = gr.components.Dataframe(
406
- value=finished_eval_queue_df,
407
- headers=EVAL_COLS,
408
- datatype=EVAL_TYPES,
409
- row_count=5,
410
- label="已完成评估队列",
411
- )
412
- with gr.Accordion(
413
- f"🔄 正在运行的评估队列 ({len(running_eval_queue_df)})",
414
- open=False,
415
- ):
416
- with gr.Row():
417
- running_eval_table = gr.components.Dataframe(
418
- value=running_eval_queue_df,
419
- headers=EVAL_COLS,
420
- datatype=EVAL_TYPES,
421
- row_count=5,
422
- label="正在运行的评估队列",
423
- )
424
-
425
- with gr.Accordion(
426
- f"⏳ 待处理的评估队列 ({len(pending_eval_queue_df)})",
427
- open=False,
428
- ):
429
- with gr.Row():
430
- pending_eval_table = gr.components.Dataframe(
431
- value=pending_eval_queue_df,
432
- headers=EVAL_COLS,
433
- datatype=EVAL_TYPES,
434
- row_count=5,
435
- label="待处理的评估队列",
436
- )
437
- with gr.Row():
438
- gr.Markdown("# ✉️✨ 在此提交您的模型!", elem_classes="markdown-text")
439
 
440
- with gr.Row():
441
- with gr.Column():
442
- model_name_textbox = gr.Textbox(label="模型名称")
443
- revision_name_textbox = gr.Textbox(label="修订提交", placeholder="main")
444
- # 设置模型类型的默认值,以体现项目焦点(例如:语言生成模型)
445
- model_type = gr.Dropdown(
446
- choices=[t.to_str(" : ") for t in ModelType if t != ModelType.Unknown],
447
- label="模型类型",
448
- multiselect=False,
449
- value=ModelType.LanguageModeling.to_str(" : "), # 示例:聚焦于语言生成模型
450
- interactive=True,
451
- )
452
-
453
- with gr.Column():
454
- precision = gr.Dropdown(
455
- choices=[i.value.name for i in Precision if i != Precision.Unknown],
456
- label="精度",
457
- multiselect=False,
458
- value="float16",
459
- interactive=True,
460
- )
461
- weight_type = gr.Dropdown(
462
- choices=[i.value.name for i in WeightType],
463
- label="权重类型",
464
- multiselect=False,
465
- value="Original",
466
- interactive=True,
467
- )
468
- base_model_name_textbox = gr.Textbox(label="基础模型 (适用于 delta 或 adapter 权重)")
469
-
470
- submit_button = gr.Button("提交评估")
471
- submission_result = gr.Markdown()
472
- submit_button.click(
473
- add_new_eval,
474
- [
475
- model_name_textbox,
476
- base_model_name_textbox,
477
- revision_name_textbox,
478
- precision,
479
- weight_type,
480
- model_type,
481
- ],
482
- submission_result,
483
- )
484
 
485
  with gr.Row():
486
  with gr.Accordion("📙 引用", open=False):
@@ -492,8 +442,10 @@ with demo:
492
  show_copy_button=True,
493
  )
494
 
 
 
495
  scheduler = BackgroundScheduler()
496
- # 30 分钟重启一次 Space,确保数据刷新
497
- scheduler.add_job(restart_space, "interval", seconds=1800)
498
  scheduler.start()
499
- demo.queue(default_concurrency_limit=40).launch()
 
 
 
 
1
  import gradio as gr
2
  from gradio_leaderboard import Leaderboard, ColumnFilter, SelectColumns
3
  import pandas as pd
4
  from apscheduler.schedulers.background import BackgroundScheduler
5
  from huggingface_hub import snapshot_download
6
  import os
7
+ import json
8
+ from transformers import AutoModelForCausalLM, AutoTokenizer
9
+ import torch # 导入 torch
10
 
11
  # 从现有的 src 导入,这些我们无法修改,但需要继续使用其提供的功能
12
  from src.about import (
13
  CITATION_BUTTON_LABEL,
14
  CITATION_BUTTON_TEXT,
15
+ EVALUATION_QUEUE_TEXT, # 这个可能不再需要,但保留以防万一
16
  INTRODUCTION_TEXT,
17
  LLM_BENCHMARKS_TEXT,
18
  TITLE,
 
21
 
22
  # =====================================================================
23
  # **重要修改开始:直接在 app.py 中定义 GRACE 相关的类和函数**
 
 
24
  # =====================================================================
25
 
26
  from enum import Enum
27
  from typing import NamedTuple, List
28
 
 
29
  class Column(NamedTuple):
30
  name: str
31
  type: str
 
34
  hidden: bool = False
35
  filterable: bool = True
36
 
 
37
  class AutoEvalColumn(Enum):
 
 
 
 
38
  model = Column("Model", "str", displayed_by_default=True, never_hidden=True)
39
  model_type = Column("Model type", "str", displayed_by_default=True)
40
  precision = Column("Precision", "str", displayed_by_default=False)
41
  params = Column("Params (B)", "number", displayed_by_default=True)
42
  license = Column("License", "str", displayed_by_default=False)
43
  still_on_hub = Column("On Hub", "boolean", displayed_by_default=True, hidden=True)
 
 
 
 
44
 
45
  # GRACE 框架新增列
46
  generalization_score = Column("G: 泛化性", "number", displayed_by_default=True, filterable=True)
 
49
  consistency_score = Column("C: 一致性", "number", displayed_by_default=True, filterable=True)
50
  efficiency_score = Column("E: 效率性", "number", displayed_by_default=True, filterable=True)
51
 
 
52
  def fields(cls: type) -> List[Column]:
53
  return [c.value for c in cls if isinstance(c.value, Column)]
54
 
 
55
  class ModelType(Enum):
56
  LanguageModeling = "语言生成模型"
57
  ImageGeneration = "图像生成模型"
58
+ Unknown = "未知"
 
 
59
 
60
  def to_str(self, sep: str = " : ") -> str:
61
  return f"{self.name}{sep}{self.value}"
62
 
 
63
  class WeightType(Enum):
64
  Original = NamedTuple("Original", [("name", str)])("Original")
65
  Lora = NamedTuple("Lora", [("name", str)])("Lora")
 
 
 
66
 
67
  class Precision(Enum):
68
  float16 = NamedTuple("float16", [("name", str)])("float16")
69
  bfloat16 = NamedTuple("bfloat16", [("name", str)])("bfloat16")
 
70
  Unknown = NamedTuple("Unknown", [("name", str)])("Unknown")
71
 
72
+ COLS = fields(AutoEvalColumn)
 
 
 
73
  BENCHMARK_COLS = [
74
  AutoEvalColumn.model.value,
75
  AutoEvalColumn.params.value,
 
78
  AutoEvalColumn.artistry_score.value,
79
  AutoEvalColumn.consistency_score.value,
80
  AutoEvalColumn.efficiency_score.value,
 
81
  ]
82
+ EVAL_COLS = [c.name for c in fields(AutoEvalColumn)]
83
+ EVAL_TYPES = [c.type for c in fields(AutoEvalColumn)]
 
 
 
 
 
84
 
85
+ # 简化 get_leaderboard_df 和 get_evaluation_queue_df
86
+ # 由于我们是手动比较,而不是自动评估,这些函数更多是用于显示模拟数据
87
  def get_leaderboard_df(eval_results_path: str, eval_requests_path: str, cols: list, benchmark_cols: list) -> pd.DataFrame:
88
+ print("使用模拟数据填充排行榜。")
89
+ # 这里我们不再尝试从文件读取,直接生成模拟数据
90
+ all_results = [
91
+ {
92
+ "model": "google/gemma-2b-it", # 示例模型1
93
+ "model_type": ModelType.LanguageModeling.to_str(),
94
+ "precision": Precision.float16.value.name,
95
+ "params": 2.0,
96
+ "license": "apache-2.0",
97
+ "still_on_hub": True,
98
+ "generalization_score": 0.0, # 初始为0,等待用户输入
99
+ "relevance_score": 0.0,
100
+ "artistry_score": 0.0,
101
+ "consistency_score": 0.0,
102
+ "efficiency_score": 0.0,
103
+ },
104
+ {
105
+ "model": "microsoft/phi-2", # 示例模型2
106
+ "model_type": ModelType.LanguageModeling.to_str(),
107
+ "precision": Precision.float16.value.name,
108
+ "params": 2.7,
109
+ "license": "mit",
110
+ "still_on_hub": True,
111
+ "generalization_score": 0.0,
112
+ "relevance_score": 0.0,
113
+ "artistry_score": 0.0,
114
+ "consistency_score": 0.0,
115
+ "efficiency_score": 0.0,
116
+ },
117
+ {
118
+ "model": "EleutherAI/gpt-neo-125m", # 示例模型3,非常小以确保能加载
119
+ "model_type": ModelType.LanguageModeling.to_str(),
120
+ "precision": Precision.float16.value.name,
121
+ "params": 0.125,
122
+ "license": "apache-2.0",
123
+ "still_on_hub": True,
124
+ "generalization_score": 0.0,
125
+ "relevance_score": 0.0,
126
+ "artistry_score": 0.0,
127
+ "consistency_score": 0.0,
128
+ "efficiency_score": 0.0,
129
+ }
130
+ ]
131
+ df = pd.DataFrame(all_results)
132
+ # 对 DataFrame 进行必要的处理,例如排序 (这里不需要排序因为分数是0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  return df
134
 
135
  def get_evaluation_queue_df(eval_requests_path: str, eval_cols: list):
136
+ # 评估队列不再是主要功能,返回空 DataFrame
137
+ empty_df = pd.DataFrame(columns=eval_cols)
138
+ return empty_df, empty_df, empty_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  # =====================================================================
141
+ # **重要修改结束**
142
  # =====================================================================
143
 
144
+ # 假设 src.envs 中的 API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN 可用
145
+ # 如果 TOKEN 未在 src.envs 中定义,您需要在 Hugging Face Space Secrets 中设置 HF_TOKEN。
146
+ # 这里为了能运行,我们直接使用 os.getenv 获取 TOKEN。
147
+ # from src.envs import API, EVAL_REQUESTS_PATH, EVAL_RESULTS_PATH, QUEUE_REPO, REPO_ID, RESULTS_REPO, TOKEN
148
+ # 这里需要调整为从环境变量读取,以适应 Hugging Face Space 的最佳实践
149
+ TOKEN = os.getenv("HF_TOKEN") # 确保您的 Space Secrets 中设置了 HF_TOKEN
150
+ # 假设这些路径是可写的,但在此场景下,我们不再依赖它们来存储评估结果
151
+ EVAL_REQUESTS_PATH = "./eval_requests"
152
+ EVAL_RESULTS_PATH = "./eval_results"
153
+ # 对于演示,我们不需要实际的 API 调用来重启 Space 或提交任务
154
+ # 所以我们可以创建一个模拟的 API 类
155
+ class MockAPI:
156
+ def restart_space(self, repo_id: str):
157
+ print(f"MockAPI: Restarting space {repo_id}. (No actual restart for demo)")
158
+ class MockSubmit:
159
+ def add_new_eval(self, *args):
160
+ # 这个函数不再用于实际提交,可以返回一个消息
161
+ return "在此演示中,模型已预先加载,无需提交新评估。"
162
+
163
+ API = MockAPI()
164
+ add_new_eval = MockSubmit().add_new_eval
165
+
166
+ # 预加载模型和分词器
167
+ # 考虑到免费 Space 的资源限制,这里选择较小的模型
168
+ MODELS_TO_COMPARE = [
169
+ {"id": "google/gemma-2b-it", "name": "Gemma 2B Instruct"},
170
+ {"id": "microsoft/phi-2", "name": "Phi-2"},
171
+ {"id": "EleutherAI/gpt-neo-125m", "name": "GPT-Neo 125M"}, # 更小的模型,确保加载
172
+ ]
173
 
174
+ # 用于存储加载的模型和分词器
175
+ loaded_models = {}
176
+
177
+ def load_models():
178
+ global loaded_models
179
+ for model_info in MODELS_TO_COMPARE:
180
+ model_id = model_info["id"]
181
+ model_name = model_info["name"]
182
+ print(f"正在加载模型: {model_name} ({model_id})...")
183
+ try:
184
+ # 尝试加载模型到 GPU (cuda) 或 CPU (cpu)
185
+ device = "cuda" if torch.cuda.is_available() else "cpu"
186
+ print(f"模型 {model_id} 将加载到 {device}")
187
+
188
+ tokenizer = AutoTokenizer.from_pretrained(model_id, token=TOKEN)
189
+ # 使用 torch.float16 torch.bfloat16 减少内存使用
190
+ if device == "cuda":
191
+ model = AutoModelForCausalLM.from_pretrained(
192
+ model_id,
193
+ torch_dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16,
194
+ token=TOKEN
195
+ ).to(device)
196
+ else: # CPU
197
+ model = AutoModelForCausalLM.from_pretrained(model_id, token=TOKEN)
198
+
199
+ loaded_models[model_id] = {"model": model, "tokenizer": tokenizer, "name": model_name}
200
+ print(f"成功加载模型: {model_name}")
201
+ except Exception as e:
202
+ print(f"加载模型 {model_name} ({model_id}) 失败: {e}")
203
+ # 如果加载失败,将该模型从比较列表中移除
204
+ # 或者将其模型对象设置为 None,以便在推理时跳过
205
+ loaded_models[model_id] = None # 表示加载失败
206
+
207
+ # 在应用程序启动时加载模型
208
+ # 注意:在 Gradio Blocks 的 launch() 之前调用,确保模型在界面初始化前加载
209
+ load_models()
210
+
211
+
212
+ # 模型生成函数
213
+ def generate_text(prompt, max_new_tokens=100):
214
+ outputs = {}
215
+ for model_id, model_data in loaded_models.items():
216
+ if model_data: # 确保模型已成功加载
217
+ model = model_data["model"]
218
+ tokenizer = model_data["tokenizer"]
219
+ model_name = model_data["name"]
220
+
221
+ try:
222
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
223
+ # print(f"Generating with {model_name} on device: {model.device}")
224
+ # 调整 generation_config 参数以获得更好的可控性
225
+ generated_ids = model.generate(
226
+ **inputs,
227
+ max_new_tokens=max_new_tokens,
228
+ do_sample=True, # 启用采样
229
+ temperature=0.7, # 控制生成文本的随机性
230
+ top_k=50, # 从概率最高的k个词中选择
231
+ top_p=0.95, # 累积概率达到p的词中选择
232
+ pad_token_id=tokenizer.eos_token_id, # 处理 pad token
233
+ eos_token_id=tokenizer.eos_token_id # 结束标志
234
+ )
235
+ generated_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
236
+ outputs[model_name] = generated_text
237
+ except Exception as e:
238
+ outputs[model_name] = f"生成失败: {e}"
239
+ else:
240
+ outputs[model_data["name"]] = "模型未加载或加载失败。"
241
+ return list(outputs.values()) # 返回一个列表,对应多个输出框
242
+
243
+ # 更新排行榜数据函数
244
+ def update_leaderboard(g_score, r_score, a_score, c_score, e_score, model_idx):
245
+ global LEADERBOARD_DF
246
+ # 假设模型的索引与 MODELS_TO_COMPARE 列表中的顺序一致
247
+ # 在实际应用中,您可能需要更健壮的方式来匹配模型
248
+ if model_idx is not None and 0 <= model_idx < len(MODELS_TO_COMPARE):
249
+ model_id_to_update = MODELS_TO_COMPARE[model_idx]["id"]
250
+ # 找到 DataFrame 中对应的行
251
+ row_index = LEADERBOARD_DF[LEADERBOARD_DF['Model'] == MODELS_TO_COMPARE[model_idx]["name"]].index
252
+ if not row_index.empty:
253
+ # 更新 GRACE 分数 (这里假设是从 0.0-1.0 的分数,Gradio 滑块可能输出 0-100)
254
+ # 如果 Gradio 滑块输出 0-100,需要除以 100 转换为 0-1.0
255
+ LEADERBOARD_DF.loc[row_index, 'G: 泛化性'] = g_score / 100.0
256
+ LEADERBOARD_DF.loc[row_index, 'R: 相关性'] = r_score / 100.0
257
+ LEADERBOARD_DF.loc[row_index, 'A: 创新表现力'] = a_score / 100.0
258
+ LEADERBOARD_DF.loc[row_index, 'C: 一致性'] = c_score / 100.0
259
+ LEADERBOARD_DF.loc[row_index, 'E: 效率性'] = e_score / 100.0
260
+ # 重新排序排行榜 (如果需要根据某个分数排序)
261
+ LEADERBOARD_DF = LEADERBOARD_DF.sort_values(by=AutoEvalColumn.generalization_score.value.name, ascending=False).reset_index(drop=True)
262
+ return LEADERBOARD_DF
263
+ return LEADERBOARD_DF # 返回更新后的 DataFrame
264
 
 
265
  LEADERBOARD_DF = get_leaderboard_df(EVAL_RESULTS_PATH, EVAL_REQUESTS_PATH, COLS, BENCHMARK_COLS)
 
266
  (
267
  finished_eval_queue_df,
268
  running_eval_queue_df,
 
273
  if dataframe is None or dataframe.empty:
274
  print("Leaderboard DataFrame 为空或 None,初始化空排行榜。")
275
  return Leaderboard(
276
+ value=pd.DataFrame(columns=[c.name for c in fields(AutoEvalColumn)]),
277
  datatype=[c.type for c in fields(AutoEvalColumn)],
278
  select_columns=SelectColumns(
279
  default_selection=[c.name for c in fields(AutoEvalColumn) if c.displayed_by_default],
 
282
  ),
283
  search_columns=[AutoEvalColumn.model.name, AutoEvalColumn.license.name],
284
  hide_columns=[c.name for c in fields(AutoEvalColumn) if c.hidden],
285
+ filter_columns=[],
286
  bool_checkboxgroup_label="隐藏模型",
287
  interactive=False,
288
  )
 
311
  AutoEvalColumn.still_on_hub.name, type="boolean", label="已删除/不完整", default=True
312
  ),
313
  # 为 GRACE 分数添加筛选器 (滑块)
 
314
  ColumnFilter(
315
  AutoEvalColumn.generalization_score.value.name,
316
  type="slider",
317
  min=0.0,
318
  max=1.0,
319
  label="G: 泛化性得分",
320
+ step=0.01 # 允许小数
321
  ),
322
  ColumnFilter(
323
  AutoEvalColumn.relevance_score.value.name,
 
325
  min=0.0,
326
  max=1.0,
327
  label="R: 相关性得分",
328
+ step=0.01
329
  ),
330
  ColumnFilter(
331
  AutoEvalColumn.artistry_score.value.name,
 
333
  min=0.0,
334
  max=1.0,
335
  label="A: 创新表现力得分",
336
+ step=0.01
337
  ),
338
  ColumnFilter(
339
  AutoEvalColumn.consistency_score.value.name,
 
341
  min=0.0,
342
  max=1.0,
343
  label="C: 一致性得���",
344
+ step=0.01
345
  ),
346
  ColumnFilter(
347
  AutoEvalColumn.efficiency_score.value.name,
 
349
  min=0.0,
350
  max=1.0,
351
  label="E: 效率性得分",
352
+ step=0.01
353
  ),
354
  ],
355
  bool_checkboxgroup_label="隐藏模型",
 
363
  gr.Markdown(INTRODUCTION_TEXT, elem_classes="markdown-text")
364
 
365
  with gr.Tabs(elem_classes="tab-buttons") as tabs:
366
+ with gr.TabItem("💬 模型比较与生成", elem_id="model-comparison-tab", id=0): # 新的标签页
367
+ gr.Markdown("## 输入您的提示,查看不同模型的生成效果!", elem_classes="markdown-text")
368
+ with gr.Row():
369
+ input_prompt = gr.Textbox(label="输入提示词", placeholder="请写一首关于春天的诗歌。", lines=3)
370
+ generate_button = gr.Button("生成文本")
371
+
372
+ # 创建多个输出框,每个模型一个
373
+ output_boxes = []
374
+ for model_info in MODELS_TO_COMPARE:
375
+ output_boxes.append(gr.Textbox(label=f"{model_info['name']} 的生成结果", lines=5, interactive=False))
376
+
377
+ # 将生成按钮与 generate_text 函数连接
378
+ generate_button.click(
379
+ fn=generate_text,
380
+ inputs=[input_prompt],
381
+ outputs=output_boxes
382
+ )
383
+
384
+ gr.Markdown("## 手动评估 GRACE 维度", elem_classes="markdown-text")
385
+ gr.Markdown("请手动评估上述生成结果,并更新排行榜中的 GRACE 分数。", elem_classes="markdown-text")
386
+
387
+ # 用于选择要评估的模型
388
+ model_selector = gr.Dropdown(
389
+ choices=[(m["name"], idx) for idx, m in enumerate(MODELS_TO_COMPARE)],
390
+ label="选择要评估的模型",
391
+ interactive=True
392
+ )
393
+
394
+ # GRACE 维度滑块
395
+ with gr.Column():
396
+ generalization_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="G: 泛化性得分 (0-100)")
397
+ relevance_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="R: 相关性得分 (0-100)")
398
+ artistry_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="A: 创新表现力得分 (0-100)")
399
+ consistency_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="C: 一致性得分 (0-100)")
400
+ efficiency_slider = gr.Slider(minimum=0, maximum=100, step=1, value=75, label="E: 效率性得分 (0-100)")
401
+
402
+ update_grace_button = gr.Button("更新 GRACE 评分到排行榜")
403
+
404
+ # 更新排行榜的逻辑
405
+ update_grace_button.click(
406
+ fn=update_leaderboard,
407
+ inputs=[
408
+ generalization_slider,
409
+ relevance_slider,
410
+ artistry_slider,
411
+ consistency_slider,
412
+ efficiency_slider,
413
+ model_selector # 传递选中的模型索引
414
+ ],
415
+ outputs=leaderboard # 更新 Leaderboard 组件
416
+ )
417
+
418
+
419
+ with gr.TabItem("🏅 LLM Benchmark", elem_id="llm-benchmark-tab-table", id=1): # 调整 ID
420
  leaderboard = init_leaderboard(LEADERBOARD_DF)
421
 
422
  with gr.TabItem("📝 关于", elem_id="llm-benchmark-tab-table", id=2):
423
  gr.Markdown(LLM_BENCHMARKS_TEXT, elem_classes="markdown-text")
424
 
425
+ with gr.TabItem("🚀 在此提交!", elem_id="llm-benchmark-tab-table", id=3): # 这个标签页保留,但内容将被简化
426
+ gr.Markdown("## 在此演示中,模型已预先加载进行比较,无需提交新模型。", elem_classes="markdown-text")
427
+ gr.Markdown("您可以在 **💬 模型比较与生成** 标签页中输入提示词并评估模型。", elem_classes="markdown-text")
428
+ # 移除所有提交相关的 UI 元素和逻辑
429
+ # 但是由于需要保持 add_new_eval 的引用,我们让它返回一个字符串
430
+ # gr.Textbox(label="模型名称") # 示例:保留一个文本框,但它不会做任何事情
431
+ # gr.Button("提交评估").click(fn=add_new_eval, inputs=[], outputs=[gr.Markdown()])
432
+ gr.Markdown("(本页面仅用于保留原始结构,实际提交功能已禁用)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
434
 
435
  with gr.Row():
436
  with gr.Accordion("📙 引用", open=False):
 
442
  show_copy_button=True,
443
  )
444
 
445
+ # 调度器,每 30 分钟重启一次 Space
446
+ # 在此演示中,由于模型是预加载的,并且没有持续的评估队列,重启的意义不大,但保留。
447
  scheduler = BackgroundScheduler()
448
+ scheduler.add_job(API.restart_space, "interval", seconds=1800, args=[REPO_ID])
 
449
  scheduler.start()
450
+
451
+ demo.queue(default_concurrency_limit=1).launch() # 降低并发限制,避免内存溢出