Fix State Service not loading when using load_flow_from_json (#1661)

* Refactor test_loading.py to improve code readability and maintainability

* Refactor code in test_template.py, __main__.py, and utils.py to improve code readability and maintainability

* Fix logger.configure() to disable logging when disable flag is True

* Refactor validate_icon function to use emoji library for emoji validation in model.py

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor state_manager.py to handle error when getting state service and use InMemoryStateService as fallback

* Refactor load_flow_from_json function in load.py to configure logs and load services

* Add test_run_flow_from_json_object function to test_loading.py

* Refactor langflow.processing.process.py and langflow.schema.graph.py

* Set all streaming to false in run_flow_from_json function

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor arun function in base.py to handle event loop and async execution

* Add docstring to run_flow_from_json

* Refactor import statements in base.py files to use logger in langflow interface

* Refactor build method in ChatOutput and TextInput classes to use build_with_record

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor import statements in PythonREPLTool.py for improved code organization and maintainability

* Refactor build method in TextOutput class to include optional record_template parameter

* Refactor build method in ChatComponent class to include build_no_record method

* Refactor input_value parameter in TextInput build method to use Text type

* Refactor import statements in FlowTool.py for improved code organization and maintainability

* Bump langflow-base version to 0.0.25 and add asyncer dependency

* Refactor code in multiple files for improved organization and maintainability

* Refactor import statements in multiple files for improved code organization and maintainability
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-04-10 11:56:37 -03:00 committed by GitHub
commit b0308336c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 3856 additions and 4439 deletions

223
poetry.lock generated
View file

@ -167,13 +167,13 @@ files = [
[[package]]
name = "anthropic"
version = "0.23.1"
version = "0.25.0"
description = "The official Python library for the anthropic API"
optional = false
python-versions = ">=3.7"
files = [
{file = "anthropic-0.23.1-py3-none-any.whl", hash = "sha256:6dc5779dae83a5834864f4a4af0166c972b70f4cb8fd2765e1558282cc6d6242"},
{file = "anthropic-0.23.1.tar.gz", hash = "sha256:9325103702cbc96bb09d1b58c36bde75c726f6a01029fb4d85f41ebba07e9066"},
{file = "anthropic-0.25.0-py3-none-any.whl", hash = "sha256:b5dfe4dfebace1641a02cfda939cd6dffac0152ab305ca1ef0c11023043a51a2"},
{file = "anthropic-0.25.0.tar.gz", hash = "sha256:63372443e699da7ffb467b2d0eb5ee7740acf877368b364a1137d795ae4e4c16"},
]
[package.dependencies]
@ -305,6 +305,20 @@ files = [
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
[[package]]
name = "asyncer"
version = "0.0.5"
description = "Asyncer, async and await, focused on developer experience."
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "asyncer-0.0.5-py3-none-any.whl", hash = "sha256:ba06d6de3c750763868dffacf89b18d40b667605b0241d31c2ee43f188e2ab74"},
{file = "asyncer-0.0.5.tar.gz", hash = "sha256:2979f3e04cbedfe5cfeb79027dcf7d004fcc4430a0ca0066ae20490f218ec06e"},
]
[package.dependencies]
anyio = ">=3.4.0,<5.0"
[[package]]
name = "attrs"
version = "23.2.0"
@ -455,17 +469,17 @@ files = [
[[package]]
name = "boto3"
version = "1.34.80"
version = "1.34.81"
description = "The AWS SDK for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "boto3-1.34.80-py3-none-any.whl", hash = "sha256:bb8f433c04dcdffbd4a802df56c1c30f2be23b1161fd8fb45e4b76c1487ec122"},
{file = "boto3-1.34.80.tar.gz", hash = "sha256:5627f6ecadb46fc7c9f8c368baf948f1b00a3fd2f8eb1275c254469853ad8fdb"},
{file = "boto3-1.34.81-py3-none-any.whl", hash = "sha256:18224d206a8a775bcaa562d22ed3d07854934699190e12b52fcde87aac76a80e"},
{file = "boto3-1.34.81.tar.gz", hash = "sha256:004dad209d37b3d2df88f41da13b7ad702a751904a335fac095897ff7a19f82b"},
]
[package.dependencies]
botocore = ">=1.34.80,<1.35.0"
botocore = ">=1.34.81,<1.35.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.10.0,<0.11.0"
@ -474,13 +488,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "botocore"
version = "1.34.80"
version = "1.34.81"
description = "Low-level, data-driven core of boto 3."
optional = false
python-versions = ">=3.8"
files = [
{file = "botocore-1.34.80-py3-none-any.whl", hash = "sha256:354a00f03faba52acc6f1a84fa4f035d48541633be98ccc24b59dc544f679f8b"},
{file = "botocore-1.34.80.tar.gz", hash = "sha256:8402262e819f3d46df504bbd781e770858c0130b90f660699f75ef3a63abca5a"},
{file = "botocore-1.34.81-py3-none-any.whl", hash = "sha256:85f6fd7c5715eeef7a236c50947de00f57d72e7439daed1125491014b70fab01"},
{file = "botocore-1.34.81.tar.gz", hash = "sha256:f79bf122566cc1f09d71cc9ac9fcf52d47ba48b761cbc3f064017b36a3c40eb8"},
]
[package.dependencies]
@ -923,17 +937,6 @@ files = [
{file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
]
[[package]]
name = "chevron"
version = "0.14.0"
description = "Mustache templating language renderer"
optional = false
python-versions = "*"
files = [
{file = "chevron-0.14.0-py3-none-any.whl", hash = "sha256:fbf996a709f8da2e745ef763f482ce2d311aa817d287593a5b990d6d6e4f0443"},
{file = "chevron-0.14.0.tar.gz", hash = "sha256:87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf"},
]
[[package]]
name = "chroma-hnswlib"
version = "0.7.3"
@ -2004,13 +2007,13 @@ zstandard = ["zstandard"]
[[package]]
name = "filelock"
version = "3.13.3"
version = "3.13.4"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.8"
files = [
{file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"},
{file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"},
{file = "filelock-3.13.4-py3-none-any.whl", hash = "sha256:404e5e9253aa60ad457cae1be07c0f0ca90a63931200a47d9b6a6af84fd7b45f"},
{file = "filelock-3.13.4.tar.gz", hash = "sha256:d13f466618bfde72bd2c18255e269f72542c6e70e7bac83a0232d6b1cc5c8cf4"},
]
[package.extras]
@ -3654,13 +3657,13 @@ adal = ["adal (>=1.0.2)"]
[[package]]
name = "langchain"
version = "0.1.14"
version = "0.1.15"
description = "Building applications with LLMs through composability"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain-0.1.14-py3-none-any.whl", hash = "sha256:94f9b5df2421faaf762d4f43b9d65c270c2f701934580d281e4c6226deef7234"},
{file = "langchain-0.1.14.tar.gz", hash = "sha256:124c6244cf3957616b98f2df07dc2992fc40dff6ed1a62d8ee8a40f1e0260a40"},
{file = "langchain-0.1.15-py3-none-any.whl", hash = "sha256:3ac516463ae7f80047091f04592a1eea138321710bbc266005f9de238d71acd3"},
{file = "langchain-0.1.15.tar.gz", hash = "sha256:79d43035327fdcc5ac81a3db10f2b879f2bd5db3b268ef82bac7baf3ec32954e"},
]
[package.dependencies]
@ -3668,8 +3671,8 @@ aiohttp = ">=3.8.3,<4.0.0"
async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""}
dataclasses-json = ">=0.5.7,<0.7"
jsonpatch = ">=1.33,<2.0"
langchain-community = ">=0.0.30,<0.1"
langchain-core = ">=0.1.37,<0.2.0"
langchain-community = ">=0.0.32,<0.1"
langchain-core = ">=0.1.41,<0.2.0"
langchain-text-splitters = ">=0.0.1,<0.1"
langsmith = ">=0.1.17,<0.2.0"
numpy = ">=1,<2"
@ -3695,19 +3698,19 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"]
[[package]]
name = "langchain-anthropic"
version = "0.1.6"
version = "0.1.7"
description = "An integration package connecting AnthropicMessages and LangChain"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain_anthropic-0.1.6-py3-none-any.whl", hash = "sha256:5626f9f2f0d3cc1665a2f5817ea1856dbfa4c745bc6f95b7043c56b6ab85e0c1"},
{file = "langchain_anthropic-0.1.6.tar.gz", hash = "sha256:544e5c8c365964c594b80eb1db994e67d90722be9efde460229e5888524545de"},
{file = "langchain_anthropic-0.1.7-py3-none-any.whl", hash = "sha256:ae022d98eadeb8151145e417d0e2edc350740a117724a08d6b5d17481379c007"},
{file = "langchain_anthropic-0.1.7.tar.gz", hash = "sha256:113a7bcc297798692c64f569a73c0681450a706d9d6acdcac0102511b2958fac"},
]
[package.dependencies]
anthropic = ">=0.23.0,<1"
defusedxml = ">=0.7.1,<0.8.0"
langchain-core = ">=0.1.33,<0.2.0"
langchain-core = ">=0.1.41,<0.2.0"
[[package]]
name = "langchain-astradb"
@ -3742,19 +3745,19 @@ langchain-core = ">=0.1.32,<0.2.0"
[[package]]
name = "langchain-community"
version = "0.0.31"
version = "0.0.32"
description = "Community contributed LangChain integrations."
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain_community-0.0.31-py3-none-any.whl", hash = "sha256:905c01b978a1cef7fdcddd2d9241dedc9987db6f23ba1b58d974e38b1cdf2775"},
{file = "langchain_community-0.0.31.tar.gz", hash = "sha256:9a970bc2bb59bb4c204b696d8c62c2534f6ddb31005005cc1b7d7f934e58a5fc"},
{file = "langchain_community-0.0.32-py3-none-any.whl", hash = "sha256:406977009999952d0705de3806de2b4867e9bb8eda8ca154a59c7a8ed58da38d"},
{file = "langchain_community-0.0.32.tar.gz", hash = "sha256:1510217d646c8380f54e9850351f6d2a0b0dd73c501b666c6f4b40baa8160b29"},
]
[package.dependencies]
aiohttp = ">=3.8.3,<4.0.0"
dataclasses-json = ">=0.5.7,<0.7"
langchain-core = ">=0.1.37,<0.2.0"
langchain-core = ">=0.1.41,<0.2.0"
langsmith = ">=0.1.0,<0.2.0"
numpy = ">=1,<2"
PyYAML = ">=5.3"
@ -3764,17 +3767,17 @@ tenacity = ">=8.1.0,<9.0.0"
[package.extras]
cli = ["typer (>=0.9.0,<0.10.0)"]
extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"]
extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"]
[[package]]
name = "langchain-core"
version = "0.1.40"
version = "0.1.41"
description = "Building applications with LLMs through composability"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain_core-0.1.40-py3-none-any.whl", hash = "sha256:618dbb7ab44d8b263b91e384db1ff07d0db256ae5bdafa0123a115b6a75a13f1"},
{file = "langchain_core-0.1.40.tar.gz", hash = "sha256:34c06fc0e6d3534b738c63f85403446b4be71161665b7e091f9bb19c914ec100"},
{file = "langchain_core-0.1.41-py3-none-any.whl", hash = "sha256:92d3da5ca0d5fb1606b3ab42bfd455c7b386fe4c38f6c0d44ba6014abf46147d"},
{file = "langchain_core-0.1.41.tar.gz", hash = "sha256:4002304883b251af8cb781f01c59f56aeee58be42c965dbbdeca0a3bfb8f96af"},
]
[package.dependencies]
@ -3790,18 +3793,18 @@ extended-testing = ["jinja2 (>=3,<4)"]
[[package]]
name = "langchain-experimental"
version = "0.0.56"
version = "0.0.57"
description = "Building applications with LLMs through composability"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain_experimental-0.0.56-py3-none-any.whl", hash = "sha256:91fd7a723b0ef3193a63726745523efdd5dd7134116d838c312cfdbf4b354298"},
{file = "langchain_experimental-0.0.56.tar.gz", hash = "sha256:ebb1c34815739d3af50c9b709c57b91d0357d567ad2042acb724853c6ba1d735"},
{file = "langchain_experimental-0.0.57-py3-none-any.whl", hash = "sha256:96479a2d45a35722cf2fe49655639e91d3fff5ccaba498cda32b088d5b184325"},
{file = "langchain_experimental-0.0.57.tar.gz", hash = "sha256:d1fb452aa1f04f32f0e08b83b083f35552f4ece1077c5bdcf86327f56f1758b5"},
]
[package.dependencies]
langchain = ">=0.1.14,<0.2.0"
langchain-core = ">=0.1.37,<0.2.0"
langchain = ">=0.1.15,<0.2.0"
langchain-core = ">=0.1.41,<0.2.0"
[package.extras]
extended-testing = ["faker (>=19.3.1,<20.0.0)", "jinja2 (>=3,<4)", "pandas (>=2.0.1,<3.0.0)", "presidio-analyzer (>=2.2.352,<3.0.0)", "presidio-anonymizer (>=2.2.352,<3.0.0)", "sentence-transformers (>=2,<3)", "tabulate (>=0.9.0,<0.10.0)", "vowpal-wabbit-next (==0.6.0)"]
@ -3826,17 +3829,17 @@ images = ["pillow (>=10.1.0,<11.0.0)"]
[[package]]
name = "langchain-openai"
version = "0.1.1"
version = "0.1.2"
description = "An integration package connecting OpenAI and LangChain"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langchain_openai-0.1.1-py3-none-any.whl", hash = "sha256:5cf4df5d2550af673337eafedaeec014ba52f9a25aeb8451206ca254bed01e5c"},
{file = "langchain_openai-0.1.1.tar.gz", hash = "sha256:d10e9a9fc4c8ea99ca98f23808ce44c7dcdd65354ac07ad10afe874ecf3401ca"},
{file = "langchain_openai-0.1.2-py3-none-any.whl", hash = "sha256:45fab91803df22c6d5fce7c010df404569898372df5ae8cd03af50bef774d2ec"},
{file = "langchain_openai-0.1.2.tar.gz", hash = "sha256:cd391e61bd93ab72ae24d8e1f250257d6acff6d9e455e623363b8c171533050a"},
]
[package.dependencies]
langchain-core = ">=0.1.33,<0.2.0"
langchain-core = ">=0.1.41,<0.2.0"
openai = ">=1.10.0,<2.0.0"
tiktoken = ">=0.5.2,<1"
@ -3873,7 +3876,7 @@ six = "*"
[[package]]
name = "langflow-base"
version = "0.0.24"
version = "0.0.25"
description = "A Python package with a built-in web application"
optional = false
python-versions = ">=3.10,<3.12"
@ -3882,6 +3885,7 @@ develop = true
[package.dependencies]
alembic = "^1.13.0"
asyncer = "^0.0.5"
bcrypt = "4.0.1"
cachetools = "^5.3.1"
cryptography = "^42.0.5"
@ -3926,18 +3930,17 @@ url = "src/backend/base"
[[package]]
name = "langfuse"
version = "2.22.0"
version = "2.23.1"
description = "A client library for accessing langfuse"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langfuse-2.22.0-py3-none-any.whl", hash = "sha256:9e244e3f8e81c391009b41f51cf8eb8bcd29281a93e90e8b861b231f99a8abe2"},
{file = "langfuse-2.22.0.tar.gz", hash = "sha256:e0ed2ced0f8216e88a84331476a21b6ac5e627b340c2b01676d61fb27c368bb4"},
{file = "langfuse-2.23.1-py3-none-any.whl", hash = "sha256:d5e2feadc988c0d784b9a89e17e35dea5d90337a58db692a528bd1e084fe01fa"},
{file = "langfuse-2.23.1.tar.gz", hash = "sha256:9c2cb4e2610f99095bc8c9db96b0472c1c8fa9b7d28c23419705640b17f460c0"},
]
[package.dependencies]
backoff = ">=2.2.1,<3.0.0"
chevron = ">=0.14.0,<0.15.0"
httpx = ">=0.15.4,<1.0"
packaging = ">=23.2,<24.0"
pydantic = ">=1.10.7,<3.0"
@ -3950,13 +3953,13 @@ openai = ["openai (>=0.27.8)"]
[[package]]
name = "langsmith"
version = "0.1.40"
version = "0.1.43"
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "langsmith-0.1.40-py3-none-any.whl", hash = "sha256:aa47d0f5a1eabd5c05ac6ce2cd3e28ccfc554d366e856a27b7c3c17c443881cb"},
{file = "langsmith-0.1.40.tar.gz", hash = "sha256:50fdf313741cf94e978de06025fd180b56acf1d1a4549b0fd5453ef23d5461ef"},
{file = "langsmith-0.1.43-py3-none-any.whl", hash = "sha256:c0a3658f10cbefaa2f53d15db519592982b59d99f24e018dc73aca6092b4158d"},
{file = "langsmith-0.1.43.tar.gz", hash = "sha256:983c5a35bf191bb23d93e453c9fc6ea7cda998b1ca96f94680a1446092caf347"},
]
[package.dependencies]
@ -3983,13 +3986,13 @@ regex = ["regex"]
[[package]]
name = "litellm"
version = "1.34.36"
version = "1.34.39"
description = "Library to easily interface with LLM API providers"
optional = false
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
files = [
{file = "litellm-1.34.36-py3-none-any.whl", hash = "sha256:e5baa7f4540dd2923472f60d3ffb4f76bb48f5288a7fb26efed2010b57b0d8ad"},
{file = "litellm-1.34.36.tar.gz", hash = "sha256:03e59c30ae21b9c1df4064dc20b015233c3d86a07bb4832c40dd73021778f3c8"},
{file = "litellm-1.34.39-py3-none-any.whl", hash = "sha256:347b7c5ac8a105eb0dccfd4429af1bef550d839cd4f76c36640ade93a267f92a"},
{file = "litellm-1.34.39.tar.gz", hash = "sha256:887ef607a0103bd06535f1fc52ac223cfe80a6223e7a2c165e902761db432e84"},
]
[package.dependencies]
@ -4009,12 +4012,12 @@ proxy = ["PyJWT (>=2.8.0,<3.0.0)", "apscheduler (>=3.10.4,<4.0.0)", "backoff", "
[[package]]
name = "llama-cpp-python"
version = "0.2.60"
version = "0.2.61"
description = "Python bindings for the llama.cpp library"
optional = true
python-versions = ">=3.8"
files = [
{file = "llama_cpp_python-0.2.60.tar.gz", hash = "sha256:0cb98955ae6a14dacb9418d9793e4fe1a5575be3b01a55c1d49d48c79c3b19c3"},
{file = "llama_cpp_python-0.2.61.tar.gz", hash = "sha256:2d554259a66040f5daae7f3cf7e43b44971dc49f10225a9ba196eb2a49778bd4"},
]
[package.dependencies]
@ -4026,24 +4029,24 @@ typing-extensions = ">=4.5.0"
[package.extras]
all = ["llama_cpp_python[dev,server,test]"]
dev = ["black (>=23.3.0)", "httpx (>=0.24.1)", "mkdocs (>=1.4.3)", "mkdocs-material (>=9.1.18)", "mkdocstrings[python] (>=0.22.0)", "pytest (>=7.4.0)", "twine (>=4.0.2)"]
server = ["fastapi (>=0.100.0)", "pydantic-settings (>=2.0.1)", "sse-starlette (>=1.6.1)", "starlette-context (>=0.3.6,<0.4)", "uvicorn (>=0.22.0)"]
server = ["PyYAML (>=5.1)", "fastapi (>=0.100.0)", "pydantic-settings (>=2.0.1)", "sse-starlette (>=1.6.1)", "starlette-context (>=0.3.6,<0.4)", "uvicorn (>=0.22.0)"]
test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"]
[[package]]
name = "llama-index"
version = "0.10.27"
version = "0.10.28"
description = "Interface between LLMs and your data"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "llama_index-0.10.27-py3-none-any.whl", hash = "sha256:e4813786c8240504ac8c394bb36a1755c6de7518a2bcbfc9e54ec78724f0af0b"},
{file = "llama_index-0.10.27.tar.gz", hash = "sha256:ef7862df50ceb1cd9f43b7e4b476121dd1a230075d2a8fdc84c92b03239602c7"},
{file = "llama_index-0.10.28-py3-none-any.whl", hash = "sha256:2fe2857af6c2d9cefdd978931ebd09f78265a57df2d9d094d0c78869dd0715b8"},
{file = "llama_index-0.10.28.tar.gz", hash = "sha256:2ecf9d6da489cc3f99b1adaea50b1549efa55e04cd050f332da784a87c2db846"},
]
[package.dependencies]
llama-index-agent-openai = ">=0.1.4,<0.3.0"
llama-index-cli = ">=0.1.2,<0.2.0"
llama-index-core = ">=0.10.27,<0.11.0"
llama-index-core = ">=0.10.28,<0.11.0"
llama-index-embeddings-openai = ">=0.1.5,<0.2.0"
llama-index-indices-managed-llama-cloud = ">=0.1.2,<0.2.0"
llama-index-legacy = ">=0.9.48,<0.10.0"
@ -4088,13 +4091,13 @@ llama-index-llms-openai = ">=0.1.1,<0.2.0"
[[package]]
name = "llama-index-core"
version = "0.10.27"
version = "0.10.28"
description = "Interface between LLMs and your data"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "llama_index_core-0.10.27-py3-none-any.whl", hash = "sha256:805b20a16a417180a32a31956710637af75e22cd0849fec2729447d182197d39"},
{file = "llama_index_core-0.10.27.tar.gz", hash = "sha256:01881a1943cb7b37f9f8147212d4a55caeef2d68ec498a0a1b864f79cf9d2be4"},
{file = "llama_index_core-0.10.28-py3-none-any.whl", hash = "sha256:73e2ec86ea42a0efdc73dcfe46e03ba39ab7725699dcd791464c160d24a02cb1"},
{file = "llama_index_core-0.10.28.tar.gz", hash = "sha256:b454640396daa2678b638299e2a5e2539fa3548afd280d45d224fd3b303c20f4"},
]
[package.dependencies]
@ -4200,13 +4203,13 @@ query-tools = ["guidance (>=0.0.64,<0.0.65)", "jsonpath-ng (>=1.6.0,<2.0.0)", "l
[[package]]
name = "llama-index-llms-openai"
version = "0.1.14"
version = "0.1.15"
description = "llama-index llms openai integration"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "llama_index_llms_openai-0.1.14-py3-none-any.whl", hash = "sha256:13cec467962a6ccb9e63451c7febe8e9c2ed536bd6b1058239c2b4fd86776060"},
{file = "llama_index_llms_openai-0.1.14.tar.gz", hash = "sha256:7eba66882ae84fa42b188941234b84267c48e449ef214f511756dcad3f9f0b62"},
{file = "llama_index_llms_openai-0.1.15-py3-none-any.whl", hash = "sha256:401ba9db1549e4287b73749dee57b11db1e0ffa814bb1464475aea1ff84442c7"},
{file = "llama_index_llms_openai-0.1.15.tar.gz", hash = "sha256:6bdbf307b1d43a9a7c2a52f72ba7db61cb96d904f99e7ea5d889dd7818f10814"},
]
[package.dependencies]
@ -4214,13 +4217,13 @@ llama-index-core = ">=0.10.24,<0.11.0"
[[package]]
name = "llama-index-multi-modal-llms-openai"
version = "0.1.4"
version = "0.1.5"
description = "llama-index multi-modal-llms openai integration"
optional = false
python-versions = ">=3.8.1,<4.0"
python-versions = "<4.0,>=3.8.1"
files = [
{file = "llama_index_multi_modal_llms_openai-0.1.4-py3-none-any.whl", hash = "sha256:03b887d110551d5d5b99b9fd110824e6311f2e31f4d5e67dafd2ee66da32818d"},
{file = "llama_index_multi_modal_llms_openai-0.1.4.tar.gz", hash = "sha256:6a5d6584c33a9d1b06cf5c874c63af2603fc93b660bde481a8c547e876c6e2c3"},
{file = "llama_index_multi_modal_llms_openai-0.1.5-py3-none-any.whl", hash = "sha256:bb332580e7e4b5f2f87488b3649d2ceb53ee82c848e59694578a982c3982ce0b"},
{file = "llama_index_multi_modal_llms_openai-0.1.5.tar.gz", hash = "sha256:9a237f4f886d1e20c27e9493e80b3e1f8753859481ff1b58fe25b7aa39b198a2"},
]
[package.dependencies]
@ -4261,13 +4264,13 @@ llama-index-program-openai = ">=0.1.1,<0.2.0"
[[package]]
name = "llama-index-readers-file"
version = "0.1.15"
version = "0.1.16"
description = "llama-index readers file integration"
optional = false
python-versions = "<4.0,>=3.8.1"
files = [
{file = "llama_index_readers_file-0.1.15-py3-none-any.whl", hash = "sha256:f0d26a46d4c40334729d4506d9fbdbed8f5e187e36e22159fb48b28d67c7f240"},
{file = "llama_index_readers_file-0.1.15.tar.gz", hash = "sha256:98087d983a1f2d26961805217f13d24b0f23cbbe8e32d2327ae86b1ee668d3b2"},
{file = "llama_index_readers_file-0.1.16-py3-none-any.whl", hash = "sha256:1a3f3bc1f09c6894318a5392edc43b118fabc2f2820f446c51cad73676662f73"},
{file = "llama_index_readers_file-0.1.16.tar.gz", hash = "sha256:7f25b8fddaf1a91bac06c66727b913b48e26ef68714fcd5197051b3f710f4cfa"},
]
[package.dependencies]
@ -6599,13 +6602,13 @@ pyasn1 = ">=0.4.6,<0.7.0"
[[package]]
name = "pyautogen"
version = "0.2.22"
version = "0.2.23"
description = "Enabling Next-Gen LLM Applications via Multi-Agent Conversation Framework"
optional = false
python-versions = "<3.13,>=3.8"
files = [
{file = "pyautogen-0.2.22-py3-none-any.whl", hash = "sha256:022d451ea286914024c5fb0e83f5c6622df925ce02a4e10f410389e9f003cbcc"},
{file = "pyautogen-0.2.22.tar.gz", hash = "sha256:8d25ae881779d95c13f477a42c448e91f1038c080c5bf6b905ccc1559f7ac535"},
{file = "pyautogen-0.2.23-py3-none-any.whl", hash = "sha256:f4e2d57f60561fd34e3d9ebf31db5005ab147bb356eeaf829a1fdbbf74400f29"},
{file = "pyautogen-0.2.23.tar.gz", hash = "sha256:88859cca22ba6718a755abb23ed0edd93ceebb9d70b822e921940c23116e5e46"},
]
[package.dependencies]
@ -8171,37 +8174,37 @@ torch = ["safetensors[numpy]", "torch (>=1.10)"]
[[package]]
name = "scikit-learn"
version = "1.4.1.post1"
version = "1.4.2"
description = "A set of python modules for machine learning and data mining"
optional = true
python-versions = ">=3.9"
files = [
{file = "scikit-learn-1.4.1.post1.tar.gz", hash = "sha256:93d3d496ff1965470f9977d05e5ec3376fb1e63b10e4fda5e39d23c2d8969a30"},
{file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c540aaf44729ab5cd4bd5e394f2b375e65ceaea9cdd8c195788e70433d91bbc5"},
{file = "scikit_learn-1.4.1.post1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4310bff71aa98b45b46cd26fa641309deb73a5d1c0461d181587ad4f30ea3c36"},
{file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f43dd527dabff5521af2786a2f8de5ba381e182ec7292663508901cf6ceaf6e"},
{file = "scikit_learn-1.4.1.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c02e27d65b0c7dc32f2c5eb601aaf5530b7a02bfbe92438188624524878336f2"},
{file = "scikit_learn-1.4.1.post1-cp310-cp310-win_amd64.whl", hash = "sha256:629e09f772ad42f657ca60a1a52342eef786218dd20cf1369a3b8d085e55ef8f"},
{file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6145dfd9605b0b50ae72cdf72b61a2acd87501369a763b0d73d004710ebb76b5"},
{file = "scikit_learn-1.4.1.post1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1afed6951bc9d2053c6ee9a518a466cbc9b07c6a3f9d43bfe734192b6125d508"},
{file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce03506ccf5f96b7e9030fea7eb148999b254c44c10182ac55857bc9b5d4815f"},
{file = "scikit_learn-1.4.1.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ba516fcdc73d60e7f48cbb0bccb9acbdb21807de3651531208aac73c758e3ab"},
{file = "scikit_learn-1.4.1.post1-cp311-cp311-win_amd64.whl", hash = "sha256:78cd27b4669513b50db4f683ef41ea35b5dddc797bd2bbd990d49897fd1c8a46"},
{file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a1e289f33f613cefe6707dead50db31930530dc386b6ccff176c786335a7b01c"},
{file = "scikit_learn-1.4.1.post1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0df87de9ce1c0140f2818beef310fb2e2afdc1e66fc9ad587965577f17733649"},
{file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712c1c69c45b58ef21635360b3d0a680ff7d83ac95b6f9b82cf9294070cda710"},
{file = "scikit_learn-1.4.1.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1754b0c2409d6ed5a3380512d0adcf182a01363c669033a2b55cca429ed86a81"},
{file = "scikit_learn-1.4.1.post1-cp312-cp312-win_amd64.whl", hash = "sha256:1d491ef66e37f4e812db7e6c8286520c2c3fc61b34bf5e59b67b4ce528de93af"},
{file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:aa0029b78ef59af22cfbd833e8ace8526e4df90212db7ceccbea582ebb5d6794"},
{file = "scikit_learn-1.4.1.post1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:14e4c88436ac96bf69eb6d746ac76a574c314a23c6961b7d344b38877f20fee1"},
{file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7cd3a77c32879311f2aa93466d3c288c955ef71d191503cf0677c3340ae8ae0"},
{file = "scikit_learn-1.4.1.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a3ee19211ded1a52ee37b0a7b373a8bfc66f95353af058a210b692bd4cda0dd"},
{file = "scikit_learn-1.4.1.post1-cp39-cp39-win_amd64.whl", hash = "sha256:234b6bda70fdcae9e4abbbe028582ce99c280458665a155eed0b820599377d25"},
{file = "scikit-learn-1.4.2.tar.gz", hash = "sha256:daa1c471d95bad080c6e44b4946c9390a4842adc3082572c20e4f8884e39e959"},
{file = "scikit_learn-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8539a41b3d6d1af82eb629f9c57f37428ff1481c1e34dddb3b9d7af8ede67ac5"},
{file = "scikit_learn-1.4.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:68b8404841f944a4a1459b07198fa2edd41a82f189b44f3e1d55c104dbc2e40c"},
{file = "scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81bf5d8bbe87643103334032dd82f7419bc8c8d02a763643a6b9a5c7288c5054"},
{file = "scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36f0ea5d0f693cb247a073d21a4123bdf4172e470e6d163c12b74cbb1536cf38"},
{file = "scikit_learn-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:87440e2e188c87db80ea4023440923dccbd56fbc2d557b18ced00fef79da0727"},
{file = "scikit_learn-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:45dee87ac5309bb82e3ea633955030df9bbcb8d2cdb30383c6cd483691c546cc"},
{file = "scikit_learn-1.4.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1d0b25d9c651fd050555aadd57431b53d4cf664e749069da77f3d52c5ad14b3b"},
{file = "scikit_learn-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0203c368058ab92efc6168a1507d388d41469c873e96ec220ca8e74079bf62e"},
{file = "scikit_learn-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c62f2b124848a28fd695db5bc4da019287abf390bfce602ddc8aa1ec186aae"},
{file = "scikit_learn-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:5cd7b524115499b18b63f0c96f4224eb885564937a0b3477531b2b63ce331904"},
{file = "scikit_learn-1.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:90378e1747949f90c8f385898fff35d73193dfcaec3dd75d6b542f90c4e89755"},
{file = "scikit_learn-1.4.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ff4effe5a1d4e8fed260a83a163f7dbf4f6087b54528d8880bab1d1377bd78be"},
{file = "scikit_learn-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:671e2f0c3f2c15409dae4f282a3a619601fa824d2c820e5b608d9d775f91780c"},
{file = "scikit_learn-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d36d0bc983336bbc1be22f9b686b50c964f593c8a9a913a792442af9bf4f5e68"},
{file = "scikit_learn-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:d762070980c17ba3e9a4a1e043ba0518ce4c55152032f1af0ca6f39b376b5928"},
{file = "scikit_learn-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9993d5e78a8148b1d0fdf5b15ed92452af5581734129998c26f481c46586d68"},
{file = "scikit_learn-1.4.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:426d258fddac674fdf33f3cb2d54d26f49406e2599dbf9a32b4d1696091d4256"},
{file = "scikit_learn-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5460a1a5b043ae5ae4596b3126a4ec33ccba1b51e7ca2c5d36dac2169f62ab1d"},
{file = "scikit_learn-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49d64ef6cb8c093d883e5a36c4766548d974898d378e395ba41a806d0e824db8"},
{file = "scikit_learn-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:c97a50b05c194be9146d61fe87dbf8eac62b203d9e87a3ccc6ae9aed2dfaf361"},
]
[package.dependencies]
joblib = ">=1.2.0"
numpy = ">=1.19.5,<2.0"
numpy = ">=1.19.5"
scipy = ">=1.6.0"
threadpoolctl = ">=2.0.0"
@ -9039,13 +9042,13 @@ tutorials = ["matplotlib", "pandas", "tabulate", "torch"]
[[package]]
name = "typer"
version = "0.12.2"
version = "0.12.3"
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
optional = false
python-versions = ">=3.7"
files = [
{file = "typer-0.12.2-py3-none-any.whl", hash = "sha256:e1accbaa7e2b2350753acec896ac30493ac573211a8d4603e88f8356217e01f7"},
{file = "typer-0.12.2.tar.gz", hash = "sha256:977929604fde12aeada011852ad9c64370501be6ac2eac248f3161cdc9eeb7c9"},
{file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"},
{file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"},
]
[package.dependencies]

View file

@ -9,6 +9,12 @@ import click
import httpx
import typer
from dotenv import load_dotenv
from langflow.main import setup_app
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service
from langflow.services.utils import initialize_services
from langflow.utils.logger import configure, logger
from langflow.utils.util import update_settings
from multiprocess import Process, cpu_count # type: ignore
from packaging import version as pkg_version
from rich import box
@ -17,12 +23,6 @@ from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from langflow.main import setup_app
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service, get_settings_service
from langflow.services.utils import initialize_services, initialize_settings_service
from langflow.utils.logger import configure, logger
console = Console()
app = typer.Typer(no_args_is_help=True)
@ -68,36 +68,6 @@ def set_var_for_macos_issue():
logger.debug("Set OBJC_DISABLE_INITIALIZE_FORK_SAFETY to YES to avoid error")
def update_settings(
config: str,
cache: Optional[str] = None,
dev: bool = False,
remove_api_keys: bool = False,
components_path: Optional[Path] = None,
store: bool = True,
):
"""Update the settings from a config file."""
# Check for database_url in the environment variables
initialize_settings_service()
settings_service = get_settings_service()
if config:
logger.debug(f"Loading settings from {config}")
settings_service.settings.update_from_yaml(config, dev=dev)
if remove_api_keys:
logger.debug(f"Setting remove_api_keys to {remove_api_keys}")
settings_service.settings.update_settings(REMOVE_API_KEYS=remove_api_keys)
if cache:
logger.debug(f"Setting cache to {cache}")
settings_service.settings.update_settings(CACHE=cache)
if components_path:
logger.debug(f"Adding component path {components_path}")
settings_service.settings.update_settings(COMPONENTS_PATH=components_path)
if not store:
logger.debug("Setting store to False")
settings_service.settings.update_settings(STORE=False)
@app.command()
def run(
host: str = typer.Option("127.0.0.1", help="Host to bind the server to.", envvar="LANGFLOW_HOST"),
@ -316,7 +286,7 @@ def is_prerelease(version: str) -> bool:
return "a" in version or "b" in version or "rc" in version
def fetch_latest_version(package_name: str, include_prerelease: bool) -> str:
def fetch_latest_version(package_name: str, include_prerelease: bool) -> Optional[str]:
response = httpx.get(f"https://pypi.org/pypi/{package_name}/json")
versions = response.json()["releases"].keys()
valid_versions = [v for v in versions if include_prerelease or not is_prerelease(v)]
@ -358,7 +328,7 @@ def print_banner(host: str, port: int):
package_name = ""
try:
from langflow.version import __version__ as langflow_version
from langflow.version import __version__ as langflow_version # type: ignore
is_pre_release |= is_prerelease(langflow_version) # Update pre-release status
notice = build_version_notice(langflow_version, "langflow")

View file

@ -14,7 +14,6 @@ from langflow.api.v1.schemas import (
RunResponse,
SimplifiedAPIRequest,
TaskStatusResponse,
Tweaks,
UpdateCustomComponentRequest,
UploadFileResponse,
)
@ -24,6 +23,7 @@ from langflow.interface.custom.custom_component import CustomComponent
from langflow.interface.custom.directory_reader import DirectoryReader
from langflow.interface.custom.utils import build_custom_component_template
from langflow.processing.process import process_tweaks, run_graph_internal
from langflow.schema.graph import Tweaks
from langflow.services.auth.utils import api_key_security, get_current_active_user
from langflow.services.cache.utils import save_uploaded_file
from langflow.services.database.models.flow import Flow
@ -373,7 +373,7 @@ async def create_upload_file(
@router.get("/version")
def get_version():
try:
from langflow.version import __version__
from langflow.version import __version__ # type: ignore
version = __version__
package = "Langflow"

View file

@ -4,10 +4,11 @@ from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator, model_serializer
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serializer
from langflow.graph.schema import RunOutputs
from langflow.schema import dotdict
from langflow.schema.graph import Tweaks
from langflow.schema.schema import InputType, OutputType
from langflow.services.database.models.api_key.model import ApiKeyRead
from langflow.services.database.models.base import orjson_dumps
@ -283,36 +284,6 @@ class InputValueRequest(BaseModel):
)
class Tweaks(RootModel):
root: dict[str, Union[str, dict[str, str]]] = Field(
description="A dictionary of tweaks to adjust the flow's execution. Allows customizing flow behavior dynamically. All tweaks are overridden by the input values.",
)
model_config = {
"json_schema_extra": {
"examples": [
{
"parameter_name": "value",
"Component Name": {"parameter_name": "value"},
"component_id": {"parameter_name": "value"},
}
]
}
}
# This should behave like a dict
def __getitem__(self, key):
return self.root[key]
def __setitem__(self, key, value):
self.root[key] = value
def __delitem__(self, key):
del self.root[key]
def items(self):
return self.root.items()
class SimplifiedAPIRequest(BaseModel):
input_value: Optional[str] = Field(default="", description="The input value")
input_type: Optional[InputType] = Field(default="chat", description="The input type")

View file

@ -79,7 +79,7 @@ class ChatComponent(CustomComponent):
records = add_messages([record])
return records[0]
def build(
def build_with_record(
self,
sender: Optional[str] = "User",
sender_name: Optional[str] = "User",
@ -116,3 +116,41 @@ class ChatComponent(CustomComponent):
if session_id and isinstance(result, (Record, str)):
self.store_message(result, session_id, sender, sender_name)
return result
def build_no_record(
self,
sender: Optional[str] = "User",
sender_name: Optional[str] = "User",
input_value: Optional[str] = None,
session_id: Optional[str] = None,
return_record: Optional[bool] = False,
record_template: str = "Text: {text}\nData: {data}",
) -> Union[Text, Record]:
input_value_record: Optional[Record] = None
if return_record:
if isinstance(input_value, Record):
# Update the data of the record
input_value.data["sender"] = sender
input_value.data["sender_name"] = sender_name
input_value.data["session_id"] = session_id
else:
input_value_record = Record(
text=input_value,
data={
"sender": sender,
"sender_name": sender_name,
"session_id": session_id,
},
)
elif isinstance(input_value, Record):
input_value = records_to_text(template=record_template, records=input_value)
if not input_value:
input_value = ""
if return_record and input_value_record:
result: Union[Text, Record] = input_value_record
else:
result = input_value
self.status = result
if session_id and isinstance(result, (Record, str)):
self.store_message(result, session_id, sender, sender_name)
return result

View file

@ -3,7 +3,6 @@ import json
from typing import List, Optional
import httpx
from langflow.interface.custom.custom_component import CustomComponent
from langflow.schema import Record
@ -47,8 +46,8 @@ class APIRequest(CustomComponent):
client: httpx.AsyncClient,
method: str,
url: str,
headers: Optional[Record] = None,
body: Optional[Record] = None,
headers: Optional[dict] = None,
body: Optional[dict] = None,
timeout: int = 5,
) -> Record:
method = method.upper()

View file

@ -1,6 +1,7 @@
from typing import Any, Dict, List, Optional
from langchain_openai.embeddings.base import OpenAIEmbeddings
from pydantic.v1 import SecretStr
from langflow.field_typing import Embeddings, NestedDict
from langflow.interface.custom.custom_component import CustomComponent
@ -113,6 +114,10 @@ class OpenAIEmbeddingsComponent(CustomComponent):
# This is to avoid errors with Vector Stores (e.g Chroma)
if disallowed_special == ["all"]:
disallowed_special = "all" # type: ignore
if openai_api_key:
api_key = SecretStr(openai_api_key)
else:
api_key = None
return OpenAIEmbeddings(
tiktoken_enabled=tiktoken_enable,
@ -128,7 +133,7 @@ class OpenAIEmbeddingsComponent(CustomComponent):
model=model,
model_kwargs=model_kwargs,
base_url=openai_api_base,
api_key=openai_api_key,
api_key=api_key,
openai_api_type=openai_api_type,
api_version=openai_api_version,
organization=openai_organization,

View file

@ -1,14 +1,14 @@
from typing import Any, List, Optional
from asyncer import syncify
from langchain_core.tools import StructuredTool
from loguru import logger
from langflow.custom import CustomComponent
from langflow.field_typing import Tool
from langflow.graph.graph.base import Graph
from langflow.helpers.flow import build_function_and_schema
from langflow.schema.dotdict import dotdict
from langflow.schema.schema import Record
from loguru import logger
class FlowToolComponent(CustomComponent):
@ -74,6 +74,7 @@ class FlowToolComponent(CustomComponent):
graph = Graph.from_payload(flow_record.data["data"])
dynamic_flow_function, schema = build_function_and_schema(flow_record, graph)
tool = StructuredTool.from_function(
func=syncify(dynamic_flow_function, raise_sync_error=False), # type: ignore
coroutine=dynamic_flow_function,
name=name,
description=description,

View file

@ -61,6 +61,6 @@ class MemoryComponent(CustomComponent):
limit=n_messages,
order=order,
)
messages_str = records_to_text(template=record_template, records=messages)
messages_str = records_to_text(template=record_template or "", records=messages)
self.status = messages_str
return messages_str

View file

@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Union
from langchain.text_splitter import CharacterTextSplitter, RecursiveCharacterTextSplitter
from langchain_core.documents import Document
@ -51,6 +51,8 @@ class SplitTextComponent(CustomComponent):
chunk_overlap: Optional[int] = 200,
recursive: bool = False,
) -> list[Record]:
if separators is None:
separators = []
separators = [unescape_string(x) for x in separators]
# Make sure chunk_size and chunk_overlap are ints
@ -58,7 +60,7 @@ class SplitTextComponent(CustomComponent):
chunk_size = int(chunk_size)
if isinstance(chunk_overlap, str):
chunk_overlap = int(chunk_overlap)
splitter: Optional[Union[CharacterTextSplitter, RecursiveCharacterTextSplitter]] = None
if recursive:
splitter = RecursiveCharacterTextSplitter(
separators=separators,

View file

@ -28,7 +28,7 @@ class ChatInput(ChatComponent):
session_id: Optional[str] = None,
return_record: Optional[bool] = False,
) -> Union[Text, Record]:
return super().build(
return super().build_no_record(
sender=sender,
sender_name=sender_name,
input_value=input_value,

View file

@ -26,7 +26,7 @@ class TextInput(TextComponent):
def build(
self,
input_value: Optional[str] = "",
input_value: Optional[Text] = "",
record_template: Optional[str] = "",
) -> Text:
return super().build(input_value=input_value, record_template=record_template)

View file

@ -1,10 +1,7 @@
from .AmazonBedrockSpecs import AmazonBedrockComponent
from .AnthropicLLMSpecs import ChatAntropicSpecsComponent
from .AzureChatOpenAISpecs import AzureChatOpenAISpecsComponent
from .BaiduQianfanChatEndpointsSpecs import QianfanChatEndpointComponent
from .BaiduQianfanLLMEndpointsSpecs import QianfanLLMEndpointComponent
from .ChatAnthropicSpecs import ChatAnthropicComponent
from .ChatAnthropicSpecs import AnthropicLLM
from .ChatLiteLLMSpecs import ChatLiteLLMComponent
from .ChatOllamaEndpointSpecs import ChatOllamaComponent
from .ChatOpenAISpecs import ChatOpenAIComponent
@ -21,7 +18,7 @@ __all__ = [
"AzureChatOpenAISpecsComponent",
"QianfanChatEndpointComponent",
"QianfanLLMEndpointComponent",
"ChatAnthropicComponent",
"AnthropicLLM",
"ChatLiteLLMComponent",
"ChatOllamaComponent",
"ChatOpenAIComponent",

View file

@ -2,6 +2,7 @@ from typing import Optional
from langchain.llms.base import BaseLanguageModel
from langchain_openai import AzureChatOpenAI
from pydantic.v1 import SecretStr
from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent
@ -105,13 +106,17 @@ class AzureChatOpenAIComponent(LCModelComponent):
max_tokens: Optional[int] = 1000,
stream: bool = False,
) -> BaseLanguageModel:
if api_key:
secret_api_key = SecretStr(api_key)
else:
secret_api_key = None
try:
output = AzureChatOpenAI(
model=model,
azure_endpoint=azure_endpoint,
azure_deployment=azure_deployment,
api_version=api_version,
api_key=api_key,
api_key=secret_api_key,
temperature=temperature,
max_tokens=max_tokens,
)

View file

@ -1,6 +1,7 @@
from typing import Optional
from langchain_openai import ChatOpenAI
from pydantic.v1 import SecretStr
from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent
@ -94,12 +95,17 @@ class OpenAIModelComponent(LCModelComponent):
) -> Text:
if not openai_api_base:
openai_api_base = "https://api.openai.com/v1"
if openai_api_key:
api_key = SecretStr(openai_api_key)
else:
api_key = None
output = ChatOpenAI(
max_tokens=max_tokens,
model_kwargs=model_kwargs,
model=model_name,
base_url=openai_api_base,
api_key=openai_api_key,
api_key=api_key,
temperature=temperature,
)

View file

@ -19,11 +19,11 @@ class ChatOutput(ChatComponent):
return_record: Optional[bool] = False,
record_template: Optional[str] = "{text}",
) -> Union[Text, Record]:
return super().build(
return super().build_with_record(
sender=sender,
sender_name=sender_name,
input_value=input_value,
session_id=session_id,
return_record=return_record,
record_template=record_template,
record_template=record_template or "",
)

View file

@ -24,5 +24,5 @@ class TextOutput(TextComponent):
},
}
def build(self, input_value: Optional[Text] = "", record_template: str = "") -> Text:
def build(self, input_value: Optional[Text] = "", record_template: Optional[str] = "") -> Text:
return super().build(input_value=input_value, record_template=record_template)

View file

@ -34,8 +34,8 @@ class PythonREPLToolComponent(CustomComponent):
global_dict = {}
for module in globals:
try:
module = importlib.import_module(module)
global_dict[module.__name__] = module
imported_module = importlib.import_module(module)
global_dict[imported_module.__name__] = imported_module
except ImportError:
print(f"Could not import module {module}")
return global_dict

View file

@ -296,18 +296,27 @@ class Graph:
# run the async function in a sync way
# this could be used in a FastAPI endpoint
# so we should take care of the event loop
loop = asyncio.get_event_loop()
return loop.run_until_complete(
self.arun(
inputs=inputs,
inputs_components=input_components,
types=types,
outputs=outputs,
session_id=session_id,
stream=stream,
)
coro = self.arun(
inputs=inputs,
inputs_components=input_components,
types=types,
outputs=outputs,
session_id=session_id,
stream=stream,
)
try:
# Attempt to get the running event loop; if none, an exception is raised
loop = asyncio.get_running_loop()
if loop.is_closed():
raise RuntimeError("The running event loop is closed.")
except RuntimeError:
# If there's no running event loop or it's closed, use asyncio.run
return asyncio.run(coro)
# If there's an existing, open event loop, use it to run the async function
return loop.run_until_complete(coro)
async def arun(
self,
inputs: list[Dict[str, str]],

View file

@ -1,15 +1,22 @@
from typing import TYPE_CHECKING, Callable
from langflow.services.deps import get_state_service
from loguru import logger
from langflow.services.deps import get_settings_service, get_state_service
if TYPE_CHECKING:
from langflow.services.state.service import StateService
class GraphStateManager:
def __init__(self):
self.state_service: "StateService" = get_state_service()
try:
self.state_service: "StateService" = get_state_service()
except Exception as e:
logger.debug(f"Error getting state service. Defaulting to InMemoryStateService: {e}")
from langflow.services.state.service import InMemoryStateService
self.state_service = InMemoryStateService(get_settings_service())
def append_state(self, key, new_state, run_id: str):
self.state_service.append_state(key, new_state, run_id)

View file

@ -1,11 +1,10 @@
from typing import TYPE_CHECKING, Any, Callable, Coroutine, List, Optional, Tuple, Type, Union, cast
from pydantic.v1 import BaseModel, Field, create_model
from sqlmodel import select
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Optional, Tuple, Type, Union, cast
from langflow.schema.schema import INPUT_FIELD_NAME, Record
from langflow.services.database.models.flow.model import Flow
from langflow.services.deps import session_scope
from pydantic.v1 import BaseModel, Field, create_model
from sqlmodel import select
if TYPE_CHECKING:
from langflow.graph.graph.base import Graph
@ -86,7 +85,7 @@ async def run_flow(
return await graph.arun(inputs_list, inputs_components=inputs_components, types=types)
def generate_function_for_flow(inputs: List["Vertex"], flow_id: str) -> Coroutine:
def generate_function_for_flow(inputs: List["Vertex"], flow_id: str) -> Callable[..., Awaitable[Any]]:
"""
Generate a dynamic flow function based on the given inputs and flow ID.
@ -145,7 +144,9 @@ async def flow_function({func_args}):
return local_scope["flow_function"]
def build_function_and_schema(flow_record: Record, graph: "Graph") -> Tuple[Callable, Type[BaseModel]]:
def build_function_and_schema(
flow_record: Record, graph: "Graph"
) -> Tuple[Callable[..., Awaitable[Any]], Type[BaseModel]]:
"""
Builds a dynamic function and schema for a given flow.

View file

@ -1,888 +0,0 @@
{
"id": "c091a57f-43a7-4a5e-b352-035ae8d8379c",
"data": {
"nodes": [
{
"id": "Prompt-uxBqP",
"type": "genericNode",
"position": {
"x": 53.588791333410654,
"y": -107.07318910019967
},
"data": {
"type": "Prompt",
"node": {
"template": {
"code": {
"type": "code",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "code",
"advanced": true,
"dynamic": true,
"info": "",
"load_from_db": false,
"title_case": false
},
"template": {
"type": "prompt",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "template",
"display_name": "Template",
"advanced": false,
"input_types": [
"Text"
],
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false
},
"_type": "CustomComponent",
"user_input": {
"field_type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "user_input",
"display_name": "user_input",
"advanced": false,
"input_types": [
"Document",
"BaseOutputParser",
"Record",
"Text"
],
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"type": "str"
}
},
"description": "Create a prompt template with dynamic variables.",
"icon": "prompts",
"is_input": null,
"is_output": null,
"is_composition": null,
"base_classes": [
"object",
"str",
"Text"
],
"name": "",
"display_name": "Prompt",
"documentation": "",
"custom_fields": {
"template": [
"user_input"
]
},
"output_types": [
"Text"
],
"full_path": null,
"field_formatters": {},
"frozen": false,
"field_order": [],
"beta": false,
"error": null
},
"id": "Prompt-uxBqP",
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt"
},
"selected": true,
"width": 384,
"height": 383,
"dragging": false,
"positionAbsolute": {
"x": 53.588791333410654,
"y": -107.07318910019967
}
},
{
"id": "OpenAIModel-k39HS",
"type": "genericNode",
"position": {
"x": 634.8148772766217,
"y": 27.035057029045305
},
"data": {
"type": "OpenAIModel",
"node": {
"template": {
"input_value": {
"type": "str",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "input_value",
"display_name": "Input",
"advanced": false,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"code": {
"type": "code",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import NestedDict, Text\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n\n field_order = [\n \"max_tokens\",\n \"model_kwargs\",\n \"model_name\",\n \"openai_api_base\",\n \"openai_api_key\",\n \"temperature\",\n \"input_value\",\n \"system_message\",\n \"stream\",\n ]\n\n def build_config(self):\n return {\n \"input_value\": {\"display_name\": \"Input\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": [\n \"gpt-4-turbo-preview\",\n \"gpt-3.5-turbo\",\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 \"value\": \"gpt-4-turbo-preview\",\n },\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"advanced\": True,\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 \"info\": \"The OpenAI API Key to use for the OpenAI model.\",\n \"advanced\": False,\n \"password\": True,\n },\n \"temperature\": {\n \"display_name\": \"Temperature\",\n \"advanced\": False,\n \"value\": 0.1,\n },\n \"stream\": {\n \"display_name\": \"Stream\",\n \"info\": STREAM_INFO_TEXT,\n \"advanced\": True,\n },\n \"system_message\": {\n \"display_name\": \"System Message\",\n \"info\": \"System message to pass to the model.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Text,\n openai_api_key: str,\n temperature: float,\n model_name: str,\n max_tokens: Optional[int] = 256,\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n stream: bool = False,\n system_message: Optional[str] = None,\n ) -> Text:\n if not openai_api_base:\n openai_api_base = \"https://api.openai.com/v1\"\n output = 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\n return self.get_chat_result(output, stream, input_value, system_message)\n",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "code",
"advanced": true,
"dynamic": true,
"info": "",
"load_from_db": false,
"title_case": false
},
"max_tokens": {
"type": "int",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": 256,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "max_tokens",
"display_name": "Max Tokens",
"advanced": true,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false
},
"model_kwargs": {
"type": "NestedDict",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": {},
"fileTypes": [],
"file_path": "",
"password": false,
"name": "model_kwargs",
"display_name": "Model Kwargs",
"advanced": true,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false
},
"model_name": {
"type": "str",
"required": true,
"placeholder": "",
"list": true,
"show": true,
"multiline": false,
"value": "gpt-3.5-turbo",
"fileTypes": [],
"file_path": "",
"password": false,
"options": [
"gpt-4-turbo-preview",
"gpt-3.5-turbo",
"gpt-4-0125-preview",
"gpt-4-1106-preview",
"gpt-4-vision-preview",
"gpt-3.5-turbo-0125",
"gpt-3.5-turbo-1106"
],
"name": "model_name",
"display_name": "Model Name",
"advanced": false,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"openai_api_base": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "openai_api_base",
"display_name": "OpenAI API Base",
"advanced": true,
"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.",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"openai_api_key": {
"type": "str",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": true,
"name": "openai_api_key",
"display_name": "OpenAI API Key",
"advanced": false,
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
"load_from_db": true,
"title_case": false,
"input_types": [
"Text"
],
"value": ""
},
"stream": {
"type": "bool",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": true,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "stream",
"display_name": "Stream",
"advanced": true,
"dynamic": false,
"info": "Stream the response from the model. Streaming works only in Chat.",
"load_from_db": false,
"title_case": false
},
"system_message": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "system_message",
"display_name": "System Message",
"advanced": true,
"dynamic": false,
"info": "System message to pass to the model.",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"temperature": {
"type": "float",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": 0.1,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "temperature",
"display_name": "Temperature",
"advanced": false,
"dynamic": false,
"info": "",
"rangeSpec": {
"step_type": "float",
"min": -1,
"max": 1,
"step": 0.1
},
"load_from_db": false,
"title_case": false
},
"_type": "CustomComponent"
},
"description": "Generates text using OpenAI LLMs.",
"icon": "OpenAI",
"base_classes": [
"object",
"Text",
"str"
],
"display_name": "OpenAI",
"documentation": "",
"custom_fields": {
"input_value": null,
"openai_api_key": null,
"temperature": null,
"model_name": null,
"max_tokens": null,
"model_kwargs": null,
"openai_api_base": null,
"stream": null,
"system_message": null
},
"output_types": [
"Text"
],
"field_formatters": {},
"frozen": false,
"field_order": [
"max_tokens",
"model_kwargs",
"model_name",
"openai_api_base",
"openai_api_key",
"temperature",
"input_value",
"system_message",
"stream"
],
"beta": false
},
"id": "OpenAIModel-k39HS",
"description": "Generates text using OpenAI LLMs.",
"display_name": "OpenAI"
},
"selected": false,
"width": 384,
"height": 563,
"positionAbsolute": {
"x": 634.8148772766217,
"y": 27.035057029045305
},
"dragging": false
},
{
"id": "ChatOutput-njtka",
"type": "genericNode",
"position": {
"x": 1193.250417197867,
"y": 71.88476890163852
},
"data": {
"type": "ChatOutput",
"node": {
"template": {
"code": {
"type": "code",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "code",
"advanced": true,
"dynamic": true,
"info": "",
"load_from_db": false,
"title_case": false
},
"input_value": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "input_value",
"display_name": "Message",
"advanced": false,
"input_types": [
"Text"
],
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false
},
"record_template": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "{text}",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "record_template",
"display_name": "Record Template",
"advanced": true,
"dynamic": false,
"info": "In case of Message being a Record, this template will be used to convert it to text.",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"return_record": {
"type": "bool",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "return_record",
"display_name": "Return Record",
"advanced": true,
"dynamic": false,
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
"load_from_db": false,
"title_case": false
},
"sender": {
"type": "str",
"required": false,
"placeholder": "",
"list": true,
"show": true,
"multiline": false,
"value": "Machine",
"fileTypes": [],
"file_path": "",
"password": false,
"options": [
"Machine",
"User"
],
"name": "sender",
"display_name": "Sender Type",
"advanced": true,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"sender_name": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": "AI",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "sender_name",
"display_name": "Sender Name",
"advanced": false,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"session_id": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "session_id",
"display_name": "Session ID",
"advanced": true,
"dynamic": false,
"info": "If provided, the message will be stored in the memory.",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"_type": "CustomComponent"
},
"description": "Display a chat message in the Interaction Panel.",
"icon": "ChatOutput",
"base_classes": [
"Record",
"Text",
"str",
"object"
],
"display_name": "Chat Output",
"documentation": "",
"custom_fields": {
"sender": null,
"sender_name": null,
"input_value": null,
"session_id": null,
"return_record": null,
"record_template": null
},
"output_types": [
"Text",
"Record"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
"beta": false
},
"id": "ChatOutput-njtka"
},
"selected": false,
"width": 384,
"height": 383,
"positionAbsolute": {
"x": 1193.250417197867,
"y": 71.88476890163852
},
"dragging": false
},
{
"id": "ChatInput-P3fgL",
"type": "genericNode",
"position": {
"x": -495.2223093083827,
"y": -232.56998443685862
},
"data": {
"type": "ChatInput",
"node": {
"template": {
"code": {
"type": "code",
"required": true,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Interaction Panel.\"\n icon = \"ChatInput\"\n\n def build_config(self):\n build_config = super().build_config()\n build_config[\"input_value\"] = {\n \"input_types\": [],\n \"display_name\": \"Message\",\n \"multiline\": True,\n }\n\n return build_config\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "code",
"advanced": true,
"dynamic": true,
"info": "",
"load_from_db": false,
"title_case": false
},
"input_value": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": true,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "input_value",
"display_name": "Message",
"advanced": false,
"input_types": [],
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"value": "hi"
},
"return_record": {
"type": "bool",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "return_record",
"display_name": "Return Record",
"advanced": true,
"dynamic": false,
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
"load_from_db": false,
"title_case": false
},
"sender": {
"type": "str",
"required": false,
"placeholder": "",
"list": true,
"show": true,
"multiline": false,
"value": "User",
"fileTypes": [],
"file_path": "",
"password": false,
"options": [
"Machine",
"User"
],
"name": "sender",
"display_name": "Sender Type",
"advanced": true,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"sender_name": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"value": "User",
"fileTypes": [],
"file_path": "",
"password": false,
"name": "sender_name",
"display_name": "Sender Name",
"advanced": false,
"dynamic": false,
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"session_id": {
"type": "str",
"required": false,
"placeholder": "",
"list": false,
"show": true,
"multiline": false,
"fileTypes": [],
"file_path": "",
"password": false,
"name": "session_id",
"display_name": "Session ID",
"advanced": true,
"dynamic": false,
"info": "If provided, the message will be stored in the memory.",
"load_from_db": false,
"title_case": false,
"input_types": [
"Text"
]
},
"_type": "CustomComponent"
},
"description": "Get chat inputs from the Interaction Panel.",
"icon": "ChatInput",
"base_classes": [
"object",
"Record",
"str",
"Text"
],
"display_name": "Chat Input",
"documentation": "",
"custom_fields": {
"sender": null,
"sender_name": null,
"input_value": null,
"session_id": null,
"return_record": null
},
"output_types": [
"Text",
"Record"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
"beta": false
},
"id": "ChatInput-P3fgL"
},
"selected": false,
"width": 384,
"height": 375,
"positionAbsolute": {
"x": -495.2223093083827,
"y": -232.56998443685862
},
"dragging": false
}
],
"edges": [
{
"source": "OpenAIModel-k39HS",
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}",
"target": "ChatOutput-njtka",
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
"data": {
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-njtka",
"inputTypes": [
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": [
"object",
"Text",
"str"
],
"dataType": "OpenAIModel",
"id": "OpenAIModel-k39HS"
}
},
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"id": "reactflow__edge-OpenAIModel-k39HS{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-k39HSœ}-ChatOutput-njtka{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-njtkaœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
},
{
"source": "Prompt-uxBqP",
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}",
"target": "OpenAIModel-k39HS",
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
"data": {
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-k39HS",
"inputTypes": [
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": [
"object",
"str",
"Text"
],
"dataType": "Prompt",
"id": "Prompt-uxBqP"
}
},
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"id": "reactflow__edge-Prompt-uxBqP{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-uxBqPœ}-OpenAIModel-k39HS{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-k39HSœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
},
{
"source": "ChatInput-P3fgL",
"sourceHandle": "{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}",
"target": "Prompt-uxBqP",
"targetHandle": "{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}",
"data": {
"targetHandle": {
"fieldName": "user_input",
"id": "Prompt-uxBqP",
"inputTypes": [
"Document",
"BaseOutputParser",
"Record",
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": [
"object",
"Record",
"str",
"Text"
],
"dataType": "ChatInput",
"id": "ChatInput-P3fgL"
}
},
"style": {
"stroke": "#555"
},
"className": "stroke-gray-900 stroke-connection",
"id": "reactflow__edge-ChatInput-P3fgL{œbaseClassesœ:[œobjectœ,œRecordœ,œstrœ,œTextœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-P3fgLœ}-Prompt-uxBqP{œfieldNameœ:œuser_inputœ,œidœ:œPrompt-uxBqPœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}"
}
],
"viewport": {
"x": 260.58251815500563,
"y": 318.2261172111936,
"zoom": 0.43514115784696294
}
},
"description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ",
"name": "Basic Prompting (Ahoy World!)",
"last_tested_version": "1.0.0a4",
"is_component": false
}

View file

@ -45,7 +45,9 @@
"name": "template",
"display_name": "Template",
"advanced": false,
"input_types": ["Text"],
"input_types": [
"Text"
],
"dynamic": false,
"info": "",
"load_from_db": false,
@ -136,14 +138,24 @@
"is_input": null,
"is_output": null,
"is_composition": null,
"base_classes": ["object", "Text", "str"],
"base_classes": [
"object",
"Text",
"str"
],
"name": "",
"display_name": "Prompt",
"documentation": "",
"custom_fields": {
"template": ["reference_1", "reference_2", "instructions"]
"template": [
"reference_1",
"reference_2",
"instructions"
]
},
"output_types": ["Text"],
"output_types": [
"Text"
],
"full_path": null,
"field_formatters": {},
"frozen": false,
@ -210,7 +222,9 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"],
"input_types": [
"Text"
],
"value": [
"https://www.promptingguide.ai/techniques/prompt_chaining"
]
@ -219,13 +233,17 @@
},
"description": "Fetch content from one or more URLs.",
"icon": "layout-template",
"base_classes": ["Record"],
"base_classes": [
"Record"
],
"display_name": "URL",
"documentation": "",
"custom_fields": {
"urls": null
},
"output_types": ["Record"],
"output_types": [
"Record"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
@ -260,7 +278,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -284,7 +302,9 @@
"name": "input_value",
"display_name": "Message",
"advanced": false,
"input_types": ["Text"],
"input_types": [
"Text"
],
"dynamic": false,
"info": "",
"load_from_db": false,
@ -308,7 +328,9 @@
"info": "In case of Message being a Record, this template will be used to convert it to text.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"return_record": {
"type": "bool",
@ -340,7 +362,10 @@
"fileTypes": [],
"file_path": "",
"password": false,
"options": ["Machine", "User"],
"options": [
"Machine",
"User"
],
"name": "sender",
"display_name": "Sender Type",
"advanced": true,
@ -348,7 +373,9 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"sender_name": {
"type": "str",
@ -368,7 +395,9 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"session_id": {
"type": "str",
@ -387,13 +416,20 @@
"info": "If provided, the message will be stored in the memory.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"_type": "CustomComponent"
},
"description": "Display a chat message in the Interaction Panel.",
"icon": "ChatOutput",
"base_classes": ["Text", "Record", "object", "str"],
"base_classes": [
"Text",
"Record",
"object",
"str"
],
"display_name": "Chat Output",
"documentation": "",
"custom_fields": {
@ -404,7 +440,10 @@
"return_record": null,
"record_template": null
},
"output_types": ["Text", "Record"],
"output_types": [
"Text",
"Record"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
@ -444,7 +483,9 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"code": {
"type": "code",
@ -529,7 +570,9 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"openai_api_base": {
"type": "str",
@ -548,7 +591,9 @@
"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.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"openai_api_key": {
"type": "str",
@ -567,7 +612,9 @@
"info": "The OpenAI API Key to use for the OpenAI model.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"],
"input_types": [
"Text"
],
"value": ""
},
"stream": {
@ -606,7 +653,9 @@
"info": "System message to pass to the model.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"temperature": {
"type": "float",
@ -637,7 +686,11 @@
},
"description": "Generates text using OpenAI LLMs.",
"icon": "OpenAI",
"base_classes": ["str", "Text", "object"],
"base_classes": [
"str",
"Text",
"object"
],
"display_name": "OpenAI",
"documentation": "",
"custom_fields": {
@ -651,7 +704,9 @@
"stream": null,
"system_message": null
},
"output_types": ["Text"],
"output_types": [
"Text"
],
"field_formatters": {},
"frozen": false,
"field_order": [
@ -724,20 +779,28 @@
"info": "",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"],
"value": ["https://www.promptingguide.ai/introduction/basics"]
"input_types": [
"Text"
],
"value": [
"https://www.promptingguide.ai/introduction/basics"
]
},
"_type": "CustomComponent"
},
"description": "Fetch content from one or more URLs.",
"icon": "layout-template",
"base_classes": ["Record"],
"base_classes": [
"Record"
],
"display_name": "URL",
"documentation": "",
"custom_fields": {
"urls": null
},
"output_types": ["Record"],
"output_types": [
"Record"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
@ -797,7 +860,10 @@
"name": "input_value",
"display_name": "Value",
"advanced": false,
"input_types": ["Record", "Text"],
"input_types": [
"Record",
"Text"
],
"dynamic": false,
"info": "Text or Record to be passed as input.",
"load_from_db": false,
@ -821,20 +887,28 @@
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
"load_from_db": false,
"title_case": false,
"input_types": ["Text"]
"input_types": [
"Text"
]
},
"_type": "CustomComponent"
},
"description": "Get text inputs from the Interaction Panel.",
"icon": "type",
"base_classes": ["object", "Text", "str"],
"base_classes": [
"object",
"Text",
"str"
],
"display_name": "Instructions",
"documentation": "",
"custom_fields": {
"input_value": null,
"record_template": null
},
"output_types": ["Text"],
"output_types": [
"Text"
],
"field_formatters": {},
"frozen": false,
"field_order": [],
@ -863,11 +937,18 @@
"targetHandle": {
"fieldName": "reference_2",
"id": "Prompt-Rse03",
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
"inputTypes": [
"Document",
"BaseOutputParser",
"Record",
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["Record"],
"baseClasses": [
"Record"
],
"dataType": "URL",
"id": "URL-HYPkR"
}
@ -887,11 +968,17 @@
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-JPlxl",
"inputTypes": ["Text"],
"inputTypes": [
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["str", "Text", "object"],
"baseClasses": [
"str",
"Text",
"object"
],
"dataType": "OpenAIModel",
"id": "OpenAIModel-gi29P"
}
@ -911,11 +998,18 @@
"targetHandle": {
"fieldName": "reference_1",
"id": "Prompt-Rse03",
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
"inputTypes": [
"Document",
"BaseOutputParser",
"Record",
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["Record"],
"baseClasses": [
"Record"
],
"dataType": "URL",
"id": "URL-2cX90"
}
@ -935,11 +1029,20 @@
"targetHandle": {
"fieldName": "instructions",
"id": "Prompt-Rse03",
"inputTypes": ["Document", "BaseOutputParser", "Record", "Text"],
"inputTypes": [
"Document",
"BaseOutputParser",
"Record",
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["object", "Text", "str"],
"baseClasses": [
"object",
"Text",
"str"
],
"dataType": "TextInput",
"id": "TextInput-og8Or"
}
@ -959,11 +1062,17 @@
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-gi29P",
"inputTypes": ["Text"],
"inputTypes": [
"Text"
],
"type": "str"
},
"sourceHandle": {
"baseClasses": ["object", "Text", "str"],
"baseClasses": [
"object",
"Text",
"str"
],
"dataType": "Prompt",
"id": "Prompt-Rse03"
}
@ -986,4 +1095,4 @@
"name": "Blog Writer",
"last_tested_version": "1.0.0a0",
"is_component": false
}
}

View file

@ -256,7 +256,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -452,7 +452,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Interaction Panel.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n record_template: Optional[str] = \"{text}\",\n ) -> Union[Text, Record]:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n record_template=record_template,\n )\n",
"fileTypes": [],
"file_path": "",
"password": false,
@ -647,7 +647,7 @@
"list": false,
"show": true,
"multiline": true,
"value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Interaction Panel.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[str] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n",
"value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextInput(TextComponent):\n display_name = \"Text Input\"\n description = \"Get text inputs from the Interaction Panel.\"\n icon = \"type\"\n\n def build_config(self):\n return {\n \"input_value\": {\n \"display_name\": \"Value\",\n \"input_types\": [\"Record\", \"Text\"],\n \"info\": \"Text or Record to be passed as input.\",\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n input_value: Optional[Text] = \"\",\n record_template: Optional[str] = \"\",\n ) -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n",
"fileTypes": [],
"file_path": "",
"password": false,

File diff suppressed because one or more lines are too long

View file

@ -1,14 +1,14 @@
from typing import ClassVar, Dict, List, Optional
from langchain.agents import types
from loguru import logger
from langflow.interface.agents.custom import CUSTOM_AGENTS
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.utils import build_template_from_class
from langflow.legacy_custom.customs import get_custom_nodes
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.agents import AgentFrontendNode
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_method
from loguru import logger
class AgentCreator(LangChainTypeCreator):

View file

@ -2,14 +2,14 @@ from typing import Any, ClassVar, Dict, List, Optional, Type
from langchain import chains
from langchain_experimental.sql import SQLDatabaseChain
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class
from langflow.interface.utils import build_template_from_class
from langflow.legacy_custom.customs import get_custom_nodes
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.chains import ChainFrontendNode
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_method
from loguru import logger
# Assuming necessary imports for Field, Template, and FrontendNode classes

View file

@ -4,9 +4,9 @@ from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.custom_lists import documentloaders_type_to_cls_dict
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.documentloaders import DocumentLoaderFrontNode
from langflow.utils.util import build_template_from_class
class DocumentLoaderCreator(LangChainTypeCreator):

View file

@ -4,10 +4,10 @@ from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.custom_lists import embedding_type_to_cls_dict
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.base import FrontendNode
from langflow.template.frontend_node.embeddings import EmbeddingFrontendNode
from langflow.utils.util import build_template_from_class
class EmbeddingCreator(LangChainTypeCreator):

View file

@ -4,9 +4,9 @@ from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.custom_lists import llm_type_to_cls_dict
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.llms import LLMFrontendNode
from langflow.utils.util import build_template_from_class
class LLMCreator(LangChainTypeCreator):

View file

@ -1,14 +1,14 @@
from typing import ClassVar, Dict, List, Optional, Type
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.custom_lists import memory_type_to_cls_dict
from langflow.interface.utils import build_template_from_class
from langflow.legacy_custom.customs import get_custom_nodes
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.base import FrontendNode
from langflow.template.frontend_node.memories import MemoryFrontendNode
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_method
from loguru import logger
class MemoryCreator(LangChainTypeCreator):

View file

@ -1,13 +1,13 @@
from typing import ClassVar, Dict, List, Optional, Type
from langchain import output_parsers
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.output_parsers import OutputParserFrontendNode
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_method
from loguru import logger
class OutputParserCreator(LangChainTypeCreator):

View file

@ -2,13 +2,12 @@ from typing import Dict, List, Optional, Type
from langchain import prompts
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class
from langflow.interface.utils import build_template_from_class
from langflow.legacy_custom.customs import get_custom_nodes
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.prompts import PromptFrontendNode
from langflow.utils.util import build_template_from_class
class PromptCreator(LangChainTypeCreator):

View file

@ -1,13 +1,13 @@
from typing import Any, ClassVar, Dict, List, Optional, Type
from langchain_community import retrievers
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.retrievers import RetrieverFrontendNode
from langflow.utils.util import build_template_from_class, build_template_from_method
from langflow.utils.util import build_template_from_method
from loguru import logger
class RetrieverCreator(LangChainTypeCreator):

View file

@ -4,9 +4,9 @@ from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.custom_lists import textsplitter_type_to_cls_dict
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.textsplitters import TextSplittersFrontendNode
from langflow.utils.util import build_template_from_class
class TextSplitterCreator(LangChainTypeCreator):

View file

@ -3,11 +3,10 @@ from typing import Callable, Dict, List, Optional
from langchain.agents import agent_toolkits
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class, import_module
from langflow.interface.utils import build_template_from_class
from langflow.services.deps import get_settings_service
from langflow.utils.util import build_template_from_class
class ToolkitCreator(LangChainTypeCreator):

View file

@ -11,7 +11,7 @@ from langflow.template.field.base import TemplateField
from langflow.template.template.base import Template
from langflow.utils import util
from langflow.utils.logger import logger
from langflow.utils.util import build_template_from_class
from langflow.interface.utils import build_template_from_class
TOOL_INPUTS = {
"str": TemplateField(

View file

@ -2,13 +2,12 @@ from typing import Dict, List, Optional, Type
from langchain_community import utilities
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.importing.utils import import_class
from langflow.interface.utils import build_template_from_class
from langflow.legacy_custom.customs import get_custom_nodes
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.utilities import UtilitiesFrontendNode
from langflow.utils.util import build_template_from_class
class UtilityCreator(LangChainTypeCreator):

View file

@ -3,14 +3,16 @@ import json
import os
import re
from io import BytesIO
from typing import Dict
import yaml
from docstring_parser import parse
from langchain.base_language import BaseLanguageModel
from loguru import logger
from PIL.Image import Image
from langflow.services.chat.config import ChatConfig
from langflow.services.deps import get_settings_service
from langflow.utils.util import format_dict, get_base_classes, get_default_factory
from loguru import logger
from PIL.Image import Image
def load_file_into_dict(file_path: str) -> dict:
@ -100,7 +102,6 @@ def setup_llm_caching():
def set_langchain_cache(settings):
from langchain.globals import set_llm_cache
from langflow.interface.importing.utils import import_class
if cache_type := os.getenv("LANGFLOW_LANGCHAIN_CACHE"):
@ -114,3 +115,51 @@ def set_langchain_cache(settings):
logger.warning(f"Could not import {cache_type}. ")
else:
logger.info("No LLM cache set.")
def build_template_from_class(name: str, type_to_cls_dict: Dict, add_function: bool = False):
classes = [item.__name__ for item in type_to_cls_dict.values()]
# Raise error if name is not in chains
if name not in classes:
raise ValueError(f"{name} not found.")
for _type, v in type_to_cls_dict.items():
if v.__name__ == name:
_class = v
# Get the docstring
docs = parse(_class.__doc__)
variables = {"_type": _type}
if "__fields__" in _class.__dict__:
for class_field_items, value in _class.__fields__.items():
if class_field_items in ["callback_manager"]:
continue
variables[class_field_items] = {}
for name_, value_ in value.__repr_args__():
if name_ == "default_factory":
try:
variables[class_field_items]["default"] = get_default_factory(
module=_class.__base__.__module__,
function=value_,
)
except Exception:
variables[class_field_items]["default"] = None
elif name_ not in ["name"]:
variables[class_field_items][name_] = value_
variables[class_field_items]["placeholder"] = (
docs.params[class_field_items] if class_field_items in docs.params else ""
)
base_classes = get_base_classes(_class)
# Adding function to base classes to allow
# the output to be a function
if add_function:
base_classes.append("Callable")
return {
"template": format_dict(variables, name),
"description": docs.short_description or "",
"base_classes": base_classes,
}

View file

@ -1,10 +1,9 @@
from typing import Dict, List, Optional
from langchain_community.utilities import requests
from loguru import logger
from langflow.interface.base import LangChainTypeCreator
from langflow.utils.util import build_template_from_class
from langflow.interface.utils import build_template_from_class
from loguru import logger
class WrapperCreator(LangChainTypeCreator):

View file

@ -2,21 +2,55 @@ import json
from pathlib import Path
from typing import List, Optional, Union
from dotenv import load_dotenv
from langflow.graph import Graph
from langflow.graph.schema import RunOutputs
from langflow.processing.process import process_tweaks, run_graph
from langflow.utils.logger import configure
from langflow.utils.util import update_settings
def load_flow_from_json(flow: Union[Path, str, dict], tweaks: Optional[dict] = None) -> Graph:
def load_flow_from_json(
flow: Union[Path, str, dict],
tweaks: Optional[dict] = None,
log_level: Optional[str] = None,
log_file: Optional[str] = None,
env_file: Optional[str] = None,
cache: Optional[str] = None,
disable_logs: Optional[bool] = True,
) -> Graph:
"""
Load flow from a JSON file or a JSON object.
Load a flow graph from a JSON file or a JSON object.
Args:
flow (Union[Path, str, dict]): The flow to load. It can be a file path (str or Path object)
or a JSON object (dict).
tweaks (Optional[dict]): Optional tweaks to apply to the loaded flow graph.
log_level (Optional[str]): Optional log level to configure for the flow processing.
log_file (Optional[str]): Optional log file to configure for the flow processing.
env_file (Optional[str]): Optional .env file to override environment variables.
cache (Optional[str]): Optional cache path to update the flow settings.
disable_logs (Optional[bool], default=True): Optional flag to disable logs during flow processing.
If log_level or log_file are set, disable_logs is not used.
Returns:
Graph: The loaded flow graph as a Graph object.
Raises:
TypeError: If the input is neither a file path (str or Path object) nor a JSON object (dict).
:param flow: JSON file path or JSON object
:param tweaks: Optional tweaks to be processed
:param build: If True, build the graph, otherwise return the graph object
:return: Langchain object or Graph object depending on the build parameter
"""
# If input is a file path, load JSON from the file
log_file_path = Path(log_file) if log_file else None
configure(log_level=log_level, log_file=log_file_path, disable=disable_logs)
# override env variables with .env file
if env_file:
load_dotenv(env_file, override=True)
# Update settings with cache and components path
update_settings(cache=cache)
if isinstance(flow, (str, Path)):
with open(flow, "r", encoding="utf-8") as f:
flow_graph = json.load(f)
@ -41,22 +75,44 @@ def run_flow_from_json(
input_type: str = "chat",
output_type: str = "chat",
output_component: Optional[str] = None,
log_level: Optional[str] = None,
log_file: Optional[str] = None,
env_file: Optional[str] = None,
cache: Optional[str] = None,
disable_logs: Optional[bool] = True,
) -> List[RunOutputs]:
"""
Runs a JSON flow by loading it from a file or dictionary and executing it with the given input value.
Run a flow from a JSON file or dictionary.
Args:
flow (Union[Path, str, dict]): The path to the JSON file, or the JSON dictionary representing the flow.
flow (Union[Path, str, dict]): The path to the JSON file or the JSON dictionary representing the flow.
input_value (str): The input value to be processed by the flow.
tweaks (Optional[dict], optional): Optional tweaks to be applied to the flow. Defaults to None.
input_type (str, optional): The type of the input value. Defaults to "chat".
output_type (str, optional): The type of the output value. Defaults to "chat".
output_component (Optional[str], optional): The specific output component to retrieve. Defaults to None.
output_component (Optional[str], optional): The specific component to output. Defaults to None.
log_level (Optional[str], optional): The log level to use. Defaults to None.
log_file (Optional[str], optional): The log file to write logs to. Defaults to None.
env_file (Optional[str], optional): The environment file to load. Defaults to None.
cache (Optional[str], optional): The cache directory to use. Defaults to None.
disable_logs (Optional[bool], optional): Whether to disable logs. Defaults to True.
Returns:
None: The result of running the flow.
List[RunOutputs]: A list of RunOutputs objects representing the results of running the flow.
"""
graph = load_flow_from_json(flow, tweaks)
# Set all streaming to false
if tweaks is None:
tweaks = {}
tweaks["stream"] = False
graph = load_flow_from_json(
flow=flow,
tweaks=tweaks,
log_level=log_level,
log_file=log_file,
env_file=env_file,
cache=cache,
disable_logs=disable_logs,
)
result = run_graph(
graph=graph,
input_value=input_value,

View file

@ -9,11 +9,12 @@ from langflow.graph.graph.base import Graph
from langflow.graph.schema import RunOutputs
from langflow.graph.vertex.base import Vertex
from langflow.interface.run import get_memory_key, update_memory_keys
from langflow.schema.graph import InputValue, Tweaks
from langflow.schema.schema import INPUT_FIELD_NAME
from langflow.services.session.service import SessionService
if TYPE_CHECKING:
from langflow.api.v1.schemas import InputValueRequest, Tweaks
from langflow.api.v1.schemas import InputValueRequest
def fix_memory_inputs(langchain_object):
@ -188,7 +189,7 @@ def run_graph(
List[RunOutputs]: A list of RunOutputs objects representing the outputs of the graph.
"""
inputs = [InputValueRequest(components=[], input_value=input_value, type=input_type)]
inputs = [InputValue(components=[], input_value=input_value, type=input_type)]
if output_component:
outputs = [output_component]
else:

View file

@ -0,0 +1,43 @@
from typing import List, Optional, Union
from langflow.schema.schema import InputType
from pydantic import BaseModel, Field, RootModel
class InputValue(BaseModel):
components: Optional[List[str]] = []
input_value: Optional[str] = None
type: Optional[InputType] = Field(
"any",
description="Defines on which components the input value should be applied. 'any' applies to all input components.",
)
class Tweaks(RootModel):
root: dict[str, Union[str, dict[str, str]]] = Field(
description="A dictionary of tweaks to adjust the flow's execution. Allows customizing flow behavior dynamically. All tweaks are overridden by the input values.",
)
model_config = {
"json_schema_extra": {
"examples": [
{
"parameter_name": "value",
"Component Name": {"parameter_name": "value"},
"component_id": {"parameter_name": "value"},
}
]
}
}
# This should behave like a dict
def __getitem__(self, key):
return self.root[key]
def __setitem__(self, key, value):
self.root[key] = value
def __delitem__(self, key):
del self.root[key]
def items(self):
return self.root.items()

View file

@ -1,6 +1,6 @@
import logging
from gunicorn import glogging
from gunicorn import glogging # type: ignore
from gunicorn.app.base import BaseApplication # type: ignore
from uvicorn.workers import UvicornWorker

View file

@ -1,14 +1,15 @@
# Path: src/backend/langflow/services/database/models/flow/model.py
import warnings
from datetime import datetime
from typing import TYPE_CHECKING, Dict, Optional
from uuid import UUID, uuid4
import emoji
from emoji import purely_emoji # type: ignore
from pydantic import field_serializer, field_validator
from sqlmodel import JSON, Column, Field, Relationship, SQLModel
from langflow.interface.custom.attributes import validate_icon
from langflow.schema.schema import Record
if TYPE_CHECKING:
@ -45,12 +46,25 @@ class FlowBase(SQLModel):
# emoji pattern in Python
if v is None:
return v
# we are going to use the emoji library to validate the emoji
# emojis can be defined using the :emoji_name: syntax
emoji = validate_icon(v)
if not v.startswith(":") and not v.endswith(":"):
return v
elif not v.startswith(":") or not v.endswith(":"):
# emoji should have both starting and ending colons
# so if one of them is missing, we will raise
raise ValueError(f"Invalid emoji. {v} is not a valid emoji.")
if purely_emoji(emoji):
emoji_value = emoji.emojize(v, variant="emoji_type")
if v == emoji_value:
warnings.warn(f"Invalid emoji. {v} is not a valid emoji.")
icon = v
icon = emoji_value
if purely_emoji(icon):
# this is indeed an emoji
return emoji
return icon
# otherwise it should be a valid lucide icon
if v is not None and not isinstance(v, str):
raise ValueError("Icon must be a string")

View file

@ -25,7 +25,9 @@ def patching(record):
record["extra"]["serialized"] = serialize(record)
def configure(log_level: Optional[str] = None, log_file: Optional[Path] = None):
def configure(log_level: Optional[str] = None, log_file: Optional[Path] = None, disable: Optional[bool] = False):
if disable and log_level is None and log_file is None:
logger.disable("langflow")
if os.getenv("LANGFLOW_LOG_LEVEL", "").upper() in VALID_LOG_LEVELS and log_level is None:
log_level = os.getenv("LANGFLOW_LOG_LEVEL")
if log_level is None:

View file

@ -2,13 +2,15 @@ import importlib
import inspect
import re
from functools import wraps
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from docstring_parser import parse
from langflow.schema.schema import Record
from langflow.services.deps import get_settings_service
from langflow.template.frontend_node.constants import FORCE_SHOW_FIELDS
from langflow.utils import constants
from langflow.utils.logger import logger
def unescape_string(s: str):
@ -66,54 +68,6 @@ def build_template_from_function(name: str, type_to_loader_dict: Dict, add_funct
}
def build_template_from_class(name: str, type_to_cls_dict: Dict, add_function: bool = False):
classes = [item.__name__ for item in type_to_cls_dict.values()]
# Raise error if name is not in chains
if name not in classes:
raise ValueError(f"{name} not found.")
for _type, v in type_to_cls_dict.items():
if v.__name__ == name:
_class = v
# Get the docstring
docs = parse(_class.__doc__)
variables = {"_type": _type}
if "__fields__" in _class.__dict__:
for class_field_items, value in _class.__fields__.items():
if class_field_items in ["callback_manager"]:
continue
variables[class_field_items] = {}
for name_, value_ in value.__repr_args__():
if name_ == "default_factory":
try:
variables[class_field_items]["default"] = get_default_factory(
module=_class.__base__.__module__,
function=value_,
)
except Exception:
variables[class_field_items]["default"] = None
elif name_ not in ["name"]:
variables[class_field_items][name_] = value_
variables[class_field_items]["placeholder"] = (
docs.params[class_field_items] if class_field_items in docs.params else ""
)
base_classes = get_base_classes(_class)
# Adding function to base classes to allow
# the output to be a function
if add_function:
base_classes.append("Callable")
return {
"template": format_dict(variables, name),
"description": docs.short_description or "",
"base_classes": base_classes,
}
def build_template_from_method(
class_name: str,
method_name: str,
@ -462,3 +416,35 @@ def build_loader_repr_from_records(records: List[Record]) -> str:
\nAvg. Record Length (characters): {int(avg_length)}
Records: {records[:3]}..."""
return "0 records"
def update_settings(
config: Optional[str] = None,
cache: Optional[str] = None,
dev: bool = False,
remove_api_keys: bool = False,
components_path: Optional[Path] = None,
store: bool = True,
):
"""Update the settings from a config file."""
from langflow.services.utils import initialize_settings_service
# Check for database_url in the environment variables
initialize_settings_service()
settings_service = get_settings_service()
if config:
logger.debug(f"Loading settings from {config}")
settings_service.settings.update_from_yaml(config, dev=dev)
if remove_api_keys:
logger.debug(f"Setting remove_api_keys to {remove_api_keys}")
settings_service.settings.update_settings(REMOVE_API_KEYS=remove_api_keys)
if cache:
logger.debug(f"Setting cache to {cache}")
settings_service.settings.update_settings(CACHE=cache)
if components_path:
logger.debug(f"Adding component path {components_path}")
settings_service.settings.update_settings(COMPONENTS_PATH=components_path)
if not store:
logger.debug("Setting store to False")
settings_service.settings.update_settings(STORE=False)

View file

@ -202,6 +202,20 @@ files = [
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
]
[[package]]
name = "asyncer"
version = "0.0.5"
description = "Asyncer, async and await, focused on developer experience."
optional = false
python-versions = ">=3.8,<4.0"
files = [
{file = "asyncer-0.0.5-py3-none-any.whl", hash = "sha256:ba06d6de3c750763868dffacf89b18d40b667605b0241d31c2ee43f188e2ab74"},
{file = "asyncer-0.0.5.tar.gz", hash = "sha256:2979f3e04cbedfe5cfeb79027dcf7d004fcc4430a0ca0066ae20490f218ec06e"},
]
[package.dependencies]
anyio = ">=3.4.0,<5.0"
[[package]]
name = "attrs"
version = "23.2.0"
@ -4444,4 +4458,4 @@ local = []
[metadata]
lock-version = "2.0"
python-versions = ">=3.10,<3.12"
content-hash = "ab99a3fe4d80dff80dfa69347dcb22b85d48d33487a14e01c709b51f7b62699e"
content-hash = "67dfc26573145c0b2b8daea7f07ae228d2a3403033a6c25b41e8e1b280b01e38"

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "langflow-base"
version = "0.0.24"
version = "0.0.25"
description = "A Python package with a built-in web application"
authors = ["Logspace <contact@logspace.ai>"]
maintainers = [
@ -60,6 +60,7 @@ pypdf = "^4.1.0"
nest-asyncio = "^1.6.0"
emoji = "^2.11.0"
cryptography = "^42.0.5"
asyncer = "^0.0.5"
[tool.poetry.group.dev.dependencies]

View file

@ -10,10 +10,6 @@ import orjson
import pytest
from fastapi.testclient import TestClient
from httpx import AsyncClient
from sqlmodel import Session, SQLModel, create_engine, select
from sqlmodel.pool import StaticPool
from typer.testing import CliRunner
from langflow.graph.graph.base import Graph
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
from langflow.services.auth.utils import get_password_hash
@ -22,6 +18,9 @@ from langflow.services.database.models.flow.model import Flow, FlowCreate
from langflow.services.database.models.user.model import User, UserCreate
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service
from sqlmodel import Session, SQLModel, create_engine, select
from sqlmodel.pool import StaticPool
from typer.testing import CliRunner
if TYPE_CHECKING:
from langflow.services.database.service import DatabaseService
@ -204,25 +203,28 @@ def complex_graph_with_groups():
@pytest.fixture(name="client", autouse=True)
def client_fixture(session: Session, monkeypatch):
def client_fixture(session: Session, monkeypatch, request):
# Set the database url to a test database
db_dir = tempfile.mkdtemp()
db_path = Path(db_dir) / "test.db"
monkeypatch.setenv("LANGFLOW_DATABASE_URL", f"sqlite:///{db_path}")
monkeypatch.setenv("LANGFLOW_AUTO_LOGIN", "false")
if "noclient" in request.keywords:
yield
else:
db_dir = tempfile.mkdtemp()
db_path = Path(db_dir) / "test.db"
monkeypatch.setenv("LANGFLOW_DATABASE_URL", f"sqlite:///{db_path}")
monkeypatch.setenv("LANGFLOW_AUTO_LOGIN", "false")
from langflow.main import create_app
from langflow.main import create_app
app = create_app()
app = create_app()
# app.dependency_overrides[get_session] = get_session_override
with TestClient(app) as client:
yield client
# app.dependency_overrides.clear()
monkeypatch.undo()
# clear the temp db
with suppress(FileNotFoundError):
db_path.unlink()
# app.dependency_overrides[get_session] = get_session_override
with TestClient(app) as client:
yield client
# app.dependency_overrides.clear()
monkeypatch.undo()
# clear the temp db
with suppress(FileNotFoundError):
db_path.unlink()
# create a fixture for session_getter above

View file

@ -1,9 +1,11 @@
import pytest
from langflow.graph import Graph
from langflow.processing.load import load_flow_from_json
from langflow.graph.schema import RunOutputs
from langflow.initial_setup.setup import load_starter_projects
from langflow.processing.load import load_flow_from_json, run_flow_from_json
@pytest.mark.noclient
def test_load_flow_from_json():
"""Test loading a flow from a json file"""
loaded = load_flow_from_json(pytest.BASIC_EXAMPLE_PATH)
@ -11,9 +13,30 @@ def test_load_flow_from_json():
assert isinstance(loaded, Graph)
@pytest.mark.noclient
def test_load_flow_from_json_with_tweaks():
"""Test loading a flow from a json file and applying tweaks"""
tweaks = {"dndnode_82": {"model_name": "gpt-3.5-turbo-16k-0613"}}
loaded = load_flow_from_json(pytest.BASIC_EXAMPLE_PATH, tweaks=tweaks)
assert loaded is not None
assert isinstance(loaded, Graph)
@pytest.mark.noclient
def test_load_flow_from_json_object():
"""Test loading a flow from a json file and applying tweaks"""
_, projects = zip(*load_starter_projects())
project = projects[0]
loaded = load_flow_from_json(project)
assert loaded is not None
assert isinstance(loaded, Graph)
@pytest.mark.noclient
def test_run_flow_from_json_object():
"""Test loading a flow from a json file and applying tweaks"""
_, projects = zip(*load_starter_projects())
project = projects[0]
results = run_flow_from_json(project, input_value="test")
assert results is not None
assert all(isinstance(result, RunOutputs) for result in results)

View file

@ -2,14 +2,9 @@ import importlib
from typing import Dict, List, Optional
import pytest
from langflow.interface.utils import build_template_from_class
from langflow.utils.constants import CHAT_OPENAI_MODELS, OPENAI_MODELS
from langflow.utils.util import (
build_template_from_class,
build_template_from_function,
format_dict,
get_base_classes,
get_default_factory,
)
from langflow.utils.util import build_template_from_function, format_dict, get_base_classes, get_default_factory
from pydantic import BaseModel