Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 20 additions & 23 deletions adalflow/adalflow/components/output_parsers/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from pydantic import BaseModel, ValidationError



__all__ = [
"OutputParser",
"YamlOutputParser",
Expand Down Expand Up @@ -144,7 +143,6 @@ class OutputParser(DataComponent):
"""

def __init__(self, *args, **kwargs) -> None:

super().__init__()
pass

Expand Down Expand Up @@ -209,7 +207,6 @@ def __init__(
exclude_fields: ExcludeType = None,
return_data_class: bool = False,
):

super().__init__()
if not is_dataclass(data_class):
raise TypeError(f"Provided class is not a dataclass: {data_class}")
Expand Down Expand Up @@ -334,7 +331,7 @@ def format_instructions(
Defaults to DataClassFormatType.SIGNATURE_JSON for less token usage compared with DataClassFormatType.SCHEMA.
Options: DataClassFormatType.SIGNATURE_YAML, DataClassFormatType.SIGNATURE_JSON, DataClassFormatType.SCHEMA.
"""
format_type = format_type or DataClassFormatType.SCHEMA
format_type = format_type or DataClassFormatType.SIGNATURE_JSON
schema = self.data_class.format_class_str(
format_type=format_type,
exclude=self._exclude_fields,
Expand Down Expand Up @@ -383,15 +380,15 @@ def _extra_repr(self) -> str:

class JsonOutputParserPydanticModel(OutputParser):
"""JSON output parser using Pydantic BaseModel for schema extraction and validation.

This parser works with Pydantic BaseModel classes instead of AdalFlow's DataClass,
providing better JSON schema generation and automatic validation.

Args:
pydantic_model (Type[BaseModel]): The Pydantic model class to use for schema and validation
examples (List[BaseModel], optional): Example instances of the Pydantic model. Defaults to None.
return_pydantic_object (bool, optional): If True, returns parsed Pydantic object. If False, returns dict. Defaults to True.

Examples:
>>> from pydantic import BaseModel
>>> from typing import List
Expand All @@ -405,40 +402,41 @@ class JsonOutputParserPydanticModel(OutputParser):
>>> format_instructions = parser.format_instructions()
>>> # Use in Generator with output_processors=parser
"""

def __init__(
self,
pydantic_model: Type[BaseModel],
examples: Optional[List[BaseModel]] = None,
return_pydantic_object: bool = True,
):
super().__init__()


if not (isinstance(pydantic_model, type) and issubclass(pydantic_model, BaseModel)):

if not (
isinstance(pydantic_model, type) and issubclass(pydantic_model, BaseModel)
):
raise TypeError(
f"Provided model must be a Pydantic BaseModel class, got: {pydantic_model}"
)

if examples is not None and len(examples) > 0:
if not isinstance(examples[0], pydantic_model):
raise TypeError(
f"Provided examples must be instances of {pydantic_model.__name__}"
)

self.pydantic_model = pydantic_model
self.examples = examples or []
self._return_pydantic_object = return_pydantic_object

# Use the same JSON_OUTPUT_FORMAT template as the regular JsonOutputParser
self.output_format_prompt = Prompt(template=JSON_OUTPUT_FORMAT)
self.output_processors = JsonParser()

def format_instructions(self) -> str:
"""Return the formatted instructions with Pydantic model schema."""
# Get JSON schema from Pydantic model
schema = self._get_pydantic_schema()

# Format examples if provided
example_str = ""
try:
Expand All @@ -452,9 +450,9 @@ def format_instructions(self) -> str:
except Exception as e:
log.error(f"Error in formatting examples for {__class__.__name__}: {e}")
example_str = None

return self.output_format_prompt(schema=schema, example=example_str)

def _get_pydantic_schema(self) -> str:
"""Generate a JSON schema description from Pydantic model using native functionality."""
try:
Expand All @@ -464,18 +462,18 @@ def _get_pydantic_schema(self) -> str:
except Exception as e:
log.error(f"Error generating Pydantic schema: {e}")
return f"Schema for {self.pydantic_model.__name__}"

def call(self, input: str) -> Union[BaseModel, Dict[str, Any]]:
"""Parse JSON string to Pydantic object or dict."""
try:
# First parse the JSON string to dict
output_dict = self.output_processors(input)
log.debug(f"{__class__.__name__} parsed dict: {output_dict}")

except Exception as e:
log.error(f"Error parsing JSON string: {e}")
raise e

if self._return_pydantic_object:
try:
# Use Pydantic's validation to create the object
Expand All @@ -488,7 +486,7 @@ def call(self, input: str) -> Union[BaseModel, Dict[str, Any]]:
raise e
else:
return output_dict

def _extra_repr(self) -> str:
return f"pydantic_model={self.pydantic_model.__name__}, examples={len(self.examples)}, return_pydantic_object={self._return_pydantic_object}"

Expand Down Expand Up @@ -529,7 +527,6 @@ def format_instructions(self) -> str:
return "The output should be a boolean value. True or False."

def call(self, input: str) -> bool:

input = input.strip()
output = None
# evaluate the expression to get the boolean value
Expand Down
Loading