diff --git a/src/backend/langflow/schema/schema.py b/src/backend/langflow/schema/schema.py index 639c9da96..5a20d941f 100644 --- a/src/backend/langflow/schema/schema.py +++ b/src/backend/langflow/schema/schema.py @@ -1,6 +1,6 @@ -from typing import Any, Optional +import copy -from langchain_core.documents import Document +from langchain_core.documents import Document # Assumed import from pydantic import BaseModel @@ -9,12 +9,11 @@ class Record(BaseModel): Represents a record with text and optional data. Attributes: - text (str): The text of the record. data (dict, optional): Additional data associated with the record. """ - text: Optional[str] = "" data: dict = {} + _default_value = None @classmethod def from_document(cls, document: Document) -> "Record": @@ -27,7 +26,22 @@ class Record(BaseModel): Returns: Record: The converted Record. """ - return cls(text=document.page_content, data=document.metadata) + data = document.metadata + data["text"] = document.page_content + return cls(data=data) + + def __add__(self, other: "Record") -> "Record": + """ + Concatenates the text of two records and combines their data. + + Args: + other (Record): The other record to concatenate with. + + Returns: + Record: The concatenated record. + """ + combined_data = {**self.data, **other.data} + return Record(data=combined_data) def to_lc_document(self) -> Document: """ @@ -38,20 +52,59 @@ class Record(BaseModel): """ return Document(page_content=self.text, metadata=self.data) - def __call__(self, *args: Any, **kwds: Any) -> Any: + def __getattr__(self, key): """ - Returns the text of the record. + Allows attribute-like access to the data dictionary. + """ + try: + if key == "data" or key.startswith("_"): + return super().__getattr__(key) - Returns: - Any: The text of the record. + return self.data.get(key, self._default_value) + except KeyError: + # Fallback to default behavior to raise AttributeError for undefined attributes + raise AttributeError( + f"'{type(self).__name__}' object has no attribute '{key}'" + ) + + def __setattr__(self, key, value): """ - return self.text + Allows attribute-like setting of values in the data dictionary, + while still allowing direct assignment to class attributes. + """ + if key == "data" or key.startswith("_"): + super().__setattr__(key, value) + else: + self.data[key] = value + + def __delattr__(self, key): + """ + Allows attribute-like deletion from the data dictionary. + """ + if key == "data" or key.startswith("_"): + super().__delattr__(key) + else: + del self.data[key] + + def __deepcopy__(self, memo): + """ + Custom deepcopy implementation to handle copying of the Record object. + """ + cls = self.__class__ + result = cls.__new__(cls) + memo[id(self)] = result + for k, v in self.__dict__.items(): + setattr(result, k, copy.deepcopy(v, memo)) + return result def __str__(self) -> str: """ - Returns the text of the record. - - Returns: - str: The text and data of the record. + Returns a string representation of the Record, including text and data. """ - return self.model_dump_json(indent=2) + # Assuming a method to dump model data as JSON string exists. + # If it doesn't, you might need to implement it or use json.dumps() directly. + # build the string considering all keys in the data dictionary + prefix = "Record(" + suffix = ")" + text = ", ".join([f"{k}={v}" for k, v in self.data.items()]) + return prefix + text + suffix