feat: updated ChatOutput component that can accept Data, Dataframe and Message (#6643)
* update chatoutput * [autofix.ci] apply automated fixes * update * tests * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * Update chat.py * update template * fix lint errors * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: rename variable for clarity in chat output component test * [autofix.ci] apply automated fixes * fix: enable loading from database for API key in starter project configurations * update templates * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
parent
d143fe4939
commit
69df913a14
29 changed files with 5561 additions and 1939 deletions
|
|
@ -1,6 +1,11 @@
|
|||
from typing import Any
|
||||
|
||||
from langflow.base.io.chat import ChatComponent
|
||||
from langflow.inputs import BoolInput
|
||||
from langflow.io import DropdownInput, MessageInput, MessageTextInput, Output
|
||||
from langflow.inputs.inputs import HandleInput
|
||||
from langflow.io import DropdownInput, MessageTextInput, Output
|
||||
from langflow.schema.data import Data
|
||||
from langflow.schema.dataframe import DataFrame
|
||||
from langflow.schema.message import Message
|
||||
from langflow.schema.properties import Source
|
||||
from langflow.utils.constants import (
|
||||
|
|
@ -18,10 +23,12 @@ class ChatOutput(ChatComponent):
|
|||
minimized = True
|
||||
|
||||
inputs = [
|
||||
MessageInput(
|
||||
HandleInput(
|
||||
name="input_value",
|
||||
display_name="Text",
|
||||
info="Message to be passed as output.",
|
||||
input_types=["Data", "DataFrame", "Message"],
|
||||
required=True,
|
||||
),
|
||||
BoolInput(
|
||||
name="should_store_message",
|
||||
|
|
@ -76,6 +83,13 @@ class ChatOutput(ChatComponent):
|
|||
info="The text color of the name",
|
||||
advanced=True,
|
||||
),
|
||||
BoolInput(
|
||||
name="clean_data",
|
||||
display_name="Basic Clean Data",
|
||||
value=True,
|
||||
info="Whether to clean the data",
|
||||
advanced=True,
|
||||
),
|
||||
]
|
||||
outputs = [
|
||||
Output(
|
||||
|
|
@ -92,16 +106,35 @@ class ChatOutput(ChatComponent):
|
|||
if display_name:
|
||||
source_dict["display_name"] = display_name
|
||||
if source:
|
||||
source_dict["source"] = source
|
||||
# Handle case where source is a ChatOpenAI object
|
||||
if hasattr(source, "model_name"):
|
||||
source_dict["source"] = source.model_name
|
||||
elif hasattr(source, "model"):
|
||||
source_dict["source"] = str(source.model)
|
||||
else:
|
||||
source_dict["source"] = str(source)
|
||||
return Source(**source_dict)
|
||||
|
||||
async def message_response(self) -> Message:
|
||||
# First convert the input to string if needed
|
||||
text = self.convert_to_string()
|
||||
|
||||
# Get source properties
|
||||
source, icon, display_name, source_id = self.get_properties_from_source_component()
|
||||
background_color = self.background_color
|
||||
text_color = self.text_color
|
||||
if self.chat_icon:
|
||||
icon = self.chat_icon
|
||||
message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)
|
||||
|
||||
# Create or use existing Message object
|
||||
if isinstance(self.input_value, Message):
|
||||
message = self.input_value
|
||||
# Update message properties
|
||||
message.text = text
|
||||
else:
|
||||
message = Message(text=text)
|
||||
|
||||
# Set message properties
|
||||
message.sender = self.sender
|
||||
message.sender_name = self.sender_name
|
||||
message.session_id = self.session_id
|
||||
|
|
@ -110,12 +143,54 @@ class ChatOutput(ChatComponent):
|
|||
message.properties.icon = icon
|
||||
message.properties.background_color = background_color
|
||||
message.properties.text_color = text_color
|
||||
if self.session_id and isinstance(message, Message) and self.should_store_message:
|
||||
stored_message = await self.send_message(
|
||||
message,
|
||||
)
|
||||
|
||||
# Store message if needed
|
||||
if self.session_id and self.should_store_message:
|
||||
stored_message = await self.send_message(message)
|
||||
self.message.value = stored_message
|
||||
message = stored_message
|
||||
|
||||
self.status = message
|
||||
return message
|
||||
|
||||
def _validate_input(self) -> None:
|
||||
"""Validate the input data and raise ValueError if invalid."""
|
||||
if self.input_value is None:
|
||||
msg = "Input data cannot be None"
|
||||
raise ValueError(msg)
|
||||
if not isinstance(self.input_value, Data | DataFrame | Message | str | list):
|
||||
msg = f"Expected Data or DataFrame or Message or str, got {type(self.input_value).__name__}"
|
||||
raise TypeError(msg)
|
||||
|
||||
def _safe_convert(self, data: Any) -> str:
|
||||
"""Safely convert input data to string."""
|
||||
try:
|
||||
if isinstance(data, str):
|
||||
return data
|
||||
if isinstance(data, Message):
|
||||
return data.get_text()
|
||||
if isinstance(data, Data):
|
||||
if data.get_text() is None:
|
||||
msg = "Empty Data object"
|
||||
raise ValueError(msg)
|
||||
return data.get_text()
|
||||
if isinstance(data, DataFrame):
|
||||
if self.clean_data:
|
||||
# Remove empty rows
|
||||
data = data.dropna(how="all")
|
||||
# Remove empty lines in each cell
|
||||
data = data.replace(r"^\s*$", "", regex=True)
|
||||
# Replace multiple newlines with a single newline
|
||||
data = data.replace(r"\n+", "\n", regex=True)
|
||||
return data.to_markdown(index=False)
|
||||
return str(data)
|
||||
except (ValueError, TypeError, AttributeError) as e:
|
||||
msg = f"Error converting data: {e!s}"
|
||||
raise ValueError(msg) from e
|
||||
|
||||
def convert_to_string(self) -> str:
|
||||
"""Convert input data to string with proper error handling."""
|
||||
self._validate_input()
|
||||
if isinstance(self.input_value, list):
|
||||
return "\n".join([self._safe_convert(item) for item in self.input_value])
|
||||
return self._safe_convert(self.input_value)
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue