| | from __future__ import annotations |
| |
|
| | import json |
| | from json import JSONDecodeError |
| | from typing import Any, List, Optional, Type, TypeVar, Union |
| |
|
| | import jsonpatch |
| | import pydantic |
| |
|
| | from langchain_core.exceptions import OutputParserException |
| | from langchain_core.output_parsers.format_instructions import JSON_FORMAT_INSTRUCTIONS |
| | from langchain_core.output_parsers.transform import BaseCumulativeTransformOutputParser |
| | from langchain_core.outputs import Generation |
| | from langchain_core.utils.json import ( |
| | parse_and_check_json_markdown, |
| | parse_json_markdown, |
| | parse_partial_json, |
| | ) |
| | from langchain_core.utils.pydantic import PYDANTIC_MAJOR_VERSION |
| |
|
| | from langchain_core.pydantic_v1 import BaseModel, Field |
| |
|
| | if PYDANTIC_MAJOR_VERSION < 2: |
| | PydanticBaseModel = pydantic.BaseModel |
| |
|
| | else: |
| | from pydantic.v1 import BaseModel |
| |
|
| | |
| | PydanticBaseModel = Union[BaseModel, pydantic.BaseModel] |
| |
|
| | TBaseModel = TypeVar("TBaseModel", bound=PydanticBaseModel) |
| |
|
| |
|
| | class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]): |
| | """Parse the output of an LLM call to a JSON object. |
| | |
| | When used in streaming mode, it will yield partial JSON objects containing |
| | all the keys that have been returned so far. |
| | |
| | In streaming, if `diff` is set to `True`, yields JSONPatch operations |
| | describing the difference between the previous and the current object. |
| | """ |
| |
|
| | pydantic_object: Optional[Type[TBaseModel]] = None |
| |
|
| | def _diff(self, prev: Optional[Any], next: Any) -> Any: |
| | return jsonpatch.make_patch(prev, next).patch |
| |
|
| | def _get_schema(self, pydantic_object: Type[TBaseModel]) -> dict[str, Any]: |
| | if PYDANTIC_MAJOR_VERSION == 2: |
| | if issubclass(pydantic_object, pydantic.BaseModel): |
| | return pydantic_object.model_json_schema() |
| | elif issubclass(pydantic_object, pydantic.v1.BaseModel): |
| | return pydantic_object.schema() |
| | return pydantic_object.schema() |
| |
|
| | def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any: |
| | text = result[0].text |
| | text = text.strip() |
| | if partial: |
| | try: |
| | return parse_json_markdown(text) |
| | except JSONDecodeError: |
| | return None |
| | else: |
| | try: |
| | return parse_json_markdown(text) |
| | except JSONDecodeError as e: |
| | msg = f"Invalid json output: {text}" |
| | raise OutputParserException(msg, llm_output=text) from e |
| |
|
| | def parse(self, text: str) -> Any: |
| | return self.parse_result([Generation(text=text)]) |
| |
|
| | def get_format_instructions(self) -> str: |
| | if self.pydantic_object is None: |
| | return "Return a JSON object." |
| | else: |
| | |
| | schema = {k: v for k, v in self._get_schema(self.pydantic_object).items()} |
| |
|
| | |
| | reduced_schema = schema |
| | if "title" in reduced_schema: |
| | del reduced_schema["title"] |
| | if "type" in reduced_schema: |
| | del reduced_schema["type"] |
| | |
| | schema_str = json.dumps(reduced_schema, ensure_ascii=False) |
| | return JSON_FORMAT_INSTRUCTIONS.format(schema=schema_str) |
| |
|
| | @property |
| | def _type(self) -> str: |
| | return "simple_json_output_parser" |
| |
|
| |
|
| | class Evaluation(BaseModel): |
| | """Nhận xét của giáo viên cho kết quả học tập của học sinh""" |
| | summary: str = Field(description="Nhận xét ngắn gọn khoảng 50 từ") |
| | detail: str = Field(description="Nhận xét chi tiết khoảng 200 từ") |
| |
|
| | evaluation_parser_v1 = JsonOutputParser(pydantic_object=Evaluation) |
| |
|
| | class EvaluationForStudent(BaseModel): |
| | """Nhận xét của giáo viên cho kết quả học tập của học sinh""" |
| | atitude: str = Field(description="Nhận xét ngắn gọn khoảng 50 từ cho thái độ của học sinh") |
| | knowleadge: str = Field(description="Nhận xét ngắn gọn khoảng 50 từ cho kiến thức của học sinh") |
| | skill: str = Field(description="Nhận xét ngắn gọn khoảng 50 từ cho kỹ năng của học sinh") |
| | interaction: str = Field(description="Nhận xét ngắn gọn khoảng 50 từ cho tương tác của học sinh") |
| | |
| |
|
| | evaluation_parser_v2 = JsonOutputParser(pydantic_object=EvaluationForStudent) |