Split Langflow into Langflow and Langflow Base (#1562)

* Initial Restructure

* Replace import langflow for import langflow_base

* Fix dependencies

* 🔧 chore(Makefile): refactor build process to separate base and frontend builds for better organization and maintainability

* 🚀 chore(Makefile): update build_frontend command to copy frontend build to the correct directory
🔖 chore(pyproject.toml): update python and httpx dependencies versions
🔧 chore(__init__.py): update import statement for load_flow_from_json function

* 🔖 chore(pyproject.toml): update package version from 0.0.6 to 0.0.8 to reflect changes in the codebase

* 🚀 feat(server.ts): change port variable case from lowercase port to uppercase PORT to improve semantics
🚀 feat(server.ts): add support for process.env.PORT environment variable to be able to run app on a configurable port

* 🐛 fix(server.ts): change port variable case from lowercase port to uppercase PORT to improve semantics
✨ feat(server.ts): add support for process.env.PORT environment variable to be able to run app on a configurable port
🚚 chore(pyproject.toml): update langflow-base version from 0.0.8 to 0.0.10
✨ feat(server.ts): add new agent component LCAgentComponent to langflow_base
✨ feat(server.ts): add new model component LCModelComponent to langflow_base
✨ feat(server.ts): add new helper functions docs_to_records and records_to_text to langflow_base
✨ feat(server.ts): add new flow helper functions list_flows, load_flow, run_flow, generate_function_for_flow, get_flow_inputs, build_schema_from_inputs to langflow_base
✨ feat(server.ts): add new prompt component PromptComponent to langflow_base
✨ feat(server.ts): add new chat components ChatInput and ChatOutput to langflow_base
✨ feat(server.ts): add new model component OpenAIModelComponent to langflow_base
🚚 chore(main.py): update import path from langflow.main to langflow_base.main
🚚 chore(service.py): update import path from langflow.services.database.manager to langflow_base.services.database.manager
🚚 chore(factory.py): update import path from langflow.services to langflow_base.services
🚚 chore(service.py): update import path from langflow.services.plugins to langflow_base.services.plugins
🚚 chore(utils.py): update import path from langflow.services to langflow_base.services
🚚 chore(validate.py): update import path from langflow.field_typing to langflow_base.field_typing
🚚 chore(pyproject.toml): update langflow-base version from 0.0.8 to 0.0.10

* Update Makefile to install backend dependencies and build langflow

* Add langflow main module and update __init__.py

* Update langflow install process to use implicit namespace

* Add langflow-base as a local dependency

* Add setup_poetry target to Makefile

* Update Poetry version and add poetry-monorepo-dependency-plugin

* Refactor code to improve performance and readability

* Update imports to custom and load

* Update content-hash in poetry.lock

---------

Co-authored-by: Matheus <jacquesmats@gmail.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@logspace.ai>
This commit is contained in:
Matheus Jacques 2024-03-26 13:26:30 +01:00 • committed by GitHub
commit 8172e62236
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
466 changed files with 5418 additions and 1144 deletions

View file

@ -429,7 +429,7 @@ export function getPythonCode(
const flowName = flow.name;
const tweaks = buildTweaks(flow);
const inputs = buildInputs();
return `from langflow import load_flow_from_json
return `from langflow.load import load_flow_from_json
TWEAKS = ${
tweak && tweak.length > 0
? buildTweakObject(tweak)

View file

@ -1,4 +1,4 @@
export const custom = `from langflow import CustomComponent
export const custom = `from langflow.custom import CustomComponent
from langchain.llms.base import BaseLLM
from langchain.chains import LLMChain

View file

@ -10,7 +10,10 @@
"height": 631,
"id": "ChatOpenAI-Hz56M",
"type": "genericNode",
"position": { "x": 543.1816229116944, "y": 942.891611351432 },
"position": {
"x": 543.1816229116944,
"y": 942.891611351432
},
"data": {
"type": "ChatOpenAI",
"node": {
@ -238,7 +241,10 @@
"height": 387,
"id": "AgentInitializer-QiQ4x",
"type": "genericNode",
"position": { "x": 1036.6064439140812, "y": 645.1919693466587 },
"position": {
"x": 1036.6064439140812,
"y": 645.1919693466587
},
"data": {
"type": "AgentInitializer",
"node": {
@ -299,7 +305,10 @@
"_type": "initialize_agent"
},
"description": "Construct a zero shot agent from an LLM and tools.",
"base_classes": ["AgentExecutor", "function"],
"base_classes": [
"AgentExecutor",
"function"
],
"display_name": "AgentInitializer"
},
"id": "AgentInitializer-QiQ4x",
@ -316,7 +325,10 @@
"height": 437,
"id": "PythonFunctionTool-kX99N",
"type": "genericNode",
"position": { "x": 553.050119331742, "y": 412.9533535948685 },
"position": {
"x": 553.050119331742,
"y": 412.9533535948685
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -360,7 +372,9 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["Tool"],
"base_classes": [
"Tool"
],
"display_name": "PythonFunctionTool"
},
"id": "PythonFunctionTool-kX99N",
@ -380,7 +394,9 @@
"sourceHandle": "{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-Hz56Mœ}",
"target": "AgentInitializer-QiQ4x",
"targetHandle": "{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-QiQ4xœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-ChatOpenAI-Hz56M{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-Hz56Mœ}-AgentInitializer-QiQ4x{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-QiQ4xœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
@ -409,14 +425,18 @@
"sourceHandle": "{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-kX99Nœ}",
"target": "AgentInitializer-QiQ4x",
"targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-QiQ4xœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-PythonFunctionTool-kX99N{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-kX99Nœ}-AgentInitializer-QiQ4x{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-QiQ4xœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"selected": false,
"data": {
"sourceHandle": {
"baseClasses": ["Tool"],
"baseClasses": [
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-kX99N"
},
@ -446,7 +466,10 @@
{
"id": "CustomComponent-w4WCp",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -456,7 +479,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -478,11 +501,18 @@
},
"id": "CustomComponent-w4WCp"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "e43cf2c8-cd64-4936-8170-b207a8b109c4",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -497,7 +527,10 @@
"height": 631,
"id": "ChatOpenAI-7GFF0",
"type": "genericNode",
"position": { "x": 543.1816229116944, "y": 942.891611351432 },
"position": {
"x": 543.1816229116944,
"y": 942.891611351432
},
"data": {
"type": "ChatOpenAI",
"node": {
@ -725,7 +758,10 @@
"height": 387,
"id": "AgentInitializer-YJgqs",
"type": "genericNode",
"position": { "x": 1036.6064439140812, "y": 645.1919693466587 },
"position": {
"x": 1036.6064439140812,
"y": 645.1919693466587
},
"data": {
"type": "AgentInitializer",
"node": {
@ -786,7 +822,10 @@
"_type": "initialize_agent"
},
"description": "Construct a zero shot agent from an LLM and tools.",
"base_classes": ["AgentExecutor", "function"],
"base_classes": [
"AgentExecutor",
"function"
],
"display_name": "AgentInitializer"
},
"id": "AgentInitializer-YJgqs",
@ -803,7 +842,10 @@
"height": 437,
"id": "PythonFunctionTool-gqQDg",
"type": "genericNode",
"position": { "x": 553.050119331742, "y": 412.9533535948685 },
"position": {
"x": 553.050119331742,
"y": 412.9533535948685
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -847,7 +889,9 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["Tool"],
"base_classes": [
"Tool"
],
"display_name": "PythonFunctionTool"
},
"id": "PythonFunctionTool-gqQDg",
@ -867,7 +911,9 @@
"sourceHandle": "{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-7GFF0œ}",
"target": "AgentInitializer-YJgqs",
"targetHandle": "{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-YJgqsœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-ChatOpenAI-7GFF0{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-7GFF0œ}-AgentInitializer-YJgqs{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-YJgqsœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
@ -896,14 +942,18 @@
"sourceHandle": "{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-gqQDgœ}",
"target": "AgentInitializer-YJgqs",
"targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-YJgqsœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-PythonFunctionTool-gqQDg{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-gqQDgœ}-AgentInitializer-YJgqs{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-YJgqsœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"selected": false,
"data": {
"sourceHandle": {
"baseClasses": ["Tool"],
"baseClasses": [
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-gqQDg"
},
@ -933,7 +983,10 @@
{
"id": "CustomComponent-iF9Zr",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -943,7 +996,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -965,11 +1018,18 @@
},
"id": "CustomComponent-iF9Zr"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "88a0e6a1-8144-4bff-b28c-d312ae5c8a10",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -984,7 +1044,10 @@
"height": 631,
"id": "ChatOpenAI-cljAK",
"type": "genericNode",
"position": { "x": 543.1816229116944, "y": 942.891611351432 },
"position": {
"x": 543.1816229116944,
"y": 942.891611351432
},
"data": {
"type": "ChatOpenAI",
"node": {
@ -1212,7 +1275,10 @@
"height": 387,
"id": "AgentInitializer-grV0u",
"type": "genericNode",
"position": { "x": 1036.6064439140812, "y": 645.1919693466587 },
"position": {
"x": 1036.6064439140812,
"y": 645.1919693466587
},
"data": {
"type": "AgentInitializer",
"node": {
@ -1273,7 +1339,10 @@
"_type": "initialize_agent"
},
"description": "Construct a zero shot agent from an LLM and tools.",
"base_classes": ["AgentExecutor", "function"],
"base_classes": [
"AgentExecutor",
"function"
],
"display_name": "AgentInitializer"
},
"id": "AgentInitializer-grV0u",
@ -1290,7 +1359,10 @@
"height": 437,
"id": "PythonFunctionTool-SctM2",
"type": "genericNode",
"position": { "x": 553.050119331742, "y": 412.9533535948685 },
"position": {
"x": 553.050119331742,
"y": 412.9533535948685
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -1334,7 +1406,9 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["Tool"],
"base_classes": [
"Tool"
],
"display_name": "PythonFunctionTool"
},
"id": "PythonFunctionTool-SctM2",
@ -1354,7 +1428,9 @@
"sourceHandle": "{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-cljAKœ}",
"target": "AgentInitializer-grV0u",
"targetHandle": "{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-grV0uœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-ChatOpenAI-cljAK{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-cljAKœ}-AgentInitializer-grV0u{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-grV0uœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
@ -1383,14 +1459,18 @@
"sourceHandle": "{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-SctM2œ}",
"target": "AgentInitializer-grV0u",
"targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-grV0uœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-PythonFunctionTool-SctM2{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-SctM2œ}-AgentInitializer-grV0u{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-grV0uœ,œinputTypesœ:null,œtypeœ:œToolœ}",
"selected": false,
"data": {
"sourceHandle": {
"baseClasses": ["Tool"],
"baseClasses": [
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-SctM2"
},
@ -1420,7 +1500,10 @@
{
"id": "CustomComponent-z5kAP",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1430,7 +1513,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1452,11 +1535,18 @@
},
"id": "CustomComponent-z5kAP"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "3128b556-35c7-4ced-a834-70fbeb1a410f",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1469,7 +1559,10 @@
{
"id": "CustomComponent-ZieNZ",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1479,7 +1572,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1501,11 +1594,18 @@
},
"id": "CustomComponent-ZieNZ"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "d3f2c379-9df5-49a0-b33d-d855c2085949",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1518,7 +1618,10 @@
{
"id": "CustomComponent-CcHG0",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1528,7 +1631,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1550,11 +1653,18 @@
},
"id": "CustomComponent-CcHG0"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "74afff1f-b540-43d5-bc66-d18f39d65d57",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1567,7 +1677,10 @@
{
"id": "CustomComponent-Q8qSr",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1577,7 +1690,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1599,11 +1712,18 @@
},
"id": "CustomComponent-Q8qSr"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "b0b1c893-6194-4748-ae10-b5f604b271c2",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1616,7 +1736,10 @@
{
"id": "CustomComponent-Lgoca",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1626,7 +1749,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1648,11 +1771,18 @@
},
"id": "CustomComponent-Lgoca"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "edf1051d-509b-46a2-84c6-b94bdcdc3a4f",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1665,7 +1795,10 @@
{
"id": "CustomComponent-6OJGW",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1675,7 +1808,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1697,11 +1830,18 @@
},
"id": "CustomComponent-6OJGW"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "65b2a4e0-4084-418a-aa86-ee914acb0ab5",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1714,7 +1854,10 @@
{
"id": "CustomComponent-tcE83",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -1724,7 +1867,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -1746,11 +1889,18 @@
},
"id": "CustomComponent-tcE83"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "534e412b-d37b-4133-8029-e5ed139fd55c",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -1765,7 +1915,10 @@
"height": 631,
"id": "ChatOpenAI-mQEi3",
"type": "genericNode",
"position": { "x": 543.1816229116944, "y": 942.891611351432 },
"position": {
"x": 543.1816229116944,
"y": 942.891611351432
},
"data": {
"type": "ChatOpenAI",
"node": {
@ -1993,7 +2146,10 @@
"height": 387,
"id": "AgentInitializer-EE8R4",
"type": "genericNode",
"position": { "x": 1036.6064439140812, "y": 645.1919693466587 },
"position": {
"x": 1036.6064439140812,
"y": 645.1919693466587
},
"data": {
"type": "AgentInitializer",
"node": {
@ -2054,7 +2210,10 @@
"_type": "initialize_agent"
},
"description": "Construct a zero shot agent from an LLM and tools.",
"base_classes": ["AgentExecutor", "function"],
"base_classes": [
"AgentExecutor",
"function"
],
"display_name": "AgentInitializer"
},
"id": "AgentInitializer-EE8R4",
@ -2071,7 +2230,10 @@
"height": 437,
"id": "PythonFunctionTool-YKkDL",
"type": "genericNode",
"position": { "x": 553.050119331742, "y": 412.9533535948685 },
"position": {
"x": 553.050119331742,
"y": 412.9533535948685
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -2115,7 +2277,9 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["Tool"],
"base_classes": [
"Tool"
],
"display_name": "PythonFunctionTool"
},
"id": "PythonFunctionTool-YKkDL",
@ -2135,7 +2299,9 @@
"sourceHandle": "{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-mQEi3œ}",
"target": "AgentInitializer-EE8R4",
"targetHandle": "{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-EE8R4œ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-ChatOpenAI-mQEi3{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-mQEi3œ}-AgentInitializer-EE8R4{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-EE8R4œ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
@ -2164,14 +2330,18 @@
"sourceHandle": "{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-YKkDLœ}",
"target": "AgentInitializer-EE8R4",
"targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-EE8R4œ,œinputTypesœ:null,œtypeœ:œToolœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-PythonFunctionTool-YKkDL{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-YKkDLœ}-AgentInitializer-EE8R4{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-EE8R4œ,œinputTypesœ:null,œtypeœ:œToolœ}",
"selected": false,
"data": {
"sourceHandle": {
"baseClasses": ["Tool"],
"baseClasses": [
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-YKkDL"
},
@ -2201,7 +2371,10 @@
{
"id": "CustomComponent-T38LS",
"type": "genericNode",
"position": { "x": 536, "y": 337 },
"position": {
"x": 536,
"y": 337
},
"data": {
"type": "CustomComponent",
"node": {
@ -2211,7 +2384,7 @@
"placeholder": "",
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"value": "from langflow.custom import CustomComponent\n\nfrom langchain.llms.base import BaseLLM\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.schema import Document\n\nimport requests\n\nclass YourComponent(CustomComponent):\n display_name: str = \"Custom Component\"\n description: str = \"Create any custom component you want!\"\n\n def build_config(self):\n return { \"url\": { \"multiline\": True, \"required\": True } }\n\n def build(self, url: str, llm: BaseLLM, prompt: PromptTemplate) -> Document:\n response = requests.get(url)\n chain = LLMChain(llm=llm, prompt=prompt)\n result = chain.run(response.text[:300])\n return Document(page_content=str(result))\n",
"password": false,
"name": "code",
"advanced": false,
@ -2233,11 +2406,18 @@
},
"id": "CustomComponent-T38LS"
},
"positionAbsolute": { "x": 536, "y": 337 }
"positionAbsolute": {
"x": 536,
"y": 337
}
}
],
"edges": [],
"viewport": { "x": 0, "y": 0, "zoom": 1 }
"viewport": {
"x": 0,
"y": 0,
"zoom": 1
}
},
"id": "ec36a3b7-7b5f-4663-983c-833bcec4d851",
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
@ -2252,7 +2432,10 @@
"height": 631,
"id": "ChatOpenAI-E1XSb",
"type": "genericNode",
"position": { "x": 543.1816229116944, "y": 942.891611351432 },
"position": {
"x": 543.1816229116944,
"y": 942.891611351432
},
"data": {
"type": "ChatOpenAI",
"node": {
@ -2480,7 +2663,10 @@
"height": 387,
"id": "AgentInitializer-goPm2",
"type": "genericNode",
"position": { "x": 1036.6064439140812, "y": 645.1919693466587 },
"position": {
"x": 1036.6064439140812,
"y": 645.1919693466587
},
"data": {
"type": "AgentInitializer",
"node": {
@ -2541,7 +2727,10 @@
"_type": "initialize_agent"
},
"description": "Construct a zero shot agent from an LLM and tools.",
"base_classes": ["AgentExecutor", "function"],
"base_classes": [
"AgentExecutor",
"function"
],
"display_name": "AgentInitializer"
},
"id": "AgentInitializer-goPm2",
@ -2558,7 +2747,10 @@
"height": 437,
"id": "PythonFunctionTool-SQikY",
"type": "genericNode",
"position": { "x": 553.050119331742, "y": 412.9533535948685 },
"position": {
"x": 553.050119331742,
"y": 412.9533535948685
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -2602,7 +2794,9 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["Tool"],
"base_classes": [
"Tool"
],
"display_name": "PythonFunctionTool"
},
"id": "PythonFunctionTool-SQikY",
@ -2622,7 +2816,9 @@
"sourceHandle": "{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-E1XSbœ}",
"target": "AgentInitializer-goPm2",
"targetHandle": "{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-goPm2œ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-ChatOpenAI-E1XSb{œbaseClassesœ:[œSerializableœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLanguageModelœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-E1XSbœ}-AgentInitializer-goPm2{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-goPm2œ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}",
@ -2651,14 +2847,18 @@
"sourceHandle": "{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-SQikYœ}",
"target": "AgentInitializer-goPm2",
"targetHandle": "{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-goPm2œ,œinputTypesœ:null,œtypeœ:œToolœ}",
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-PythonFunctionTool-SQikY{œbaseClassesœ:[œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-SQikYœ}-AgentInitializer-goPm2{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-goPm2œ,œinputTypesœ:null,œtypeœ:œToolœ}",
"selected": false,
"data": {
"sourceHandle": {
"baseClasses": ["Tool"],
"baseClasses": [
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-SQikY"
},
@ -2681,4 +2881,4 @@
"user_id": "6f6ebc2c-9e7a-4c35-84fc-51760db10d9b"
}
]
}
}

View file

@ -5,7 +5,10 @@
{
"id": "PythonFunctionTool-RfJui",
"type": "genericNode",
"position": { "x": 117.54690105175428, "y": -84.2465475108354 },
"position": {
"x": 117.54690105175428,
"y": -84.2465475108354
},
"data": {
"type": "PythonFunctionTool",
"node": {
@ -43,7 +46,9 @@
"dynamic": false,
"info": "",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"name": {
"type": "str",
@ -61,7 +66,9 @@
"dynamic": false,
"info": "",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"return_direct": {
"type": "bool",
@ -83,7 +90,10 @@
"_type": "PythonFunctionTool"
},
"description": "Python function to be executed.",
"base_classes": ["BaseTool", "Tool"],
"base_classes": [
"BaseTool",
"Tool"
],
"display_name": "PythonFunctionTool",
"documentation": "",
"custom_fields": {},
@ -97,13 +107,19 @@
"selected": true,
"width": 384,
"height": 466,
"positionAbsolute": { "x": 117.54690105175428, "y": -84.2465475108354 },
"positionAbsolute": {
"x": 117.54690105175428,
"y": -84.2465475108354
},
"dragging": false
},
{
"id": "AgentInitializer-tPdJw",
"type": "genericNode",
"position": { "x": 677.68677055088, "y": 127.19859565276168 },
"position": {
"x": 677.68677055088,
"y": 127.19859565276168
},
"data": {
"type": "AgentInitializer",
"node": {
@ -192,7 +208,9 @@
"dynamic": false,
"info": "",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"code": {
"type": "code",
@ -201,7 +219,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Callable, List, Optional, Union\n\nfrom langchain.agents import AgentExecutor, AgentType, initialize_agent, types\nfrom langflow import CustomComponent\nfrom langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool\n\n\nclass AgentInitializerComponent(CustomComponent):\n display_name: str = \"Agent Initializer\"\n description: str = \"Initialize a Langchain Agent.\"\n documentation: str = \"https://python.langchain.com/docs/modules/agents/agent_types/\"\n\n def build_config(self):\n agents = list(types.AGENT_TO_CLASS.keys())\n # field_type and required are optional\n return {\n \"agent\": {\"options\": agents, \"value\": agents[0], \"display_name\": \"Agent Type\"},\n \"max_iterations\": {\"display_name\": \"Max Iterations\", \"value\": 10},\n \"memory\": {\"display_name\": \"Memory\"},\n \"tools\": {\"display_name\": \"Tools\"},\n \"llm\": {\"display_name\": \"Language Model\"},\n \"code\": {\"advanced\": True},\n }\n\n def build(\n self,\n agent: str,\n llm: BaseLanguageModel,\n tools: List[Tool],\n max_iterations: int,\n memory: Optional[BaseChatMemory] = None,\n ) -> Union[AgentExecutor, Callable]:\n agent = AgentType(agent)\n if memory:\n return initialize_agent(\n tools=tools,\n llm=llm,\n agent=agent,\n memory=memory,\n return_intermediate_steps=True,\n handle_parsing_errors=True,\n max_iterations=max_iterations,\n )\n return initialize_agent(\n tools=tools,\n llm=llm,\n agent=agent,\n return_intermediate_steps=True,\n handle_parsing_errors=True,\n max_iterations=max_iterations,\n )\n",
"value": "from typing import Callable, List, Optional, Union\n\nfrom langchain.agents import AgentExecutor, AgentType, initialize_agent, types\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool\n\n\nclass AgentInitializerComponent(CustomComponent):\n display_name: str = \"Agent Initializer\"\n description: str = \"Initialize a Langchain Agent.\"\n documentation: str = \"https://python.langchain.com/docs/modules/agents/agent_types/\"\n\n def build_config(self):\n agents = list(types.AGENT_TO_CLASS.keys())\n # field_type and required are optional\n return {\n \"agent\": {\"options\": agents, \"value\": agents[0], \"display_name\": \"Agent Type\"},\n \"max_iterations\": {\"display_name\": \"Max Iterations\", \"value\": 10},\n \"memory\": {\"display_name\": \"Memory\"},\n \"tools\": {\"display_name\": \"Tools\"},\n \"llm\": {\"display_name\": \"Language Model\"},\n \"code\": {\"advanced\": True},\n }\n\n def build(\n self,\n agent: str,\n llm: BaseLanguageModel,\n tools: List[Tool],\n max_iterations: int,\n memory: Optional[BaseChatMemory] = None,\n ) -> Union[AgentExecutor, Callable]:\n agent = AgentType(agent)\n if memory:\n return initialize_agent(\n tools=tools,\n llm=llm,\n agent=agent,\n memory=memory,\n return_intermediate_steps=True,\n handle_parsing_errors=True,\n max_iterations=max_iterations,\n )\n return initialize_agent(\n tools=tools,\n llm=llm,\n agent=agent,\n return_intermediate_steps=True,\n handle_parsing_errors=True,\n max_iterations=max_iterations,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -251,7 +269,10 @@
"max_iterations": null,
"memory": null
},
"output_types": ["AgentExecutor", "Callable"],
"output_types": [
"AgentExecutor",
"Callable"
],
"field_formatters": {},
"pinned": false,
"beta": true
@ -265,7 +286,10 @@
{
"id": "ChatOpenAISpecs-stxRM",
"type": "genericNode",
"position": { "x": 18.226716205350385, "y": 432.6122491402193 },
"position": {
"x": 18.226716205350385,
"y": 432.6122491402193
},
"data": {
"type": "ChatOpenAISpecs",
"node": {
@ -277,7 +301,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langchain.llms import BaseLLM\nfrom langchain_community.chat_models.openai import ChatOpenAI\nfrom langflow import CustomComponent\nfrom langflow.field_typing import BaseLanguageModel, NestedDict\n\n\nclass ChatOpenAIComponent(CustomComponent):\n display_name = \"ChatOpenAI\"\n description = \"`OpenAI` Chat large language models API.\"\n icon = \"OpenAI\"\n\n def build_config(self):\n return {\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": False,\n \"required\": False,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n \"required\": False,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"required\": False,\n \"options\": [\n \"gpt-4-turbo-preview\",\n \"gpt-4-0125-preview\",\n \"gpt-4-1106-preview\",\n \"gpt-4-vision-preview\",\n \"gpt-3.5-turbo-0125\",\n \"gpt-3.5-turbo-1106\",\n ],\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": False,\n \"required\": False,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"advanced\": False,\n \"required\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"required\": False,\n \"value\": 0.7,\n },\n }\n\n def build(\n self,\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n model_name: str = \"gpt-4-1106-preview\",\n openai_api_base: Optional[str] = None,\n openai_api_key: Optional[str] = None,\n temperature: float = 0.7,\n ) -> Union[BaseLanguageModel, BaseLLM]:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n return ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=openai_api_key,\n temperature=temperature,\n )\n",
"value": "from typing import Optional, Union\n\nfrom langchain.llms import BaseLLM\nfrom langchain_community.chat_models.openai import ChatOpenAI\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import BaseLanguageModel, NestedDict\n\n\nclass ChatOpenAIComponent(CustomComponent):\n display_name = \"ChatOpenAI\"\n description = \"`OpenAI` Chat large language models API.\"\n icon = \"OpenAI\"\n\n def build_config(self):\n return {\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": False,\n \"required\": False,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n \"required\": False,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"required\": False,\n \"options\": [\n \"gpt-4-turbo-preview\",\n \"gpt-4-0125-preview\",\n \"gpt-4-1106-preview\",\n \"gpt-4-vision-preview\",\n \"gpt-3.5-turbo-0125\",\n \"gpt-3.5-turbo-1106\",\n ],\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": False,\n \"required\": False,\n \"info\": (\n \"The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\\n\\n\"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\"\n ),\n },\n \"openai_api_key\": {\n \"display_name\": \"OpenAI API Key\",\n \"advanced\": False,\n \"required\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"required\": False,\n \"value\": 0.7,\n },\n }\n\n def build(\n self,\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n model_name: str = \"gpt-4-1106-preview\",\n openai_api_base: Optional[str] = None,\n openai_api_key: Optional[str] = None,\n temperature: float = 0.7,\n ) -> Union[BaseLanguageModel, BaseLLM]:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n return ChatOpenAI(\n max_tokens=max_tokens,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=openai_api_key,\n temperature=temperature,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -348,7 +372,9 @@
"dynamic": false,
"info": "",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"openai_api_base": {
"type": "str",
@ -366,7 +392,9 @@
"dynamic": false,
"info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"openai_api_key": {
"type": "str",
@ -384,7 +412,9 @@
"dynamic": false,
"info": "",
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"temperature": {
"type": "float",
@ -402,7 +432,11 @@
"advanced": false,
"dynamic": false,
"info": "",
"rangeSpec": { "min": -1, "max": 1, "step": 0.1 },
"rangeSpec": {
"min": -1,
"max": 1,
"step": 0.1
},
"title_case": false
},
"_type": "CustomComponent"
@ -428,7 +462,10 @@
"openai_api_key": null,
"temperature": null
},
"output_types": ["BaseLanguageModel", "BaseLLM"],
"output_types": [
"BaseLanguageModel",
"BaseLLM"
],
"field_formatters": {},
"pinned": false,
"beta": true
@ -438,7 +475,10 @@
"selected": false,
"width": 384,
"height": 666,
"positionAbsolute": { "x": 18.226716205350385, "y": 432.6122491402193 },
"positionAbsolute": {
"x": 18.226716205350385,
"y": 432.6122491402193
},
"dragging": false
}
],
@ -469,7 +509,9 @@
"id": "ChatOpenAISpecs-stxRM"
}
},
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-foreground stroke-connection",
"id": "reactflow__edge-ChatOpenAISpecs-stxRM{œbaseClassesœ:[œRunnableœ,œBaseLLMœ,œSerializableœ,œBaseLanguageModelœ,œobjectœ,œGenericœ,œRunnableSerializableœ],œdataTypeœ:œChatOpenAISpecsœ,œidœ:œChatOpenAISpecs-stxRMœ}-AgentInitializer-tPdJw{œfieldNameœ:œllmœ,œidœ:œAgentInitializer-tPdJwœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}"
},
@ -486,12 +528,17 @@
"type": "Tool"
},
"sourceHandle": {
"baseClasses": ["BaseTool", "Tool"],
"baseClasses": [
"BaseTool",
"Tool"
],
"dataType": "PythonFunctionTool",
"id": "PythonFunctionTool-RfJui"
}
},
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-foreground stroke-connection",
"id": "reactflow__edge-PythonFunctionTool-RfJui{œbaseClassesœ:[œBaseToolœ,œToolœ],œdataTypeœ:œPythonFunctionToolœ,œidœ:œPythonFunctionTool-RfJuiœ}-AgentInitializer-tPdJw{œfieldNameœ:œtoolsœ,œidœ:œAgentInitializer-tPdJwœ,œinputTypesœ:null,œtypeœ:œToolœ}"
}
@ -506,4 +553,4 @@
"name": "Untitled document (20)",
"last_tested_version": "0.7.0a0",
"is_component": false
}
}

View file

@ -8,7 +8,10 @@
"height": 461,
"id": "CustomComponent-MtJjl",
"type": "genericNode",
"position": { "x": 534.3712097224906, "y": -135.01908566635723 },
"position": {
"x": 534.3712097224906,
"y": -135.01908566635723
},
"data": {
"type": "CustomComponent",
"node": {
@ -20,7 +23,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\nfrom langflow.field_typing import Data\nfrom pathlib import Path\nfrom platformdirs import user_cache_dir\nimport os\n\nclass Component(CustomComponent):\n documentation: str = \"http://docs.langflow.org/components/custom\"\n\n def build_config(self):\n return {\"text_input\":{\"display_name\":\"Text Input\", \"input_types\":[\"str\"]},\"save_path\":{\"display_name\":\"Save Path\",\n \"info\":\"Put the full path with the file name and extension\",\"value\":Path(user_cache_dir(\"langflow\"))/\"text.t1.txt\"}}\n\n def build(self, text_input:str,save_path:str) -> str:\n try:\n # Create the directory if it doesn't exist\n os.makedirs(os.path.dirname(save_path), exist_ok=True)\n\n # Open the file in write mode and save the text\n with open(save_path, 'w') as file:\n file.write(text_input)\n except Exception as e:\n raise e\n self.status = text_input\n return text_input",
"value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import Data\nfrom pathlib import Path\nfrom platformdirs import user_cache_dir\nimport os\n\nclass Component(CustomComponent):\n documentation: str = \"http://docs.langflow.org/components/custom\"\n\n def build_config(self):\n return {\"text_input\":{\"display_name\":\"Text Input\", \"input_types\":[\"str\"]},\"save_path\":{\"display_name\":\"Save Path\",\n \"info\":\"Put the full path with the file name and extension\",\"value\":Path(user_cache_dir(\"langflow\"))/\"text.t1.txt\"}}\n\n def build(self, text_input:str,save_path:str) -> str:\n try:\n # Create the directory if it doesn't exist\n os.makedirs(os.path.dirname(save_path), exist_ok=True)\n\n # Open the file in write mode and save the text\n with open(save_path, 'w') as file:\n file.write(text_input)\n except Exception as e:\n raise e\n self.status = text_input\n return text_input",
"fileTypes": [],
"file_path": "",
"password": false,
@ -59,18 +62,27 @@
"name": "text_input",
"display_name": "Text Input",
"advanced": false,
"input_types": ["str"],
"input_types": [
"str"
],
"dynamic": false,
"info": "",
"value": ""
},
"_type": "CustomComponent"
},
"base_classes": ["str"],
"base_classes": [
"str"
],
"display_name": "text checkpoint",
"documentation": "http://docs.langflow.org/components/custom",
"custom_fields": { "save_path": null, "text_input": null },
"output_types": ["str"],
"custom_fields": {
"save_path": null,
"text_input": null
},
"output_types": [
"str"
],
"field_formatters": {},
"beta": true
},
@ -78,14 +90,20 @@
},
"selected": false,
"dragging": false,
"positionAbsolute": { "x": 534.3712097224906, "y": -135.01908566635723 }
"positionAbsolute": {
"x": 534.3712097224906,
"y": -135.01908566635723
}
},
{
"width": 384,
"height": 453,
"id": "CustomComponent-7NQoq",
"type": "genericNode",
"position": { "x": 27.487979888011637, "y": -414.43998171034826 },
"position": {
"x": 27.487979888011637,
"y": -414.43998171034826
},
"data": {
"type": "CustomComponent",
"node": {
@ -131,7 +149,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from langflow import CustomComponent\nfrom typing import Optional, List, Dict, Union\nfrom langflow.field_typing import (\n AgentExecutor,\n BaseChatMemory,\n BaseLanguageModel,\n BaseLLM,\n BaseLoader,\n BaseMemory,\n BaseOutputParser,\n BasePromptTemplate,\n BaseRetriever,\n Callable,\n Chain,\n ChatPromptTemplate,\n Data,\n Document,\n Embeddings,\n NestedDict,\n Object,\n PromptTemplate,\n TextSplitter,\n Tool,\n VectorStore,\n)\n\nfrom openai import OpenAI\nimport os\nimport ffmpeg\n\nclass Component(CustomComponent):\n display_name: str = \"Whisper Transcriber\"\n description: str = \"Converts audio to text using OpenAI's Whisper.\"\n\n def build_config(self):\n return {\"audio\": {\"field_type\": \"file\", \"suffixes\": [\".mp3\", \".mp4\", \".m4a\"]}, \"OpenAIKey\": {\"field_type\": \"str\", \"password\": True}}\n\n def calculate_segment_duration(self, audio_path, target_chunk_size_mb=24):\n # Calculate the target chunk size in bytes\n target_chunk_size_bytes = target_chunk_size_mb * 1024 * 1024\n\n # Use ffprobe to get the audio file information\n ffprobe_output = ffmpeg.probe(audio_path)\n print(ffprobe_output)\n # Convert duration to float\n duration = float(ffprobe_output[\"format\"][\"duration\"])\n\n # Calculate the approximate bitrate\n bitrate = os.path.getsize(audio_path) / duration\n\n # Calculate the segment duration to achieve the target chunk size\n segment_duration = target_chunk_size_bytes / bitrate\n\n return segment_duration\n\n def split_audio_into_chunks(self, audio_path, target_chunk_size_mb=24):\n # Calculate the segment duration\n segment_duration = self.calculate_segment_duration(audio_path, target_chunk_size_mb)\n\n # Create a directory to store the chunks\n output_directory = f\"{os.path.splitext(audio_path)[0]}_chunks\"\n os.makedirs(output_directory, exist_ok=True)\n\n # Use ffmpeg-python to split the audio file into chunks\n (\n ffmpeg.input(audio_path)\n .output(f\"{output_directory}/%03d{os.path.splitext(audio_path)[1]}\", codec=\"copy\", f=\"segment\", segment_time=segment_duration)\n .run()\n )\n\n # Get the list of generated chunk files\n chunks = [os.path.join(output_directory, file) for file in os.listdir(output_directory)]\n\n return chunks\n\n def build(self, audio: str, OpenAIKey: str) -> str:\n # Split audio into chunks\n audio_chunks = self.split_audio_into_chunks(audio)\n\n client = OpenAI(api_key=OpenAIKey)\n transcripts = []\n\n try:\n for chunk in audio_chunks:\n with open(chunk, \"rb\") as chunk_file:\n transcript = client.audio.transcriptions.create(\n model=\"whisper-1\",\n file=chunk_file,\n response_format=\"text\"\n )\n transcripts.append(transcript)\n finally:\n # Clean up temporary chunk files\n for chunk in audio_chunks:\n os.remove(chunk)\n\n # Concatenate transcripts into the final response\n final_response = \"\\n\".join(transcripts)\n self.status = final_response\n return final_response\n",
"value": "from langflow.custom import CustomComponent\nfrom typing import Optional, List, Dict, Union\nfrom langflow.field_typing import (\n AgentExecutor,\n BaseChatMemory,\n BaseLanguageModel,\n BaseLLM,\n BaseLoader,\n BaseMemory,\n BaseOutputParser,\n BasePromptTemplate,\n BaseRetriever,\n Callable,\n Chain,\n ChatPromptTemplate,\n Data,\n Document,\n Embeddings,\n NestedDict,\n Object,\n PromptTemplate,\n TextSplitter,\n Tool,\n VectorStore,\n)\n\nfrom openai import OpenAI\nimport os\nimport ffmpeg\n\nclass Component(CustomComponent):\n display_name: str = \"Whisper Transcriber\"\n description: str = \"Converts audio to text using OpenAI's Whisper.\"\n\n def build_config(self):\n return {\"audio\": {\"field_type\": \"file\", \"suffixes\": [\".mp3\", \".mp4\", \".m4a\"]}, \"OpenAIKey\": {\"field_type\": \"str\", \"password\": True}}\n\n def calculate_segment_duration(self, audio_path, target_chunk_size_mb=24):\n # Calculate the target chunk size in bytes\n target_chunk_size_bytes = target_chunk_size_mb * 1024 * 1024\n\n # Use ffprobe to get the audio file information\n ffprobe_output = ffmpeg.probe(audio_path)\n print(ffprobe_output)\n # Convert duration to float\n duration = float(ffprobe_output[\"format\"][\"duration\"])\n\n # Calculate the approximate bitrate\n bitrate = os.path.getsize(audio_path) / duration\n\n # Calculate the segment duration to achieve the target chunk size\n segment_duration = target_chunk_size_bytes / bitrate\n\n return segment_duration\n\n def split_audio_into_chunks(self, audio_path, target_chunk_size_mb=24):\n # Calculate the segment duration\n segment_duration = self.calculate_segment_duration(audio_path, target_chunk_size_mb)\n\n # Create a directory to store the chunks\n output_directory = f\"{os.path.splitext(audio_path)[0]}_chunks\"\n os.makedirs(output_directory, exist_ok=True)\n\n # Use ffmpeg-python to split the audio file into chunks\n (\n ffmpeg.input(audio_path)\n .output(f\"{output_directory}/%03d{os.path.splitext(audio_path)[1]}\", codec=\"copy\", f=\"segment\", segment_time=segment_duration)\n .run()\n )\n\n # Get the list of generated chunk files\n chunks = [os.path.join(output_directory, file) for file in os.listdir(output_directory)]\n\n return chunks\n\n def build(self, audio: str, OpenAIKey: str) -> str:\n # Split audio into chunks\n audio_chunks = self.split_audio_into_chunks(audio)\n\n client = OpenAI(api_key=OpenAIKey)\n transcripts = []\n\n try:\n for chunk in audio_chunks:\n with open(chunk, \"rb\") as chunk_file:\n transcript = client.audio.transcriptions.create(\n model=\"whisper-1\",\n file=chunk_file,\n response_format=\"text\"\n )\n transcripts.append(transcript)\n finally:\n # Clean up temporary chunk files\n for chunk in audio_chunks:\n os.remove(chunk)\n\n # Concatenate transcripts into the final response\n final_response = \"\\n\".join(transcripts)\n self.status = final_response\n return final_response\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -143,11 +161,18 @@
"_type": "CustomComponent"
},
"description": "Converts audio to text using OpenAI's Whisper.",
"base_classes": ["str"],
"base_classes": [
"str"
],
"display_name": "Whisper Transcriber",
"documentation": "",
"custom_fields": { "OpenAIKey": null, "audio": null },
"output_types": ["str"],
"custom_fields": {
"OpenAIKey": null,
"audio": null
},
"output_types": [
"str"
],
"field_formatters": {},
"beta": true
},
@ -171,26 +196,36 @@
"targetHandle": {
"fieldName": "text_input",
"id": "CustomComponent-MtJjl",
"inputTypes": ["str"],
"inputTypes": [
"str"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["str"],
"baseClasses": [
"str"
],
"dataType": "CustomComponent",
"id": "CustomComponent-7NQoq"
}
},
"style": { "stroke": "#555" },
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"animated": false,
"id": "reactflow__edge-CustomComponent-7NQoq{œbaseClassesœ:[œstrœ],œdataTypeœ:œCustomComponentœ,œidœ:œCustomComponent-7NQoqœ}-CustomComponent-MtJjl{œfieldNameœ:œtext_inputœ,œidœ:œCustomComponent-MtJjlœ,œinputTypesœ:[œstrœ],œtypeœ:œstrœ}"
}
],
"viewport": { "x": 119.37759169012509, "y": 351.3082742479685, "zoom": 1 }
"viewport": {
"x": 119.37759169012509,
"y": 351.3082742479685,
"zoom": 1
}
},
"is_component": false,
"updated_at": "2023-12-13T23:51:56.874099",
"folder": null,
"id": "1b0814b7-2964-4e09-9b4b-f7413c4fb50b",
"user_id": "8b5cf798-f1b8-4108-88fd-d7274d08d471"
}
}