Add session_id and component_id to ChatOutputResponse schema
This commit is contained in:
parent
815e9cfb59
commit
d403ca7a6c
8 changed files with 138 additions and 17 deletions
|
|
@ -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."""
|
||||||
|
|
|
||||||
58
src/backend/langflow/components/utilities/RunFlow.py
Normal file
58
src/backend/langflow/components/utilities/RunFlow.py
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue