feat: add dynamic metadata to components + search on sidebar (#3945)

*  (frontend_node/base.py): add metadata attribute to store additional information for the component node

*  (constants.py): add 'metadata' attribute to NODE_FORMAT_ATTRIBUTES list to include additional metadata information for nodes in the application.

* 📝 (attributes.py): add new function getattr_return_dict to return a dictionary if the value is of type dict, otherwise return an empty dictionary. Update ATTR_FUNC_MAPPING to include the new function for the "metadata" attribute.

* update basic examples

* 📝 (extraSidebarComponent/index.tsx): refactor handleSearchInput function to improve code readability and maintainability
🐛 (extraSidebarComponent/index.tsx): fix searchInMetadata function to correctly handle nested objects in metadata for search functionality

* 📝 (component.py): add _metadata attribute to CONFIG_ATTRIBUTES list to include it in the configuration attributes
This commit is contained in:
Cristhian Zanforlin Lousa 2024-09-27 12:19:35 -03:00 committed by GitHub
commit 3ddd123b66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 120 additions and 14 deletions

View file

@ -11,7 +11,7 @@ import orjson
STREAM_INFO_TEXT = "Stream the response from the model. Streaming works only in Chat."
NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description", "output_types", "edited"]
NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description", "output_types", "edited", "metadata"]
FIELD_FORMAT_ATTRIBUTES = [

View file

@ -49,6 +49,12 @@ def getattr_return_list_of_values_from_dict(value):
return []
def getattr_return_dict(value):
if isinstance(value, dict):
return value
return {}
ATTR_FUNC_MAPPING: dict[str, Callable] = {
"display_name": getattr_return_str,
"description": getattr_return_str,
@ -63,4 +69,5 @@ ATTR_FUNC_MAPPING: dict[str, Callable] = {
"_inputs": getattr_return_list_of_values_from_dict,
"outputs": getattr_return_list_of_object,
"inputs": getattr_return_list_of_object,
"metadata": getattr_return_dict,
}

View file

@ -31,7 +31,7 @@ if TYPE_CHECKING:
from langflow.inputs.inputs import InputTypes
BACKWARDS_COMPATIBLE_ATTRIBUTES = ["user_id", "vertex", "tracing_service"]
CONFIG_ATTRIBUTES = ["_display_name", "_description", "_icon", "_name"]
CONFIG_ATTRIBUTES = ["_display_name", "_description", "_icon", "_name", "_metadata"]
class Component(CustomComponent):
@ -40,6 +40,7 @@ class Component(CustomComponent):
code_class_base_inheritance: ClassVar[str] = "Component"
_output_logs: dict[str, Log] = {}
_current_output: str = ""
_metadata: dict = {}
def __init__(self, **kwargs):
# if key starts with _ it is a config

View file

@ -159,6 +159,7 @@
"frozen": false,
"icon": "ChatInput",
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -380,6 +381,7 @@
"frozen": false,
"icon": "ChatOutput",
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -588,6 +590,7 @@
"frozen": false,
"icon": "OpenAI",
"lf_version": "1.0.16",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1166,6 +1169,7 @@
"frozen": false,
"icon": "calculator",
"lf_version": "1.0.16",
"metadata": {},
"official": false,
"output_types": [],
"outputs": [
@ -1277,6 +1281,7 @@
"code"
],
"frozen": false,
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -108,6 +108,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -323,6 +324,7 @@
],
"frozen": false,
"icon": "prompts",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -443,6 +445,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -644,6 +647,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -156,6 +156,7 @@
],
"frozen": false,
"icon": "layout-template",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -287,6 +288,7 @@
],
"frozen": false,
"icon": "braces",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -423,6 +425,7 @@
],
"frozen": false,
"icon": "prompts",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -664,6 +667,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -865,6 +869,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -629,6 +629,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -874,6 +875,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1164,6 +1166,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1349,6 +1352,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1488,6 +1492,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1742,6 +1747,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2001,6 +2007,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2295,6 +2302,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"metadata": {},
"name": "",
"output_types": [],
"outputs": [
@ -2409,6 +2417,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2616,6 +2625,7 @@
"edited": false,
"field_order": [],
"frozen": false,
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2733,6 +2743,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -3147,6 +3158,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -3585,6 +3597,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -3881,6 +3894,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"metadata": {},
"name": "",
"output_types": [],
"outputs": [
@ -4047,6 +4061,7 @@
"search_params"
],
"frozen": false,
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -161,6 +161,7 @@
],
"frozen": false,
"icon": "prompts",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -305,6 +306,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -521,6 +523,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -722,6 +725,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1009,6 +1013,7 @@
],
"frozen": false,
"icon": "braces",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1141,6 +1146,7 @@
],
"frozen": false,
"icon": "file-text",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -326,6 +326,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -574,6 +575,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -868,6 +870,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1058,6 +1061,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1202,6 +1206,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1460,6 +1465,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1721,6 +1727,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2019,6 +2026,7 @@
"is_composition": null,
"is_input": null,
"is_output": null,
"metadata": {},
"name": "",
"output_types": [],
"outputs": [
@ -2137,6 +2145,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2356,6 +2365,7 @@
],
"frozen": false,
"icon": "CrewAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2606,6 +2616,7 @@
"search_params"
],
"frozen": false,
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -135,6 +135,7 @@
],
"frozen": false,
"icon": "prompts",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -279,6 +280,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -502,6 +504,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -792,6 +795,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -984,6 +988,7 @@
],
"frozen": false,
"icon": "message-square-more",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -390,6 +390,7 @@
"frozen": false,
"icon": "CrewAI",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -587,6 +588,7 @@
"frozen": false,
"icon": "OpenAI",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -878,6 +880,7 @@
"frozen": false,
"icon": "ChatOutput",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1161,6 +1164,7 @@
"frozen": false,
"icon": "prompts",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1281,6 +1285,7 @@
"frozen": false,
"icon": "prompts",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1401,6 +1406,7 @@
"frozen": false,
"icon": "prompts",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1528,6 +1534,7 @@
"frozen": false,
"icon": "CrewAI",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1878,6 +1885,7 @@
"frozen": false,
"icon": "CrewAI",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2228,6 +2236,7 @@
"frozen": false,
"icon": "CrewAI",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2562,6 +2571,7 @@
"field_order": [],
"frozen": false,
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -399,6 +399,7 @@
"frozen": false,
"icon": "ChatInput",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -620,6 +621,7 @@
"frozen": false,
"icon": "ChatOutput",
"lf_version": "1.0.15",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -827,6 +829,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1405,6 +1408,7 @@
],
"frozen": false,
"lf_version": "1.0.15",
"metadata": {},
"official": false,
"output_types": [],
"outputs": [
@ -2265,6 +2269,7 @@
"frozen": false,
"icon": "calculator",
"lf_version": "1.0.15",
"metadata": {},
"official": false,
"output_types": [],
"outputs": [

View file

@ -291,6 +291,7 @@
],
"frozen": false,
"icon": "ChatInput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -523,6 +524,7 @@
],
"frozen": false,
"icon": "AstraDB",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -994,6 +996,7 @@
],
"frozen": false,
"icon": "braces",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1130,6 +1133,7 @@
],
"frozen": false,
"icon": "prompts",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1274,6 +1278,7 @@
],
"frozen": false,
"icon": "ChatOutput",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1465,6 +1470,7 @@
],
"frozen": false,
"icon": "scissors-line-dashed",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1609,6 +1615,7 @@
],
"frozen": false,
"icon": "file-text",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -1757,6 +1764,7 @@
],
"frozen": false,
"icon": "AstraDB",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2246,6 +2254,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -2699,6 +2708,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{
@ -3144,6 +3154,7 @@
],
"frozen": false,
"icon": "OpenAI",
"metadata": {},
"output_types": [],
"outputs": [
{

View file

@ -53,6 +53,8 @@ class FrontendNode(BaseModel):
"""Error message for the frontend node."""
edited: bool = False
"""Whether the frontend node has been edited."""
metadata: dict = {}
"""Metadata for the component node."""
def set_documentation(self, documentation: str) -> None:
"""Sets the documentation of the frontend node."""

View file

@ -46,29 +46,48 @@ export default function ExtraSidebar(): JSX.Element {
event.dataTransfer.setDragImage(crt, 0, 0);
event.dataTransfer.setData("genericNode", JSON.stringify(data));
}
function normalizeString(str: string): string {
return str.toLowerCase().replace(/_/g, " ").replace(/\s+/g, "");
}
// Handle showing components after use search input
function searchInMetadata(metadata: any, searchTerm: string): boolean {
if (!metadata || typeof metadata !== "object") return false;
return Object.entries(metadata).some(([key, value]) => {
if (typeof value === "string") {
return (
normalizeString(key).includes(searchTerm) ||
normalizeString(value).includes(searchTerm)
);
}
if (typeof value === "object") {
return searchInMetadata(value, searchTerm);
}
return false;
});
}
function handleSearchInput(e: string) {
if (e === "") {
setFilterData(data);
return;
}
const searchTerm = normalizeString(e);
setFilterData((_) => {
let ret = {};
Object.keys(data).forEach((d: keyof APIObjectType, i) => {
let ret: APIObjectType = {};
Object.keys(data).forEach((d: keyof APIObjectType) => {
ret[d] = {};
let keys = Object.keys(data[d]).filter(
(nd) =>
normalizeString(nd).includes(normalizeString(e)) ||
normalizeString(data[d][nd].display_name).includes(
normalizeString(e),
) ||
normalizeString(d.toString()).includes(normalizeString(e)),
);
let keys = Object.keys(data[d]).filter((nd) => {
const item = data[d][nd];
return (
normalizeString(nd).includes(searchTerm) ||
normalizeString(item.display_name).includes(searchTerm) ||
normalizeString(d.toString()).includes(searchTerm) ||
(item.metadata && searchInMetadata(item.metadata, searchTerm))
);
});
keys.forEach((element) => {
ret[d][element] = data[d][element];
});