ELBench-live / src /elbench /loaders /normalizer.py
adelevett's picture
Deploy ELBench-live dashboard
5db30ac verified
Raw History Blame Contribute Delete
3.47 kB
from __future__ import annotations
import hashlib
import json
from typing import Any
from elbench.loaders.resolvers import resolve_dimension
from elbench.registry import ResolvedRegistryItem
from elbench.schemas.evaluation import RawRecord, Sample
class RecordNormalizer:
def normalize(self, item: ResolvedRegistryItem, raw_record: RawRecord) -> Sample:
record = raw_record.record
mapping = item.mapping
prompt = self._build_prompt(mapping, record)
sample_id = self._build_sample_id(item, raw_record)
dimension = self._extract_dimension(mapping, record)
reference = self._extract_reference(mapping.reference_fields, record)
metadata = self._extract_metadata(mapping.metadata_fields, raw_record)
return Sample(
sample_id=sample_id,
source_file=item.entry.canonical_name,
source_path=str(item.path),
module=item.entry.module,
subset=item.entry.subset,
task=item.entry.task,
dimension=dimension,
prompt=prompt,
reference=reference,
metadata=metadata,
raw_record=record,
)
def _build_prompt(self, mapping: Any, record: dict[str, Any]) -> str:
if mapping.prompt_template:
rendered = mapping.prompt_template
for key, value in record.items():
rendered = rendered.replace(f"{{{{ {key} }}}}", self._stringify(value))
return rendered.strip()
for key in mapping.prompt_fields:
value = record.get(key)
if value not in (None, ""):
return self._stringify(value)
raise ValueError("Prompt fields are empty for record.")
def _build_sample_id(self, item: ResolvedRegistryItem, raw_record: RawRecord) -> str:
parts = []
for key in item.mapping.sample_id_fields:
value = raw_record.record.get(key)
if value not in (None, ""):
parts.append(self._stringify(value))
if not parts:
parts = [item.entry.canonical_name, str(raw_record.row_index), json.dumps(raw_record.record, ensure_ascii=False)]
digest = hashlib.sha1("||".join(parts).encode("utf-8")).hexdigest()[:16]
return f"{_safe_stem(item.entry.canonical_name)}-{digest}"
def _extract_dimension(self, mapping: Any, record: dict[str, Any]) -> str | None:
for key in mapping.dimension_fields:
value = record.get(key)
if value not in (None, ""):
return self._stringify(value)
return resolve_dimension(mapping.dimension_resolver, record)
def _extract_reference(self, fields: list[str], record: dict[str, Any]) -> dict[str, Any] | None:
reference = {key: record.get(key) for key in fields if key in record}
return reference or None
def _extract_metadata(self, fields: list[str], raw_record: RawRecord) -> dict[str, Any]:
metadata = {key: raw_record.record.get(key) for key in fields if key in raw_record.record}
metadata["row_index"] = raw_record.row_index
return metadata
def _stringify(self, value: Any) -> str:
if isinstance(value, str):
return value
return json.dumps(value, ensure_ascii=False) if isinstance(value, (dict, list)) else str(value)
def _safe_stem(filename: str) -> str:
return filename.replace(".", "_").replace("/", "_").replace("\\", "_")