Packages

Dataset management and caching for AI research benchmarks

Retired package: Deprecated - Use 0.5.0+

Current section

Files

Jump to
crucible_datasets lib dataset_manager loader rubric.ex
Raw

lib/dataset_manager/loader/rubric.ex

defmodule CrucibleDatasets.Loader.Rubric do
@moduledoc """
Loader for rubric-based evaluation datasets.
Supports:
- Feedback-Collection (prometheus-eval/Feedback-Collection)
These datasets contain instructions with scoring rubrics for training
evaluator/grader models.
## Examples
# Load Feedback-Collection
{:ok, dataset} = CrucibleDatasets.Loader.Rubric.load(:feedback_collection)
# Load with sample size
{:ok, dataset} = CrucibleDatasets.Loader.Rubric.load(:feedback_collection, sample_size: 500)
"""
alias CrucibleDatasets.Dataset
alias CrucibleDatasets.Fetcher.HuggingFace
@datasets %{
feedback_collection: %{
repo_id: "prometheus-eval/Feedback-Collection",
description: "Prometheus Feedback Collection for rubric-based evaluation"
}
}
@doc """
Load a rubric-based evaluation dataset.
## Arguments
* `dataset_name` - Currently only `:feedback_collection`
* `opts` - Options (see below)
## Options
* `:split` - Dataset split (default: "train")
* `:sample_size` - Limit number of items
* `:token` - HuggingFace API token
"""
@spec load(atom(), keyword()) :: {:ok, Dataset.t()} | {:error, term()}
def load(dataset_name, opts \\ [])
def load(dataset_name, opts) when is_atom(dataset_name) do
case Map.get(@datasets, dataset_name) do
nil ->
{:error, {:unknown_dataset, dataset_name, Map.keys(@datasets)}}
dataset_info ->
load_from_huggingface(dataset_name, dataset_info, opts)
end
end
defp load_from_huggingface(dataset_name, %{repo_id: repo_id}, opts) do
split = Keyword.get(opts, :split, "train") |> to_string()
sample_size = Keyword.get(opts, :sample_size)
token = Keyword.get(opts, :token)
# Feedback-Collection uses a single JSON file, not standard train/test splits
# Download the specific file directly
file_path = "new_feedback_collection.json"
case HuggingFace.download_file(repo_id, file_path, token: token) do
{:ok, data} ->
case Jason.decode(data) do
{:ok, raw_data} when is_list(raw_data) ->
items = parse_rubric_data(raw_data)
items = if sample_size, do: Enum.take(items, sample_size), else: items
dataset =
Dataset.new(
to_string(dataset_name),
"1.0",
items,
%{
source: "huggingface:#{repo_id}",
split: split,
license: "apache-2.0",
domain: "rubric_evaluation"
}
)
{:ok, dataset}
{:ok, _} ->
{:error, {:parse_error, :expected_array}}
{:error, reason} ->
{:error, {:json_parse_error, reason}}
end
{:error, reason} ->
{:error, {:huggingface_fetch_failed, reason}}
end
end
defp parse_rubric_data(raw_data) do
raw_data
|> Enum.with_index()
|> Enum.map(fn {item, idx} ->
parse_feedback_item(item, idx)
end)
|> Enum.reject(&is_nil/1)
end
defp parse_feedback_item(item, idx) do
instruction = item["orig_instruction"] || item["instruction"] || ""
criteria = item["orig_criteria"] || item["criteria"] || ""
reference = item["orig_reference_answer"] || item["reference_answer"] || ""
# Build rubric from score descriptions
rubric = build_rubric(item)
%{
id: "feedback_#{idx}",
input: %{
instruction: instruction,
criteria: criteria
},
expected: %{
reference_answer: reference,
rubric: rubric
},
metadata: %{
source: "feedback_collection",
has_rubric: map_size(rubric) > 0
}
}
end
defp build_rubric(item) do
# Feedback-Collection has score1_description through score5_description
1..5
|> Enum.reduce(%{}, fn i, acc ->
key = "orig_score#{i}_description"
alt_key = "score#{i}_description"
case item[key] || item[alt_key] do
nil -> acc
description -> Map.put(acc, i, description)
end
end)
end
@doc """
List available rubric datasets.
"""
@spec available_datasets() :: [atom()]
def available_datasets, do: Map.keys(@datasets)
end