Skip to content

Commit 3322e5f

Browse files
authored
lilac adapter (#389)
* lilac adapter * updated adapter * updated adapters
1 parent a5b0060 commit 3322e5f

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

eval_protocol/adapters/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,19 @@
9999
__all__.extend(["WeaveAdapter"])
100100
except ImportError:
101101
pass
102+
103+
# DataFrame adapter (pandas integration for Lilac, etc.)
104+
try:
105+
from .dataframe import (
106+
evaluation_rows_to_dataframe,
107+
dataframe_to_evaluation_rows,
108+
)
109+
110+
__all__.extend(
111+
[
112+
"evaluation_rows_to_dataframe",
113+
"dataframe_to_evaluation_rows",
114+
]
115+
)
116+
except ImportError:
117+
pass
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
Pandas DataFrame adapter for Eval Protocol.
3+
4+
This module provides utilities for converting between EvaluationRow format
5+
and pandas DataFrame format, enabling integration with data curation tools
6+
such as Lilac, Great Expectations, or any pandas-based workflow.
7+
8+
Example usage:
9+
>>> from eval_protocol.adapters.dataframe import (
10+
... evaluation_rows_to_dataframe,
11+
... dataframe_to_evaluation_rows,
12+
... )
13+
>>>
14+
>>> # Convert EvaluationRows to DataFrame
15+
>>> df = evaluation_rows_to_dataframe(rows)
16+
>>>
17+
>>> # Convert back to EvaluationRows
18+
>>> rows = dataframe_to_evaluation_rows(df)
19+
"""
20+
21+
from __future__ import annotations
22+
23+
import logging
24+
25+
import pandas as pd
26+
27+
from ..models import EvaluationRow
28+
29+
logger = logging.getLogger(__name__)
30+
31+
32+
def evaluation_rows_to_dataframe(rows: list[EvaluationRow]) -> pd.DataFrame:
33+
"""Convert EvaluationRows to a pandas DataFrame.
34+
35+
Uses EvaluationRow.to_dict() for serialization.
36+
37+
Args:
38+
rows: List of EvaluationRow objects
39+
40+
Returns:
41+
DataFrame with 'data_json' containing serialized rows plus convenience fields
42+
"""
43+
records = [row.to_dict() for row in rows]
44+
return pd.DataFrame(records)
45+
46+
47+
def dataframe_to_evaluation_rows(df: pd.DataFrame) -> list[EvaluationRow]:
48+
"""Convert a pandas DataFrame back to EvaluationRows.
49+
50+
Uses EvaluationRow.from_dict() for deserialization.
51+
52+
Args:
53+
df: DataFrame with 'data_json' column containing serialized EvaluationRows
54+
55+
Returns:
56+
List of EvaluationRow objects
57+
"""
58+
rows = []
59+
for _, row_data in df.iterrows():
60+
try:
61+
row = EvaluationRow.from_dict(row_data.to_dict())
62+
rows.append(row)
63+
except Exception as e:
64+
logger.warning(f"Failed to convert row: {e}")
65+
continue
66+
return rows

eval_protocol/models.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,49 @@ def get_termination_reason(self) -> str:
10051005
return str(reason)
10061006
return "unknown"
10071007

1008+
def to_dict(self) -> Dict[str, Any]:
1009+
"""Serialize this EvaluationRow to a dictionary.
1010+
1011+
The entire EvaluationRow is serialized to JSON, allowing full reconstruction.
1012+
Additional scalar fields are included for convenient filtering/grouping.
1013+
1014+
Returns:
1015+
Dictionary with 'data_json' containing the full serialized row,
1016+
plus convenience fields for filtering.
1017+
"""
1018+
return {
1019+
"data_json": self.model_dump_json(),
1020+
"row_id": self.input_metadata.row_id if self.input_metadata else None,
1021+
"score": self.evaluation_result.score if self.evaluation_result else None,
1022+
"message_count": len(self.messages),
1023+
"has_tools": bool(self.tools),
1024+
"created_at": self.created_at.isoformat() if self.created_at else None,
1025+
}
1026+
1027+
@classmethod
1028+
def from_dict(cls, data: Dict[str, Any]) -> "EvaluationRow":
1029+
"""Reconstruct an EvaluationRow from a dictionary.
1030+
1031+
Args:
1032+
data: Dictionary containing 'data_json' with the serialized EvaluationRow.
1033+
1034+
Returns:
1035+
Reconstructed EvaluationRow instance.
1036+
1037+
Raises:
1038+
ValueError: If 'data_json' is missing or invalid.
1039+
"""
1040+
from pydantic import ValidationError
1041+
1042+
data_json = data.get("data_json")
1043+
if not data_json:
1044+
raise ValueError("Missing 'data_json' field in dictionary")
1045+
1046+
try:
1047+
return cls.model_validate_json(data_json)
1048+
except ValidationError as e:
1049+
raise ValueError(f"Failed to deserialize EvaluationRow: {e}") from e
1050+
10081051
def __hash__(self) -> int:
10091052
# Use a stable hash that works across Python processes
10101053
return self._stable_hash()

0 commit comments

Comments
 (0)