fix(upstream): add multi-layer cache to survive GitHub raw 429
Browse files起動時に GitHub raw から all_datasets.yaml を直接取得しており、
raw.githubusercontent.com の 429 (rate limit) でアプリ起動が
クラッシュしていた。取得を多層フォールバック化して耐障害性を確保する。
- GitHub raw を指数バックオフで最大3回リトライ
- 429 等で失敗したら jsDelivr CDN ミラーへフォールバック
- ネットワーク取得成功分をローカル永続キャッシュへ退避し再利用
- コールドスタート用にリポジトリ同梱フォールバック (src/data) を追加
- 実行時生成キャッシュ /upstream/ を .gitignore に追加
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- .gitignore +3 -0
- src/data/all_datasets.yaml +227 -0
- src/envs.py +13 -4
- src/upstream.py +118 -6
.gitignore
CHANGED
|
@@ -12,3 +12,6 @@ eval-results/
|
|
| 12 |
eval-queue-bk/
|
| 13 |
eval-results-bk/
|
| 14 |
logs/
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
eval-queue-bk/
|
| 13 |
eval-results-bk/
|
| 14 |
logs/
|
| 15 |
+
|
| 16 |
+
# upstream YAML の永続キャッシュ (実行時生成)
|
| 17 |
+
/upstream/
|
src/data/all_datasets.yaml
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
datasets:
|
| 2 |
+
- aime2024
|
| 3 |
+
- aime2025
|
| 4 |
+
- aio
|
| 5 |
+
- alt-j-to-e
|
| 6 |
+
- alt-e-to-j
|
| 7 |
+
- bigbenchhard_direct
|
| 8 |
+
- bigbenchhard_cot
|
| 9 |
+
- bigbenchhard_ja_direct
|
| 10 |
+
- bigbenchhard_ja_cot
|
| 11 |
+
- chabsa
|
| 12 |
+
- commonsensemoralja
|
| 13 |
+
- drop
|
| 14 |
+
- gsm8k
|
| 15 |
+
- gpqa_diamond_en
|
| 16 |
+
- gpqa_extended_en
|
| 17 |
+
- gpqa_main_en
|
| 18 |
+
- gpqa_diamond_ja
|
| 19 |
+
- gpqa_extended_ja
|
| 20 |
+
- gpqa_main_ja
|
| 21 |
+
- jamc-qa
|
| 22 |
+
- jculture-mcq
|
| 23 |
+
- jamp
|
| 24 |
+
- janli
|
| 25 |
+
- jcommonsenseqa
|
| 26 |
+
- jemhopqa
|
| 27 |
+
- jfinqa
|
| 28 |
+
- jhumaneval
|
| 29 |
+
- jmmlu
|
| 30 |
+
- jnli
|
| 31 |
+
- jsem
|
| 32 |
+
- jsick
|
| 33 |
+
- jsquad
|
| 34 |
+
- jsts
|
| 35 |
+
- kuci
|
| 36 |
+
- mawps
|
| 37 |
+
- mbpp
|
| 38 |
+
- mgsm
|
| 39 |
+
- mmlu_en
|
| 40 |
+
- mmlu_prox_ja
|
| 41 |
+
- mmlu_prox_en
|
| 42 |
+
- mif_eval_ja
|
| 43 |
+
- mif_eval_en
|
| 44 |
+
- mmmlu
|
| 45 |
+
- niilc
|
| 46 |
+
- openbookqa
|
| 47 |
+
- polymath-en
|
| 48 |
+
- polymath-ja
|
| 49 |
+
- structeval
|
| 50 |
+
- triviaqa
|
| 51 |
+
- winogrande_xl
|
| 52 |
+
- wiki_coreference
|
| 53 |
+
- wiki_dependency
|
| 54 |
+
- wiki_ner
|
| 55 |
+
- wiki_pas
|
| 56 |
+
- wiki_reading
|
| 57 |
+
- wikicorpus-j-to-e
|
| 58 |
+
- wikicorpus-e-to-j
|
| 59 |
+
- xlsum_ja
|
| 60 |
+
- hle
|
| 61 |
+
- jhle
|
| 62 |
+
- jblimp
|
| 63 |
+
- jcola-in-domain
|
| 64 |
+
- jcola-out-of-domain
|
| 65 |
+
categories:
|
| 66 |
+
NLI:
|
| 67 |
+
description: "Natural Language Inference"
|
| 68 |
+
default_metric: exact_match
|
| 69 |
+
metrics: {}
|
| 70 |
+
datasets:
|
| 71 |
+
- jamp
|
| 72 |
+
- janli
|
| 73 |
+
- jnli
|
| 74 |
+
- jsem
|
| 75 |
+
- jsick
|
| 76 |
+
QA:
|
| 77 |
+
description: "Question Answering"
|
| 78 |
+
default_metric: exact_match
|
| 79 |
+
metrics:
|
| 80 |
+
triviaqa: triviaqa_f1
|
| 81 |
+
drop: drop_f1
|
| 82 |
+
jculture-mcq: set_f1
|
| 83 |
+
datasets:
|
| 84 |
+
- jemhopqa
|
| 85 |
+
- niilc
|
| 86 |
+
- aio
|
| 87 |
+
- triviaqa
|
| 88 |
+
- drop
|
| 89 |
+
- jamc-qa
|
| 90 |
+
- jculture-mcq
|
| 91 |
+
RC:
|
| 92 |
+
description: "Reading Comprehension"
|
| 93 |
+
default_metric: exact_match
|
| 94 |
+
metrics: {}
|
| 95 |
+
datasets:
|
| 96 |
+
- jsquad
|
| 97 |
+
CR:
|
| 98 |
+
description: "Commonsense Reasoning"
|
| 99 |
+
default_metric: exact_match
|
| 100 |
+
metrics: {}
|
| 101 |
+
datasets:
|
| 102 |
+
- jcommonsenseqa
|
| 103 |
+
- commonsensemoralja
|
| 104 |
+
- kuci
|
| 105 |
+
- winogrande_xl
|
| 106 |
+
HE-JA:
|
| 107 |
+
description: "Human Evaluation"
|
| 108 |
+
default_metric: exact_match
|
| 109 |
+
metrics:
|
| 110 |
+
jhle: hle_exact_match
|
| 111 |
+
datasets:
|
| 112 |
+
- mmmlu
|
| 113 |
+
- jmmlu
|
| 114 |
+
- mmlu_prox_ja
|
| 115 |
+
- gpqa_diamond_ja
|
| 116 |
+
- gpqa_extended_ja
|
| 117 |
+
- gpqa_main_ja
|
| 118 |
+
- jhle
|
| 119 |
+
HE-EN:
|
| 120 |
+
description: "Human Evaluation"
|
| 121 |
+
default_metric: exact_match
|
| 122 |
+
metrics:
|
| 123 |
+
hle: hle_exact_match
|
| 124 |
+
datasets:
|
| 125 |
+
- mmlu_en
|
| 126 |
+
- mmlu_prox_en
|
| 127 |
+
- openbookqa
|
| 128 |
+
- gpqa_diamond_en
|
| 129 |
+
- gpqa_extended_en
|
| 130 |
+
- gpqa_main_en
|
| 131 |
+
- hle
|
| 132 |
+
EL:
|
| 133 |
+
description: "Entity Linking"
|
| 134 |
+
default_metric: set_f1
|
| 135 |
+
metrics: {}
|
| 136 |
+
datasets:
|
| 137 |
+
- chabsa
|
| 138 |
+
FA:
|
| 139 |
+
description: "Fine-grained Analysis"
|
| 140 |
+
default_metric: set_f1
|
| 141 |
+
metrics:
|
| 142 |
+
wiki_reading: char_f1
|
| 143 |
+
datasets:
|
| 144 |
+
- wiki_ner
|
| 145 |
+
- wiki_dependency
|
| 146 |
+
- wiki_pas
|
| 147 |
+
- wiki_coreference
|
| 148 |
+
- wiki_reading
|
| 149 |
+
MR:
|
| 150 |
+
description: "Math Reasoning"
|
| 151 |
+
default_metric: mathematical_equivalence
|
| 152 |
+
metrics:
|
| 153 |
+
polymath-en: polymath_weighted_accuracy
|
| 154 |
+
polymath-ja: polymath_weighted_accuracy
|
| 155 |
+
datasets:
|
| 156 |
+
- aime2024
|
| 157 |
+
- aime2025
|
| 158 |
+
- gsm8k
|
| 159 |
+
- jfinqa
|
| 160 |
+
- mawps
|
| 161 |
+
- mgsm
|
| 162 |
+
- polymath-en
|
| 163 |
+
- polymath-ja
|
| 164 |
+
MT:
|
| 165 |
+
description: "Machine Translation"
|
| 166 |
+
default_metric: comet_wmt22
|
| 167 |
+
metrics: {}
|
| 168 |
+
datasets:
|
| 169 |
+
- alt-e-to-j
|
| 170 |
+
- alt-j-to-e
|
| 171 |
+
- wikicorpus-e-to-j
|
| 172 |
+
- wikicorpus-j-to-e
|
| 173 |
+
CG:
|
| 174 |
+
description: "Code Generation"
|
| 175 |
+
default_metric: code_exec_sandbox
|
| 176 |
+
metrics: {}
|
| 177 |
+
datasets:
|
| 178 |
+
- mbpp
|
| 179 |
+
- jhumaneval
|
| 180 |
+
SUM:
|
| 181 |
+
description: "Summarization"
|
| 182 |
+
default_metric: rouge2_scaling
|
| 183 |
+
metrics: {}
|
| 184 |
+
datasets:
|
| 185 |
+
- xlsum_ja
|
| 186 |
+
IF:
|
| 187 |
+
description: "Instruction Following"
|
| 188 |
+
default_metric: mifeval_strict
|
| 189 |
+
metrics:
|
| 190 |
+
structeval: structeval
|
| 191 |
+
datasets:
|
| 192 |
+
- mif_eval_ja
|
| 193 |
+
- mif_eval_en
|
| 194 |
+
- structeval
|
| 195 |
+
BBH:
|
| 196 |
+
description: "BIG-Bench Hard"
|
| 197 |
+
default_metric: exact_match
|
| 198 |
+
metrics: {}
|
| 199 |
+
datasets:
|
| 200 |
+
- bigbenchhard_direct
|
| 201 |
+
- bigbenchhard_cot
|
| 202 |
+
- bigbenchhard_ja_direct
|
| 203 |
+
- bigbenchhard_ja_cot
|
| 204 |
+
LM:
|
| 205 |
+
description: "Language Modeling"
|
| 206 |
+
default_metric: exact_match
|
| 207 |
+
metrics: {}
|
| 208 |
+
datasets:
|
| 209 |
+
- jblimp
|
| 210 |
+
- jcola-in-domain
|
| 211 |
+
- jcola-out-of-domain
|
| 212 |
+
dataset_info_overrides: {}
|
| 213 |
+
# you can override the below attributes.
|
| 214 |
+
# instruction: str
|
| 215 |
+
# output_length: int
|
| 216 |
+
# metrics: list[str]
|
| 217 |
+
# samples: list[Sample]
|
| 218 |
+
# label_list: list[str] = field(default_factory=list)
|
| 219 |
+
# answer_extract_pattern: Optional[str] = ""
|
| 220 |
+
# num_few_shots: int | None = None
|
| 221 |
+
# answer_pattern_id: AnswerPatternId = AnswerPatternId.CUSTOM
|
| 222 |
+
# language: Literal["ja", "en"] = "ja"
|
| 223 |
+
# custom_prompt_template: Optional[str] = None
|
| 224 |
+
# for example, revise `dataset_info_overrides: {}` to `dataset_info_overrides:`, and write the below.
|
| 225 |
+
# jamp:
|
| 226 |
+
# answer_pattern_id: AnswerPatternId = AnswerPatternId.CUSTOM
|
| 227 |
+
# num_few_shots: 0
|
src/envs.py
CHANGED
|
@@ -22,9 +22,18 @@ EVAL_REQUESTS_PATH = CACHE_PATH / "eval-queue"
|
|
| 22 |
|
| 23 |
# llm-jp-eval upstream の dataset 定義 (dev branch を直接参照することで
|
| 24 |
# 新 dataset が upstream にマージされた瞬間にフロントが認識する)
|
| 25 |
-
LLM_JP_EVAL_DATASETS_URL =
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
API = HfApi(token=HF_TOKEN)
|
|
|
|
| 22 |
|
| 23 |
# llm-jp-eval upstream の dataset 定義 (dev branch を直接参照することで
|
| 24 |
# 新 dataset が upstream にマージされた瞬間にフロントが認識する)
|
| 25 |
+
LLM_JP_EVAL_DATASETS_URL = "https://raw.githubusercontent.com/llm-jp/llm-jp-eval/dev/eval_configs/all_datasets.yaml"
|
| 26 |
+
|
| 27 |
+
# raw.githubusercontent.com が 429 (rate limit) を返した際の CDN ミラー。
|
| 28 |
+
# jsDelivr は GitHub を長期キャッシュ配信するため rate limit を回避できる。
|
| 29 |
+
LLM_JP_EVAL_DATASETS_MIRROR_URL = "https://cdn.jsdelivr.net/gh/llm-jp/llm-jp-eval@dev/eval_configs/all_datasets.yaml"
|
| 30 |
+
|
| 31 |
+
# ネットワーク取得成功時に内容を退避する永続キャッシュ。次回以降 upstream/
|
| 32 |
+
# ミラーがともに落ちていても、直近取得分でフロントを起動できる。
|
| 33 |
+
LLM_JP_EVAL_DATASETS_CACHE_PATH = CACHE_PATH / "upstream" / "all_datasets.yaml"
|
| 34 |
+
|
| 35 |
+
# リポジトリ同梱の最終フォールバック。キャッシュが未生成のコールドスタートでも
|
| 36 |
+
# 起動を保証する (取得成功時に上書きはしない)。
|
| 37 |
+
LLM_JP_EVAL_DATASETS_FALLBACK_PATH = pathlib.Path(__file__).parent / "data" / "all_datasets.yaml"
|
| 38 |
|
| 39 |
API = HfApi(token=HF_TOKEN)
|
src/upstream.py
CHANGED
|
@@ -1,11 +1,110 @@
|
|
| 1 |
-
"""llm-jp-eval upstream から all_datasets.yaml を取得するモジュール。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
import functools
|
|
|
|
|
|
|
| 4 |
|
| 5 |
import requests
|
| 6 |
import yaml
|
| 7 |
|
| 8 |
-
from src.envs import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
@functools.lru_cache(maxsize=1)
|
|
@@ -13,11 +112,24 @@ def load_upstream_eval_config() -> dict:
|
|
| 13 |
"""llm-jp-eval upstream から all_datasets.yaml の全内容を取得して返す。
|
| 14 |
|
| 15 |
categories / datasets / dataset_info_overrides を含む dict。
|
| 16 |
-
プロセス起動中は lru_cache で memoize する。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
"""
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
|
| 23 |
def load_canonical_dataset_set() -> frozenset[str]:
|
|
|
|
| 1 |
+
"""llm-jp-eval upstream から all_datasets.yaml を取得するモジュール。
|
| 2 |
+
|
| 3 |
+
取得は多層フォールバックで冗長化しており、次の優先順位で最初に成功したものを
|
| 4 |
+
採用する:
|
| 5 |
+
|
| 6 |
+
1. GitHub raw (最新の dev branch) — リトライ付き
|
| 7 |
+
2. jsDelivr CDN ミラー — raw が 429 (rate limit) の際の回避経路
|
| 8 |
+
3. ローカル永続キャッシュ — 直近のネットワーク取得成功分
|
| 9 |
+
4. リポジトリ同梱フォールバック — コールドスタート時の最終手段
|
| 10 |
+
|
| 11 |
+
いずれかのネットワーク取得に成功した時点で内容を永続キャッシュに退避するため、
|
| 12 |
+
以降 upstream / ミラーが同時に落ちていてもフロントの起動失敗を防げる。
|
| 13 |
+
"""
|
| 14 |
|
| 15 |
import functools
|
| 16 |
+
import logging
|
| 17 |
+
import time
|
| 18 |
|
| 19 |
import requests
|
| 20 |
import yaml
|
| 21 |
|
| 22 |
+
from src.envs import (
|
| 23 |
+
LLM_JP_EVAL_DATASETS_CACHE_PATH,
|
| 24 |
+
LLM_JP_EVAL_DATASETS_FALLBACK_PATH,
|
| 25 |
+
LLM_JP_EVAL_DATASETS_MIRROR_URL,
|
| 26 |
+
LLM_JP_EVAL_DATASETS_URL,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
logger = logging.getLogger(__name__)
|
| 30 |
+
|
| 31 |
+
_REQUEST_TIMEOUT_SEC = 10
|
| 32 |
+
_MAX_ATTEMPTS = 3
|
| 33 |
+
_BACKOFF_BASE_SEC = 1.0
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _fetch_from_url(url: str) -> str:
|
| 37 |
+
"""指定 URL から YAML テキストを取得する。指数バックオフでリトライする。
|
| 38 |
+
|
| 39 |
+
Args:
|
| 40 |
+
url: 取得対象の YAML の URL。
|
| 41 |
+
|
| 42 |
+
Returns:
|
| 43 |
+
取得した YAML テキスト。
|
| 44 |
+
|
| 45 |
+
Raises:
|
| 46 |
+
requests.RequestException: 全リトライが失敗した場合。
|
| 47 |
+
"""
|
| 48 |
+
for attempt in range(1, _MAX_ATTEMPTS + 1):
|
| 49 |
+
try:
|
| 50 |
+
response = requests.get(url, timeout=_REQUEST_TIMEOUT_SEC)
|
| 51 |
+
response.raise_for_status()
|
| 52 |
+
return response.text
|
| 53 |
+
except requests.RequestException as exc:
|
| 54 |
+
logger.warning("upstream YAML の取得に失敗 (%s, 試行 %d/%d): %s", url, attempt, _MAX_ATTEMPTS, exc)
|
| 55 |
+
if attempt >= _MAX_ATTEMPTS:
|
| 56 |
+
raise
|
| 57 |
+
time.sleep(_BACKOFF_BASE_SEC * 2 ** (attempt - 1))
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def _fetch_from_network() -> str:
|
| 61 |
+
"""upstream raw → CDN ミラーの順にネットワーク取得を試みる。
|
| 62 |
+
|
| 63 |
+
Returns:
|
| 64 |
+
最初に成功した経路の YAML テキスト。
|
| 65 |
+
|
| 66 |
+
Raises:
|
| 67 |
+
requests.RequestException: 全経路が失敗した場合 (ミラーの例外を送出)。
|
| 68 |
+
"""
|
| 69 |
+
try:
|
| 70 |
+
return _fetch_from_url(LLM_JP_EVAL_DATASETS_URL)
|
| 71 |
+
except requests.RequestException:
|
| 72 |
+
logger.warning("raw 取得に失敗。CDN ミラーにフォールバックする: %s", LLM_JP_EVAL_DATASETS_MIRROR_URL)
|
| 73 |
+
return _fetch_from_url(LLM_JP_EVAL_DATASETS_MIRROR_URL)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def _write_cache(text: str) -> None:
|
| 77 |
+
"""取得済み YAML テキストを永続キャッシュへ退避する (ベストエフォート)。
|
| 78 |
+
|
| 79 |
+
書き込み失敗は起動を止める理由にならないため、警告ログに留めて握り潰す。
|
| 80 |
+
"""
|
| 81 |
+
try:
|
| 82 |
+
LLM_JP_EVAL_DATASETS_CACHE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
| 83 |
+
LLM_JP_EVAL_DATASETS_CACHE_PATH.write_text(text, encoding="utf-8")
|
| 84 |
+
except OSError as exc:
|
| 85 |
+
logger.warning("upstream YAML のキャッシュ書き込みに失敗: %s", exc)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def _read_local(reason: str) -> str | None:
|
| 89 |
+
"""永続キャッシュ → 同梱フォールバックの順にローカルから読む。
|
| 90 |
+
|
| 91 |
+
Args:
|
| 92 |
+
reason: フォールバックに至った理由 (ログ用)。
|
| 93 |
+
|
| 94 |
+
Returns:
|
| 95 |
+
読み込めた YAML テキスト。どちらも存在しなければ None。
|
| 96 |
+
"""
|
| 97 |
+
for label, path in (
|
| 98 |
+
("永続キャッシュ", LLM_JP_EVAL_DATASETS_CACHE_PATH),
|
| 99 |
+
("同梱フォールバック", LLM_JP_EVAL_DATASETS_FALLBACK_PATH),
|
| 100 |
+
):
|
| 101 |
+
try:
|
| 102 |
+
text = path.read_text(encoding="utf-8")
|
| 103 |
+
except OSError:
|
| 104 |
+
continue
|
| 105 |
+
logger.warning("%s のため %s (%s) を使用する", reason, label, path)
|
| 106 |
+
return text
|
| 107 |
+
return None
|
| 108 |
|
| 109 |
|
| 110 |
@functools.lru_cache(maxsize=1)
|
|
|
|
| 112 |
"""llm-jp-eval upstream から all_datasets.yaml の全内容を取得して返す。
|
| 113 |
|
| 114 |
categories / datasets / dataset_info_overrides を含む dict。
|
| 115 |
+
プロセス起動中は lru_cache で memoize する。ネットワーク取得に成功すれば
|
| 116 |
+
永続キャッシュを更新し、失敗時はキャッシュ / 同梱フォールバックへ退避する。
|
| 117 |
+
|
| 118 |
+
Returns:
|
| 119 |
+
upstream YAML をパースした dict。
|
| 120 |
+
|
| 121 |
+
Raises:
|
| 122 |
+
requests.RequestException: ネットワーク取得が全滅し、かつローカルの
|
| 123 |
+
キャッシュ・同梱フォールバックも読めなかった場合。
|
| 124 |
"""
|
| 125 |
+
try:
|
| 126 |
+
text = _fetch_from_network()
|
| 127 |
+
_write_cache(text)
|
| 128 |
+
except requests.RequestException as exc:
|
| 129 |
+
text = _read_local(reason=f"upstream/ミラー取得失敗 ({exc})")
|
| 130 |
+
if text is None:
|
| 131 |
+
raise
|
| 132 |
+
return yaml.safe_load(text)
|
| 133 |
|
| 134 |
|
| 135 |
def load_canonical_dataset_set() -> frozenset[str]:
|