Add session_id and component_id to ChatOutputResponse schema

This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-03-04 15:17:57 -03:00
commit d403ca7a6c
8 changed files with 138 additions and 17 deletions

View file

@ -232,7 +232,7 @@ class VertexBuildResponse(BaseModel):
inactivated_vertices: Optional[List[str]] = None inactivated_vertices: Optional[List[str]] = None
next_vertices_ids: Optional[List[str]] = None next_vertices_ids: Optional[List[str]] = None
valid: bool valid: bool
params: Optional[str] params: Optional[Any] = Field(default_factory=dict)
"""JSON string of the params.""" """JSON string of the params."""
data: ResultDataResponse data: ResultDataResponse
"""Mapping of vertex ids to result dict containing the param name and result value.""" """Mapping of vertex ids to result dict containing the param name and result value."""

View file

@ -0,0 +1,58 @@
from typing import List, Optional
from langflow import CustomComponent
from langflow.field_typing import NestedDict, Text
from langflow.graph.schema import ResultData
from langflow.schema import Record
class RunFlowComponent(CustomComponent):
display_name = "Run Flow"
description = "A component to run a flow."
def get_flow_names(self) -> List[str]:
flow_records = self.list_flows()
return [flow_record.data["name"] for flow_record in flow_records]
def build_config(self):
return {
"input_value": {
"display_name": "Input Value",
"multiline": True,
},
"flow_name": {
"display_name": "Flow Name",
"info": "The name of the flow to run.",
"options": self.get_flow_names,
},
"tweaks": {
"display_name": "Tweaks",
"info": "Tweaks to apply to the flow.",
},
}
def build_records_from_result_data(self, result_data: ResultData) -> Record:
messages = result_data.messages
records = []
for message in messages:
record = Record(text=message.get("text", ""), data={"result": result_data})
records.append(record)
return records
async def build(
self, input_value: Text, flow_name: str, tweaks: NestedDict
) -> Record:
results: List[Optional[ResultData]] = await self.run_flow(
input_value=input_value, flow_name=flow_name, tweaks=tweaks
)
if isinstance(results, list):
records = []
for result in results:
if result:
records.extend(self.build_records_from_result_data(result))
else:
records = self.build_records_from_result_data(results)
self.status = records
return records

View file

@ -4,12 +4,13 @@ from typing import Any, Optional
from pydantic import BaseModel, Field, field_serializer from pydantic import BaseModel, Field, field_serializer
from langflow.graph.utils import serialize_field from langflow.graph.utils import serialize_field
from langflow.utils.schemas import ContainsEnumMeta from langflow.utils.schemas import ChatOutputResponse, ContainsEnumMeta
class ResultData(BaseModel): class ResultData(BaseModel):
results: Optional[Any] = Field(default_factory=dict) results: Optional[Any] = Field(default_factory=dict)
artifacts: Optional[Any] = Field(default_factory=dict) artifacts: Optional[Any] = Field(default_factory=dict)
messages: Optional[list[ChatOutputResponse]] = Field(default_factory=list)
timedelta: Optional[float] = None timedelta: Optional[float] = None
duration: Optional[str] = None duration: Optional[str] = None

View file

@ -28,6 +28,7 @@ from langflow.interface.initialize import loading
from langflow.interface.listing import lazy_load_dict from langflow.interface.listing import lazy_load_dict
from langflow.services.deps import get_storage_service from langflow.services.deps import get_storage_service
from langflow.utils.constants import DIRECT_TYPES from langflow.utils.constants import DIRECT_TYPES
from langflow.utils.schemas import ChatOutputResponse
from langflow.utils.util import sync_to_async from langflow.utils.util import sync_to_async
if TYPE_CHECKING: if TYPE_CHECKING:
@ -411,15 +412,43 @@ class Vertex:
self._built = True self._built = True
def extract_messages_from_artifacts(self, artifacts: Dict[str, Any]) -> List[str]:
"""
Extracts messages from the artifacts.
Args:
artifacts (Dict[str, Any]): The artifacts to extract messages from.
Returns:
List[str]: The extracted messages.
"""
messages = []
for key, artifact in artifacts.items():
if not isinstance(artifact, dict):
continue
if "message" in artifact:
chat_output_response = ChatOutputResponse(
message=artifact["message"],
sender=artifact.get("sender"),
sender_name=artifact.get("sender_name"),
session_id=artifact.get("session_id"),
component_id=self.id,
)
messages.append(chat_output_response.model_dump(exclude_none=True))
return messages
def _finalize_build(self): def _finalize_build(self):
result_dict = self.get_built_result() result_dict = self.get_built_result()
# We need to set the artifacts to pass information # We need to set the artifacts to pass information
# to the frontend # to the frontend
self.set_artifacts() self.set_artifacts()
artifacts = self.artifacts artifacts = self.artifacts
messages = self.extract_messages_from_artifacts(artifacts)
result_dict = ResultData( result_dict = ResultData(
results=result_dict, results=result_dict,
artifacts=artifacts, artifacts=artifacts,
messages=messages,
) )
self.set_result(result_dict) self.set_result(result_dict)

View file

@ -132,7 +132,7 @@ class CustomComponent(Component):
return yaml.dump(self.repr_value) return yaml.dump(self.repr_value)
if isinstance(self.repr_value, str): if isinstance(self.repr_value, str):
return self.repr_value return self.repr_value
return str(self.repr_value) return self.repr_value
def build_config(self): def build_config(self):
return self.field_config return self.field_config

View file

@ -1,4 +1,4 @@
from typing import Any from typing import Any, Optional
from langchain_core.documents import Document from langchain_core.documents import Document
from pydantic import BaseModel from pydantic import BaseModel
@ -13,7 +13,7 @@ class Record(BaseModel):
data (dict, optional): Additional data associated with the record. data (dict, optional): Additional data associated with the record.
""" """
text: str text: Optional[str] = ""
data: dict = {} data: dict = {}
@classmethod @classmethod
@ -52,8 +52,6 @@ class Record(BaseModel):
Returns the text of the record. Returns the text of the record.
Returns: Returns:
str: The text of the record. str: The text and data of the record.
""" """
return self.text return self.model_dump_json(indent=2)

View file

@ -11,7 +11,9 @@ class ChatOutputResponse(BaseModel):
message: Union[str, List[Union[str, Dict]]] message: Union[str, List[Union[str, Dict]]]
sender: Optional[str] = "Machine" sender: Optional[str] = "Machine"
sender_name: Optional[str] = "AI" sender_name: Optional[str] = "AI"
session_id: Optional[str] = None
stream_url: Optional[str] = None stream_url: Optional[str] = None
component_id: Optional[str] = None
@classmethod @classmethod
def from_message( def from_message(

View file

@ -9,6 +9,7 @@ import Loading from "../../components/ui/loading";
import { Textarea } from "../../components/ui/textarea"; import { Textarea } from "../../components/ui/textarea";
import Xmark from "../../components/ui/xmark"; import Xmark from "../../components/ui/xmark";
import { import {
RUN_TIMESTAMP_PREFIX,
STATUS_BUILD, STATUS_BUILD,
STATUS_BUILDING, STATUS_BUILDING,
priorityFields, priorityFields,
@ -59,6 +60,8 @@ export default function GenericNode({
useState<validationStatusType | null>(null); useState<validationStatusType | null>(null);
const [handles, setHandles] = useState<number>(0); const [handles, setHandles] = useState<number>(0);
const [validationString, setValidationString] = useState<string>("");
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
function countHandles(): void { function countHandles(): void {
@ -131,6 +134,18 @@ export default function GenericNode({
} }
}, [flowPool[data.id], data.id]); }, [flowPool[data.id], data.id]);
useEffect(() => {
if (validationStatus?.params) {
// if it is not a string turn it into a string
let newValidationString = validationStatus.params;
if (typeof newValidationString !== "string") {
newValidationString = JSON.stringify(validationStatus.params);
}
setValidationString(newValidationString);
}
}, [validationStatus, validationStatus?.params]);
const showNode = data.showNode ?? true; const showNode = data.showNode ?? true;
const nameEditable = true; const nameEditable = true;
@ -493,14 +508,32 @@ export default function GenericNode({
) : !validationStatus ? ( ) : !validationStatus ? (
<span className="flex">{STATUS_BUILD}</span> <span className="flex">{STATUS_BUILD}</span>
) : ( ) : (
<div className="max-h-96 overflow-auto"> <div className="max-h-100">
{typeof validationStatus.params === "string" <div>
? `${durationString}\n${validationStatus.params}` {lastRunTime && (
.split("\n") <div className="justify-left flex text-muted-foreground">
.map((line, index) => ( <div>{RUN_TIMESTAMP_PREFIX}</div>
<div className="ml-1 text-status-blue">
{lastRunTime}
</div>
</div>
)}
</div>
<div className="justify-left flex text-muted-foreground">
<div>Duration:</div>
<div className="ml-1 text-status-blue">
{validationStatus?.data.duration}
</div>
</div>
<hr />
<span className="flex justify-center text-muted-foreground ">
Output
</span>
<div className="max-h-96 overflow-auto custom-scroll">
{validationString.split("\n").map((line, index) => (
<div key={index}>{line}</div> <div key={index}>{line}</div>
)) ))}
: durationString} </div>
</div> </div>
) )
} }