diff --git a/.gitattributes b/.gitattributes index 4b878819c..d6e351bc3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,12 +11,12 @@ *.ts text *.tsx text *.md text -*.mdx text +*.mdx text working-tree-encoding = UTF-8 *.yml text *.yaml text *.xml text *.csv text -*.json text +*.json text working-tree-encoding = UTF-8 *.sh text *.Dockerfile text Dockerfile text @@ -32,3 +32,4 @@ Dockerfile text *.mp4 binary *.svg binary *.csv binary + diff --git a/.vscode/launch.json b/.vscode/launch.json index 40a60f354..82e39fcc9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,7 +3,7 @@ "configurations": [ { "name": "Debug Backend", - "type": "python", + "type": "debugpy", "request": "launch", "module": "uvicorn", "args": [ @@ -26,7 +26,7 @@ }, { "name": "Debug CLI", - "type": "python", + "type": "debugpy", "request": "launch", "module": "langflow", "args": [ @@ -43,7 +43,7 @@ }, { "name": "Python: Remote Attach", - "type": "python", + "type": "debugpy", "request": "attach", "justMyCode": true, "connect": { @@ -65,7 +65,7 @@ }, { "name": "Python: Debug Tests", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${file}", "purpose": ["debug-test"], diff --git a/docs/docs/components/toolkits.mdx b/docs/docs/components/toolkits.mdx index ea6758aee..3ba7ed7c7 100644 --- a/docs/docs/components/toolkits.mdx +++ b/docs/docs/components/toolkits.mdx @@ -1,9 +1,11 @@ -import Admonition from '@theme/Admonition'; +import Admonition from "@theme/Admonition"; # Toolkits -

- We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝 -

-
\ No newline at end of file +

+ We appreciate your understanding as we polish our documentation - it may + contain some rough edges. Share your feedback or report issues to help us + improve! 🛠️📝 +

+ diff --git a/poetry.lock b/poetry.lock index 71be043b6..67ba34d2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -471,17 +471,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.121" +version = "1.34.122" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.121-py3-none-any.whl", hash = "sha256:4e79e400d6d44b4eee5deda6ac0ecd08a3f5a30c45a0d30712795cdc4459fd79"}, - {file = "boto3-1.34.121.tar.gz", hash = "sha256:ec89f3e0b0dc959c418df29e14d3748c0b05ab7acf7c0b90c839e9f340a659fa"}, + {file = "boto3-1.34.122-py3-none-any.whl", hash = "sha256:b2d7400ff84fa547e53b3d9acfa3c95d65d45b5886ba1ede1f7df4768d1cc0b1"}, + {file = "boto3-1.34.122.tar.gz", hash = "sha256:56840d8ce91654d182f1c113f0791fa2113c3aa43230c50b4481f235348a6037"}, ] [package.dependencies] -botocore = ">=1.34.121,<1.35.0" +botocore = ">=1.34.122,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -490,13 +490,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.121" +version = "1.34.122" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.121-py3-none-any.whl", hash = "sha256:25b05c7646a9f240cde1c8f839552a43f27e71e15c42600275dea93e219f7dd9"}, - {file = "botocore-1.34.121.tar.gz", hash = "sha256:1a8f94b917c47dfd84a0b531ab607dc53570efb0d073d8686600f2d2be985323"}, + {file = "botocore-1.34.122-py3-none-any.whl", hash = "sha256:6d75df3af831b62f0c7baa109728d987e0a8d34bfadf0476eb32e2f29a079a36"}, + {file = "botocore-1.34.122.tar.gz", hash = "sha256:9374e16a36f1062c3e27816e8599b53eba99315dfac71cc84fc3aee3f5d3cbe3"}, ] [package.dependencies] @@ -1450,13 +1450,13 @@ tests = ["pytest"] [[package]] name = "dataclasses-json" -version = "0.6.6" +version = "0.6.7" description = "Easily serialize dataclasses to and from JSON." optional = false python-versions = "<4.0,>=3.7" files = [ - {file = "dataclasses_json-0.6.6-py3-none-any.whl", hash = "sha256:e54c5c87497741ad454070ba0ed411523d46beb5da102e221efb873801b0ba85"}, - {file = "dataclasses_json-0.6.6.tar.gz", hash = "sha256:0c09827d26fffda27f1be2fed7a7a01a29c5ddcd2eb6393ad5ebf9d77e9deae8"}, + {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"}, + {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"}, ] [package.dependencies] @@ -1590,6 +1590,23 @@ files = [ [package.dependencies] packaging = "*" +[[package]] +name = "dictdiffer" +version = "0.9.0" +description = "Dictdiffer is a library that helps you to diff and patch dictionaries." +optional = false +python-versions = "*" +files = [ + {file = "dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595"}, + {file = "dictdiffer-0.9.0.tar.gz", hash = "sha256:17bacf5fbfe613ccf1b6d512bd766e6b21fb798822a133aa86098b8ac9997578"}, +] + +[package.extras] +all = ["Sphinx (>=3)", "check-manifest (>=0.42)", "mock (>=1.3.0)", "numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "sphinx-rtd-theme (>=0.2)", "tox (>=3.7.0)"] +docs = ["Sphinx (>=3)", "sphinx-rtd-theme (>=0.2)"] +numpy = ["numpy (>=1.13.0)", "numpy (>=1.15.0)", "numpy (>=1.18.0)", "numpy (>=1.20.0)"] +tests = ["check-manifest (>=0.42)", "mock (>=1.3.0)", "pytest (==5.4.3)", "pytest (>=6)", "pytest-cov (>=2.10.1)", "pytest-isort (>=1.2.0)", "pytest-pycodestyle (>=2)", "pytest-pycodestyle (>=2.2.0)", "pytest-pydocstyle (>=2)", "pytest-pydocstyle (>=2.2.0)", "sphinx (>=3)", "tox (>=3.7.0)"] + [[package]] name = "dill" version = "0.3.7" @@ -2392,8 +2409,8 @@ files = [ [package.dependencies] cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} greenlet = [ - {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, {version = ">=3.0rc3", markers = "platform_python_implementation == \"CPython\" and python_version >= \"3.11\""}, + {version = ">=2.0.0", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}, ] "zope.event" = "*" "zope.interface" = "*" @@ -2520,12 +2537,12 @@ files = [ google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = [ - {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, ] grpcio-status = [ - {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, ] proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" @@ -2594,13 +2611,13 @@ httplib2 = ">=0.19.0" [[package]] name = "google-cloud-aiplatform" -version = "1.54.0" +version = "1.54.1" description = "Vertex AI API client library" optional = false python-versions = ">=3.8" files = [ - {file = "google-cloud-aiplatform-1.54.0.tar.gz", hash = "sha256:6f5187d35a32951028465804fbb42b478362bf41e2b634ddd22b150299f6e1d8"}, - {file = "google_cloud_aiplatform-1.54.0-py2.py3-none-any.whl", hash = "sha256:7b3ed849b9fb59a01bd6f44444ccbb7d18495b867a26f913542f6b2d4c3de252"}, + {file = "google-cloud-aiplatform-1.54.1.tar.gz", hash = "sha256:01c231961cc1a1a3b049ea3ef71fb11e77b2d56d632d020ce09e419b27ff77f2"}, + {file = "google_cloud_aiplatform-1.54.1-py2.py3-none-any.whl", hash = "sha256:43f70fcd572f15317d769e5a0e04cfb7c0e259ead3fe581d2fba4f203ace5617"}, ] [package.dependencies] @@ -4291,13 +4308,13 @@ extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] [[package]] name = "langchainhub" -version = "0.1.17" +version = "0.1.18" description = "The LangChain Hub API client" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchainhub-0.1.17-py3-none-any.whl", hash = "sha256:4c609b3948252c71670f0d98f73413b515cfd2f6701a7b40ce959203e6133e04"}, - {file = "langchainhub-0.1.17.tar.gz", hash = "sha256:af7df0cb1cebc7a6e0864e8632ae48ecad39ed96568f699c78657b9d04e50b46"}, + {file = "langchainhub-0.1.18-py3-none-any.whl", hash = "sha256:11501f15e7f34715ecc8892587daa35c6f2a3005e1f2926c9bcabd31fc2c100c"}, + {file = "langchainhub-0.1.18.tar.gz", hash = "sha256:f2d0d8bf3abe4ca5e70511d8220bdc9ccea28d5267bcfd0e5ef9c53bd5bd3bad"}, ] [package.dependencies] @@ -4363,13 +4380,13 @@ url = "src/backend/base" [[package]] name = "langfuse" -version = "2.35.0" +version = "2.35.2" description = "A client library for accessing langfuse" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langfuse-2.35.0-py3-none-any.whl", hash = "sha256:e9df2474a01f8e167b7b13674c554915415b27064e48ad207054475f7fa8f82d"}, - {file = "langfuse-2.35.0.tar.gz", hash = "sha256:b1d4b478233eefbc8a6fc63ca00ca82f6afecf2b0fdc1835ca65e751cf901577"}, + {file = "langfuse-2.35.2-py3-none-any.whl", hash = "sha256:d01a23842cab484594f03878aacb9732ef8fd361158eb819c7bf43f758a0954b"}, + {file = "langfuse-2.35.2.tar.gz", hash = "sha256:32b2e6c5bc71b4efdc430c6b964ab1c1e1ba1e105a4a73912c38b3959dc4502d"}, ] [package.dependencies] @@ -4403,13 +4420,13 @@ requests = ">=2,<3" [[package]] name = "litellm" -version = "1.40.4" +version = "1.40.7" 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.40.4-py3-none-any.whl", hash = "sha256:b3b8e4401f717c3a18595446bfdb80fc6bb74974aac4eae537fb7b3be37fbf9e"}, - {file = "litellm-1.40.4.tar.gz", hash = "sha256:3edaa1189742afd7c7df2b122f77373d47154a8fb6df6187ff5875e188baa3e1"}, + {file = "litellm-1.40.7-py3-none-any.whl", hash = "sha256:c98dd8733e632aba16f14bf82e56f7159222097a6d085b242a3140b5d3e7baa4"}, + {file = "litellm-1.40.7.tar.gz", hash = "sha256:557bb19e8e484d0dfe8e4eaa9ccefc888617852988a46d6e7adc41585a2c0600"}, ] [package.dependencies] @@ -4451,13 +4468,13 @@ test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"] [[package]] name = "locust" -version = "2.28.0" +version = "2.29.0" description = "Developer-friendly load testing framework" optional = false python-versions = ">=3.9" files = [ - {file = "locust-2.28.0-py3-none-any.whl", hash = "sha256:766be879db030c0118e7d9fca712f3538c4e628bdebf59468fa1c6c2fab217d3"}, - {file = "locust-2.28.0.tar.gz", hash = "sha256:260557eec866f7e34a767b6c916b5b278167562a280480aadb88f43d962fbdeb"}, + {file = "locust-2.29.0-py3-none-any.whl", hash = "sha256:aa9d94d3604ed9f2aab3248460d91e55d3de980a821dffdf8658b439b049d03f"}, + {file = "locust-2.29.0.tar.gz", hash = "sha256:649c99ce49d00720a3084c0109547035ad9021222835386599a8b545d31ebe51"}, ] [package.dependencies] @@ -4471,7 +4488,10 @@ msgpack = ">=1.0.0" psutil = ">=5.9.1" pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" -requests = ">=2.26.0" +requests = [ + {version = ">=2.32.2", markers = "python_version > \"3.11\""}, + {version = ">=2.26.0", markers = "python_version <= \"3.11\""}, +] tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} Werkzeug = ">=2.0.0" @@ -5567,13 +5587,13 @@ sympy = "*" [[package]] name = "openai" -version = "1.32.0" +version = "1.33.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.32.0-py3-none-any.whl", hash = "sha256:953d57669f309002044fd2f678aba9f07a43256d74b3b00cd04afb5b185568ea"}, - {file = "openai-1.32.0.tar.gz", hash = "sha256:a6df15a7ab9344b1bc2bc8d83639f68b7a7e2453c0f5e50c1666547eee86f0bd"}, + {file = "openai-1.33.0-py3-none-any.whl", hash = "sha256:621163b56570897ab8389d187f686a53d4771fd6ce95d481c0a9611fe8bc4229"}, + {file = "openai-1.33.0.tar.gz", hash = "sha256:1169211a7b326ecbc821cafb427c29bfd0871f9a3e0947dd9e51acb3b0f1df78"}, ] [package.dependencies] @@ -5899,9 +5919,9 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -9025,13 +9045,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.1" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.1-py3-none-any.whl", hash = "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a"}, - {file = "typing_extensions-4.12.1.tar.gz", hash = "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -10038,4 +10058,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "2ba268be17a69253c9631ec721ece465a85a22949c2df7c712b7aa12d1a002fa" +content-hash = "0ee3f3bef82d57be2ab4ae7b70215ebca67b5bd5223e6a9322ee1837516a3cc6" diff --git a/pyproject.toml b/pyproject.toml index 84ddf1144..cf11dc07d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,6 +115,7 @@ pytest-asyncio = "^0.23.0" pytest-profiling = "^1.7.0" pre-commit = "^3.7.0" vulture = "^2.11" +dictdiffer = "^0.9.0" [tool.poetry.extras] deploy = ["celery", "redis", "flower"] diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index 0ca6b4944..004517575 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -161,7 +161,7 @@ async def build_vertex( else: graph = cache.get("result") vertex = graph.get_vertex(vertex_id) - log_object = None + try: lock = chat_service._cache_locks[flow_id_str] ( diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index b748e4955..9714e4592 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -1,4 +1,5 @@ from typing import List, Optional + from fastapi import APIRouter, Depends, HTTPException, Query from langflow.services.deps import get_monitor_service @@ -79,7 +80,7 @@ async def delete_messages( @router.post("/messages/{message_id}", response_model=MessageModelResponse) async def update_message( - message_id: str, + message_id: int, message: MessageModelRequest, monitor_service: MonitorService = Depends(get_monitor_service), ): @@ -135,3 +136,4 @@ async def get_transactions( return result except Exception as e: raise HTTPException(status_code=500, detail=str(e)) + raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/api/v1/schemas.py b/src/backend/base/langflow/api/v1/schemas.py index cb230c9f5..1e0308bd5 100644 --- a/src/backend/base/langflow/api/v1/schemas.py +++ b/src/backend/base/langflow/api/v1/schemas.py @@ -2,7 +2,6 @@ from datetime import datetime, timezone from enum import Enum from pathlib import Path from typing import Any, Dict, List, Optional, Union -from typing_extensions import TypedDict from uuid import UUID from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serializer @@ -15,7 +14,6 @@ from langflow.services.database.models.api_key.model import ApiKeyRead from langflow.services.database.models.base import orjson_dumps from langflow.services.database.models.flow import FlowCreate, FlowRead from langflow.services.database.models.user import UserRead -from langflow.utils.schemas import ChatOutputResponse class BuildStatus(Enum): @@ -244,6 +242,7 @@ class VerticesOrderResponse(BaseModel): run_id: UUID vertices_to_run: List[str] + class ResultDataResponse(BaseModel): results: Optional[Any] = Field(default_factory=dict) logs: List[Log | None] = Field(default_factory=list) diff --git a/src/backend/base/langflow/base/agents/agent.py b/src/backend/base/langflow/base/agents/agent.py index ce40f1f51..d4328032d 100644 --- a/src/backend/base/langflow/base/agents/agent.py +++ b/src/backend/base/langflow/base/agents/agent.py @@ -7,7 +7,7 @@ from langchain_core.runnables import Runnable from langflow.base.agents.utils import get_agents_list, records_to_messages from langflow.custom import CustomComponent from langflow.field_typing import Text, Tool -from langflow.schema.schema import Record +from langflow.schema import Record class LCAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/base/agents/utils.py b/src/backend/base/langflow/base/agents/utils.py index cb34d1cea..781fa2362 100644 --- a/src/backend/base/langflow/base/agents/utils.py +++ b/src/backend/base/langflow/base/agents/utils.py @@ -13,7 +13,7 @@ from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate from langchain_core.tools import BaseTool from pydantic import BaseModel -from langflow.schema.schema import Record +from langflow.schema import Record from .default_prompts import XML_AGENT_PROMPT diff --git a/src/backend/base/langflow/base/constants.py b/src/backend/base/langflow/base/constants.py index 498b46f65..cb520a835 100644 --- a/src/backend/base/langflow/base/constants.py +++ b/src/backend/base/langflow/base/constants.py @@ -7,9 +7,11 @@ Constants: - FIELD_FORMAT_ATTRIBUTES: A list of attributes used for formatting fields. """ +import orjson + STREAM_INFO_TEXT = "Stream the response from the model. Streaming works only in Chat." -NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description"] +NODE_FORMAT_ATTRIBUTES = ["beta", "icon", "display_name", "description", "output_types"] FIELD_FORMAT_ATTRIBUTES = [ @@ -27,3 +29,5 @@ FIELD_FORMAT_ATTRIBUTES = [ "refresh_button_text", "options", ] + +ORJSON_OPTIONS = orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS | orjson.OPT_OMIT_MICROSECONDS diff --git a/src/backend/base/langflow/base/curl/parse.py b/src/backend/base/langflow/base/curl/parse.py index 0503f325e..c3c2d31ce 100644 --- a/src/backend/base/langflow/base/curl/parse.py +++ b/src/backend/base/langflow/base/curl/parse.py @@ -16,7 +16,7 @@ from collections import OrderedDict, namedtuple from http.cookies import SimpleCookie ParsedArgs = namedtuple( - "ParsedContext", + "ParsedArgs", [ "command", "url", diff --git a/src/backend/base/langflow/base/data/utils.py b/src/backend/base/langflow/base/data/utils.py index e955b2e11..3779e8065 100644 --- a/src/backend/base/langflow/base/data/utils.py +++ b/src/backend/base/langflow/base/data/utils.py @@ -1,13 +1,14 @@ -import json +import unicodedata import xml.etree.ElementTree as ET from concurrent import futures from pathlib import Path from typing import Callable, List, Optional, Text -import unicodedata + import chardet +import orjson import yaml -from langflow.schema.schema import Record +from langflow.schema import Record # Types of files that can be read simply by file.read() # and have 100% to be completely readable @@ -106,7 +107,7 @@ def read_text_file(file_path: str) -> str: result = chardet.detect(raw_data) encoding = result["encoding"] - if encoding in ["Windows-1254", "MacRoman"]: + if encoding in ["Windows-1252", "Windows-1254"]: encoding = "utf-8" with open(file_path, "r", encoding=encoding) as f: @@ -139,7 +140,7 @@ def parse_text_file_to_record(file_path: str, silent_errors: bool) -> Optional[R # if file is json, yaml, or xml, we can parse it if file_path.endswith(".json"): - text = json.loads(text) + text = orjson.loads(text) if isinstance(text, dict): text = {k: normalize_text(v) if isinstance(v, str) else v for k, v in text.items()} elif isinstance(text, list): diff --git a/src/backend/base/langflow/base/flow_processing/utils.py b/src/backend/base/langflow/base/flow_processing/utils.py index 4e121f128..1f756a1db 100644 --- a/src/backend/base/langflow/base/flow_processing/utils.py +++ b/src/backend/base/langflow/base/flow_processing/utils.py @@ -1,7 +1,7 @@ from typing import List from langflow.graph.schema import ResultData, RunOutputs -from langflow.schema.schema import Record +from langflow.schema import Record def build_records_from_run_outputs(run_outputs: RunOutputs) -> List[Record]: diff --git a/src/backend/base/langflow/base/io/chat.py b/src/backend/base/langflow/base/io/chat.py index d718c7cab..fd16c1988 100644 --- a/src/backend/base/langflow/base/io/chat.py +++ b/src/backend/base/langflow/base/io/chat.py @@ -2,10 +2,9 @@ from typing import Optional, Union from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES from langflow.custom import CustomComponent -from langflow.field_typing import Text -from langflow.helpers.record import records_to_text from langflow.memory import store_message from langflow.schema import Record +from langflow.schema.message import Message class ChatComponent(CustomComponent): @@ -52,102 +51,34 @@ class ChatComponent(CustomComponent): def store_message( self, - message: Union[str, Text, Record], - session_id: Optional[str] = None, - sender: Optional[str] = None, - sender_name: Optional[str] = None, - ) -> list[Record]: - records = store_message( + message: Message, + ) -> list[Message]: + messages = store_message( message, - session_id=session_id, - sender=sender, - sender_name=sender_name, flow_id=self.graph.flow_id, ) - self.status = records - return records + self.status = messages + return messages def build_with_record( self, sender: Optional[str] = "User", sender_name: Optional[str] = "User", - input_value: Optional[Union[str, Record]] = None, + input_value: Optional[Union[str, Record, Message]] = None, files: Optional[list[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 - input_value.data["files"] = files - else: - input_value_record = Record( - text=input_value, - data={ - "sender": sender, - "sender_name": sender_name, - "session_id": session_id, - "files": files, - }, - ) - 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 + ) -> Message: + message: Message | None = None - def build_no_record( - self, - sender: Optional[str] = "User", - sender_name: Optional[str] = "User", - input_value: Optional[str] = None, - files: Optional[list[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 files and not return_record: - raise ValueError("Files can only be provided when Return Record is enabled.") - 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 - input_value.data["files"] = files - else: - input_value_record = Record( - text=input_value, - data={ - "sender": sender, - "sender_name": sender_name, - "session_id": session_id, - "files": files, - }, - ) - 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 + if isinstance(input_value, Record): + # Update the data of the record + message = Message.from_record(input_value) 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 + message = Message( + text=input_value, sender=sender, sender_name=sender_name, files=files, session_id=session_id + ) + self.status = message + if session_id and isinstance(message, Message): + self.store_message(message) + return message diff --git a/src/backend/base/langflow/base/io/text.py b/src/backend/base/langflow/base/io/text.py index 5ecfea11a..5b6ece996 100644 --- a/src/backend/base/langflow/base/io/text.py +++ b/src/backend/base/langflow/base/io/text.py @@ -3,7 +3,7 @@ from typing import Optional from langflow.custom import CustomComponent from langflow.field_typing import Text from langflow.helpers.record import records_to_text -from langflow.schema.schema import Record +from langflow.schema import Record class TextComponent(CustomComponent): diff --git a/src/backend/base/langflow/base/memory/memory.py b/src/backend/base/langflow/base/memory/memory.py index 0fb8cf209..fe372a96b 100644 --- a/src/backend/base/langflow/base/memory/memory.py +++ b/src/backend/base/langflow/base/memory/memory.py @@ -1,7 +1,7 @@ from typing import Optional from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class BaseMemoryComponent(CustomComponent): diff --git a/src/backend/base/langflow/base/models/model.py b/src/backend/base/langflow/base/models/model.py index 72f7ca0a7..74d350446 100644 --- a/src/backend/base/langflow/base/models/model.py +++ b/src/backend/base/langflow/base/models/model.py @@ -3,11 +3,10 @@ from typing import Optional, Union from langchain_core.language_models.chat_models import BaseChatModel from langchain_core.language_models.llms import LLM -from langchain_core.load import load from langchain_core.messages import AIMessage, HumanMessage, SystemMessage from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.field_typing.prompt import Prompt class LCModelComponent(CustomComponent): @@ -85,7 +84,7 @@ class LCModelComponent(CustomComponent): return status_message def get_chat_result( - self, runnable: BaseChatModel, stream: bool, input_value: str | Record, system_message: Optional[str] = None + self, runnable: BaseChatModel, stream: bool, input_value: str | Prompt, system_message: Optional[str] = None ): messages: list[Union[HumanMessage, SystemMessage]] = [] if not input_value and not system_message: @@ -93,20 +92,21 @@ class LCModelComponent(CustomComponent): if system_message: messages.append(SystemMessage(content=system_message)) if input_value: - if isinstance(input_value, Record): + if isinstance(input_value, Prompt): with warnings.catch_warnings(): warnings.simplefilter("ignore") if "prompt" in input_value: - prompt = load(input_value.prompt) + prompt = input_value.load_lc_prompt() runnable = prompt | runnable else: messages.append(input_value.to_lc_message()) else: messages.append(HumanMessage(content=input_value)) + inputs = messages or {} if stream: - return runnable.stream(messages) + return runnable.stream(inputs) else: - message = runnable.invoke(messages) + message = runnable.invoke(inputs) result = message.content if isinstance(message, AIMessage): status_message = self.build_status_message(message) diff --git a/src/backend/base/langflow/base/prompts/utils.py b/src/backend/base/langflow/base/prompts/utils.py index c4b4e08c2..0fa62ea3b 100644 --- a/src/backend/base/langflow/base/prompts/utils.py +++ b/src/backend/base/langflow/base/prompts/utils.py @@ -1,10 +1,9 @@ -import base64 from copy import deepcopy from langchain_core.documents import Document from langflow.schema import Record -from langflow.services.deps import get_storage_service +from langflow.schema.message import Message def record_to_string(record: Record) -> str: @@ -20,7 +19,7 @@ def record_to_string(record: Record) -> str: return record.get_text() -async def dict_values_to_string(d: dict) -> dict: +def dict_values_to_string(d: dict) -> dict: """ Converts the values of a dictionary to strings. @@ -36,44 +35,21 @@ async def dict_values_to_string(d: dict) -> dict: # it could be a list of records or documents or strings if isinstance(value, list): for i, item in enumerate(value): - if isinstance(item, Record): - d_copy[key][i] = item.to_lc_message() + if isinstance(item, Message): + d_copy[key][i] = item.text + elif isinstance(item, Record): + d_copy[key][i] = record_to_string(item) elif isinstance(item, Document): d_copy[key][i] = document_to_string(item) + elif isinstance(value, Message): + d_copy[key] = value.text elif isinstance(value, Record): - if "files" in value and value.files: - files = await get_file_paths(value.files) - value.files = files - d_copy[key] = value.to_lc_message() + d_copy[key] = record_to_string(value) elif isinstance(value, Document): d_copy[key] = document_to_string(value) return d_copy -async def get_file_paths(files: list[str]): - storage_service = get_storage_service() - file_paths = [] - for file in files: - flow_id, file_name = file.split("/") - file_paths.append(storage_service.build_full_path(flow_id=flow_id, file_name=file_name)) - return file_paths - - -async def get_files( - file_paths: str, - convert_to_base64: bool = False, -): - storage_service = get_storage_service() - file_objects = [] - for file_path in file_paths: - flow_id, file_name = file_path.split("/") - file_object = await storage_service.get_file(flow_id=flow_id, file_name=file_name) - if convert_to_base64: - file_object = base64.b64encode(file_object).decode("utf-8") - file_objects.append(file_object) - return file_objects - - def document_to_string(document: Document) -> str: """ Convert a document to a string. diff --git a/src/backend/base/langflow/components/agents/ToolCallingAgent.py b/src/backend/base/langflow/components/agents/ToolCallingAgent.py index b4a319e2f..91fcb1132 100644 --- a/src/backend/base/langflow/components/agents/ToolCallingAgent.py +++ b/src/backend/base/langflow/components/agents/ToolCallingAgent.py @@ -5,7 +5,7 @@ from langchain_core.prompts import ChatPromptTemplate from langflow.base.agents.agent import LCAgentComponent from langflow.field_typing import BaseLanguageModel, Text, Tool -from langflow.schema.schema import Record +from langflow.schema import Record class ToolCallingAgentComponent(LCAgentComponent): diff --git a/src/backend/base/langflow/components/agents/XMLAgent.py b/src/backend/base/langflow/components/agents/XMLAgent.py index 76f96da53..47f823ba4 100644 --- a/src/backend/base/langflow/components/agents/XMLAgent.py +++ b/src/backend/base/langflow/components/agents/XMLAgent.py @@ -3,10 +3,9 @@ from typing import List, Optional from langchain.agents import create_xml_agent from langchain_core.prompts import ChatPromptTemplate - from langflow.base.agents.agent import LCAgentComponent from langflow.field_typing import BaseLanguageModel, Text, Tool -from langflow.schema.schema import Record +from langflow.schema import Record class XMLAgentComponent(LCAgentComponent): diff --git a/src/backend/base/langflow/components/chains/RetrievalQA.py b/src/backend/base/langflow/components/chains/RetrievalQA.py index da77f89d4..ca9910279 100644 --- a/src/backend/base/langflow/components/chains/RetrievalQA.py +++ b/src/backend/base/langflow/components/chains/RetrievalQA.py @@ -5,7 +5,7 @@ from langchain_core.documents import Document from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, BaseMemory, BaseRetriever, Text -from langflow.schema.schema import Record +from langflow.schema import Record class RetrievalQAComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/data/Webhook.py b/src/backend/base/langflow/components/data/Webhook.py index cf82e07d2..a1989cd49 100644 --- a/src/backend/base/langflow/components/data/Webhook.py +++ b/src/backend/base/langflow/components/data/Webhook.py @@ -3,8 +3,8 @@ import uuid from typing import Any, Optional from langflow.custom import CustomComponent +from langflow.schema import Record from langflow.schema.dotdict import dotdict -from langflow.schema.schema import Record class WebhookComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/AgentComponent.py b/src/backend/base/langflow/components/experimental/AgentComponent.py index 9a6840a41..abd8826d4 100644 --- a/src/backend/base/langflow/components/experimental/AgentComponent.py +++ b/src/backend/base/langflow/components/experimental/AgentComponent.py @@ -6,8 +6,8 @@ from langchain_core.prompts.chat import HumanMessagePromptTemplate, SystemMessag from langflow.base.agents.agent import LCAgentComponent from langflow.base.agents.utils import AGENTS, AgentSpec, get_agents_list from langflow.field_typing import BaseLanguageModel, Text, Tool +from langflow.schema import Record from langflow.schema.dotdict import dotdict -from langflow.schema.schema import Record class AgentComponent(LCAgentComponent): diff --git a/src/backend/base/langflow/components/experimental/FlowTool.py b/src/backend/base/langflow/components/experimental/FlowTool.py index fa81f6351..eaebb0c6e 100644 --- a/src/backend/base/langflow/components/experimental/FlowTool.py +++ b/src/backend/base/langflow/components/experimental/FlowTool.py @@ -7,8 +7,8 @@ from langflow.custom import CustomComponent from langflow.field_typing import Tool from langflow.graph.graph.base import Graph from langflow.helpers.flow import get_flow_inputs +from langflow.schema import Record from langflow.schema.dotdict import dotdict -from langflow.schema.schema import Record class FlowToolComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/StoreMessage.py b/src/backend/base/langflow/components/experimental/StoreMessage.py index 761646188..19be36068 100644 --- a/src/backend/base/langflow/components/experimental/StoreMessage.py +++ b/src/backend/base/langflow/components/experimental/StoreMessage.py @@ -2,7 +2,7 @@ from typing import List, Optional from langflow.custom import CustomComponent from langflow.memory import get_messages, store_message -from langflow.schema import Record +from langflow.schema.message import Message class StoreMessageComponent(CustomComponent): @@ -31,12 +31,11 @@ class StoreMessageComponent(CustomComponent): sender_name: Optional[str] = None, session_id: Optional[str] = None, message: str = "", - ) -> List[Record]: + ) -> List[Message]: store_message( - sender=sender, - sender_name=sender_name, - session_id=session_id, - message=message, + message=Message( + text=message, sender=sender, sender_name=sender_name, flow_id=self.graph.flow_id, session_id=session_id + ) ) self.status = get_messages(session_id=session_id) diff --git a/src/backend/base/langflow/components/helpers/MemoryComponent.py b/src/backend/base/langflow/components/helpers/MemoryComponent.py index 6d19bfd59..96e82da1e 100644 --- a/src/backend/base/langflow/components/helpers/MemoryComponent.py +++ b/src/backend/base/langflow/components/helpers/MemoryComponent.py @@ -2,9 +2,9 @@ from typing import Optional from langflow.base.memory.memory import BaseMemoryComponent from langflow.field_typing import Text -from langflow.helpers.record import records_to_text +from langflow.helpers.record import messages_to_text from langflow.memory import get_messages -from langflow.schema.schema import Record +from langflow.schema.message import Message class MemoryComponent(BaseMemoryComponent): @@ -43,7 +43,7 @@ class MemoryComponent(BaseMemoryComponent): }, } - def get_messages(self, **kwargs) -> list[Record]: + def get_messages(self, **kwargs) -> list[Message]: # Validate kwargs by checking if it contains the correct keys if "sender" not in kwargs: kwargs["sender"] = None @@ -77,6 +77,6 @@ class MemoryComponent(BaseMemoryComponent): limit=n_messages, order=order, ) - messages_str = records_to_text(template=record_template or "", records=messages) + messages_str = messages_to_text(template=record_template or "", messages=messages) self.status = messages_str return messages_str diff --git a/src/backend/base/langflow/components/inputs/ChatInput.py b/src/backend/base/langflow/components/inputs/ChatInput.py index 75af91cbd..4b42e9cb0 100644 --- a/src/backend/base/langflow/components/inputs/ChatInput.py +++ b/src/backend/base/langflow/components/inputs/ChatInput.py @@ -1,8 +1,7 @@ -from typing import Optional, Union +from typing import Optional from langflow.base.io.chat import ChatComponent -from langflow.field_typing import Text -from langflow.schema import Record +from langflow.schema.message import Message class ChatInput(ChatComponent): @@ -27,13 +26,11 @@ class ChatInput(ChatComponent): input_value: Optional[str] = None, files: Optional[list[str]] = None, session_id: Optional[str] = None, - return_record: Optional[bool] = False, - ) -> Union[Text, Record]: - return super().build_no_record( + ) -> Message: + return super().build_with_record( sender=sender, sender_name=sender_name, input_value=input_value, files=files, session_id=session_id, - return_record=return_record, ) diff --git a/src/backend/base/langflow/components/inputs/Prompt.py b/src/backend/base/langflow/components/inputs/Prompt.py index f51c1aaab..e65d27576 100644 --- a/src/backend/base/langflow/components/inputs/Prompt.py +++ b/src/backend/base/langflow/components/inputs/Prompt.py @@ -1,9 +1,6 @@ -from langchain_core.prompts import ChatPromptTemplate - -from langflow.base.prompts.utils import dict_values_to_string from langflow.custom import CustomComponent -from langflow.field_typing import Prompt, TemplateField, Text -from langflow.schema.schema import Record +from langflow.field_typing import TemplateField +from langflow.field_typing.prompt import Prompt class PromptComponent(CustomComponent): @@ -21,10 +18,7 @@ class PromptComponent(CustomComponent): self, template: Prompt, **kwargs, - ) -> Record: - prompt_template = ChatPromptTemplate.from_template(Text(template)) - kwargs = await dict_values_to_string(kwargs) - messages = list(kwargs.values()) - prompt = prompt_template + messages - self.status = f'Prompt:\n"{template}"' - return Record(data={"prompt": prompt.to_json()}) + ) -> Prompt: + prompt = await Prompt.from_template_and_variables(template, kwargs) + self.status = prompt.format_text() + return prompt diff --git a/src/backend/base/langflow/components/langchain_utilities/SearchApi.py b/src/backend/base/langflow/components/langchain_utilities/SearchApi.py index 3dcd48d9f..3e6721fd6 100644 --- a/src/backend/base/langflow/components/langchain_utilities/SearchApi.py +++ b/src/backend/base/langflow/components/langchain_utilities/SearchApi.py @@ -3,7 +3,7 @@ from typing import Optional from langchain_community.utilities.searchapi import SearchApiAPIWrapper from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record from langflow.services.database.models.base import orjson_dumps diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageReader.py b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py index bbb732f16..f2e93d19d 100644 --- a/src/backend/base/langflow/components/memories/AstraDBMessageReader.py +++ b/src/backend/base/langflow/components/memories/AstraDBMessageReader.py @@ -4,7 +4,7 @@ from langchain_astradb.chat_message_histories import AstraDBChatMessageHistory from langflow.base.memory.memory import BaseMemoryComponent from langflow.field_typing import Text -from langflow.schema.schema import Record +from langflow.schema import Record class AstraDBMessageReaderComponent(BaseMemoryComponent): diff --git a/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py index 265f60cf4..a95c7a15c 100644 --- a/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py +++ b/src/backend/base/langflow/components/memories/AstraDBMessageWriter.py @@ -1,11 +1,11 @@ from typing import Optional +from langchain_astradb import AstraDBChatMessageHistory +from langchain_core.messages import BaseMessage + from langflow.base.memory.memory import BaseMemoryComponent from langflow.field_typing import Text -from langflow.schema.schema import Record - -from langchain_core.messages import BaseMessage -from langchain_astradb import AstraDBChatMessageHistory +from langflow.schema import Record class AstraDBMessageWriterComponent(BaseMemoryComponent): diff --git a/src/backend/base/langflow/components/memories/ZepMessageReader.py b/src/backend/base/langflow/components/memories/ZepMessageReader.py index 75b27091f..feef017a6 100644 --- a/src/backend/base/langflow/components/memories/ZepMessageReader.py +++ b/src/backend/base/langflow/components/memories/ZepMessageReader.py @@ -4,7 +4,7 @@ from langchain_community.chat_message_histories.zep import SearchScope, SearchTy from langflow.base.memory.memory import BaseMemoryComponent from langflow.field_typing import Text -from langflow.schema.schema import Record +from langflow.schema import Record class ZepMessageReaderComponent(BaseMemoryComponent): diff --git a/src/backend/base/langflow/components/memories/ZepMessageWriter.py b/src/backend/base/langflow/components/memories/ZepMessageWriter.py index b062f66bf..c3d55a721 100644 --- a/src/backend/base/langflow/components/memories/ZepMessageWriter.py +++ b/src/backend/base/langflow/components/memories/ZepMessageWriter.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Optional from langflow.base.memory.memory import BaseMemoryComponent from langflow.field_typing import Text -from langflow.schema.schema import Record +from langflow.schema import Record if TYPE_CHECKING: from zep_python.langchain import ZepChatMessageHistory diff --git a/src/backend/base/langflow/components/models/AmazonBedrockModel.py b/src/backend/base/langflow/components/models/AmazonBedrockModel.py index 2ab1f426e..99229deb2 100644 --- a/src/backend/base/langflow/components/models/AmazonBedrockModel.py +++ b/src/backend/base/langflow/components/models/AmazonBedrockModel.py @@ -58,7 +58,7 @@ class AmazonBedrockComponent(LCModelComponent): "advanced": True, }, "cache": {"display_name": "Cache"}, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "system_message": { "display_name": "System Message", "info": "System message to pass to the model.", diff --git a/src/backend/base/langflow/components/models/AnthropicModel.py b/src/backend/base/langflow/components/models/AnthropicModel.py index 8ea796f0d..bac7708d4 100644 --- a/src/backend/base/langflow/components/models/AnthropicModel.py +++ b/src/backend/base/langflow/components/models/AnthropicModel.py @@ -63,7 +63,7 @@ class AnthropicLLM(LCModelComponent): "info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.", }, "code": {"show": False}, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "advanced": True, diff --git a/src/backend/base/langflow/components/models/AzureOpenAIModel.py b/src/backend/base/langflow/components/models/AzureOpenAIModel.py index 54ac1ec84..97ee88920 100644 --- a/src/backend/base/langflow/components/models/AzureOpenAIModel.py +++ b/src/backend/base/langflow/components/models/AzureOpenAIModel.py @@ -78,7 +78,7 @@ class AzureChatOpenAIComponent(LCModelComponent): "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", }, "code": {"show": False}, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/BaiduQianfanChatModel.py b/src/backend/base/langflow/components/models/BaiduQianfanChatModel.py index 8ff9a424f..aaae3112f 100644 --- a/src/backend/base/langflow/components/models/BaiduQianfanChatModel.py +++ b/src/backend/base/langflow/components/models/BaiduQianfanChatModel.py @@ -81,7 +81,7 @@ class QianfanChatEndpointComponent(LCModelComponent): "info": "Endpoint of the Qianfan LLM, required if custom model used.", }, "code": {"show": False}, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py b/src/backend/base/langflow/components/models/ChatLiteLLMModel.py index 6d03f613e..aa3cf6976 100644 --- a/src/backend/base/langflow/components/models/ChatLiteLLMModel.py +++ b/src/backend/base/langflow/components/models/ChatLiteLLMModel.py @@ -111,7 +111,7 @@ class ChatLiteLLMModelComponent(LCModelComponent): "required": False, "default": False, }, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/CohereModel.py b/src/backend/base/langflow/components/models/CohereModel.py index a223a1455..b5ecbab9f 100644 --- a/src/backend/base/langflow/components/models/CohereModel.py +++ b/src/backend/base/langflow/components/models/CohereModel.py @@ -43,7 +43,7 @@ class CohereComponent(LCModelComponent): "type": "float", "show": True, }, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/HuggingFaceModel.py b/src/backend/base/langflow/components/models/HuggingFaceModel.py index 9b7949bc7..949598b2d 100644 --- a/src/backend/base/langflow/components/models/HuggingFaceModel.py +++ b/src/backend/base/langflow/components/models/HuggingFaceModel.py @@ -37,7 +37,7 @@ class HuggingFaceEndpointsComponent(LCModelComponent): "advanced": True, }, "code": {"show": False}, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/MistralModel.py b/src/backend/base/langflow/components/models/MistralModel.py index dc77655b0..75937e70d 100644 --- a/src/backend/base/langflow/components/models/MistralModel.py +++ b/src/backend/base/langflow/components/models/MistralModel.py @@ -27,7 +27,7 @@ class MistralAIModelComponent(LCModelComponent): def build_config(self): return { - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "max_tokens": { "display_name": "Max Tokens", "advanced": True, diff --git a/src/backend/base/langflow/components/models/OllamaModel.py b/src/backend/base/langflow/components/models/OllamaModel.py index a68fff9e3..cca2a0f48 100644 --- a/src/backend/base/langflow/components/models/OllamaModel.py +++ b/src/backend/base/langflow/components/models/OllamaModel.py @@ -194,7 +194,7 @@ class ChatOllamaComponent(LCModelComponent): "info": "Template to use for generating text.", "advanced": True, }, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/models/OpenAIModel.py b/src/backend/base/langflow/components/models/OpenAIModel.py index 94e0a78ee..c1aea52d4 100644 --- a/src/backend/base/langflow/components/models/OpenAIModel.py +++ b/src/backend/base/langflow/components/models/OpenAIModel.py @@ -28,7 +28,7 @@ class OpenAIModelComponent(LCModelComponent): def build_config(self): return { - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "max_tokens": { "display_name": "Max Tokens", "advanced": True, diff --git a/src/backend/base/langflow/components/models/VertexAiModel.py b/src/backend/base/langflow/components/models/VertexAiModel.py index b5af1fac2..33bbbbc46 100644 --- a/src/backend/base/langflow/components/models/VertexAiModel.py +++ b/src/backend/base/langflow/components/models/VertexAiModel.py @@ -73,7 +73,7 @@ class ChatVertexAIComponent(LCModelComponent): "value": False, "advanced": True, }, - "input_value": {"display_name": "Input", "input_types": ["Text", "Record"]}, + "input_value": {"display_name": "Input", "input_types": ["Text", "Record", "Prompt"]}, "stream": { "display_name": "Stream", "info": STREAM_INFO_TEXT, diff --git a/src/backend/base/langflow/components/outputs/ChatOutput.py b/src/backend/base/langflow/components/outputs/ChatOutput.py index 5d944853c..9a118f37e 100644 --- a/src/backend/base/langflow/components/outputs/ChatOutput.py +++ b/src/backend/base/langflow/components/outputs/ChatOutput.py @@ -1,8 +1,7 @@ -from typing import Optional, Union +from typing import Optional from langflow.base.io.chat import ChatComponent -from langflow.field_typing import Text -from langflow.schema import Record +from langflow.schema.message import Message class ChatOutput(ChatComponent): @@ -16,16 +15,12 @@ class ChatOutput(ChatComponent): sender_name: Optional[str] = "AI", input_value: Optional[str] = None, session_id: Optional[str] = None, - return_record: Optional[bool] = False, - record_template: Optional[str] = "{text}", files: Optional[list[str]] = None, - ) -> Union[Text, Record]: + ) -> Message: 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 or "", files=files, ) diff --git a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py index ee340ab26..9f60d7c88 100644 --- a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py @@ -3,7 +3,7 @@ from typing import List from langchain_text_splitters import CharacterTextSplitter from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record from langflow.utils.util import unescape_string diff --git a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py index 7ef7d5c24..a43fdcd72 100644 --- a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py @@ -3,7 +3,7 @@ from typing import List, Optional from langchain_text_splitters import Language, RecursiveCharacterTextSplitter from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class LanguageRecursiveTextSplitterComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/tools/SearchApi.py b/src/backend/base/langflow/components/tools/SearchApi.py index 3dcd48d9f..3e6721fd6 100644 --- a/src/backend/base/langflow/components/tools/SearchApi.py +++ b/src/backend/base/langflow/components/tools/SearchApi.py @@ -3,7 +3,7 @@ from typing import Optional from langchain_community.utilities.searchapi import SearchApiAPIWrapper from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record from langflow.services.database.models.base import orjson_dumps diff --git a/src/backend/base/langflow/components/vectorsearch/RedisSearch.py b/src/backend/base/langflow/components/vectorsearch/RedisSearch.py index afe653f6e..75aba7f8a 100644 --- a/src/backend/base/langflow/components/vectorsearch/RedisSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/RedisSearch.py @@ -1,10 +1,11 @@ from typing import List, Optional +from langchain_core.embeddings import Embeddings + from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.Redis import RedisComponent from langflow.field_typing import Text from langflow.schema import Record -from langchain_core.embeddings import Embeddings class RedisSearchComponent(RedisComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py b/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py index b51f65a55..b70dfa41d 100644 --- a/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/WeaviateSearch.py @@ -1,10 +1,11 @@ from typing import List, Optional +from langchain_core.embeddings import Embeddings + from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.Weaviate import WeaviateVectorStoreComponent from langflow.field_typing import Text from langflow.schema import Record -from langchain_core.embeddings import Embeddings class WeaviateSearchVectorStore(WeaviateVectorStoreComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py b/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py index c6bedfede..304439ff4 100644 --- a/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py +++ b/src/backend/base/langflow/components/vectorsearch/pgvectorSearch.py @@ -1,10 +1,11 @@ from typing import List +from langchain_core.embeddings import Embeddings + from langflow.components.vectorstores.base.model import LCVectorStoreComponent from langflow.components.vectorstores.pgvector import PGVectorComponent from langflow.field_typing import Text from langflow.schema import Record -from langchain_core.embeddings import Embeddings class PGVectorSearchComponent(PGVectorComponent, LCVectorStoreComponent): diff --git a/src/backend/base/langflow/components/vectorstores/AstraDB.py b/src/backend/base/langflow/components/vectorstores/AstraDB.py index 07ded028e..c9f7da8ee 100644 --- a/src/backend/base/langflow/components/vectorstores/AstraDB.py +++ b/src/backend/base/langflow/components/vectorstores/AstraDB.py @@ -1,11 +1,12 @@ from typing import List, Optional, Union + from langchain_astradb import AstraDBVectorStore from langchain_astradb.utils.astradb import SetupMode +from langchain_core.retrievers import BaseRetriever from langflow.custom import CustomComponent from langflow.field_typing import Embeddings, VectorStore from langflow.schema import Record -from langchain_core.retrievers import BaseRetriever class AstraDBVectorStoreComponent(CustomComponent): @@ -156,3 +157,4 @@ class AstraDBVectorStoreComponent(CustomComponent): ) return vector_store + return vector_store diff --git a/src/backend/base/langflow/components/vectorstores/Chroma.py b/src/backend/base/langflow/components/vectorstores/Chroma.py index 3671dbbdb..5742aad7b 100644 --- a/src/backend/base/langflow/components/vectorstores/Chroma.py +++ b/src/backend/base/langflow/components/vectorstores/Chroma.py @@ -8,7 +8,7 @@ from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class ChromaComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Couchbase.py b/src/backend/base/langflow/components/vectorstores/Couchbase.py index f99ac7d40..81fa0727a 100644 --- a/src/backend/base/langflow/components/vectorstores/Couchbase.py +++ b/src/backend/base/langflow/components/vectorstores/Couchbase.py @@ -1,18 +1,16 @@ -from typing import List, Optional, Union - -from langchain_community.vectorstores import CouchbaseVectorStore - -from langflow.custom import CustomComponent -from langflow.field_typing import Embeddings, VectorStore -from langflow.schema import Record - from datetime import timedelta +from typing import List, Optional, Union from couchbase.auth import PasswordAuthenticator # type: ignore from couchbase.cluster import Cluster # type: ignore from couchbase.options import ClusterOptions # type: ignore +from langchain_community.vectorstores import CouchbaseVectorStore from langchain_core.retrievers import BaseRetriever +from langflow.custom import CustomComponent +from langflow.field_typing import Embeddings, VectorStore +from langflow.schema import Record + class CouchbaseComponent(CustomComponent): display_name = "Couchbase" diff --git a/src/backend/base/langflow/components/vectorstores/FAISS.py b/src/backend/base/langflow/components/vectorstores/FAISS.py index 9d9624919..3efd5b722 100644 --- a/src/backend/base/langflow/components/vectorstores/FAISS.py +++ b/src/backend/base/langflow/components/vectorstores/FAISS.py @@ -6,7 +6,7 @@ from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.schema.schema import Record +from langflow.schema import Record class FAISSComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py b/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py index 8c045a1bd..61c4933e9 100644 --- a/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py +++ b/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py @@ -4,7 +4,7 @@ from langchain_community.vectorstores.mongodb_atlas import MongoDBAtlasVectorSea from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.schema.schema import Record +from langflow.schema import Record class MongoDBAtlasComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Pinecone.py b/src/backend/base/langflow/components/vectorstores/Pinecone.py index 2bc0e2252..135dd7501 100644 --- a/src/backend/base/langflow/components/vectorstores/Pinecone.py +++ b/src/backend/base/langflow/components/vectorstores/Pinecone.py @@ -8,7 +8,7 @@ from langchain_pinecone.vectorstores import PineconeVectorStore from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.schema.schema import Record +from langflow.schema import Record class PineconeComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Qdrant.py b/src/backend/base/langflow/components/vectorstores/Qdrant.py index 794e282db..6c1bdbcb6 100644 --- a/src/backend/base/langflow/components/vectorstores/Qdrant.py +++ b/src/backend/base/langflow/components/vectorstores/Qdrant.py @@ -6,7 +6,7 @@ from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.schema.schema import Record +from langflow.schema import Record class QdrantComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Redis.py b/src/backend/base/langflow/components/vectorstores/Redis.py index 04d137538..c35ec018e 100644 --- a/src/backend/base/langflow/components/vectorstores/Redis.py +++ b/src/backend/base/langflow/components/vectorstores/Redis.py @@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class RedisComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py b/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py index 5e87a09ca..e7c847f2b 100644 --- a/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py +++ b/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py @@ -7,7 +7,7 @@ from supabase.client import Client, create_client from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.schema.schema import Record +from langflow.schema import Record class SupabaseComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Upstash.py b/src/backend/base/langflow/components/vectorstores/Upstash.py index c066d7f44..2695abecc 100644 --- a/src/backend/base/langflow/components/vectorstores/Upstash.py +++ b/src/backend/base/langflow/components/vectorstores/Upstash.py @@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class UpstashVectorStoreComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Vectara.py b/src/backend/base/langflow/components/vectorstores/Vectara.py index 247614345..5a51b5a1b 100644 --- a/src/backend/base/langflow/components/vectorstores/Vectara.py +++ b/src/backend/base/langflow/components/vectorstores/Vectara.py @@ -9,7 +9,7 @@ from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent from langflow.field_typing import BaseRetriever -from langflow.schema.schema import Record +from langflow.schema import Record class VectaraComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Weaviate.py b/src/backend/base/langflow/components/vectorstores/Weaviate.py index e1a802000..fafa2f390 100644 --- a/src/backend/base/langflow/components/vectorstores/Weaviate.py +++ b/src/backend/base/langflow/components/vectorstores/Weaviate.py @@ -8,7 +8,7 @@ from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class WeaviateVectorStoreComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/pgvector.py b/src/backend/base/langflow/components/vectorstores/pgvector.py index 75c833ded..3ea7b6eb6 100644 --- a/src/backend/base/langflow/components/vectorstores/pgvector.py +++ b/src/backend/base/langflow/components/vectorstores/pgvector.py @@ -6,7 +6,7 @@ from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore from langflow.custom import CustomComponent -from langflow.schema.schema import Record +from langflow.schema import Record class PGVectorComponent(CustomComponent): diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py index f6b90a368..896b07337 100644 --- a/src/backend/base/langflow/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -7,6 +7,7 @@ import yaml from cachetools import TTLCache, cachedmethod from langchain_core.documents import Document from pydantic import BaseModel + from langflow.custom.code_parser.utils import ( extract_inner_type_from_generic_alias, extract_union_types_from_generic_alias, diff --git a/src/backend/base/langflow/field_typing/__init__.py b/src/backend/base/langflow/field_typing/__init__.py index 15ce03693..67dfec050 100644 --- a/src/backend/base/langflow/field_typing/__init__.py +++ b/src/backend/base/langflow/field_typing/__init__.py @@ -19,13 +19,13 @@ from .constants import ( Embeddings, NestedDict, Object, - Prompt, PromptTemplate, Text, TextSplitter, Tool, VectorStore, ) +from .prompt import Prompt from .range_spec import RangeSpec diff --git a/src/backend/base/langflow/field_typing/constants.py b/src/backend/base/langflow/field_typing/constants.py index d73257c14..807f9a77e 100644 --- a/src/backend/base/langflow/field_typing/constants.py +++ b/src/backend/base/langflow/field_typing/constants.py @@ -6,7 +6,7 @@ from langchain.memory.chat_memory import BaseChatMemory from langchain_core.document_loaders import BaseLoader from langchain_core.documents import Document from langchain_core.embeddings import Embeddings -from langchain_core.language_models import BaseLLM, BaseLanguageModel +from langchain_core.language_models import BaseLanguageModel, BaseLLM from langchain_core.memory import BaseMemory from langchain_core.output_parsers import BaseOutputParser from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate, PromptTemplate @@ -15,6 +15,8 @@ from langchain_core.tools import Tool from langchain_core.vectorstores import VectorStore from langchain_text_splitters import TextSplitter +from langflow.field_typing.prompt import Prompt + # Type alias for more complex dicts NestedDict = Dict[str, Union[str, Dict]] @@ -27,10 +29,6 @@ class Data: pass -class Prompt: - pass - - class Code: pass diff --git a/src/backend/base/langflow/field_typing/prompt.py b/src/backend/base/langflow/field_typing/prompt.py new file mode 100644 index 000000000..ef6c7ce9a --- /dev/null +++ b/src/backend/base/langflow/field_typing/prompt.py @@ -0,0 +1,41 @@ +from langchain_core.load import load +from langchain_core.messages import HumanMessage +from langchain_core.prompts import BaseChatPromptTemplate, ChatPromptTemplate, PromptTemplate + +from langflow.base.prompts.utils import dict_values_to_string +from langflow.schema.message import Message +from langflow.schema.record import Record + + +class Prompt(Record): + def load_lc_prompt(self): + if "prompt" not in self: + raise ValueError("Prompt is required.") + return load(self.prompt) + + @classmethod + def from_lc_prompt( + cls, + prompt: BaseChatPromptTemplate, + ): + prompt_json = prompt.to_json() + return cls(prompt=prompt_json) + + def format_text(self): + prompt_template = PromptTemplate.from_template(self.template) + variables_with_str_values = dict_values_to_string(self.variables) + formatted_prompt = prompt_template.format(**variables_with_str_values) + return formatted_prompt + + @classmethod + async def from_template_and_variables(cls, template: str, variables: dict): + instance = cls(template=template, variables=variables) + contents = [{"type": "text", "text": instance.format_text()}] + # Get all Message instances from the kwargs + for value in variables.values(): + if isinstance(value, Message): + content_dicts = await value.get_file_content_dicts() + contents.extend(content_dicts) + prompt_template = ChatPromptTemplate.from_messages([HumanMessage(content=contents)]) + instance.prompt = prompt_template.to_json() + return instance diff --git a/src/backend/base/langflow/graph/utils.py b/src/backend/base/langflow/graph/utils.py index fd7f1e122..06b7ca90a 100644 --- a/src/backend/base/langflow/graph/utils.py +++ b/src/backend/base/langflow/graph/utils.py @@ -2,11 +2,11 @@ from enum import Enum from typing import Any, Generator, Union from langchain_core.documents import Document -from langflow.schema.schema import Record from pydantic import BaseModel from langflow.interface.utils import extract_input_variables_from_prompt -from langflow.schema.schema import Record +from langflow.schema import Record +from langflow.schema.message import Message class UnbuiltObject: @@ -24,6 +24,7 @@ class ArtifactType(str, Enum): ARRAY = "array" STREAM = "stream" UNKNOWN = "unknown" + MESSAGE = "message" def validate_prompt(prompt: str): @@ -80,9 +81,14 @@ def get_artifact_type(custom_component, build_result) -> str: case list(): result = ArtifactType.ARRAY + case Message(): + result = ArtifactType.MESSAGE + if result == ArtifactType.UNKNOWN: if isinstance(build_result, Generator): result = ArtifactType.STREAM + elif isinstance(value, Message) and isinstance(value.text, Generator): + result = ArtifactType.STREAM return result.value diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py index a94bd7a46..86cf9cd4e 100644 --- a/src/backend/base/langflow/graph/vertex/base.py +++ b/src/backend/base/langflow/graph/vertex/base.py @@ -4,7 +4,7 @@ import inspect import os import types from enum import Enum -from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Dict, Iterator, List, Optional +from typing import TYPE_CHECKING, Any, AsyncIterator, Callable, Dict, Iterator, List, Mapping, Optional from loguru import logger @@ -373,7 +373,7 @@ class Vertex: self.load_from_db_fields = load_from_db_fields self._raw_params = params.copy() - def update_raw_params(self, new_params: Dict[str, str | list[str]], overwrite: bool = False): + def update_raw_params(self, new_params: Mapping[str, str | list[str]], overwrite: bool = False): """ Update the raw parameters of the vertex with the given new parameters. @@ -424,7 +424,7 @@ class Vertex: try: messages = [ ChatOutputResponse( - message=artifacts["message"], + message=artifacts["text"], sender=artifacts.get("sender"), sender_name=artifacts.get("sender_name"), session_id=artifacts.get("session_id"), @@ -444,7 +444,7 @@ class Vertex: # We need to set the artifacts to pass information # to the frontend self.set_artifacts() - artifacts = self.artifacts + artifacts = self.artifacts_raw if isinstance(artifacts, dict): messages = self.extract_messages_from_artifacts(artifacts) else: diff --git a/src/backend/base/langflow/graph/vertex/types.py b/src/backend/base/langflow/graph/vertex/types.py index fa527f75e..ba91a2597 100644 --- a/src/backend/base/langflow/graph/vertex/types.py +++ b/src/backend/base/langflow/graph/vertex/types.py @@ -9,6 +9,7 @@ from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, Interface from langflow.graph.utils import ArtifactType, UnbuiltObject, serialize_field from langflow.graph.vertex.base import Vertex from langflow.schema import Record +from langflow.schema.message import Message from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.monitor.utils import log_vertex_build from langflow.utils.schemas import ChatOutputResponse, RecordOutputResponse @@ -98,11 +99,13 @@ class InterfaceVertex(Vertex): # Turn the dict into a pleasing to # read JSON inside a code block message = dict_to_codeblock(self._built_object) - elif isinstance(self._built_object, Record): - message = self._built_object.text - elif isinstance(message, (AsyncIterator, Iterator)): - stream_url = self.build_stream_url() - message = "" + elif isinstance(self._built_object, Message): + if isinstance(message, (AsyncIterator, Iterator)): + stream_url = self.build_stream_url() + message = "" + self._built_object.text = message + else: + message = self._built_object.text elif not isinstance(self._built_object, str): message = str(self._built_object) # if the message is a generator or iterator diff --git a/src/backend/base/langflow/helpers/__init__.py b/src/backend/base/langflow/helpers/__init__.py index adfa72088..38b460af2 100644 --- a/src/backend/base/langflow/helpers/__init__.py +++ b/src/backend/base/langflow/helpers/__init__.py @@ -1,3 +1,3 @@ -from .record import docs_to_records, records_to_text +from .record import docs_to_records, records_to_text, messages_to_text -__all__ = ["docs_to_records", "records_to_text"] +__all__ = ["docs_to_records", "records_to_text", "messages_to_text"] diff --git a/src/backend/base/langflow/helpers/flow.py b/src/backend/base/langflow/helpers/flow.py index 16db82939..61674942a 100644 --- a/src/backend/base/langflow/helpers/flow.py +++ b/src/backend/base/langflow/helpers/flow.py @@ -6,7 +6,8 @@ from pydantic.v1 import BaseModel, Field, create_model from sqlmodel import Session, select from langflow.graph.schema import RunOutputs -from langflow.schema.schema import INPUT_FIELD_NAME, Record +from langflow.schema import Record +from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.database.models.flow import Flow from langflow.services.deps import get_session, get_settings_service, session_scope @@ -279,4 +280,4 @@ def generate_unique_flow_name(flow_name, user_id, session): # If a flow with the name already exists, append (n) to the name and increment n flow_name = f"{original_name} ({n})" - n += 1 \ No newline at end of file + n += 1 diff --git a/src/backend/base/langflow/helpers/record.py b/src/backend/base/langflow/helpers/record.py index 7c13a9ad4..88d0bcd13 100644 --- a/src/backend/base/langflow/helpers/record.py +++ b/src/backend/base/langflow/helpers/record.py @@ -1,7 +1,9 @@ from typing import Union + from langchain_core.documents import Document from langflow.schema import Record +from langflow.schema.message import Message def docs_to_records(documents: list[Document]) -> list[Record]: @@ -27,7 +29,7 @@ def records_to_text(template: str, records: Union[Record, list[Record]]) -> str: Returns: list[str]: The converted list of texts. """ - if isinstance(records, Record): + if isinstance(records, (Record)): records = [records] # Check if there are any format strings in the template _records = [] @@ -39,3 +41,27 @@ def records_to_text(template: str, records: Union[Record, list[Record]]) -> str: formated_records = [template.format(data=record.data, **record.data) for record in _records] return "\n".join(formated_records) + + +def messages_to_text(template: str, messages: Union[Message, list[Message]]) -> str: + """ + Converts a list of Messages to a list of texts. + + Args: + messages (list[Message]): The list of Messages to convert. + + Returns: + list[str]: The converted list of texts. + """ + if isinstance(messages, (Message)): + messages = [messages] + # Check if there are any format strings in the template + _messages = [] + for message in messages: + # If it is not a message, create one with the key "text" + if not isinstance(message, Message): + raise ValueError("All elements in the list must be of type Message.") + _messages.append(message) + + formated_messages = [template.format(data=message.model_dump(), **message.model_dump()) for message in _messages] + return "\n".join(formated_messages) diff --git a/src/backend/base/langflow/initial_setup/setup.py b/src/backend/base/langflow/initial_setup/setup.py index e10d55dd9..56739cd5c 100644 --- a/src/backend/base/langflow/initial_setup/setup.py +++ b/src/backend/base/langflow/initial_setup/setup.py @@ -1,3 +1,4 @@ +import json import logging import os import shutil @@ -12,17 +13,14 @@ from emoji import demojize, purely_emoji # type: ignore from loguru import logger from sqlmodel import select -from langflow.base.constants import FIELD_FORMAT_ATTRIBUTES, NODE_FORMAT_ATTRIBUTES +from langflow.base.constants import FIELD_FORMAT_ATTRIBUTES, NODE_FORMAT_ATTRIBUTES, ORJSON_OPTIONS from langflow.interface.types import get_all_components from langflow.services.auth.utils import create_super_user from langflow.services.database.models.flow.model import Flow, FlowCreate from langflow.services.database.models.folder.model import Folder, FolderCreate -from langflow.services.database.models.user.crud import get_user_by_username -from langflow.services.deps import get_settings_service, session_scope - from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist -from langflow.services.deps import get_variable_service, get_storage_service - +from langflow.services.database.models.user.crud import get_user_by_username +from langflow.services.deps import get_settings_service, get_storage_service, get_variable_service, session_scope STARTER_FOLDER_NAME = "Starter Projects" STARTER_FOLDER_DESCRIPTION = "Starter projects to help you get started in Langflow." @@ -75,10 +73,84 @@ def update_projects_components_with_latest_component_versions(project_data, all_ } ) node_data["template"][field_name][attr] = field_dict[attr] + # Remove fields that are not in the latest template + if node_data.get("display_name") != "Prompt": + for field_name in list(node_data["template"].keys()): + if field_name not in latest_template: + node_data["template"].pop(field_name) log_node_changes(node_changes_log) return project_data_copy +def update_edges_with_latest_component_versions(project_data): + edge_changes_log = defaultdict(list) + project_data_copy = deepcopy(project_data) + for edge in project_data_copy.get("edges", []): + source_handle = edge.get("data").get("sourceHandle") + target_handle = edge.get("data").get("targetHandle") + # Now find the source and target nodes in the nodes list + source_node = next( + (node for node in project_data.get("nodes", []) if node.get("id") == edge.get("source")), None + ) + target_node = next( + (node for node in project_data.get("nodes", []) if node.get("id") == edge.get("target")), None + ) + if source_node and target_node: + source_node_data = source_node.get("data").get("node") + target_node_data = target_node.get("data").get("node") + new_base_classes = source_node_data.get("base_classes") + if source_handle["baseClasses"] != new_base_classes: + edge_changes_log[source_node_data["display_name"]].append( + { + "attr": "baseClasses", + "old_value": source_handle["baseClasses"], + "new_value": new_base_classes, + } + ) + source_handle["baseClasses"] = new_base_classes + + field_name = target_handle.get("fieldName") + if field_name in target_node_data.get("template"): + if target_handle["inputTypes"] != target_node_data.get("template").get(field_name).get("input_types"): + edge_changes_log[target_node_data["display_name"]].append( + { + "attr": "inputTypes", + "old_value": target_handle["inputTypes"], + "new_value": target_node_data.get("template").get(field_name).get("input_types"), + } + ) + target_handle["inputTypes"] = target_node_data.get("template").get(field_name).get("input_types") + escaped_source_handle = escape_json_dump(source_handle) + escaped_target_handle = escape_json_dump(target_handle) + if edge["sourceHandle"] != escaped_source_handle: + edge_changes_log[source_node_data["display_name"]].append( + { + "attr": "sourceHandle", + "old_value": edge["sourceHandle"], + "new_value": escaped_source_handle, + } + ) + edge["sourceHandle"] = escaped_source_handle + if edge["targetHandle"] != escaped_target_handle: + edge_changes_log[target_node_data["display_name"]].append( + { + "attr": "targetHandle", + "old_value": edge["targetHandle"], + "new_value": escaped_target_handle, + } + ) + edge["targetHandle"] = escaped_target_handle + + else: + logger.error(f"Source or target node not found for edge: {edge}") + log_node_changes(edge_changes_log) + return project_data_copy + + +def escape_json_dump(edge_dict): + return json.dumps(edge_dict).replace('"', "œ") + + def log_node_changes(node_changes_log): # The idea here is to log the changes that were made to the nodes in debug # Something like: @@ -155,7 +227,7 @@ def get_project_data(project): def update_project_file(project_path, project, updated_project_data): project["data"] = updated_project_data with open(project_path, "w", encoding="utf-8") as f: - f.write(orjson.dumps(project, option=orjson.OPT_INDENT_2).decode()) + f.write(orjson.dumps(project, option=ORJSON_OPTIONS).decode()) logger.info(f"Updated starter project {project['name']} file") @@ -320,6 +392,7 @@ def create_or_update_starter_projects(): updated_project_data = update_projects_components_with_latest_component_versions( project_data, all_types_dict ) + updated_project_data = update_edges_with_latest_component_versions(updated_project_data) if updated_project_data != project_data: project_data = updated_project_data # We also need to update the project data in the file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json index 52bc386c8..ca22d72ed 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, world!).json @@ -1,353 +1,251 @@ { - "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-k39HS" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-njtka", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "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": "OpenAIModel-k39HS", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-k39HSœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-njtka", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-njtkaœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-uxBqP" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-k39HS", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "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": "Prompt-uxBqP", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-uxBqPœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-k39HS", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-k39HSœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Record", + "str", + "Text" + ], + "dataType": "ChatInput", + "id": "ChatInput-P3fgL" + }, + "targetHandle": { + "fieldName": "user_input", + "id": "Prompt-uxBqP", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "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œ}", + "source": "ChatInput-P3fgL", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œRecordœ, œstrœ, œTextœ], œdataTypeœ: œChatInputœ, œidœ: œChatInput-P3fgLœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-uxBqP", + "targetHandle": "{œfieldNameœ: œuser_inputœ, œidœ: œPrompt-uxBqPœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { - "id": "Prompt-uxBqP", - "type": "genericNode", - "position": { - "x": 53.588791333410654, - "y": -107.07318910019967 - }, "data": { - "type": "Prompt", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-uxBqP", "node": { + "base_classes": [ + "object", + "str", + "Text" + ], + "beta": false, + "custom_fields": { + "template": [ + "user_input" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], "template": { + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", "advanced": true, "dynamic": true, + "fileTypes": [], + "file_path": "", "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" }, "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", + "advanced": false, "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": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", "password": false, - "name": "user_input", - "display_name": "user_input", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: " + }, + "user_input": { "advanced": false, + "display_name": "user_input", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", "input_types": [ "Document", "BaseOutputParser", "Record", "Text" ], - "dynamic": false, - "info": "", + "list": false, "load_from_db": false, + "multiline": true, + "name": "user_input", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "type": "str" + "type": "str", + "value": "" } - }, - "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" + "type": "Prompt" }, - "selected": true, - "width": 384, - "height": 383, "dragging": false, + "height": 383, + "id": "Prompt-uxBqP", + "position": { + "x": 53.588791333410654, + "y": -107.07318910019967 + }, "positionAbsolute": { "x": 53.588791333410654, "y": -107.07318910019967 - } + }, + "selected": true, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIModel-k39HS", - "type": "genericNode", - "position": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, "data": { - "type": "OpenAIModel", + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "id": "OpenAIModel-k39HS", "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", "Record"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "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": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "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": "OPENAI_API_KEY" - }, - "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": false, - "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": "", + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -359,432 +257,561 @@ "system_message", "stream" ], - "beta": false + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-3.5-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "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.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "System message to pass to the model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 + } + } }, - "id": "OpenAIModel-k39HS", - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI" + "type": "OpenAIModel" }, - "selected": false, - "width": 384, + "dragging": false, "height": 563, + "id": "OpenAIModel-k39HS", + "position": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, "positionAbsolute": { "x": 634.8148772766217, "y": 27.035057029045305 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "ChatOutput-njtka", - "type": "genericNode", - "position": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, "data": { - "type": "ChatOutput", + "id": "ChatOutput-njtka", "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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" + "base_classes": [ + "Record", + "Text", + "str", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null }, "description": "Display a chat message in the Playground.", - "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 + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } }, - "id": "ChatOutput-njtka" + "type": "ChatOutput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 383, + "id": "ChatOutput-njtka", + "position": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, "positionAbsolute": { "x": 1193.250417197867, "y": 71.88476890163852 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "ChatInput-P3fgL", + "node": { + "base_classes": [ + "object", + "Record", + "str", + "Text" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Get chat inputs from the Playground.", + "display_name": "Chat Input", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatInput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n ) -> Message:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\n session_id=session_id,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "hi" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "ChatInput" + }, + "dragging": false, + "height": 375, "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 Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\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 Playground.", - "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œ}" + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -794,7 +821,8 @@ } }, "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 (Hello, World)", + "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", + "is_component": false, "last_tested_version": "1.0.0a4", - "is_component": false -} + "name": "Basic Prompting (Hello, World)" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json index ede2f4692..4069fa6bd 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Blog Writter.json @@ -1,657 +1,603 @@ { - "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "URL", + "id": "URL-HYPkR" + }, + "targetHandle": { + "fieldName": "reference_2", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-URL-HYPkR{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}-Prompt-Rse03{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "URL-HYPkR", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œURLœ, œidœ: œURL-HYPkRœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-Rse03", + "targetHandle": "{œfieldNameœ: œreference_2œ, œidœ: œPrompt-Rse03œ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-gi29P" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-JPlxl", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-gi29P{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}-ChatOutput-JPlxl{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-gi29P", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-gi29Pœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-JPlxl", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-JPlxlœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "URL", + "id": "URL-2cX90" + }, + "targetHandle": { + "fieldName": "reference_1", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-URL-2cX90{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}-Prompt-Rse03{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "URL-2cX90", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œURLœ, œidœ: œURL-2cX90œ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-Rse03", + "targetHandle": "{œfieldNameœ: œreference_1œ, œidœ: œPrompt-Rse03œ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "TextInput", + "id": "TextInput-og8Or" + }, + "targetHandle": { + "fieldName": "instructions", + "id": "Prompt-Rse03", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-TextInput-og8Or{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}-Prompt-Rse03{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "TextInput-og8Or", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œTextInputœ, œidœ: œTextInput-og8Orœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-Rse03", + "targetHandle": "{œfieldNameœ: œinstructionsœ, œidœ: œPrompt-Rse03œ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "Prompt", + "id": "Prompt-Rse03" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-gi29P", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-Rse03{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}-OpenAIModel-gi29P{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-Rse03", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-Rse03œ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-gi29P", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-gi29Pœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-Rse03", + "node": { + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, + "custom_fields": { + "template": [ + "reference_1", + "reference_2", + "instructions" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "instructions": { + "advanced": false, + "display_name": "instructions", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "instructions", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "reference_1": { + "advanced": false, + "display_name": "reference_1", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "reference_1", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "reference_2": { + "advanced": false, + "display_name": "reference_2", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "reference_2", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 571, "id": "Prompt-Rse03", - "type": "genericNode", "position": { "x": 1331.381712783371, "y": 535.0279854229713 }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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": "Reference 1:\n\n{reference_1}\n\n---\n\nReference 2:\n\n{reference_2}\n\n---\n\n{instructions}\n\nBlog: \n\n\n", - "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", - "reference_1": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_1", - "display_name": "reference_1", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "reference_2": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "reference_2", - "display_name": "reference_2", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "instructions": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "instructions", - "display_name": "instructions", - "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", "Text", "str"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["reference_1", "reference_2", "instructions"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-Rse03", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 571, - "dragging": false, "positionAbsolute": { "x": 1331.381712783371, "y": 535.0279854229713 - } + }, + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "URL-HYPkR", - "type": "genericNode", - "position": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, "data": { - "type": "URL", + "id": "URL-HYPkR", "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": [ - "https://www.promptingguide.ai/techniques/prompt_chaining" - ] - }, - "_type": "CustomComponent" - }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": ["Record"], - "display_name": "URL", - "documentation": "", + "base_classes": [ + "Record" + ], + "beta": false, "custom_fields": { "urls": null }, - "output_types": ["Record"], + "description": "Fetch content from one or more URLs.", + "display_name": "URL", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "layout-template", + "output_types": [ + "Record" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n" + }, + "urls": { + "advanced": false, + "display_name": "URL", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "urls", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": [ + "https://www.promptingguide.ai/techniques/prompt_chaining" + ] + } + } }, - "id": "URL-HYPkR" + "type": "URL" }, - "selected": false, - "width": 384, + "dragging": false, "height": 281, + "id": "URL-HYPkR", + "position": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, "positionAbsolute": { "x": 568.2971412887712, "y": 700.9983368007821 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "ChatOutput-JPlxl", + "node": { + "base_classes": [ + "Text", + "Record", + "object", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "ChatOutput" + }, + "height": 383, "id": "ChatOutput-JPlxl", - "type": "genericNode", "position": { "x": 2503.8617424688505, "y": 789.3005578928434 }, - "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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 Playground.", - "icon": "ChatOutput", - "base_classes": ["Text", "Record", "object", "str"], - "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-JPlxl" - }, "selected": false, - "width": 384, - "height": 383 + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIModel-gi29P", - "type": "genericNode", - "position": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, "data": { - "type": "OpenAIModel", + "id": "OpenAIModel-gi29P", "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", "Record"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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": "1024", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "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": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo-0125", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "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": false, - "title_case": false, - "input_types": ["Text"], - "value": "OPENAI_API_KEY" - }, - "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": false, - "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": ["str", "Text", "object"], - "display_name": "OpenAI", - "documentation": "", + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -663,315 +609,439 @@ "system_message", "stream" ], - "beta": false + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": "1024" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-3.5-turbo-0125" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "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.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "System message to pass to the model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": "0.1" + } + } }, - "id": "OpenAIModel-gi29P" + "type": "OpenAIModel" }, - "selected": false, - "width": 384, + "dragging": false, "height": 563, + "id": "OpenAIModel-gi29P", + "position": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, "positionAbsolute": { "x": 1917.7089968570963, "y": 575.9186499244129 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "URL-2cX90", + "node": { + "base_classes": [ + "Record" + ], + "beta": false, + "custom_fields": { + "urls": null + }, + "description": "Fetch content from one or more URLs.", + "display_name": "URL", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "layout-template", + "output_types": [ + "Record" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n" + }, + "urls": { + "advanced": false, + "display_name": "URL", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "urls", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": [ + "https://www.promptingguide.ai/introduction/basics" + ] + } + } + }, + "type": "URL" + }, + "dragging": false, + "height": 281, "id": "URL-2cX90", - "type": "genericNode", "position": { "x": 573.961301764604, "y": 336.41463436122086 }, - "data": { - "type": "URL", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Any, Dict\n\nfrom langchain_community.document_loaders.web_base import WebBaseLoader\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass URLComponent(CustomComponent):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"urls\": {\"display_name\": \"URL\"},\n }\n\n def build(\n self,\n urls: list[str],\n ) -> list[Record]:\n loader = WebBaseLoader(web_paths=urls)\n docs = loader.load()\n records = self.to_records(docs)\n self.status = records\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "urls": { - "type": "str", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "urls", - "display_name": "URL", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "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"], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-2cX90" - }, - "selected": false, - "width": 384, - "height": 281, "positionAbsolute": { "x": 573.961301764604, "y": 336.41463436122086 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "TextInput-og8Or", - "type": "genericNode", - "position": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, "data": { - "type": "TextInput", + "id": "TextInput-og8Or", "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 Playground.\"\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", - "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": false, - "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "_type": "CustomComponent" - }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": ["object", "Text", "str"], - "display_name": "Instructions", - "documentation": "", + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, "custom_fields": { "input_value": null, "record_template": null }, - "output_types": ["Text"], + "description": "Get text inputs from the Playground.", + "display_name": "Instructions", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "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 Playground.\"\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" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as input.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Use the references above for style to write a new blog/tutorial about prompt engineering techniques. Suggest non-covered topics." + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } }, - "id": "TextInput-og8Or" + "type": "TextInput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 289, + "id": "TextInput-og8Or", + "position": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, "positionAbsolute": { "x": 569.9387927203336, "y": 1095.3352160671316 }, - "dragging": false - } - ], - "edges": [ - { - "source": "URL-HYPkR", - "target": "Prompt-Rse03", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}", - "targetHandle": "{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-URL-HYPkR{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-HYPkRœ}-Prompt-Rse03{œfieldNameœ:œreference_2œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "reference_2", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "URL", - "id": "URL-HYPkR" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIModel-gi29P", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}", - "target": "ChatOutput-JPlxl", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-JPlxl", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-gi29P" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-gi29P{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gi29Pœ}-ChatOutput-JPlxl{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-JPlxlœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "URL-2cX90", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}", - "target": "Prompt-Rse03", - "targetHandle": "{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "reference_1", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "URL", - "id": "URL-2cX90" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-URL-2cX90{œbaseClassesœ:[œRecordœ],œdataTypeœ:œURLœ,œidœ:œURL-2cX90œ}-Prompt-Rse03{œfieldNameœ:œreference_1œ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "TextInput-og8Or", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}", - "target": "Prompt-Rse03", - "targetHandle": "{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "instructions", - "id": "Prompt-Rse03", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "TextInput", - "id": "TextInput-og8Or" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-og8Or{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-og8Orœ}-Prompt-Rse03{œfieldNameœ:œinstructionsœ,œidœ:œPrompt-Rse03œ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-Rse03", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}", - "target": "OpenAIModel-gi29P", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-gi29P", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "Prompt", - "id": "Prompt-Rse03" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-Rse03{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-Rse03œ}-OpenAIModel-gi29P{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gi29Pœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "selected": false + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -981,7 +1051,8 @@ } }, "description": "This flow can be used to create a blog post following instructions from the user, using two other blogs as reference.", - "name": "Blog Writer", + "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", + "is_component": false, "last_tested_version": "1.0.0a0", - "is_component": false -} + "name": "Blog Writer" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json index c2e2c1d70..ecbcd04d7 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Document QA.json @@ -1,161 +1,327 @@ { - "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Record", + "Text", + "object" + ], + "dataType": "ChatInput", + "id": "ChatInput-MsSJ9" + }, + "targetHandle": { + "fieldName": "Question", + "id": "Prompt-tHwPf", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-MsSJ9{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}-Prompt-tHwPf{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-MsSJ9", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œRecordœ, œTextœ, œobjectœ], œdataTypeœ: œChatInputœ, œidœ: œChatInput-MsSJ9œ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-tHwPf", + "targetHandle": "{œfieldNameœ: œQuestionœ, œidœ: œPrompt-tHwPfœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "File", + "id": "File-6TEsD" + }, + "targetHandle": { + "fieldName": "Document", + "id": "Prompt-tHwPf", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-File-6TEsD{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}-Prompt-tHwPf{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "File-6TEsD", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œFileœ, œidœ: œFile-6TEsDœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-tHwPf", + "targetHandle": "{œfieldNameœ: œDocumentœ, œidœ: œPrompt-tHwPfœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-tHwPf" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-Bt067", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-tHwPf{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}-OpenAIModel-Bt067{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-tHwPf", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-tHwPfœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-Bt067", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-Bt067œ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-Bt067" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-F5Awj", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-Bt067{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}-ChatOutput-F5Awj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-Bt067", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-Bt067œ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-F5Awj", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-F5Awjœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { + "data": { + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-tHwPf", + "node": { + "base_classes": [ + "object", + "str", + "Text" + ], + "beta": false, + "custom_fields": { + "template": [ + "Document", + "Question" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], + "template": { + "Document": { + "advanced": false, + "display_name": "Document", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "Document", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "Question": { + "advanced": false, + "display_name": "Question", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "Question", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "Answer user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 479, "id": "Prompt-tHwPf", - "type": "genericNode", "position": { "x": 585.7906101139403, "y": 117.52115876762832 }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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 user's questions based on the document below:\n\n---\n\n{Document}\n\n---\n\nQuestion:\n{Question}\n\nAnswer:\n", - "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", - "Document": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Document", - "display_name": "Document", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "Question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "Question", - "display_name": "Question", - "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": ["Document", "Question"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-tHwPf", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 479, "positionAbsolute": { "x": 585.7906101139403, "y": 117.52115876762832 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "File-6TEsD", - "type": "genericNode", - "position": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, "data": { - "type": "File", + "id": "File-6TEsD", "node": { + "base_classes": [ + "Record" + ], + "beta": false, + "custom_fields": { + "path": null, + "silent_errors": null + }, + "description": "A generic file loader.", + "display_name": "Files", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "output_types": [ + "Record" + ], "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, "show": true, - "multiline": false, + "title_case": false, + "type": "code", + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n" + }, + "path": { + "advanced": false, + "display_name": "Path", + "dynamic": false, "fileTypes": [ ".txt", ".md", @@ -170,633 +336,395 @@ ".pdf", ".docx" ], - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx", + "list": false, "load_from_db": false, + "multiline": false, + "name": "path", + "password": false, + "placeholder": "", + "required": true, + "show": true, "title_case": false, + "type": "file", "value": "" }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"Files\"\n description = \"A generic file loader.\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, + "advanced": true, + "display_name": "Silent Errors", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, "info": "If true, errors will not raise an exception.", + "list": false, "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "A generic file loader.", - "base_classes": ["Record"], - "display_name": "Files", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false + "multiline": false, + "name": "silent_errors", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + } + } }, - "id": "File-6TEsD" + "type": "File" }, - "selected": false, - "width": 384, + "dragging": false, "height": 282, + "id": "File-6TEsD", + "position": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, "positionAbsolute": { "x": -18.636536329280602, "y": 3.951948774836353 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "ChatInput-MsSJ9", - "type": "genericNode", - "position": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, "data": { - "type": "ChatInput", + "id": "ChatInput-MsSJ9", "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 Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\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": "" - }, - "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" + "base_classes": [ + "str", + "Record", + "Text", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null }, "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["str", "Record", "Text", "object"], "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 + "frozen": false, + "icon": "ChatInput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n ) -> Message:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\n session_id=session_id,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } }, - "id": "ChatInput-MsSJ9" + "type": "ChatInput" }, - "selected": true, - "width": 384, + "dragging": false, "height": 377, + "id": "ChatInput-MsSJ9", + "position": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, "positionAbsolute": { "x": -28.80036300619821, "y": 379.81180230285355 }, - "dragging": false + "selected": true, + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "ChatOutput-F5Awj", + "node": { + "base_classes": [ + "str", + "Record", + "Text", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "ChatOutput" + }, + "dragging": false, + "height": 385, "id": "ChatOutput-F5Awj", - "type": "genericNode", "position": { "x": 1733.3012915204283, "y": 168.76098809939327 }, - "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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 - }, - "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 Playground.", - "icon": "ChatOutput", - "base_classes": ["str", "Record", "Text", "object"], - "display_name": "Chat Output", - "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": "ChatOutput-F5Awj" - }, - "selected": false, - "width": 384, - "height": 385, "positionAbsolute": { "x": 1733.3012915204283, "y": 168.76098809939327 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIModel-Bt067", - "type": "genericNode", - "position": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, "data": { - "type": "OpenAIModel", + "id": "OpenAIModel-Bt067", "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", "Record"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "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": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "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": false, - "title_case": false, - "input_types": ["Text"], - "value": "OPENAI_API_KEY" - }, - "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": false, - "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": false, - "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", "str", "Text"], - "display_name": "OpenAI", - "documentation": "", + "base_classes": [ + "object", + "str", + "Text" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -808,116 +736,247 @@ "system_message", "stream" ], - "beta": false + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-4-turbo-preview" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "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.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "stream": { + "advanced": false, + "display_name": "Stream", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "System message to pass to the model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 + } + } }, - "id": "OpenAIModel-Bt067" + "type": "OpenAIModel" }, - "selected": false, - "width": 384, + "dragging": false, "height": 642, + "id": "OpenAIModel-Bt067", + "position": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, "positionAbsolute": { "x": 1137.6078582863759, "y": -14.41920034020356 }, - "dragging": false - } - ], - "edges": [ - { - "source": "ChatInput-MsSJ9", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}", - "target": "Prompt-tHwPf", - "targetHandle": "{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "Question", - "id": "Prompt-tHwPf", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Record", "Text", "object"], - "dataType": "ChatInput", - "id": "ChatInput-MsSJ9" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-MsSJ9{œbaseClassesœ:[œstrœ,œRecordœ,œTextœ,œobjectœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-MsSJ9œ}-Prompt-tHwPf{œfieldNameœ:œQuestionœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "File-6TEsD", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}", - "target": "Prompt-tHwPf", - "targetHandle": "{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "Document", - "id": "Prompt-tHwPf", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "File", - "id": "File-6TEsD" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-File-6TEsD{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-6TEsDœ}-Prompt-tHwPf{œfieldNameœ:œDocumentœ,œidœ:œPrompt-tHwPfœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-tHwPf", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}", - "target": "OpenAIModel-Bt067", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-Bt067", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-tHwPf" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-tHwPf{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-tHwPfœ}-OpenAIModel-Bt067{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Bt067œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-Bt067", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}", - "target": "ChatOutput-F5Awj", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-F5Awj", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-Bt067" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-Bt067{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Bt067œ}-ChatOutput-F5Awj{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-F5Awjœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -927,7 +986,8 @@ } }, "description": "This flow integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", - "name": "Document QA", + "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", + "is_component": false, "last_tested_version": "1.0.0a0", - "is_component": false -} + "name": "Document QA" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json index 5d9004316..c23f7b08c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Memory Conversation.json @@ -1,883 +1,863 @@ { - "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", - "icon": "🤖", - "icon_bg_color": "#FFD700", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + }, + "targetHandle": { + "fieldName": "context", + "id": "Prompt-ODkUx", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-Prompt-ODkUx{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œMemoryComponentœ, œidœ: œMemoryComponent-cdA1Jœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-ODkUx", + "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-ODkUxœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Text", + "object", + "Record", + "str" + ], + "dataType": "ChatInput", + "id": "ChatInput-t7F8v" + }, + "targetHandle": { + "fieldName": "user_message", + "id": "Prompt-ODkUx", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-t7F8v{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}-Prompt-ODkUx{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-t7F8v", + "sourceHandle": "{œbaseClassesœ: [œTextœ, œobjectœ, œRecordœ, œstrœ], œdataTypeœ: œChatInputœ, œidœ: œChatInput-t7F8vœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-ODkUx", + "targetHandle": "{œfieldNameœ: œuser_messageœ, œidœ: œPrompt-ODkUxœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object" + ], + "dataType": "Prompt", + "id": "Prompt-ODkUx" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-9RykF", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-ODkUx{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}-OpenAIModel-9RykF{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-ODkUx", + "sourceHandle": "{œbaseClassesœ: [œTextœ, œstrœ, œobjectœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-ODkUxœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-9RykF", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-9RykFœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "object", + "Text" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-9RykF" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-P1jEe", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-9RykF{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}-ChatOutput-P1jEe{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-9RykF", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œobjectœ, œTextœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-9RykFœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-P1jEe", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-P1jEeœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-foreground stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "MemoryComponent", + "id": "MemoryComponent-cdA1J" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-vrs6T", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-TextOutput-vrs6T{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œMemoryComponentœ, œidœ: œMemoryComponent-cdA1Jœ}", + "style": { + "stroke": "#555" + }, + "target": "TextOutput-vrs6T", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-vrs6Tœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { - "id": "ChatInput-t7F8v", - "type": "genericNode", - "position": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, "data": { - "type": "ChatInput", + "id": "ChatInput-t7F8v", "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 Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\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": "" - }, - "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": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "MySessionID" - }, - "_type": "CustomComponent" + "base_classes": [ + "Text", + "object", + "Record", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null }, "description": "Get chat inputs from the Playground.", - "icon": "ChatInput", - "base_classes": ["Text", "object", "Record", "str"], "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 + "frozen": false, + "icon": "ChatInput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n ) -> Message:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\n session_id=session_id,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": false, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "MySessionID" + } + } }, - "id": "ChatInput-t7F8v" + "type": "ChatInput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 469, + "id": "ChatInput-t7F8v", + "position": { + "x": 1283.2700598313072, + "y": 982.5953650473145 + }, "positionAbsolute": { "x": 1283.2700598313072, "y": 982.5953650473145 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "ChatOutput-P1jEe", - "type": "genericNode", - "position": { - "x": 3154.916355514023, - "y": 851.051882666333 - }, "data": { - "type": "ChatOutput", + "id": "ChatOutput-P1jEe", "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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 - }, - "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": false, - "dynamic": false, - "info": "If provided, the message will be stored in the memory.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "MySessionID" - }, - "_type": "CustomComponent" + "base_classes": [ + "Text", + "object", + "Record", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null }, "description": "Display a chat message in the Playground.", - "icon": "ChatOutput", - "base_classes": ["Text", "object", "Record", "str"], "display_name": "Chat Output", "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 + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": false, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "MySessionID" + } + } }, - "id": "ChatOutput-P1jEe" + "type": "ChatOutput" }, - "selected": false, - "width": 384, - "height": 477, "dragging": false, + "height": 477, + "id": "ChatOutput-P1jEe", + "position": { + "x": 3154.916355514023, + "y": 851.051882666333 + }, "positionAbsolute": { "x": 3154.916355514023, "y": 851.051882666333 - } + }, + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "MemoryComponent-cdA1J", - "type": "genericNode", - "position": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - }, "data": { - "type": "MemoryComponent", + "description": "Retrieves stored chat messages given a specific Session ID.", + "display_name": "Chat Memory", + "id": "MemoryComponent-cdA1J", "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\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 get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "n_messages": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 5, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "n_messages", - "display_name": "Number of Messages", - "advanced": false, - "dynamic": false, - "info": "Number of messages to retrieve.", - "load_from_db": false, - "title_case": false - }, - "order": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Descending", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Ascending", "Descending"], - "name": "order", - "display_name": "Order", - "advanced": true, - "dynamic": false, - "info": "Order of the messages.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "{sender_name}: {text}", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "sender": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Machine and User", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Machine", "User", "Machine and User"], - "name": "sender", - "display_name": "Sender Type", - "advanced": false, - "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, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "sender_name", - "display_name": "Sender Name", - "advanced": true, - "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": false, - "input_types": ["Text"], - "dynamic": false, - "info": "Session ID of the chat history.", - "load_from_db": false, - "title_case": false, - "value": "MySessionID" - }, - "_type": "CustomComponent" - }, - "description": "Retrieves stored chat messages given a specific Session ID.", - "icon": "history", - "base_classes": ["str", "Text", "object"], - "display_name": "Chat Memory", - "documentation": "", + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": true, "custom_fields": { - "sender": null, - "sender_name": null, - "session_id": null, "n_messages": null, "order": null, - "record_template": null + "record_template": null, + "sender": null, + "sender_name": null, + "session_id": null }, - "output_types": ["Text"], + "description": "Retrieves stored chat messages given a specific Session ID.", + "display_name": "Chat Memory", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": true + "frozen": false, + "icon": "history", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import messages_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.message import Message\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\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 get_messages(self, **kwargs) -> list[Message]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = messages_to_text(template=record_template or \"\", messages=messages)\n self.status = messages_str\n return messages_str\n" + }, + "n_messages": { + "advanced": false, + "display_name": "Number of Messages", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Number of messages to retrieve.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "n_messages", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 5 + }, + "order": { + "advanced": true, + "display_name": "Order", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Order of the messages.", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "order", + "options": [ + "Ascending", + "Descending" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Descending" + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "{sender_name}: {text}" + }, + "sender": { + "advanced": false, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User", + "Machine and User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine and User" + }, + "sender_name": { + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "session_id": { + "advanced": false, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Session ID of the chat history.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "MySessionID" + } + } }, - "id": "MemoryComponent-cdA1J", - "description": "Retrieves stored chat messages given a specific Session ID.", - "display_name": "Chat Memory" + "type": "MemoryComponent" }, - "selected": false, - "width": 384, - "height": 489, "dragging": false, + "height": 489, + "id": "MemoryComponent-cdA1J", + "position": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + }, "positionAbsolute": { "x": 1289.9606870058817, "y": 442.16804561053766 - } + }, + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "description": "A component for creating prompt templates using dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-ODkUx", + "node": { + "base_classes": [ + "Text", + "str", + "object" + ], + "beta": false, + "custom_fields": { + "template": [ + "context", + "user_message" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "context": { + "advanced": false, + "display_name": "context", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "context", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "{context}\n\nUser: {user_message}\nAI: " + }, + "user_message": { + "advanced": false, + "display_name": "user_message", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "user_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 477, "id": "Prompt-ODkUx", - "type": "genericNode", "position": { "x": 1894.594426342426, "y": 753.3797365481901 }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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": "{context}\n\nUser: {user_message}\nAI: ", - "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", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - }, - "user_message": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_message", - "display_name": "user_message", - "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": ["Text", "str", "object"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["context", "user_message"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-ODkUx", - "description": "A component for creating prompt templates using dynamic variables.", - "display_name": "Prompt" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, "positionAbsolute": { "x": 1894.594426342426, "y": 753.3797365481901 - } + }, + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIModel-9RykF", - "type": "genericNode", - "position": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, "data": { - "type": "OpenAIModel", + "id": "OpenAIModel-9RykF", "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", "Record"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "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": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-1106-preview", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "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": false, - "title_case": false, - "input_types": ["Text"], - "value": "OPENAI_API_KEY" - }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "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": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.2", - "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": ["str", "object", "Text"], - "display_name": "OpenAI", - "documentation": "", + "base_classes": [ + "str", + "object", + "Text" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -889,239 +869,355 @@ "system_message", "stream" ], - "beta": false + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-4-1106-preview" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "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.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "System message to pass to the model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": "0.2" + } + } }, - "id": "OpenAIModel-9RykF" + "type": "OpenAIModel" }, - "selected": false, - "width": 384, + "dragging": false, "height": 563, + "id": "OpenAIModel-9RykF", + "position": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, "positionAbsolute": { "x": 2561.5850334731617, "y": 553.2745131130916 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "TextOutput-vrs6T", - "type": "genericNode", - "position": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, "data": { - "type": "TextOutput", + "id": "TextOutput-vrs6T", "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "object", "Text"], - "display_name": "Inspect Memory", - "documentation": "", + "base_classes": [ + "str", + "object", + "Text" + ], + "beta": false, "custom_fields": { "input_value": null, "record_template": null }, - "output_types": ["Text"], + "description": "Display a text output in the Playground.", + "display_name": "Inspect Memory", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as output.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } }, - "id": "TextOutput-vrs6T" + "type": "TextOutput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 289, + "id": "TextOutput-vrs6T", + "position": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, "positionAbsolute": { "x": 1911.4785906252087, "y": 247.39079954376987 }, - "dragging": false - } - ], - "edges": [ - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}", - "target": "Prompt-ODkUx", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "context", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-Prompt-ODkUx{œfieldNameœ:œcontextœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "selected": false - }, - { - "source": "ChatInput-t7F8v", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}", - "target": "Prompt-ODkUx", - "targetHandle": "{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "user_message", - "type": "str", - "id": "Prompt-ODkUx", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"] - }, - "sourceHandle": { - "baseClasses": ["Text", "object", "Record", "str"], - "dataType": "ChatInput", - "id": "ChatInput-t7F8v" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-t7F8v{œbaseClassesœ:[œTextœ,œobjectœ,œRecordœ,œstrœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-t7F8vœ}-Prompt-ODkUx{œfieldNameœ:œuser_messageœ,œidœ:œPrompt-ODkUxœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "selected": false - }, - { - "source": "Prompt-ODkUx", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}", - "target": "OpenAIModel-9RykF", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-9RykF", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object"], - "dataType": "Prompt", - "id": "Prompt-ODkUx" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-ODkUx{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-ODkUxœ}-OpenAIModel-9RykF{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-9RykFœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-9RykF", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}", - "target": "ChatOutput-P1jEe", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-P1jEe", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "object", "Text"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-9RykF" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-9RykF{œbaseClassesœ:[œstrœ,œobjectœ,œTextœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9RykFœ}-ChatOutput-P1jEe{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-P1jEeœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}", - "target": "TextOutput-vrs6T", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-vrs6T", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "MemoryComponent", - "id": "MemoryComponent-cdA1J" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-foreground stroke-connection", - "id": "reactflow__edge-MemoryComponent-cdA1J{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œMemoryComponentœ,œidœ:œMemoryComponent-cdA1Jœ}-TextOutput-vrs6T{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-vrs6Tœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -1131,7 +1227,10 @@ } }, "description": "This project can be used as a starting point for building a Chat experience with user specific memory. You can set a different Session ID to start a new message history.", - "name": "Memory Chatbot", + "icon": "🤖", + "icon_bg_color": "#FFD700", + "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", + "is_component": false, "last_tested_version": "1.0.0a0", - "is_component": false -} + "name": "Memory Chatbot" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json index 62bcf2c70..e43723236 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Langflow Prompt Chaining.json @@ -1,863 +1,1155 @@ { - "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "TextInput", + "id": "TextInput-sptaH" + }, + "targetHandle": { + "fieldName": "document", + "id": "Prompt-amqBu", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-TextInput-sptaH{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}-Prompt-amqBu{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "TextInput-sptaH", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œTextInputœ, œidœ: œTextInput-sptaHœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-amqBu", + "targetHandle": "{œfieldNameœ: œdocumentœ, œidœ: œPrompt-amqBuœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-amqBu" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-2MS4a", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-TextOutput-2MS4a{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-amqBu", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-amqBuœ}", + "style": { + "stroke": "#555" + }, + "target": "TextOutput-2MS4a", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-2MS4aœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-amqBu" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-uYXZJ", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-OpenAIModel-uYXZJ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-amqBu", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-amqBuœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-uYXZJ", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-uYXZJœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + }, + "targetHandle": { + "fieldName": "summary", + "id": "Prompt-gTNiz", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-Prompt-gTNiz{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uYXZJœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-gTNiz", + "targetHandle": "{œfieldNameœ: œsummaryœ, œidœ: œPrompt-gTNizœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-uYXZJ" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-EJkG3", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-ChatOutput-EJkG3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uYXZJœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-EJkG3", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-EJkG3œ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-MUDOR", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-TextOutput-MUDOR{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-gTNiz", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-gTNizœ}", + "style": { + "stroke": "#555" + }, + "target": "TextOutput-MUDOR", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-MUDORœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "str", + "Text" + ], + "dataType": "Prompt", + "id": "Prompt-gTNiz" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-XawYB", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-OpenAIModel-XawYB{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "Prompt-gTNiz", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œstrœ, œTextœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-gTNizœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-XawYB", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-XawYBœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "str", + "Text", + "object" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-XawYB" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-DNmvg", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-XawYB{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}-ChatOutput-DNmvg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "OpenAIModel-XawYB", + "sourceHandle": "{œbaseClassesœ: [œstrœ, œTextœ, œobjectœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-XawYBœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-DNmvg", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-DNmvgœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { - "id": "Prompt-amqBu", - "type": "genericNode", - "position": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, "data": { - "type": "Prompt", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-amqBu", "node": { + "base_classes": [ + "object", + "str", + "Text" + ], + "beta": false, + "custom_fields": { + "template": [ + "document" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], "template": { + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n", "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", - "document": { - "field_type": "str", - "required": false, - "placeholder": "", "list": false, - "show": true, + "load_from_db": false, "multiline": true, - "value": "", + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "document": { + "advanced": false, + "display_name": "document", + "dynamic": false, + "field_type": "str", "fileTypes": [], "file_path": "", - "password": false, - "name": "document", - "display_name": "document", - "advanced": false, + "info": "", "input_types": [ "Document", "BaseOutputParser", "Record", "Text" ], - "dynamic": false, - "info": "", + "list": false, "load_from_db": false, + "multiline": true, + "name": "document", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "type": "str" + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "You are a helpful assistant. Given a long document, your task is to create a concise summary that captures the main points and key details. The summary should be clear, accurate, and succinct. Please provide the summary in the format below:\n####\n{document}\n####\n" } - }, - "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": ["document"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null + } }, - "id": "Prompt-amqBu", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" + "type": "Prompt" }, - "selected": false, - "width": 384, + "dragging": false, "height": 385, + "id": "Prompt-amqBu", + "position": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 + }, "positionAbsolute": { "x": 2191.5837146441663, "y": 1047.9307944451873 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-gTNiz", + "node": { + "base_classes": [ + "object", + "str", + "Text" + ], + "beta": false, + "custom_fields": { + "template": [ + "summary" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "summary": { + "advanced": false, + "display_name": "summary", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "summary", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####" + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 385, "id": "Prompt-gTNiz", - "type": "genericNode", "position": { "x": 3731.0813766902447, "y": 799.631909121391 }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { "data": { - "type": "Prompt", + "id": "ChatOutput-EJkG3", "node": { + "base_classes": [ + "object", + "Record", + "Text", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], "template": { + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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": "Given a summary of an article, please create two multiple-choice questions that cover the key points and details mentioned. Ensure the questions are clear and provide three options (A, B, C), with one correct answer.\n####\n{summary}\n####", "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", - "summary": { - "field_type": "str", - "required": false, - "placeholder": "", "list": false, - "show": true, + "load_from_db": false, "multiline": true, - "value": "", + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "summary", - "display_name": "summary", - "advanced": false, + "info": "", "input_types": [ - "Document", - "BaseOutputParser", - "Record", "Text" ], - "dynamic": false, - "info": "", + "list": false, "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Summarizer" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, "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": ["summary"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null + } }, - "id": "Prompt-gTNiz", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" + "type": "ChatOutput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 385, - "dragging": false - }, - { "id": "ChatOutput-EJkG3", - "type": "genericNode", "position": { "x": 3722.1747844849388, "y": 1283.413553222214 }, - "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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": "Summarizer", - "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 Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Record", "Text", "str"], - "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-EJkG3" - }, "selected": false, - "width": 384, - "height": 385, - "dragging": false + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "ChatOutput-DNmvg", + "node": { + "base_classes": [ + "object", + "Record", + "Text", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Question Generator" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "ChatOutput" + }, + "height": 385, "id": "ChatOutput-DNmvg", - "type": "genericNode", "position": { "x": 5077.71285886074, "y": 1232.9152769735522 }, - "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\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": "Question Generator", - "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 Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Record", "Text", "str"], - "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-DNmvg" - }, "selected": false, - "width": 384, - "height": 385 + "type": "genericNode", + "width": 384 }, { - "id": "TextInput-sptaH", - "type": "genericNode", - "position": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, "data": { - "type": "TextInput", + "id": "TextInput-sptaH", "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 Playground.\"\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, - "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": false, - "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology.", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as input.", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "_type": "CustomComponent" + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null }, "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], "display_name": "Text Input", "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "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 Playground.\"\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" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as input.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Revolutionary Nano-Battery Technology Unveiled In a groundbreaking announcement yesterday, researchers from the fictional Tech Innovations Institute revealed the development of a new nano-battery technology that promises to revolutionize energy storage. The new battery, dubbed the \"EnerGCell\", uses advanced nanomaterials to achieve unprecedented efficiency and storage capacities. According to lead researcher Dr. Ada Byron, the EnerGCell can store up to ten times more energy than the best lithium-ion batteries available today, while charging in just a fraction of the time. \"We're talking about charging your electric vehicle in just five minutes for a range of over 1,000 miles,\" Dr. Byron stated during the press conference. The technology behind the EnerGCell involves a complex arrangement of nanostructured electrodes that allow for rapid ion transfer and extremely high energy density. This breakthrough was achieved after a decade of research into nanomaterials and their applications in energy storage. The implications of this technology are vast, promising to accelerate the adoption of renewable energy by making it more practical and affordable to store wind and solar power. It could also lead to significant advancements in electric vehicles, mobile devices, and any other technology that relies on batteries. Despite the excitement, some experts are calling for patience, noting that the EnerGCell is still in its early stages of development and may take several years before it's commercially available. However, the potential impact of such a technology on the environment and the global economy is undeniable. Tech Innovations Institute plans to continue refining the EnerGCell and begin pilot projects with select partners in the coming year. If successful, this nano-battery technology could indeed be the breakthrough needed to usher in a new era of clean energy and technology." + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } }, - "id": "TextInput-sptaH" + "type": "TextInput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 290, + "id": "TextInput-sptaH", + "position": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, "positionAbsolute": { "x": 1700.5624822024752, "y": 1039.603088937466 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "TextOutput-2MS4a", - "type": "genericNode", - "position": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, "data": { - "type": "TextOutput", + "id": "TextOutput-2MS4a", "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], - "display_name": "First Prompt", - "documentation": "", + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, "custom_fields": { "input_value": null, "record_template": null }, - "output_types": ["Text"], + "description": "Display a text output in the Playground.", + "display_name": "First Prompt", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as output.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } }, - "id": "TextOutput-2MS4a" + "type": "TextOutput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 290, + "id": "TextOutput-2MS4a", + "position": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, "positionAbsolute": { "x": 2917.216113690115, "y": 513.0058511435552 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIModel-uYXZJ", - "type": "genericNode", - "position": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, "data": { - "type": "OpenAIModel", + "id": "OpenAIModel-uYXZJ", "node": { + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "max_tokens": null, + "model_kwargs": null, + "model_name": null, + "openai_api_base": null, + "openai_api_key": null, + "stream": null, + "system_message": null, + "temperature": null + }, + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", + "field_formatters": {}, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], "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", "Record"] - }, + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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, + "fileTypes": [], + "file_path": "", "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" }, "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 }, "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} }, "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", + "advanced": false, + "display_name": "Model Name", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", "options": [ "gpt-4o", "gpt-4-turbo", @@ -865,138 +1157,274 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-0125" ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str", + "value": "gpt-4-turbo-preview" }, "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": 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.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": 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": false, + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "OPENAI_API_KEY" }, "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, + "advanced": true, + "display_name": "Stream", + "dynamic": false, "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.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false }, "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "System Message", + "dynamic": 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.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "temperature": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, + "advanced": false, + "display_name": "Temperature", + "dynamic": false, "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 - }, + "list": false, "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "Text", "object"], - "display_name": "OpenAI", - "documentation": "", + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 + } + } + }, + "type": "OpenAIModel" + }, + "dragging": false, + "height": 565, + "id": "OpenAIModel-uYXZJ", + "position": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "positionAbsolute": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "TextOutput-MUDOR", + "node": { + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null + }, + "description": "Display a text output in the Playground.", + "display_name": "Second Prompt", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as output.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + } + } + }, + "type": "TextOutput" + }, + "dragging": false, + "height": 290, + "id": "TextOutput-MUDOR", + "position": { + "x": 4446.064323520379, + "y": 633.833297518702 + }, + "positionAbsolute": { + "x": 4446.064323520379, + "y": 633.833297518702 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIModel-XawYB", + "node": { + "base_classes": [ + "str", + "Text", + "object" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -1008,213 +1436,106 @@ "system_message", "stream" ], - "beta": false - }, - "id": "OpenAIModel-uYXZJ" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "dragging": false - }, - { - "id": "TextOutput-MUDOR", - "type": "genericNode", - "position": { - "x": 4446.064323520379, - "y": 633.833297518702 - }, - "data": { - "type": "TextOutput", - "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "record_template": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "record_template", - "display_name": "Record Template", - "advanced": true, - "dynamic": false, - "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"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "Text", "object"], - "display_name": "Second Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-MUDOR" - }, - "selected": false, - "width": 384, - "height": 290, - "dragging": false, - "positionAbsolute": { - "x": 4446.064323520379, - "y": 633.833297518702 - } - }, - { - "id": "OpenAIModel-XawYB", - "type": "genericNode", - "position": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "data": { - "type": "OpenAIModel", - "node": { + "icon": "OpenAI", + "output_types": [ + "Text" + ], "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", "Record"] - }, + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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, + "fileTypes": [], + "file_path": "", "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" }, "max_tokens": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 256, + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "max_tokens", - "display_name": "Max Tokens", - "advanced": true, - "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 }, "model_kwargs": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "model_kwargs", - "display_name": "Model Kwargs", - "advanced": true, - "dynamic": false, "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} }, "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-4-turbo-preview", + "advanced": false, + "display_name": "Model Name", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", "options": [ "gpt-4o", "gpt-4-turbo", @@ -1222,355 +1543,140 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-0125" ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str", + "value": "gpt-4-turbo-preview" }, "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": 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.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": 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.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "" }, "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, + "advanced": true, + "display_name": "Stream", + "dynamic": false, "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.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false }, "system_message": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "System Message", + "dynamic": 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.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "temperature": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, + "advanced": false, + "display_name": "Temperature", + "dynamic": false, "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 - }, + "list": false, "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "Text", "object"], - "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 + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 + } + } }, - "id": "OpenAIModel-XawYB" + "type": "OpenAIModel" }, - "selected": false, - "width": 384, + "dragging": false, "height": 565, + "id": "OpenAIModel-XawYB", + "position": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, "positionAbsolute": { "x": 4500.152018344182, "y": 1027.7382026227656 }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextInput-sptaH", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}", - "target": "Prompt-amqBu", - "targetHandle": "{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "document", - "id": "Prompt-amqBu", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "TextInput", - "id": "TextInput-sptaH" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-TextInput-sptaH{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œTextInputœ,œidœ:œTextInput-sptaHœ}-Prompt-amqBu{œfieldNameœ:œdocumentœ,œidœ:œPrompt-amqBuœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}", - "target": "TextOutput-2MS4a", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-2MS4a", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-TextOutput-2MS4a{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-2MS4aœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}", - "target": "OpenAIModel-uYXZJ", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-uYXZJ", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-amqBu" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-amqBu{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-amqBuœ}-OpenAIModel-uYXZJ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uYXZJœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}", - "target": "Prompt-gTNiz", - "targetHandle": "{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "summary", - "id": "Prompt-gTNiz", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-Prompt-gTNiz{œfieldNameœ:œsummaryœ,œidœ:œPrompt-gTNizœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}", - "target": "ChatOutput-EJkG3", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-EJkG3", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-uYXZJ" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-uYXZJ{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uYXZJœ}-ChatOutput-EJkG3{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EJkG3œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}", - "target": "TextOutput-MUDOR", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-MUDOR", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-TextOutput-MUDOR{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-MUDORœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}", - "target": "OpenAIModel-XawYB", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-XawYB", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "str", "Text"], - "dataType": "Prompt", - "id": "Prompt-gTNiz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-Prompt-gTNiz{œbaseClassesœ:[œobjectœ,œstrœ,œTextœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-gTNizœ}-OpenAIModel-XawYB{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XawYBœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "OpenAIModel-XawYB", - "sourceHandle": "{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}", - "target": "ChatOutput-DNmvg", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-DNmvg", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["str", "Text", "object"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-XawYB" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIModel-XawYB{œbaseClassesœ:[œstrœ,œTextœ,œobjectœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XawYBœ}-ChatOutput-DNmvg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DNmvgœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -1580,7 +1686,8 @@ } }, "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", - "name": "Prompt Chaining", + "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", + "is_component": false, "last_tested_version": "1.0.0a0", - "is_component": false -} + "name": "Prompt Chaining" +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json index ed9188788..57e164986 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/VectorStore-RAG-Flows.json @@ -1,738 +1,592 @@ { - "id": "51e2b78a-199b-4054-9f32-e288eef6924c", "data": { + "edges": [ + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "TextOutput", + "id": "TextOutput-BDknO" + }, + "targetHandle": { + "fieldName": "context", + "id": "Prompt-xeI6K", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-TextOutput-BDknO{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}-Prompt-xeI6K{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "TextOutput-BDknO", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œTextOutputœ, œidœ: œTextOutput-BDknOœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-xeI6K", + "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-xeI6Kœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object", + "Record" + ], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + }, + "targetHandle": { + "fieldName": "question", + "id": "Prompt-xeI6K", + "inputTypes": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-Prompt-xeI6K{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-yxMKE", + "sourceHandle": "{œbaseClassesœ: [œTextœ, œstrœ, œobjectœ, œRecordœ], œdataTypeœ: œChatInputœ, œidœ: œChatInput-yxMKEœ}", + "style": { + "stroke": "#555" + }, + "target": "Prompt-xeI6K", + "targetHandle": "{œfieldNameœ: œquestionœ, œidœ: œPrompt-xeI6Kœ, œinputTypesœ: [œDocumentœ, œBaseOutputParserœ, œRecordœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "Prompt", + "id": "Prompt-xeI6K" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "OpenAIModel-EjXlN", + "inputTypes": [ + "Text", + "Record", + "Prompt" + ], + "type": "str" + } + }, + "id": "reactflow__edge-Prompt-xeI6K{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}-OpenAIModel-EjXlN{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-xeI6K", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œPromptœ, œidœ: œPrompt-xeI6Kœ}", + "style": { + "stroke": "#555" + }, + "target": "OpenAIModel-EjXlN", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-EjXlNœ, œinputTypesœ: [œTextœ, œRecordœ, œPromptœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "object", + "Text", + "str" + ], + "dataType": "OpenAIModel", + "id": "OpenAIModel-EjXlN" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-Q39I8", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-OpenAIModel-EjXlN{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}-ChatOutput-Q39I8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "OpenAIModel-EjXlN", + "sourceHandle": "{œbaseClassesœ: [œobjectœ, œTextœ, œstrœ], œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-EjXlNœ}", + "style": { + "stroke": "#555" + }, + "target": "ChatOutput-Q39I8", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Q39I8œ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "File", + "id": "File-t0a6a" + }, + "targetHandle": { + "fieldName": "inputs", + "id": "RecursiveCharacterTextSplitter-tR9QM", + "inputTypes": [ + "Document", + "Record" + ], + "type": "Document" + } + }, + "id": "reactflow__edge-File-t0a6a{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}-RecursiveCharacterTextSplitter-tR9QM{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", + "selected": false, + "source": "File-t0a6a", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œFileœ, œidœ: œFile-t0a6aœ}", + "style": { + "stroke": "#555" + }, + "target": "RecursiveCharacterTextSplitter-tR9QM", + "targetHandle": "{œfieldNameœ: œinputsœ, œidœ: œRecursiveCharacterTextSplitter-tR9QMœ, œinputTypesœ: [œDocumentœ, œRecordœ], œtypeœ: œDocumentœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Embeddings" + ], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-ZlOk1" + }, + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDBSearch-41nRz", + "inputTypes": null, + "type": "Embeddings" + } + }, + "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}-AstraDBSearch-41nRz{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", + "source": "OpenAIEmbeddings-ZlOk1", + "sourceHandle": "{œbaseClassesœ: [œEmbeddingsœ], œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-ZlOk1œ}", + "style": { + "stroke": "#555" + }, + "target": "AstraDBSearch-41nRz", + "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDBSearch-41nRzœ, œinputTypesœ: null, œtypeœ: œEmbeddingsœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Text", + "str", + "object", + "Record" + ], + "dataType": "ChatInput", + "id": "ChatInput-yxMKE" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "AstraDBSearch-41nRz", + "inputTypes": [ + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-AstraDBSearch-41nRz{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", + "source": "ChatInput-yxMKE", + "sourceHandle": "{œbaseClassesœ: [œTextœ, œstrœ, œobjectœ, œRecordœ], œdataTypeœ: œChatInputœ, œidœ: œChatInput-yxMKEœ}", + "style": { + "stroke": "#555" + }, + "target": "AstraDBSearch-41nRz", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAstraDBSearch-41nRzœ, œinputTypesœ: [œTextœ], œtypeœ: œstrœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "RecursiveCharacterTextSplitter", + "id": "RecursiveCharacterTextSplitter-tR9QM" + }, + "targetHandle": { + "fieldName": "inputs", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Record" + } + }, + "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}-AstraDB-eUCSS{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", + "selected": false, + "source": "RecursiveCharacterTextSplitter-tR9QM", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œRecursiveCharacterTextSplitterœ, œidœ: œRecursiveCharacterTextSplitter-tR9QMœ}", + "style": { + "stroke": "#555" + }, + "target": "AstraDB-eUCSS", + "targetHandle": "{œfieldNameœ: œinputsœ, œidœ: œAstraDB-eUCSSœ, œinputTypesœ: null, œtypeœ: œRecordœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Embeddings" + ], + "dataType": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-9TPjc" + }, + "targetHandle": { + "fieldName": "embedding", + "id": "AstraDB-eUCSS", + "inputTypes": null, + "type": "Embeddings" + } + }, + "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}-AstraDB-eUCSS{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", + "selected": false, + "source": "OpenAIEmbeddings-9TPjc", + "sourceHandle": "{œbaseClassesœ: [œEmbeddingsœ], œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-9TPjcœ}", + "style": { + "stroke": "#555" + }, + "target": "AstraDB-eUCSS", + "targetHandle": "{œfieldNameœ: œembeddingœ, œidœ: œAstraDB-eUCSSœ, œinputTypesœ: null, œtypeœ: œEmbeddingsœ}" + }, + { + "className": "stroke-gray-900 stroke-connection", + "data": { + "sourceHandle": { + "baseClasses": [ + "Record" + ], + "dataType": "AstraDBSearch", + "id": "AstraDBSearch-41nRz" + }, + "targetHandle": { + "fieldName": "input_value", + "id": "TextOutput-BDknO", + "inputTypes": [ + "Record", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-AstraDBSearch-41nRz{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}-TextOutput-BDknO{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", + "source": "AstraDBSearch-41nRz", + "sourceHandle": "{œbaseClassesœ: [œRecordœ], œdataTypeœ: œAstraDBSearchœ, œidœ: œAstraDBSearch-41nRzœ}", + "style": { + "stroke": "#555" + }, + "target": "TextOutput-BDknO", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œTextOutput-BDknOœ, œinputTypesœ: [œRecordœ, œTextœ], œtypeœ: œstrœ}" + } + ], "nodes": [ { + "data": { + "id": "ChatInput-yxMKE", + "node": { + "base_classes": [ + "Text", + "str", + "object", + "Record" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Get chat inputs from the Playground.", + "display_name": "Chat Input", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatInput", + "output_types": [ + "Message" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n ) -> Message:\n return super().build_with_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\n session_id=session_id,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "what is a line" + }, + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "User" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "ChatInput" + }, + "height": 383, "id": "ChatInput-yxMKE", - "type": "genericNode", "position": { "x": 1195.5276981160775, "y": 209.421875 }, - "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 Playground.\"\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 files: Optional[list[str]] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build_no_record(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n files=files,\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": "what is a line" - }, - "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 Playground.", - "icon": "ChatInput", - "base_classes": ["Text", "str", "object", "Record"], - "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-yxMKE" - }, "selected": false, - "width": 384, - "height": 383 + "type": "genericNode", + "width": 384 }, { - "id": "TextOutput-BDknO", - "type": "genericNode", - "position": { - "x": 2322.600672827879, - "y": 604.9467307442569 - }, "data": { - "type": "TextOutput", + "id": "TextOutput-BDknO", "node": { - "template": { - "input_value": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Value", - "advanced": false, - "input_types": ["Record", "Text"], - "dynamic": false, - "info": "Text or Record to be passed as output.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "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 TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "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": "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"] - }, - "_type": "CustomComponent" - }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["object", "Text", "str"], - "display_name": "Extracted Chunks", - "documentation": "", + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, "custom_fields": { "input_value": null, "record_template": null }, - "output_types": ["Text"], + "description": "Display a text output in the Playground.", + "display_name": "Extracted Chunks", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "icon": "type", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.text import TextComponent\nfrom langflow.field_typing import Text\n\n\nclass TextOutput(TextComponent):\n display_name = \"Text Output\"\n description = \"Display a text output in the Playground.\"\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 output.\",\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(self, input_value: Optional[Text] = \"\", record_template: str = \"\") -> Text:\n return super().build(input_value=input_value, record_template=record_template)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Text or Record to be passed as output.", + "input_types": [ + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "record_template": { + "advanced": true, + "display_name": "Record Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "record_template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "{text}" + } + } }, - "id": "TextOutput-BDknO" + "type": "TextOutput" }, - "selected": false, - "width": 384, + "dragging": false, "height": 289, + "id": "TextOutput-BDknO", + "position": { + "x": 2322.600672827879, + "y": 604.9467307442569 + }, "positionAbsolute": { "x": 2322.600672827879, "y": 604.9467307442569 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIEmbeddings-ZlOk1", - "type": "genericNode", - "position": { - "x": 1183.667250865064, - "y": 687.3171828430261 - }, "data": { - "type": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-ZlOk1", "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, NestedDict\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": ["all"], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "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 - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "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": "", - "load_from_db": true, - "title_case": false, - "input_types": ["Text"], - "value": "OPENAI_API_KEY" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": ["Embeddings"], - "display_name": "OpenAI Embeddings", - "documentation": "", + "base_classes": [ + "Embeddings" + ], + "beta": false, "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, "allowed_special": null, - "disallowed_special": null, "chunk_size": null, "client": null, + "default_headers": null, + "default_query": null, "deployment": null, + "disallowed_special": null, "embedding_ctx_length": null, "max_retries": null, "model": null, "model_kwargs": null, "openai_api_base": null, + "openai_api_key": null, "openai_api_type": null, "openai_api_version": null, "openai_organization": null, @@ -743,255 +597,512 @@ "tiktoken_enable": null, "tiktoken_model_name": null }, - "output_types": ["Embeddings"], + "description": "Generate embeddings using OpenAI models.", + "display_name": "OpenAI Embeddings", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false - }, - "id": "OpenAIEmbeddings-ZlOk1" - }, - "selected": false, - "width": 384, - "height": 383, - "dragging": false - }, - { - "id": "OpenAIModel-EjXlN", - "type": "genericNode", - "position": { - "x": 3410.117202077183, - "y": 431.2038048137648 - }, - "data": { - "type": "OpenAIModel", - "node": { + "frozen": false, + "output_types": [ + "Embeddings" + ], "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "_type": "CustomComponent", + "allowed_special": { + "advanced": true, + "display_name": "Allowed Special", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, "info": "", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "allowed_special", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text", "Record"] + "type": "str", + "value": [] + }, + "chunk_size": { + "advanced": true, + "display_name": "Chunk Size", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "chunk_size", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1000 }, "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=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": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, NestedDict\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n" + }, + "default_headers": { + "advanced": true, + "display_name": "Default Headers", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "default_headers", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict" + }, + "default_query": { + "advanced": true, + "display_name": "Default Query", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "default_query", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "deployment": { + "advanced": true, + "display_name": "Deployment", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "deployment", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "text-embedding-ada-002" + }, + "disallowed_special": { + "advanced": true, + "display_name": "Disallowed Special", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "disallowed_special", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": [ + "all" + ] + }, + "embedding_ctx_length": { + "advanced": true, + "display_name": "Embedding Context Length", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "embedding_ctx_length", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 8191 + }, + "max_retries": { + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_retries", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 6 + }, + "model": { + "advanced": false, + "display_name": "Model", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model", + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "text-embedding-ada-002" }, "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, + "display_name": "Model Kwargs", "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "gpt-3.5-turbo", "fileTypes": [], "file_path": "", - "password": false, - "options": [ - "gpt-4o", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125" - ], - "name": "model_name", - "display_name": "Model Name", - "advanced": false, - "dynamic": false, "info": "", + "list": false, "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "NestedDict", + "value": {} }, "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": 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.", + "info": "", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": true, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "openai_api_key": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": 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.", + "info": "", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "OPENAI_API_KEY" }, - "stream": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "stream", - "display_name": "Stream", + "openai_api_type": { "advanced": true, + "display_name": "OpenAI API Type", "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": false, - "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 - }, + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "openai_api_type", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "Text", "str"], - "display_name": "OpenAI", - "documentation": "", + "openai_api_version": { + "advanced": true, + "display_name": "OpenAI API Version", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_version", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_organization": { + "advanced": true, + "display_name": "OpenAI Organization", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_organization", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_proxy": { + "advanced": true, + "display_name": "OpenAI Proxy", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_proxy", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "request_timeout": { + "advanced": true, + "display_name": "Request Timeout", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "request_timeout", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float" + }, + "show_progress_bar": { + "advanced": true, + "display_name": "Show Progress Bar", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "show_progress_bar", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "skip_empty": { + "advanced": true, + "display_name": "Skip Empty", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "skip_empty", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "tiktoken_enable": { + "advanced": true, + "display_name": "TikToken Enable", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "tiktoken_enable", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "tiktoken_model_name": { + "advanced": true, + "display_name": "TikToken Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "tiktoken_model_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } + }, + "type": "OpenAIEmbeddings" + }, + "dragging": false, + "height": 383, + "id": "OpenAIEmbeddings-ZlOk1", + "position": { + "x": 1183.667250865064, + "y": 687.3171828430261 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "OpenAIModel-EjXlN", + "node": { + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, "custom_fields": { "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, "max_tokens": null, "model_kwargs": null, + "model_name": null, "openai_api_base": null, + "openai_api_key": null, "stream": null, - "system_message": null + "system_message": null, + "temperature": null }, - "output_types": ["Text"], + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "max_tokens", "model_kwargs", @@ -1003,352 +1114,599 @@ "system_message", "stream" ], - "beta": false + "frozen": false, + "icon": "OpenAI", + "output_types": [ + "Text" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.constants import STREAM_INFO_TEXT\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import MODEL_NAMES\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\", \"input_types\": [\"Text\", \"Record\", \"Prompt\"]},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n \"info\": \"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\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\": MODEL_NAMES,\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 = 0.1,\n model_name: str = \"gpt-4o\",\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 if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature,\n )\n\n return self.get_chat_result(output, stream, input_value, system_message)\n" + }, + "input_value": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text", + "Record", + "Prompt" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "max_tokens": { + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_tokens", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 256 + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "model_name": { + "advanced": false, + "display_name": "Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model_name", + "options": [ + "gpt-4o", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-0125" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "gpt-3.5-turbo" + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "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.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "stream": { + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Stream the response from the model. Streaming works only in Chat.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "stream", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "system_message": { + "advanced": true, + "display_name": "System Message", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "System message to pass to the model.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "system_message", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "temperature": { + "advanced": false, + "display_name": "Temperature", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "temperature", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float", + "value": 0.1 + } + } }, - "id": "OpenAIModel-EjXlN" + "type": "OpenAIModel" }, - "selected": true, - "width": 384, + "dragging": false, "height": 563, + "id": "OpenAIModel-EjXlN", + "position": { + "x": 3410.117202077183, + "y": 431.2038048137648 + }, "positionAbsolute": { "x": 3410.117202077183, "y": 431.2038048137648 }, - "dragging": false + "selected": true, + "type": "genericNode", + "width": 384 }, { + "data": { + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "id": "Prompt-xeI6K", + "node": { + "base_classes": [ + "object", + "Text", + "str" + ], + "beta": false, + "custom_fields": { + "template": [ + "context", + "question" + ] + }, + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt", + "documentation": "", + "error": null, + "field_formatters": {}, + "field_order": [], + "frozen": false, + "full_path": null, + "icon": "prompts", + "is_composition": null, + "is_input": null, + "is_output": null, + "name": "", + "output_types": [ + "Prompt" + ], + "template": { + "_type": "CustomComponent", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langflow.custom import CustomComponent\nfrom langflow.field_typing import TemplateField\nfrom langflow.field_typing.prompt import Prompt\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Prompt:\n prompt = await Prompt.from_template_and_variables(template, kwargs)\n self.status = prompt.format_text()\n return prompt\n" + }, + "context": { + "advanced": false, + "display_name": "context", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "context", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "question": { + "advanced": false, + "display_name": "question", + "dynamic": false, + "field_type": "str", + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": true, + "name": "question", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "template": { + "advanced": false, + "display_name": "Template", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "template", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "prompt", + "value": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\n\nAnswer: " + } + } + }, + "type": "Prompt" + }, + "dragging": false, + "height": 477, "id": "Prompt-xeI6K", - "type": "genericNode", "position": { "x": 2969.0261961391298, "y": 442.1613649809069 }, + "positionAbsolute": { + "x": 2969.0261961391298, + "y": 442.1613649809069 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { "data": { - "type": "Prompt", + "id": "ChatOutput-Q39I8", "node": { + "base_classes": [ + "object", + "Text", + "Record", + "str" + ], + "beta": false, + "custom_fields": { + "input_value": null, + "record_template": null, + "return_record": null, + "sender": null, + "sender_name": null, + "session_id": null + }, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "ChatOutput", + "output_types": [ + "Message" + ], "template": { + "_type": "CustomComponent", "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import ChatPromptTemplate\n\nfrom langflow.base.prompts.utils import dict_values_to_string\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.schema.schema import Record\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 async def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Record:\n prompt_template = ChatPromptTemplate.from_template(Text(template))\n kwargs = await dict_values_to_string(kwargs)\n messages = list(kwargs.values())\n prompt = prompt_template + messages\n self.status = f'Prompt:\\n\"{template}\"'\n return Record(data={\"prompt\": prompt.to_json()})\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": "{context}\n\n---\n\nGiven the context above, answer the question as best as possible.\n\nQuestion: {question}\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", - "context": { - "field_type": "str", - "required": false, - "placeholder": "", "list": false, - "show": true, + "load_from_db": false, "multiline": true, - "value": "", + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.schema.message import Message\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\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 files: Optional[list[str]] = None,\n ) -> Message:\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 files=files,\n )\n" + }, + "input_value": { + "advanced": false, + "display_name": "Message", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "context", - "display_name": "context", - "advanced": false, + "info": "", "input_types": [ - "Document", - "BaseOutputParser", - "Record", "Text" ], - "dynamic": false, - "info": "", + "list": false, "load_from_db": false, + "multiline": true, + "name": "input_value", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, "type": "str" }, - "question": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", + "sender": { + "advanced": true, + "display_name": "Sender Type", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "question", - "display_name": "question", - "advanced": false, + "info": "", "input_types": [ - "Document", - "BaseOutputParser", - "Record", "Text" ], - "dynamic": false, - "info": "", + "list": true, "load_from_db": false, + "multiline": false, + "name": "sender", + "options": [ + "Machine", + "User" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "advanced": false, + "display_name": "Sender Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "sender_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "AI" + }, + "session_id": { + "advanced": true, + "display_name": "Session ID", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "If provided, the message will be stored in the memory.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "session_id", + "password": false, + "placeholder": "", + "required": false, + "show": true, "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", "Text", "str"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["context", "question"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null + } }, - "id": "Prompt-xeI6K", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" + "type": "ChatOutput" }, - "selected": false, - "width": 384, - "height": 477, - "positionAbsolute": { - "x": 2969.0261961391298, - "y": 442.1613649809069 - }, - "dragging": false - }, - { + "dragging": false, + "height": 383, "id": "ChatOutput-Q39I8", - "type": "genericNode", "position": { "x": 3887.2073667611485, "y": 588.4801225794856 }, + "positionAbsolute": { + "x": 3887.2073667611485, + "y": 588.4801225794856 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { "data": { - "type": "ChatOutput", + "id": "File-t0a6a", "node": { + "base_classes": [ + "Record" + ], + "beta": false, + "custom_fields": { + "path": null, + "silent_errors": null + }, + "description": "A generic file loader.", + "display_name": "File", + "documentation": "", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "icon": "file-text", + "output_types": [ + "Record" + ], "template": { + "_type": "CustomComponent", "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 Playground.\"\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 files: Optional[list[str]] = None,\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 or \"\",\n files=files,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", "advanced": true, "dynamic": true, + "fileTypes": [], + "file_path": "", "info": "", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": false, - "placeholder": "", "list": false, - "show": true, + "load_from_db": false, "multiline": true, - "fileTypes": [], - "file_path": "", + "name": "code", "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 Playground.", - "icon": "ChatOutput", - "base_classes": ["object", "Text", "Record", "str"], - "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-Q39I8" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 3887.2073667611485, - "y": 588.4801225794856 - }, - "dragging": false - }, - { - "id": "File-t0a6a", - "type": "genericNode", - "position": { - "x": 2257.233450682836, - "y": 1747.5389618367233 - }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", "required": true, - "placeholder": "", - "list": false, "show": true, - "multiline": false, + "title_case": false, + "type": "code", + "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n" + }, + "path": { + "advanced": false, + "display_name": "Path", + "dynamic": false, "fileTypes": [ ".txt", ".md", @@ -1370,618 +1728,235 @@ ".tsx" ], "file_path": "51e2b78a-199b-4054-9f32-e288eef6924c/Langflow conversation.pdf", - "password": false, - "name": "path", - "display_name": "Path", - "advanced": false, - "dynamic": false, "info": "Supported file types: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx", + "list": false, "load_from_db": false, + "multiline": false, + "name": "path", + "password": false, + "placeholder": "", + "required": true, + "show": true, "title_case": false, + "type": "file", "value": "" }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from pathlib import Path\nfrom typing import Any, Dict\n\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\n\n\nclass FileComponent(CustomComponent):\n display_name = \"File\"\n description = \"A generic file loader.\"\n icon = \"file-text\"\n\n def build_config(self) -> Dict[str, Any]:\n return {\n \"path\": {\n \"display_name\": \"Path\",\n \"field_type\": \"file\",\n \"file_types\": TEXT_FILE_TYPES,\n \"info\": f\"Supported file types: {', '.join(TEXT_FILE_TYPES)}\",\n },\n \"silent_errors\": {\n \"display_name\": \"Silent Errors\",\n \"advanced\": True,\n \"info\": \"If true, errors will not raise an exception.\",\n },\n }\n\n def load_file(self, path: str, silent_errors: bool = False) -> Record:\n resolved_path = self.resolve_path(path)\n path_obj = Path(resolved_path)\n extension = path_obj.suffix[1:].lower()\n if extension == \"doc\":\n raise ValueError(\"doc files are not supported. Please save as .docx\")\n if extension not in TEXT_FILE_TYPES:\n raise ValueError(f\"Unsupported file type: {extension}\")\n record = parse_text_file_to_record(resolved_path, silent_errors)\n self.status = record if record else \"No data\"\n return record or Record()\n\n def build(\n self,\n path: str,\n silent_errors: bool = False,\n ) -> Record:\n record = self.load_file(path, silent_errors)\n self.status = record\n return record\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, "silent_errors": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, + "advanced": true, + "display_name": "Silent Errors", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "silent_errors", - "display_name": "Silent Errors", - "advanced": true, - "dynamic": false, "info": "If true, errors will not raise an exception.", + "list": false, "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "A generic file loader.", - "icon": "file-text", - "base_classes": ["Record"], - "display_name": "File", - "documentation": "", - "custom_fields": { - "path": null, - "silent_errors": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false + "multiline": false, + "name": "silent_errors", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + } + } }, - "id": "File-t0a6a" + "type": "File" }, - "selected": false, - "width": 384, + "dragging": false, "height": 281, + "id": "File-t0a6a", + "position": { + "x": 2257.233450682836, + "y": 1747.5389618367233 + }, "positionAbsolute": { "x": 2257.233450682836, "y": 1747.5389618367233 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { + "data": { + "id": "RecursiveCharacterTextSplitter-tR9QM", + "node": { + "base_classes": [ + "Record" + ], + "beta": false, + "custom_fields": { + "chunk_overlap": null, + "chunk_size": null, + "inputs": null, + "separators": null + }, + "description": "Split text into chunks of a specified length.", + "display_name": "Recursive Character Text Splitter", + "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", + "field_formatters": {}, + "field_order": [], + "frozen": false, + "output_types": [ + "Record" + ], + "template": { + "_type": "CustomComponent", + "chunk_overlap": { + "advanced": false, + "display_name": "Chunk Overlap", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The amount of overlap between chunks.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "chunk_overlap", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 200 + }, + "chunk_size": { + "advanced": false, + "display_name": "Chunk Size", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The maximum length of each chunk.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "chunk_size", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1000 + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Optional\n\nfrom langchain_core.documents import Document\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n" + }, + "inputs": { + "advanced": false, + "display_name": "Input", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The texts to split.", + "input_types": [ + "Document", + "Record" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "inputs", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "Document" + }, + "separators": { + "advanced": false, + "display_name": "Separators", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "separators", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": [ + "" + ] + } + } + }, + "type": "RecursiveCharacterTextSplitter" + }, + "dragging": false, + "height": 501, "id": "RecursiveCharacterTextSplitter-tR9QM", - "type": "genericNode", "position": { "x": 2791.013514133929, "y": 1462.9588953494142 }, - "data": { - "type": "RecursiveCharacterTextSplitter", - "node": { - "template": { - "inputs": { - "type": "Document", - "required": true, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Input", - "advanced": false, - "input_types": ["Document", "Record"], - "dynamic": false, - "info": "The texts to split.", - "load_from_db": false, - "title_case": false - }, - "chunk_overlap": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 200, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_overlap", - "display_name": "Chunk Overlap", - "advanced": false, - "dynamic": false, - "info": "The amount of overlap between chunks.", - "load_from_db": false, - "title_case": false - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": false, - "dynamic": false, - "info": "The maximum length of each chunk.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_core.documents import Document\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\n\nfrom langflow.custom import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\n\n\nclass RecursiveCharacterTextSplitterComponent(CustomComponent):\n display_name: str = \"Recursive Character Text Splitter\"\n description: str = \"Split text into chunks of a specified length.\"\n documentation: str = \"https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter\"\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Input\",\n \"info\": \"The texts to split.\",\n \"input_types\": [\"Document\", \"Record\"],\n },\n \"separators\": {\n \"display_name\": \"Separators\",\n \"info\": 'The characters to split on.\\nIf left empty defaults to [\"\\\\n\\\\n\", \"\\\\n\", \" \", \"\"].',\n \"is_list\": True,\n },\n \"chunk_size\": {\n \"display_name\": \"Chunk Size\",\n \"info\": \"The maximum length of each chunk.\",\n \"field_type\": \"int\",\n \"value\": 1000,\n },\n \"chunk_overlap\": {\n \"display_name\": \"Chunk Overlap\",\n \"info\": \"The amount of overlap between chunks.\",\n \"field_type\": \"int\",\n \"value\": 200,\n },\n \"code\": {\"show\": False},\n }\n\n def build(\n self,\n inputs: list[Document],\n separators: Optional[list[str]] = None,\n chunk_size: Optional[int] = 1000,\n chunk_overlap: Optional[int] = 200,\n ) -> list[Record]:\n \"\"\"\n Split text into chunks of a specified length.\n\n Args:\n separators (list[str]): The characters to split on.\n chunk_size (int): The maximum length of each chunk.\n chunk_overlap (int): The amount of overlap between chunks.\n length_function (function): The function to use to calculate the length of the text.\n\n Returns:\n list[str]: The chunks of text.\n \"\"\"\n\n if separators == \"\":\n separators = None\n elif separators:\n # check if the separators list has escaped characters\n # if there are escaped characters, unescape them\n separators = [unescape_string(x) for x in separators]\n\n # Make sure chunk_size and chunk_overlap are ints\n if isinstance(chunk_size, str):\n chunk_size = int(chunk_size)\n if isinstance(chunk_overlap, str):\n chunk_overlap = int(chunk_overlap)\n splitter = RecursiveCharacterTextSplitter(\n separators=separators,\n chunk_size=chunk_size,\n chunk_overlap=chunk_overlap,\n )\n documents = []\n for _input in inputs:\n if isinstance(_input, Record):\n documents.append(_input.to_lc_document())\n else:\n documents.append(_input)\n docs = splitter.split_documents(documents)\n records = self.to_records(docs)\n self.repr_value = build_loader_repr_from_records(records)\n return records\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "separators": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "separators", - "display_name": "Separators", - "advanced": false, - "dynamic": false, - "info": "The characters to split on.\nIf left empty defaults to [\"\\n\\n\", \"\\n\", \" \", \"\"].", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": [""] - }, - "_type": "CustomComponent" - }, - "description": "Split text into chunks of a specified length.", - "base_classes": ["Record"], - "display_name": "Recursive Character Text Splitter", - "documentation": "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter", - "custom_fields": { - "inputs": null, - "separators": null, - "chunk_size": null, - "chunk_overlap": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "RecursiveCharacterTextSplitter-tR9QM" - }, - "selected": false, - "width": 384, - "height": 501, "positionAbsolute": { "x": 2791.013514133929, "y": 1462.9588953494142 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "AstraDBSearch-41nRz", - "type": "genericNode", - "position": { - "x": 1723.976434815103, - "y": 277.03317407245913 - }, "data": { - "type": "AstraDBSearch", + "id": "AstraDBSearch-41nRz", "node": { - "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input Value", - "advanced": false, - "dynamic": false, - "info": "Input value to search", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, - "info": "API endpoint URL for the Astra DB service.", - "load_from_db": true, - "title_case": false, - "input_types": ["Text"], - "value": "ASTRA_DB_API_ENDPOINT" - }, - "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, - "info": "Optional number of records to process in a single batch.", - "load_from_db": false, - "title_case": false - }, - "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk delete operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations.", - "load_from_db": false, - "title_case": false - }, - "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, - "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, - "info": "Optional dictionary defining the indexing policy for the collection.", - "load_from_db": false, - "title_case": false - }, - "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, - "info": "The name of the collection within Astra DB where the vectors will be stored.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"], - "value": "langflow" - }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to include in the indexing.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, - "info": "Optional distance metric for vector comparisons in the vector store.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, - "info": "Optional namespace within Astra DB to use for the collection.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "number_of_results": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 4, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "number_of_results", - "display_name": "Number of Results", - "advanced": true, - "dynamic": false, - "info": "Number of results to return.", - "load_from_db": false, - "title_case": false - }, - "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, - "info": "Boolean flag to determine whether to delete the collection before creating a new one.", - "load_from_db": false, - "title_case": false - }, - "search_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Similarity", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Similarity", "MMR"], - "name": "search_type", - "display_name": "Search Type", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Sync", - "fileTypes": [], - "file_path": "", - "password": false, - "options": ["Sync", "Async", "Off"], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, - "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, - "info": "Authentication token for accessing Astra DB.", - "load_from_db": true, - "title_case": false, - "input_types": ["Text"], - "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "_type": "CustomComponent" - }, - "description": "Searches an existing Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": ["Record"], - "display_name": "Astra DB Search", - "documentation": "", + "base_classes": [ + "Record" + ], + "beta": false, "custom_fields": { - "embedding": null, - "collection_name": null, - "input_value": null, - "token": null, "api_endpoint": null, - "search_type": null, - "number_of_results": null, - "namespace": null, - "metric": null, "batch_size": null, + "bulk_delete_concurrency": null, "bulk_insert_batch_concurrency": null, "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, + "collection_indexing_policy": null, + "collection_name": null, + "embedding": null, + "input_value": null, "metadata_indexing_exclude": null, - "collection_indexing_policy": null + "metadata_indexing_include": null, + "metric": null, + "namespace": null, + "number_of_results": null, + "pre_delete_collection": null, + "search_type": null, + "setup_mode": null, + "token": null }, - "output_types": ["Record"], + "description": "Searches an existing Astra DB Vector Store.", + "display_name": "Astra DB Search", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "token", "api_endpoint", @@ -1989,378 +1964,450 @@ "input_value", "embedding" ], - "beta": false - }, - "id": "AstraDBSearch-41nRz" - }, - "selected": false, - "width": 384, - "height": 713, - "dragging": false, - "positionAbsolute": { - "x": 1723.976434815103, - "y": 277.03317407245913 - } - }, - { - "id": "AstraDB-eUCSS", - "type": "genericNode", - "position": { - "x": 3372.04958055989, - "y": 1611.0742035495277 - }, - "data": { - "type": "AstraDB", - "node": { + "frozen": false, + "icon": "AstraDB", + "output_types": [ + "Record" + ], "template": { - "embedding": { - "type": "Embeddings", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding", - "display_name": "Embedding", - "advanced": false, - "dynamic": false, - "info": "Embedding to use", - "load_from_db": false, - "title_case": false - }, - "inputs": { - "type": "Record", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "inputs", - "display_name": "Inputs", - "advanced": false, - "dynamic": false, - "info": "Optional list of records to be processed and stored in the vector store.", - "load_from_db": false, - "title_case": false - }, + "_type": "CustomComponent", "api_endpoint": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "API Endpoint", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "api_endpoint", - "display_name": "API Endpoint", - "advanced": false, - "dynamic": false, "info": "API endpoint URL for the Astra DB service.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": true, + "multiline": false, + "name": "api_endpoint", + "password": false, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "ASTRA_DB_API_ENDPOINT" }, "batch_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Batch Size", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "batch_size", - "display_name": "Batch Size", - "advanced": true, - "dynamic": false, "info": "Optional number of records to process in a single batch.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "batch_size", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" }, "bulk_delete_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Bulk Delete Concurrency", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "bulk_delete_concurrency", - "display_name": "Bulk Delete Concurrency", - "advanced": true, - "dynamic": false, "info": "Optional concurrency level for bulk delete operations.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "bulk_delete_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" }, "bulk_insert_batch_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Bulk Insert Batch Concurrency", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "bulk_insert_batch_concurrency", - "display_name": "Bulk Insert Batch Concurrency", - "advanced": true, - "dynamic": false, "info": "Optional concurrency level for bulk insert operations.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "bulk_insert_batch_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" }, "bulk_insert_overwrite_concurrency": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Bulk Insert Overwrite Concurrency", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "bulk_insert_overwrite_concurrency", - "display_name": "Bulk Insert Overwrite Concurrency", - "advanced": true, - "dynamic": false, "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "bulk_insert_overwrite_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" }, "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import List, Optional, Union\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\nfrom langchain_core.retrievers import BaseRetriever\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", "advanced": true, "dynamic": true, + "fileTypes": [], + "file_path": "", "info": "", + "list": false, "load_from_db": false, - "title_case": false + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import List, Optional\n\nfrom langflow.components.vectorstores.AstraDB import AstraDBVectorStoreComponent\nfrom langflow.components.vectorstores.base.model import LCVectorStoreComponent\nfrom langflow.field_typing import Embeddings, Text\nfrom langflow.schema import Record\n\n\nclass AstraDBSearchComponent(LCVectorStoreComponent):\n display_name = \"Astra DB Search\"\n description = \"Searches an existing Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"input_value\", \"embedding\"]\n\n def build_config(self):\n return {\n \"search_type\": {\n \"display_name\": \"Search Type\",\n \"options\": [\"Similarity\", \"MMR\"],\n },\n \"input_value\": {\n \"display_name\": \"Input Value\",\n \"info\": \"Input value to search\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n \"number_of_results\": {\n \"display_name\": \"Number of Results\",\n \"info\": \"Number of results to return.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n collection_name: str,\n input_value: Text,\n token: str,\n api_endpoint: str,\n search_type: str = \"Similarity\",\n number_of_results: int = 4,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> List[Record]:\n vector_store = AstraDBVectorStoreComponent().build(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n try:\n return self.search_with_vector_store(input_value, search_type, vector_store, k=number_of_results)\n except KeyError as e:\n if \"content\" in str(e):\n raise ValueError(\n \"You should ingest data through Langflow (or LangChain) to query it in Langflow. Your collection does not contain a field name 'content'.\"\n )\n else:\n raise e\n" }, "collection_indexing_policy": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Collection Indexing Policy", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "collection_indexing_policy", - "display_name": "Collection Indexing Policy", - "advanced": true, - "dynamic": false, "info": "Optional dictionary defining the indexing policy for the collection.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "collection_indexing_policy", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict" }, "collection_name": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "Collection Name", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "collection_name", - "display_name": "Collection Name", - "advanced": false, - "dynamic": false, "info": "The name of the collection within Astra DB where the vectors will be stored.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "collection_name", + "password": false, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "langflow" }, - "metadata_indexing_exclude": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, + "embedding": { + "advanced": false, + "display_name": "Embedding", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "metadata_indexing_exclude", - "display_name": "Metadata Indexing Exclude", - "advanced": true, - "dynamic": false, - "info": "Optional list of metadata fields to exclude from the indexing.", + "info": "Embedding to use", + "list": false, "load_from_db": false, + "multiline": false, + "name": "embedding", + "password": false, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "Embeddings" + }, + "input_value": { + "advanced": false, + "display_name": "Input Value", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Input value to search", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "input_value", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str" + }, + "metadata_indexing_exclude": { + "advanced": true, + "display_name": "Metadata Indexing Exclude", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional list of metadata fields to exclude from the indexing.", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "metadata_indexing_exclude", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" }, "metadata_indexing_include": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Metadata Indexing Include", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "metadata_indexing_include", - "display_name": "Metadata Indexing Include", - "advanced": true, - "dynamic": false, "info": "Optional list of metadata fields to include in the indexing.", + "input_types": [ + "Text" + ], + "list": true, "load_from_db": false, + "multiline": false, + "name": "metadata_indexing_include", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "metric": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Metric", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "metric", - "display_name": "Metric", - "advanced": true, - "dynamic": false, "info": "Optional distance metric for vector comparisons in the vector store.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "metric", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" }, "namespace": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": true, + "display_name": "Namespace", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "namespace", - "display_name": "Namespace", - "advanced": true, - "dynamic": false, "info": "Optional namespace within Astra DB to use for the collection.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": false, + "multiline": false, + "name": "namespace", + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str" + }, + "number_of_results": { + "advanced": true, + "display_name": "Number of Results", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Number of results to return.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "number_of_results", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 4 }, "pre_delete_collection": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, + "advanced": true, + "display_name": "Pre Delete Collection", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "name": "pre_delete_collection", - "display_name": "Pre Delete Collection", - "advanced": true, - "dynamic": false, "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "list": false, "load_from_db": false, - "title_case": false + "multiline": false, + "name": "pre_delete_collection", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "search_type": { + "advanced": false, + "display_name": "Search Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "search_type", + "options": [ + "Similarity", + "MMR" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Similarity" }, "setup_mode": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "Sync", + "advanced": true, + "display_name": "Setup Mode", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": false, - "options": ["Sync", "Async", "Off"], - "name": "setup_mode", - "display_name": "Setup Mode", - "advanced": true, - "dynamic": false, "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", + "input_types": [ + "Text" + ], + "list": true, "load_from_db": false, + "multiline": false, + "name": "setup_mode", + "options": [ + "Sync", + "Async", + "Off" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, "title_case": false, - "input_types": ["Text"] + "type": "str", + "value": "Sync" }, "token": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, + "advanced": false, + "display_name": "Token", + "dynamic": false, "fileTypes": [], "file_path": "", - "password": true, - "name": "token", - "display_name": "Token", - "advanced": false, - "dynamic": false, "info": "Authentication token for accessing Astra DB.", + "input_types": [ + "Text" + ], + "list": false, "load_from_db": true, + "multiline": false, + "name": "token", + "password": true, + "placeholder": "", + "required": true, + "show": true, "title_case": false, - "input_types": ["Text"], + "type": "str", "value": "ASTRA_DB_APPLICATION_TOKEN" - }, - "_type": "CustomComponent" - }, - "description": "Builds or loads an Astra DB Vector Store.", - "icon": "AstraDB", - "base_classes": ["VectorStore"], - "display_name": "Astra DB", - "documentation": "", + } + } + }, + "type": "AstraDBSearch" + }, + "dragging": false, + "height": 713, + "id": "AstraDBSearch-41nRz", + "position": { + "x": 1723.976434815103, + "y": 277.03317407245913 + }, + "positionAbsolute": { + "x": 1723.976434815103, + "y": 277.03317407245913 + }, + "selected": false, + "type": "genericNode", + "width": 384 + }, + { + "data": { + "id": "AstraDB-eUCSS", + "node": { + "base_classes": [ + "VectorStore" + ], + "beta": false, "custom_fields": { - "embedding": null, - "token": null, "api_endpoint": null, - "collection_name": null, - "inputs": null, - "namespace": null, - "metric": null, "batch_size": null, + "bulk_delete_concurrency": null, "bulk_insert_batch_concurrency": null, "bulk_insert_overwrite_concurrency": null, - "bulk_delete_concurrency": null, - "setup_mode": null, - "pre_delete_collection": null, - "metadata_indexing_include": null, + "collection_indexing_policy": null, + "collection_name": null, + "embedding": null, + "inputs": null, "metadata_indexing_exclude": null, - "collection_indexing_policy": null + "metadata_indexing_include": null, + "metric": null, + "namespace": null, + "pre_delete_collection": null, + "setup_mode": null, + "token": null }, - "output_types": ["VectorStore"], + "description": "Builds or loads an Astra DB Vector Store.", + "display_name": "Astra DB", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [ "token", "api_endpoint", @@ -2368,499 +2415,395 @@ "inputs", "embedding" ], - "beta": false + "frozen": false, + "icon": "AstraDB", + "output_types": [ + "VectorStore", + "BaseRetriever" + ], + "template": { + "_type": "CustomComponent", + "api_endpoint": { + "advanced": false, + "display_name": "API Endpoint", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "API endpoint URL for the Astra DB service.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "api_endpoint", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "ASTRA_DB_API_ENDPOINT" + }, + "batch_size": { + "advanced": true, + "display_name": "Batch Size", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional number of records to process in a single batch.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "batch_size", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" + }, + "bulk_delete_concurrency": { + "advanced": true, + "display_name": "Bulk Delete Concurrency", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional concurrency level for bulk delete operations.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "bulk_delete_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" + }, + "bulk_insert_batch_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Batch Concurrency", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional concurrency level for bulk insert operations.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "bulk_insert_batch_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" + }, + "bulk_insert_overwrite_concurrency": { + "advanced": true, + "display_name": "Bulk Insert Overwrite Concurrency", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional concurrency level for bulk insert operations that overwrite existing records.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "bulk_insert_overwrite_concurrency", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import List, Optional, Union\n\nfrom langchain_astradb import AstraDBVectorStore\nfrom langchain_astradb.utils.astradb import SetupMode\nfrom langchain_core.retrievers import BaseRetriever\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, VectorStore\nfrom langflow.schema import Record\n\n\nclass AstraDBVectorStoreComponent(CustomComponent):\n display_name = \"Astra DB\"\n description = \"Builds or loads an Astra DB Vector Store.\"\n icon = \"AstraDB\"\n field_order = [\"token\", \"api_endpoint\", \"collection_name\", \"inputs\", \"embedding\"]\n\n def build_config(self):\n return {\n \"inputs\": {\n \"display_name\": \"Inputs\",\n \"info\": \"Optional list of records to be processed and stored in the vector store.\",\n },\n \"embedding\": {\"display_name\": \"Embedding\", \"info\": \"Embedding to use\"},\n \"collection_name\": {\n \"display_name\": \"Collection Name\",\n \"info\": \"The name of the collection within Astra DB where the vectors will be stored.\",\n },\n \"token\": {\n \"display_name\": \"Token\",\n \"info\": \"Authentication token for accessing Astra DB.\",\n \"password\": True,\n },\n \"api_endpoint\": {\n \"display_name\": \"API Endpoint\",\n \"info\": \"API endpoint URL for the Astra DB service.\",\n },\n \"namespace\": {\n \"display_name\": \"Namespace\",\n \"info\": \"Optional namespace within Astra DB to use for the collection.\",\n \"advanced\": True,\n },\n \"metric\": {\n \"display_name\": \"Metric\",\n \"info\": \"Optional distance metric for vector comparisons in the vector store.\",\n \"advanced\": True,\n },\n \"batch_size\": {\n \"display_name\": \"Batch Size\",\n \"info\": \"Optional number of records to process in a single batch.\",\n \"advanced\": True,\n },\n \"bulk_insert_batch_concurrency\": {\n \"display_name\": \"Bulk Insert Batch Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations.\",\n \"advanced\": True,\n },\n \"bulk_insert_overwrite_concurrency\": {\n \"display_name\": \"Bulk Insert Overwrite Concurrency\",\n \"info\": \"Optional concurrency level for bulk insert operations that overwrite existing records.\",\n \"advanced\": True,\n },\n \"bulk_delete_concurrency\": {\n \"display_name\": \"Bulk Delete Concurrency\",\n \"info\": \"Optional concurrency level for bulk delete operations.\",\n \"advanced\": True,\n },\n \"setup_mode\": {\n \"display_name\": \"Setup Mode\",\n \"info\": \"Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.\",\n \"options\": [\"Sync\", \"Async\", \"Off\"],\n \"advanced\": True,\n },\n \"pre_delete_collection\": {\n \"display_name\": \"Pre Delete Collection\",\n \"info\": \"Boolean flag to determine whether to delete the collection before creating a new one.\",\n \"advanced\": True,\n },\n \"metadata_indexing_include\": {\n \"display_name\": \"Metadata Indexing Include\",\n \"info\": \"Optional list of metadata fields to include in the indexing.\",\n \"advanced\": True,\n },\n \"metadata_indexing_exclude\": {\n \"display_name\": \"Metadata Indexing Exclude\",\n \"info\": \"Optional list of metadata fields to exclude from the indexing.\",\n \"advanced\": True,\n },\n \"collection_indexing_policy\": {\n \"display_name\": \"Collection Indexing Policy\",\n \"info\": \"Optional dictionary defining the indexing policy for the collection.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n embedding: Embeddings,\n token: str,\n api_endpoint: str,\n collection_name: str,\n inputs: Optional[List[Record]] = None,\n namespace: Optional[str] = None,\n metric: Optional[str] = None,\n batch_size: Optional[int] = None,\n bulk_insert_batch_concurrency: Optional[int] = None,\n bulk_insert_overwrite_concurrency: Optional[int] = None,\n bulk_delete_concurrency: Optional[int] = None,\n setup_mode: str = \"Sync\",\n pre_delete_collection: bool = False,\n metadata_indexing_include: Optional[List[str]] = None,\n metadata_indexing_exclude: Optional[List[str]] = None,\n collection_indexing_policy: Optional[dict] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n try:\n setup_mode_value = SetupMode[setup_mode.upper()]\n except KeyError:\n raise ValueError(f\"Invalid setup mode: {setup_mode}\")\n if inputs:\n documents = [_input.to_lc_document() for _input in inputs]\n\n vector_store = AstraDBVectorStore.from_documents(\n documents=documents,\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n else:\n vector_store = AstraDBVectorStore(\n embedding=embedding,\n collection_name=collection_name,\n token=token,\n api_endpoint=api_endpoint,\n namespace=namespace,\n metric=metric,\n batch_size=batch_size,\n bulk_insert_batch_concurrency=bulk_insert_batch_concurrency,\n bulk_insert_overwrite_concurrency=bulk_insert_overwrite_concurrency,\n bulk_delete_concurrency=bulk_delete_concurrency,\n setup_mode=setup_mode_value,\n pre_delete_collection=pre_delete_collection,\n metadata_indexing_include=metadata_indexing_include,\n metadata_indexing_exclude=metadata_indexing_exclude,\n collection_indexing_policy=collection_indexing_policy,\n )\n\n return vector_store\n return vector_store\n" + }, + "collection_indexing_policy": { + "advanced": true, + "display_name": "Collection Indexing Policy", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional dictionary defining the indexing policy for the collection.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "collection_indexing_policy", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict" + }, + "collection_name": { + "advanced": false, + "display_name": "Collection Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "The name of the collection within Astra DB where the vectors will be stored.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "collection_name", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "langflow" + }, + "embedding": { + "advanced": false, + "display_name": "Embedding", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Embedding to use", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "embedding", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "Embeddings" + }, + "inputs": { + "advanced": false, + "display_name": "Inputs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional list of records to be processed and stored in the vector store.", + "list": true, + "load_from_db": false, + "multiline": false, + "name": "inputs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "Record" + }, + "metadata_indexing_exclude": { + "advanced": true, + "display_name": "Metadata Indexing Exclude", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional list of metadata fields to exclude from the indexing.", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "metadata_indexing_exclude", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "metadata_indexing_include": { + "advanced": true, + "display_name": "Metadata Indexing Include", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional list of metadata fields to include in the indexing.", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "metadata_indexing_include", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "metric": { + "advanced": true, + "display_name": "Metric", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional distance metric for vector comparisons in the vector store.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "metric", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "namespace": { + "advanced": true, + "display_name": "Namespace", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Optional namespace within Astra DB to use for the collection.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "namespace", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "pre_delete_collection": { + "advanced": true, + "display_name": "Pre Delete Collection", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Boolean flag to determine whether to delete the collection before creating a new one.", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "pre_delete_collection", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "setup_mode": { + "advanced": true, + "display_name": "Setup Mode", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "setup_mode", + "options": [ + "Sync", + "Async", + "Off" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "Sync" + }, + "token": { + "advanced": false, + "display_name": "Token", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "Authentication token for accessing Astra DB.", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "token", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "ASTRA_DB_APPLICATION_TOKEN" + } + } }, - "id": "AstraDB-eUCSS" + "type": "AstraDB" }, - "selected": false, - "width": 384, + "dragging": false, "height": 573, + "id": "AstraDB-eUCSS", + "position": { + "x": 3372.04958055989, + "y": 1611.0742035495277 + }, "positionAbsolute": { "x": 3372.04958055989, "y": 1611.0742035495277 }, - "dragging": false + "selected": false, + "type": "genericNode", + "width": 384 }, { - "id": "OpenAIEmbeddings-9TPjc", - "type": "genericNode", - "position": { - "x": 2814.0402191223047, - "y": 1955.9268168273086 - }, "data": { - "type": "OpenAIEmbeddings", + "id": "OpenAIEmbeddings-9TPjc", "node": { - "template": { - "allowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": [], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "allowed_special", - "display_name": "Allowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "chunk_size": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 1000, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "chunk_size", - "display_name": "Chunk Size", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "client": { - "type": "Any", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "client", - "display_name": "Client", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, NestedDict\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_headers": { - "type": "dict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_headers", - "display_name": "Default Headers", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "default_query": { - "type": "NestedDict", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": {}, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "default_query", - "display_name": "Default Query", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "deployment": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "deployment", - "display_name": "Deployment", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "disallowed_special": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": ["all"], - "fileTypes": [], - "file_path": "", - "password": false, - "name": "disallowed_special", - "display_name": "Disallowed Special", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "embedding_ctx_length": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 8191, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "embedding_ctx_length", - "display_name": "Embedding Context Length", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "max_retries": { - "type": "int", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 6, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "max_retries", - "display_name": "Max Retries", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "model": { - "type": "str", - "required": false, - "placeholder": "", - "list": true, - "show": true, - "multiline": false, - "value": "text-embedding-ada-002", - "fileTypes": [], - "file_path": "", - "password": false, - "options": [ - "text-embedding-3-small", - "text-embedding-3-large", - "text-embedding-ada-002" - ], - "name": "model", - "display_name": "Model", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "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 - }, - "openai_api_base": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_base", - "display_name": "OpenAI API Base", - "advanced": true, - "dynamic": false, - "info": "", - "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": "", - "load_from_db": true, - "title_case": false, - "input_types": ["Text"], - "value": "OPENAI_API_KEY" - }, - "openai_api_type": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": true, - "name": "openai_api_type", - "display_name": "OpenAI API Type", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_api_version": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_api_version", - "display_name": "OpenAI API Version", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_organization": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_organization", - "display_name": "OpenAI Organization", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "openai_proxy": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "openai_proxy", - "display_name": "OpenAI Proxy", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "request_timeout": { - "type": "float", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "request_timeout", - "display_name": "Request Timeout", - "advanced": true, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "show_progress_bar": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "show_progress_bar", - "display_name": "Show Progress Bar", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "skip_empty": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "skip_empty", - "display_name": "Skip Empty", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_enable": { - "type": "bool", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": true, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_enable", - "display_name": "TikToken Enable", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "tiktoken_model_name": { - "type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "tiktoken_model_name", - "display_name": "TikToken Model Name", - "advanced": true, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "_type": "CustomComponent" - }, - "description": "Generate embeddings using OpenAI models.", - "base_classes": ["Embeddings"], - "display_name": "OpenAI Embeddings", - "documentation": "", + "base_classes": [ + "Embeddings" + ], + "beta": false, "custom_fields": { - "openai_api_key": null, - "default_headers": null, - "default_query": null, "allowed_special": null, - "disallowed_special": null, "chunk_size": null, "client": null, + "default_headers": null, + "default_query": null, "deployment": null, + "disallowed_special": null, "embedding_ctx_length": null, "max_retries": null, "model": null, "model_kwargs": null, "openai_api_base": null, + "openai_api_key": null, "openai_api_type": null, "openai_api_version": null, "openai_organization": null, @@ -2871,271 +2814,490 @@ "tiktoken_enable": null, "tiktoken_model_name": null }, - "output_types": ["Embeddings"], + "description": "Generate embeddings using OpenAI models.", + "display_name": "OpenAI Embeddings", + "documentation": "", "field_formatters": {}, - "frozen": false, "field_order": [], - "beta": false + "frozen": false, + "output_types": [ + "Embeddings" + ], + "template": { + "_type": "CustomComponent", + "allowed_special": { + "advanced": true, + "display_name": "Allowed Special", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "allowed_special", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": [] + }, + "chunk_size": { + "advanced": true, + "display_name": "Chunk Size", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "chunk_size", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 1000 + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Embeddings, NestedDict\n\n\nclass OpenAIEmbeddingsComponent(CustomComponent):\n display_name = \"OpenAI Embeddings\"\n description = \"Generate embeddings using OpenAI models.\"\n\n def build_config(self):\n return {\n \"allowed_special\": {\n \"display_name\": \"Allowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"default_headers\": {\n \"display_name\": \"Default Headers\",\n \"advanced\": True,\n \"field_type\": \"dict\",\n },\n \"default_query\": {\n \"display_name\": \"Default Query\",\n \"advanced\": True,\n \"field_type\": \"NestedDict\",\n },\n \"disallowed_special\": {\n \"display_name\": \"Disallowed Special\",\n \"advanced\": True,\n \"field_type\": \"str\",\n \"is_list\": True,\n },\n \"chunk_size\": {\"display_name\": \"Chunk Size\", \"advanced\": True},\n \"client\": {\"display_name\": \"Client\", \"advanced\": True},\n \"deployment\": {\"display_name\": \"Deployment\", \"advanced\": True},\n \"embedding_ctx_length\": {\n \"display_name\": \"Embedding Context Length\",\n \"advanced\": True,\n },\n \"max_retries\": {\"display_name\": \"Max Retries\", \"advanced\": True},\n \"model\": {\n \"display_name\": \"Model\",\n \"advanced\": False,\n \"options\": [\n \"text-embedding-3-small\",\n \"text-embedding-3-large\",\n \"text-embedding-ada-002\",\n ],\n },\n \"model_kwargs\": {\"display_name\": \"Model Kwargs\", \"advanced\": True},\n \"openai_api_base\": {\n \"display_name\": \"OpenAI API Base\",\n \"password\": True,\n \"advanced\": True,\n },\n \"openai_api_key\": {\"display_name\": \"OpenAI API Key\", \"password\": True},\n \"openai_api_type\": {\n \"display_name\": \"OpenAI API Type\",\n \"advanced\": True,\n \"password\": True,\n },\n \"openai_api_version\": {\n \"display_name\": \"OpenAI API Version\",\n \"advanced\": True,\n },\n \"openai_organization\": {\n \"display_name\": \"OpenAI Organization\",\n \"advanced\": True,\n },\n \"openai_proxy\": {\"display_name\": \"OpenAI Proxy\", \"advanced\": True},\n \"request_timeout\": {\"display_name\": \"Request Timeout\", \"advanced\": True},\n \"show_progress_bar\": {\n \"display_name\": \"Show Progress Bar\",\n \"advanced\": True,\n },\n \"skip_empty\": {\"display_name\": \"Skip Empty\", \"advanced\": True},\n \"tiktoken_model_name\": {\n \"display_name\": \"TikToken Model Name\",\n \"advanced\": True,\n },\n \"tiktoken_enable\": {\"display_name\": \"TikToken Enable\", \"advanced\": True},\n }\n\n def build(\n self,\n openai_api_key: str,\n default_headers: Optional[Dict[str, str]] = None,\n default_query: Optional[NestedDict] = {},\n allowed_special: List[str] = [],\n disallowed_special: List[str] = [\"all\"],\n chunk_size: int = 1000,\n deployment: str = \"text-embedding-ada-002\",\n embedding_ctx_length: int = 8191,\n max_retries: int = 6,\n model: str = \"text-embedding-ada-002\",\n model_kwargs: NestedDict = {},\n openai_api_base: Optional[str] = None,\n openai_api_type: Optional[str] = None,\n openai_api_version: Optional[str] = None,\n openai_organization: Optional[str] = None,\n openai_proxy: Optional[str] = None,\n request_timeout: Optional[float] = None,\n show_progress_bar: bool = False,\n skip_empty: bool = False,\n tiktoken_enable: bool = True,\n tiktoken_model_name: Optional[str] = None,\n ) -> Embeddings:\n # This is to avoid errors with Vector Stores (e.g Chroma)\n if disallowed_special == [\"all\"]:\n disallowed_special = \"all\" # type: ignore\n if openai_api_key:\n api_key = SecretStr(openai_api_key)\n else:\n api_key = None\n\n return OpenAIEmbeddings(\n tiktoken_enabled=tiktoken_enable,\n default_headers=default_headers,\n default_query=default_query,\n allowed_special=set(allowed_special),\n disallowed_special=\"all\",\n chunk_size=chunk_size,\n deployment=deployment,\n embedding_ctx_length=embedding_ctx_length,\n max_retries=max_retries,\n model=model,\n model_kwargs=model_kwargs,\n base_url=openai_api_base,\n api_key=api_key,\n openai_api_type=openai_api_type,\n api_version=openai_api_version,\n organization=openai_organization,\n openai_proxy=openai_proxy,\n timeout=request_timeout,\n show_progress_bar=show_progress_bar,\n skip_empty=skip_empty,\n tiktoken_model_name=tiktoken_model_name,\n )\n" + }, + "default_headers": { + "advanced": true, + "display_name": "Default Headers", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "default_headers", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "dict" + }, + "default_query": { + "advanced": true, + "display_name": "Default Query", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "default_query", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "deployment": { + "advanced": true, + "display_name": "Deployment", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "deployment", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "text-embedding-ada-002" + }, + "disallowed_special": { + "advanced": true, + "display_name": "Disallowed Special", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "disallowed_special", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": [ + "all" + ] + }, + "embedding_ctx_length": { + "advanced": true, + "display_name": "Embedding Context Length", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "embedding_ctx_length", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 8191 + }, + "max_retries": { + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "max_retries", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "int", + "value": 6 + }, + "model": { + "advanced": false, + "display_name": "Model", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": true, + "load_from_db": false, + "multiline": false, + "name": "model", + "options": [ + "text-embedding-3-small", + "text-embedding-3-large", + "text-embedding-ada-002" + ], + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "text-embedding-ada-002" + }, + "model_kwargs": { + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "model_kwargs", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "NestedDict", + "value": {} + }, + "openai_api_base": { + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_base", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_key": { + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": true, + "multiline": false, + "name": "openai_api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "openai_api_type": { + "advanced": true, + "display_name": "OpenAI API Type", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_type", + "password": true, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_api_version": { + "advanced": true, + "display_name": "OpenAI API Version", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_api_version", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_organization": { + "advanced": true, + "display_name": "OpenAI Organization", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_organization", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "openai_proxy": { + "advanced": true, + "display_name": "OpenAI Proxy", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "openai_proxy", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + }, + "request_timeout": { + "advanced": true, + "display_name": "Request Timeout", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "request_timeout", + "password": false, + "placeholder": "", + "rangeSpec": { + "max": 1, + "min": -1, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "type": "float" + }, + "show_progress_bar": { + "advanced": true, + "display_name": "Show Progress Bar", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "show_progress_bar", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "skip_empty": { + "advanced": true, + "display_name": "Skip Empty", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "skip_empty", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": false + }, + "tiktoken_enable": { + "advanced": true, + "display_name": "TikToken Enable", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": false, + "name": "tiktoken_enable", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "bool", + "value": true + }, + "tiktoken_model_name": { + "advanced": true, + "display_name": "TikToken Model Name", + "dynamic": false, + "fileTypes": [], + "file_path": "", + "info": "", + "input_types": [ + "Text" + ], + "list": false, + "load_from_db": false, + "multiline": false, + "name": "tiktoken_model_name", + "password": false, + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "type": "str" + } + } }, - "id": "OpenAIEmbeddings-9TPjc" + "type": "OpenAIEmbeddings" }, - "selected": false, - "width": 384, + "dragging": false, "height": 383, + "id": "OpenAIEmbeddings-9TPjc", + "position": { + "x": 2814.0402191223047, + "y": 1955.9268168273086 + }, "positionAbsolute": { "x": 2814.0402191223047, "y": 1955.9268168273086 }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextOutput-BDknO", - "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}", - "targetHandle": "{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-TextOutput-BDknO{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œTextOutputœ,œidœ:œTextOutput-BDknOœ}-Prompt-xeI6K{œfieldNameœ:œcontextœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "context", - "id": "Prompt-xeI6K", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "TextOutput", - "id": "TextOutput-BDknO" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "ChatInput-yxMKE", - "target": "Prompt-xeI6K", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", - "targetHandle": "{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-Prompt-xeI6K{œfieldNameœ:œquestionœ,œidœ:œPrompt-xeI6Kœ,œinputTypesœ:[œDocumentœ,œBaseOutputParserœ,œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "question", - "id": "Prompt-xeI6K", - "inputTypes": ["Document", "BaseOutputParser", "Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object", "Record"], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "Prompt-xeI6K", - "target": "OpenAIModel-EjXlN", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-Prompt-xeI6K{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œPromptœ,œidœ:œPrompt-xeI6Kœ}-OpenAIModel-EjXlN{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-EjXlNœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-EjXlN", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "Prompt", - "id": "Prompt-xeI6K" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIModel-EjXlN", - "target": "ChatOutput-Q39I8", - "sourceHandle": "{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "id": "reactflow__edge-OpenAIModel-EjXlN{œbaseClassesœ:[œobjectœ,œTextœ,œstrœ],œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-EjXlNœ}-ChatOutput-Q39I8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Q39I8œ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-Q39I8", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["object", "Text", "str"], - "dataType": "OpenAIModel", - "id": "OpenAIModel-EjXlN" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "File-t0a6a", - "target": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", - "id": "reactflow__edge-File-t0a6a{œbaseClassesœ:[œRecordœ],œdataTypeœ:œFileœ,œidœ:œFile-t0a6aœ}-RecursiveCharacterTextSplitter-tR9QM{œfieldNameœ:œinputsœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ,œinputTypesœ:[œDocumentœ,œRecordœ],œtypeœ:œDocumentœ}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "RecursiveCharacterTextSplitter-tR9QM", - "inputTypes": ["Document", "Record"], - "type": "Document" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "File", - "id": "File-t0a6a" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "selected": false - }, - { - "source": "OpenAIEmbeddings-ZlOk1", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDBSearch-41nRz", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": ["Embeddings"], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-ZlOk1" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-ZlOk1{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-ZlOk1œ}-AstraDBSearch-41nRz{œfieldNameœ:œembeddingœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}" - }, - { - "source": "ChatInput-yxMKE", - "sourceHandle": "{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}", - "target": "AstraDBSearch-41nRz", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "AstraDBSearch-41nRz", - "inputTypes": ["Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Text", "str", "object", "Record"], - "dataType": "ChatInput", - "id": "ChatInput-yxMKE" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-ChatInput-yxMKE{œbaseClassesœ:[œTextœ,œstrœ,œobjectœ,œRecordœ],œdataTypeœ:œChatInputœ,œidœ:œChatInput-yxMKEœ}-AstraDBSearch-41nRz{œfieldNameœ:œinput_valueœ,œidœ:œAstraDBSearch-41nRzœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}" - }, - { - "source": "RecursiveCharacterTextSplitter-tR9QM", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}", - "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", - "data": { - "targetHandle": { - "fieldName": "inputs", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Record" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "RecursiveCharacterTextSplitter", - "id": "RecursiveCharacterTextSplitter-tR9QM" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-RecursiveCharacterTextSplitter-tR9QM{œbaseClassesœ:[œRecordœ],œdataTypeœ:œRecursiveCharacterTextSplitterœ,œidœ:œRecursiveCharacterTextSplitter-tR9QMœ}-AstraDB-eUCSS{œfieldNameœ:œinputsœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œRecordœ}", - "selected": false - }, - { - "source": "OpenAIEmbeddings-9TPjc", - "sourceHandle": "{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}", - "target": "AstraDB-eUCSS", - "targetHandle": "{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "data": { - "targetHandle": { - "fieldName": "embedding", - "id": "AstraDB-eUCSS", - "inputTypes": null, - "type": "Embeddings" - }, - "sourceHandle": { - "baseClasses": ["Embeddings"], - "dataType": "OpenAIEmbeddings", - "id": "OpenAIEmbeddings-9TPjc" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-OpenAIEmbeddings-9TPjc{œbaseClassesœ:[œEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9TPjcœ}-AstraDB-eUCSS{œfieldNameœ:œembeddingœ,œidœ:œAstraDB-eUCSSœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}", - "selected": false - }, - { - "source": "AstraDBSearch-41nRz", - "sourceHandle": "{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}", - "target": "TextOutput-BDknO", - "targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}", - "data": { - "targetHandle": { - "fieldName": "input_value", - "id": "TextOutput-BDknO", - "inputTypes": ["Record", "Text"], - "type": "str" - }, - "sourceHandle": { - "baseClasses": ["Record"], - "dataType": "AstraDBSearch", - "id": "AstraDBSearch-41nRz" - } - }, - "style": { - "stroke": "#555" - }, - "className": "stroke-gray-900 stroke-connection", - "id": "reactflow__edge-AstraDBSearch-41nRz{œbaseClassesœ:[œRecordœ],œdataTypeœ:œAstraDBSearchœ,œidœ:œAstraDBSearch-41nRzœ}-TextOutput-BDknO{œfieldNameœ:œinput_valueœ,œidœ:œTextOutput-BDknOœ,œinputTypesœ:[œRecordœ,œTextœ],œtypeœ:œstrœ}" + "selected": false, + "type": "genericNode", + "width": 384 } ], "viewport": { @@ -3145,7 +3307,8 @@ } }, "description": "Visit https://pre-release.langflow.org/tutorials/rag-with-astradb for a detailed guide of this project.\nThis project give you both Ingestion and RAG in a single file. You'll need to visit https://astra.datastax.com/ to create an Astra DB instance, your Token and grab an API Endpoint.\nRunning this project requires you to add a file in the Files component, then define a Collection Name and click on the Play icon on the Astra DB component. \n\nAfter the ingestion ends you are ready to click on the Run button at the lower left corner and start asking questions about your data.", - "name": "Vector Store RAG", + "id": "51e2b78a-199b-4054-9f32-e288eef6924c", + "is_component": false, "last_tested_version": "1.0.0a0", - "is_component": false -} + "name": "Vector Store RAG" +} \ No newline at end of file diff --git a/src/backend/base/langflow/interface/initialize/loading.py b/src/backend/base/langflow/interface/initialize/loading.py index 7b336487e..afe653e42 100644 --- a/src/backend/base/langflow/interface/initialize/loading.py +++ b/src/backend/base/langflow/interface/initialize/loading.py @@ -8,7 +8,7 @@ from loguru import logger from langflow.custom.eval import eval_custom_component_code from langflow.graph.utils import get_artifact_type, post_process_raw -from langflow.schema.schema import Record +from langflow.schema import Record if TYPE_CHECKING: from langflow.custom import CustomComponent @@ -130,10 +130,10 @@ async def instantiate_custom_component(params, user_id, vertex, fallback_to_env_ if not isinstance(custom_repr, str): custom_repr = str(custom_repr) raw = custom_component.repr_value - if hasattr(raw, "data"): + if hasattr(raw, "data") and raw is not None: raw = raw.data - elif hasattr(raw, "model_dump"): + elif hasattr(raw, "model_dump") and raw is not None: raw = raw.model_dump() artifact_type = get_artifact_type(custom_component, build_result) diff --git a/src/backend/base/langflow/memory.py b/src/backend/base/langflow/memory.py index f44958fdd..9a07f4bc1 100644 --- a/src/backend/base/langflow/memory.py +++ b/src/backend/base/langflow/memory.py @@ -1,9 +1,9 @@ import warnings -from typing import List, Optional, Union +from typing import List, Optional from loguru import logger -from langflow.schema import Record +from langflow.schema.message import Message from langflow.services.deps import get_monitor_service from langflow.services.monitor.schema import MessageModel @@ -39,54 +39,46 @@ def get_messages( order=order, ) - records: list[Record] = [] + messages: list[Message] = [] # messages_df has a timestamp # it gets the last 5 messages, for example # but now they are ordered from most recent to least recent # so we need to reverse the order messages_df = messages_df[::-1] if order == "DESC" else messages_df for row in messages_df.itertuples(): - record = Record( - data={ - "text": row.message, - "sender": row.sender, - "sender_name": row.sender_name, - "session_id": row.session_id, - "timestamp": row.timestamp, - }, - ) - records.append(record) + msg = Message(text=row.text, sender=row.sender, sender_name=row.sender_name, timestamp=row.timestamp) - return records + messages.append(msg) + + return messages -def add_messages(records: Union[list[Record], Record], flow_id: Optional[str] = None): +def add_messages(messages: Message | list[Message], flow_id: Optional[str] = None): """ Add a message to the monitor service. """ try: monitor_service = get_monitor_service() + if not isinstance(messages, list): + messages = [messages] - if isinstance(records, Record): - records = [records] + if not all(isinstance(message, Message) for message in messages): + types = ", ".join([str(type(message)) for message in messages]) + raise ValueError(f"The messages must be instances of Message. Found: {types}") - if not all(isinstance(record, (Record, str)) for record in records): - types = ", ".join([str(type(record)) for record in records]) - raise ValueError(f"The records must be instances of Record. Found: {types}") + messages_models: list[MessageModel] = [] + for msg in messages: + msg.timestamp = monitor_service.get_timestamp() + messages_models.append(MessageModel.from_message(msg, flow_id=flow_id)) - messages: list[MessageModel] = [] - for record in records: - record.timestamp = monitor_service.get_timestamp() - messages.append(MessageModel.from_record(record, flow_id=flow_id)) - - for message in messages: + for message_model in messages_models: try: - monitor_service.add_message(message) + monitor_service.add_message(message_model) except Exception as e: logger.error(f"Error adding message to monitor service: {e}") logger.exception(e) raise e - return records + return messages_models except Exception as e: logger.exception(e) raise e @@ -100,28 +92,22 @@ def delete_messages(session_id: str): session_id (str): The session ID associated with the messages to delete. """ monitor_service = get_monitor_service() - monitor_service.delete_messages(session_id) + monitor_service.delete_messages_session(session_id) def store_message( - message: Union[str, Record], - session_id: Optional[str] = None, - sender: Optional[str] = None, - sender_name: Optional[str] = None, + message: Message, flow_id: Optional[str] = None, -) -> List[Record]: +) -> List[Message]: """ Stores a message in the memory. Args: - message (Union[str, Record]): The message to be stored. It can be either a string or a Record object. - session_id (Optional[str]): The session ID associated with the message. - sender (Optional[str]): The sender ID associated with the message. - sender_name (Optional[str]): The name of the sender associated with the message. + message (Message): The message to store. flow_id (Optional[str]): The flow ID associated with the message. When running from the CustomComponent you can access this using `self.graph.flow_id`. Returns: - List[Record]: A list of records containing the stored message. + List[Message]: A list of records containing the stored message. Raises: ValueError: If any of the required parameters (session_id, sender, sender_name) is not provided. @@ -130,26 +116,7 @@ def store_message( warnings.warn("No message provided.") return [] - if not session_id or not sender or not sender_name: + if not message.session_id or not message.sender or not message.sender_name: raise ValueError("All of session_id, sender, and sender_name must be provided.") - if isinstance(message, Record): - record = message - record.data.update( - { - "session_id": session_id, - "sender": sender, - "sender_name": sender_name, - } - ) - elif isinstance(message, str): - record = Record( - data={ - "text": message, - "session_id": session_id, - "sender": sender, - "sender_name": sender_name, - }, - ) - - return add_messages([record], flow_id=flow_id) + return add_messages([message], flow_id=flow_id) diff --git a/src/backend/base/langflow/schema/__init__.py b/src/backend/base/langflow/schema/__init__.py index 14230578c..9f7e3b384 100644 --- a/src/backend/base/langflow/schema/__init__.py +++ b/src/backend/base/langflow/schema/__init__.py @@ -1,4 +1,4 @@ from .dotdict import dotdict -from .schema import Record +from .record import Record __all__ = ["Record", "dotdict"] diff --git a/src/backend/base/langflow/schema/image.py b/src/backend/base/langflow/schema/image.py new file mode 100644 index 000000000..552f75b8b --- /dev/null +++ b/src/backend/base/langflow/schema/image.py @@ -0,0 +1,63 @@ +import base64 + +from PIL import Image as PILImage +from pydantic import BaseModel + +from langflow.services.deps import get_storage_service + +IMAGE_ENDPOINT = "/files/images/" + + +def is_image_file(file_path): + try: + with PILImage.open(file_path) as img: + img.verify() # Verify that it is, in fact, an image + return True + except (IOError, SyntaxError): + return False + + +async def get_file_paths(files: list[str]): + storage_service = get_storage_service() + file_paths = [] + for file in files: + flow_id, file_name = file.split("/") + file_paths.append(storage_service.build_full_path(flow_id=flow_id, file_name=file_name)) + return file_paths + + +async def get_files( + file_paths: list[str], + convert_to_base64: bool = False, +): + storage_service = get_storage_service() + file_objects: list[str | bytes] = [] + for file_path in file_paths: + flow_id, file_name = file_path.split("/") + file_object = await storage_service.get_file(flow_id=flow_id, file_name=file_name) + if convert_to_base64: + file_base64 = base64.b64encode(file_object).decode("utf-8") + file_objects.append(file_base64) + else: + file_objects.append(file_object) + return file_objects + + +class Image(BaseModel): + path: str | None = None + url: str | None = None + + def to_base64(self): + if self.path: + files = get_files([self.path], convert_to_base64=True) + return files[0] + raise ValueError("Image path is not set.") + + def to_content_dict(self): + return { + "type": "image_url", + "image_url": self.to_base64(), + } + + def get_url(self): + return f"{IMAGE_ENDPOINT}{self.path}" diff --git a/src/backend/base/langflow/schema/message.py b/src/backend/base/langflow/schema/message.py new file mode 100644 index 000000000..865d684bf --- /dev/null +++ b/src/backend/base/langflow/schema/message.py @@ -0,0 +1,111 @@ +from datetime import datetime, timezone +from typing import Annotated, Any, AsyncIterator, Iterator, Optional + +from langchain_core.messages import AIMessage, BaseMessage, HumanMessage +from langchain_core.prompt_values import ImagePromptValue +from langchain_core.prompts.image import ImagePromptTemplate +from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, field_serializer + +from langflow.schema.image import Image, get_file_paths, is_image_file +from langflow.schema.record import Record + + +def _timestamp_to_str(timestamp: datetime) -> str: + return timestamp.strftime("%Y-%m-%d %H:%M:%S") + + +class Message(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) + # Helper class to deal with image data + text: Optional[str | AsyncIterator | Iterator] = Field(default="") + sender: str + sender_name: str + files: Optional[list[str | Image]] = Field(default=[]) + session_id: Optional[str] = Field(default="") + timestamp: Annotated[str, BeforeValidator(_timestamp_to_str)] = Field( + default=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S") + ) + flow_id: Optional[str] = None + + def model_post_init(self, __context: Any) -> None: + new_files = [] + for file in self.files or []: + if is_image_file(file): + new_files.append(Image(path=file)) + else: + new_files.append(file) + self.files = new_files + + def to_lc_message( + self, + ) -> BaseMessage: + """ + Converts the Record to a BaseMessage. + + Returns: + BaseMessage: The converted BaseMessage. + """ + # The idea of this function is to be a helper to convert a Record to a BaseMessage + # It will use the "sender" key to determine if the message is Human or AI + # If the key is not present, it will default to AI + # But first we check if all required keys are present in the data dictionary + # they are: "text", "sender" + if self.text is None or not self.sender: + raise ValueError("Missing required keys ('text', 'sender') in Message.") + + if self.sender == "User": + if self.files: + contents = [{"type": "text", "text": self.text}] + contents.extend(self.get_file_content_dicts()) + human_message = HumanMessage(content=contents) + else: + human_message = HumanMessage( + content=[{"type": "text", "text": self.text}], + ) + + return human_message + + return AIMessage(content=self.text) + + @classmethod + def from_record(cls, record: Record) -> "Message": + """ + Converts a BaseMessage to a Record. + + Args: + record (BaseMessage): The BaseMessage to convert. + + Returns: + Record: The converted Record. + """ + + return cls( + text=record.text, + sender=record.sender, + sender_name=record.sender_name, + files=record.files, + session_id=record.session_id, + timestamp=record.timestamp, + flow_id=record.flow_id, + ) + + @field_serializer("text", mode="plain") + def serialize_text(self, value): + if isinstance(value, AsyncIterator): + return "" + elif isinstance(value, Iterator): + return "" + return value + + async def get_file_content_dicts(self): + content_dicts = [] + files = await get_file_paths(self.files) + + for file in files: + if isinstance(file, Image): + content_dicts.append(file.to_content_dict()) + else: + image_template = ImagePromptTemplate() + image_prompt_value: ImagePromptValue = image_template.invoke(input={"path": file}) + content_dicts.append({"type": "image_url", "image_url": image_prompt_value.image_url}) + return content_dicts diff --git a/src/backend/base/langflow/schema/record.py b/src/backend/base/langflow/schema/record.py new file mode 100644 index 000000000..830f576ba --- /dev/null +++ b/src/backend/base/langflow/schema/record.py @@ -0,0 +1,202 @@ +import copy +import json +from typing import cast, Optional + +from langchain_core.documents import Document +from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage +from langchain_core.prompts.image import ImagePromptTemplate +from pydantic import BaseModel, model_serializer, model_validator +from langchain_core.prompt_values import ImagePromptValue + + +class Record(BaseModel): + """ + Represents a record with text and optional data. + + Attributes: + data (dict, optional): Additional data associated with the record. + """ + + text_key: str = "text" + data: dict = {} + default_value: Optional[str] = "" + + @model_validator(mode="before") + def validate_data(cls, values): + if not values.get("data"): + values["data"] = {} + # Any other keyword should be added to the data dictionary + for key in values: + if key not in values["data"] and key not in {"text_key", "data", "default_value"}: + values["data"][key] = values[key] + return values + + @model_serializer(mode="plain", when_used="json") + def serialize_model(self): + data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()} + return data + + def get_text(self): + """ + Retrieves the text value from the data dictionary. + + If the text key is present in the data dictionary, the corresponding value is returned. + Otherwise, the default value is returned. + + Returns: + The text value from the data dictionary or the default value. + """ + return self.data.get(self.text_key, self.default_value) + + @classmethod + def from_document(cls, document: Document) -> "Record": + """ + Converts a Document to a Record. + + Args: + document (Document): The Document to convert. + + Returns: + Record: The converted Record. + """ + data = document.metadata + data["text"] = document.page_content + return cls(data=data, text_key="text") + + @classmethod + def from_lc_message(cls, message: BaseMessage) -> "Record": + """ + Converts a BaseMessage to a Record. + + Args: + message (BaseMessage): The BaseMessage to convert. + + Returns: + Record: The converted Record. + """ + data: dict = {"text": message.content} + data["metadata"] = cast(dict, message.to_json()) + return cls(data=data, text_key="text") + + def __add__(self, other: "Record") -> "Record": + """ + Combines the data of two records by attempting to add values for overlapping keys + for all types that support the addition operation. Falls back to the value from 'other' + record when addition is not supported. + """ + combined_data = self.data.copy() + for key, value in other.data.items(): + # If the key exists in both records and both values support the addition operation + if key in combined_data: + try: + combined_data[key] += value + except TypeError: + # Fallback: Use the value from 'other' record if addition is not supported + combined_data[key] = value + else: + # If the key is not in the first record, simply add it + combined_data[key] = value + + return Record(data=combined_data) + + def to_lc_document(self) -> Document: + """ + Converts the Record to a Document. + + Returns: + Document: The converted Document. + """ + text = self.data.pop(self.text_key, self.default_value) + return Document(page_content=text, metadata=self.data) + + def to_lc_message( + self, + ) -> HumanMessage | SystemMessage: + """ + Converts the Record to a BaseMessage. + + Returns: + BaseMessage: The converted BaseMessage. + """ + # The idea of this function is to be a helper to convert a Record to a BaseMessage + # It will use the "sender" key to determine if the message is Human or AI + # If the key is not present, it will default to AI + # But first we check if all required keys are present in the data dictionary + # they are: "text", "sender" + if not all(key in self.data for key in ["text", "sender"]): + raise ValueError(f"Missing required keys ('text', 'sender') in Record: {self.data}") + sender = self.data.get("sender", "Machine") + text = self.data.get("text", "") + files = self.data.get("files", []) + if sender == "User": + if files: + contents = [{"type": "text", "text": text}] + for file_path in files: + image_template = ImagePromptTemplate() + image_prompt_value: ImagePromptValue = image_template.invoke(input={"path": file_path}) + contents.append({"type": "image_url", "image_url": image_prompt_value.image_url}) + human_message = HumanMessage(content=contents) + else: + human_message = HumanMessage( + content=[{"type": "text", "text": text}], + ) + + return human_message + + return AIMessage(content=text) + + def __getattr__(self, key): + """ + Allows attribute-like access to the data dictionary. + """ + try: + if key.startswith("__"): + return self.__getattribute__(key) + if key in {"data", "text_key"} or key.startswith("_"): + return super().__getattr__(key) + + return self.data.get(key, self.default_value) + except KeyError: + # Fallback to default behavior to raise AttributeError for undefined attributes + raise AttributeError(f"'{type(self).__name__}' object has no attribute '{key}'") + + def __setattr__(self, key, value): + """ + Allows attribute-like setting of values in the data dictionary, + while still allowing direct assignment to class attributes. + """ + if key in {"data", "text_key"} or key.startswith("_"): + super().__setattr__(key, value) + else: + self.data[key] = value + + def __delattr__(self, key): + """ + Allows attribute-like deletion from the data dictionary. + """ + if key in {"data", "text_key"} or key.startswith("_"): + super().__delattr__(key) + else: + del self.data[key] + + def __deepcopy__(self, memo): + """ + Custom deepcopy implementation to handle copying of the Record object. + """ + # Create a new Record object with a deep copy of the data dictionary + return Record(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value) + + # check which attributes the Record has by checking the keys in the data dictionary + def __dir__(self): + return super().__dir__() + list(self.data.keys()) + + def __str__(self) -> str: + # return a JSON string representation of the Record atributes + try: + data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()} + return json.dumps(data, indent=4) + except Exception: + return str(self.data) + + def __contains__(self, key): + return key in self.data diff --git a/src/backend/base/langflow/schema/schema.py b/src/backend/base/langflow/schema/schema.py index 209cb51c8..5153941a5 100644 --- a/src/backend/base/langflow/schema/schema.py +++ b/src/backend/base/langflow/schema/schema.py @@ -1,207 +1,7 @@ -import copy -import json -from typing import Literal, Optional, cast +from typing import Literal + from typing_extensions import TypedDict -from langchain_core.documents import Document -from langchain_core.messages import AIMessage, BaseMessage, HumanMessage -from langchain_core.prompts.image import ImagePromptTemplate -from pydantic import BaseModel, model_serializer, model_validator - - -class Record(BaseModel): - """ - Represents a record with text and optional data. - - Attributes: - data (dict, optional): Additional data associated with the record. - """ - - text_key: str = "text" - data: dict = {} - default_value: Optional[str] = "" - - @model_validator(mode="before") - def validate_data(cls, values): - if not values.get("data"): - values["data"] = {} - # Any other keyword should be added to the data dictionary - for key in values: - if key not in values["data"] and key not in {"text_key", "data", "default_value"}: - values["data"][key] = values[key] - return values - - @model_serializer(mode="plain", when_used="json") - def serialize_model(self): - data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()} - return data - - def get_text(self): - """ - Retrieves the text value from the data dictionary. - - If the text key is present in the data dictionary, the corresponding value is returned. - Otherwise, the default value is returned. - - Returns: - The text value from the data dictionary or the default value. - """ - return self.data.get(self.text_key, self.default_value) - - @classmethod - def from_document(cls, document: Document) -> "Record": - """ - Converts a Document to a Record. - - Args: - document (Document): The Document to convert. - - Returns: - Record: The converted Record. - """ - data = document.metadata - data["text"] = document.page_content - return cls(data=data, text_key="text") - - @classmethod - def from_lc_message(cls, message: BaseMessage) -> "Record": - """ - Converts a BaseMessage to a Record. - - Args: - message (BaseMessage): The BaseMessage to convert. - - Returns: - Record: The converted Record. - """ - data: dict = {"text": message.content} - data["metadata"] = cast(dict, message.to_json()) - return cls(data=data, text_key="text") - - def __add__(self, other: "Record") -> "Record": - """ - Combines the data of two records by attempting to add values for overlapping keys - for all types that support the addition operation. Falls back to the value from 'other' - record when addition is not supported. - """ - combined_data = self.data.copy() - for key, value in other.data.items(): - # If the key exists in both records and both values support the addition operation - if key in combined_data: - try: - combined_data[key] += value - except TypeError: - # Fallback: Use the value from 'other' record if addition is not supported - combined_data[key] = value - else: - # If the key is not in the first record, simply add it - combined_data[key] = value - - return Record(data=combined_data) - - def to_lc_document(self) -> Document: - """ - Converts the Record to a Document. - - Returns: - Document: The converted Document. - """ - text = self.data.pop(self.text_key, self.default_value) - return Document(page_content=text, metadata=self.data) - - def to_lc_message( - self, - ) -> BaseMessage: - """ - Converts the Record to a BaseMessage. - - Returns: - BaseMessage: The converted BaseMessage. - """ - # The idea of this function is to be a helper to convert a Record to a BaseMessage - # It will use the "sender" key to determine if the message is Human or AI - # If the key is not present, it will default to AI - # But first we check if all required keys are present in the data dictionary - # they are: "text", "sender" - if not all(key in self.data for key in ["text", "sender"]): - raise ValueError(f"Missing required keys ('text', 'sender') in Record: {self.data}") - sender = self.data.get("sender", "Machine") - text = self.data.get("text", "") - files = self.data.get("files", []) - if sender == "User": - if files: - contents = [{"type": "text", "text": text}] - for file_path in files: - image_template = ImagePromptTemplate() - image_prompt_value = image_template.invoke(input={"path": file_path}) - contents.append({"type": "image_url", "image_url": image_prompt_value.image_url}) - human_message = HumanMessage(content=contents) - else: - human_message = HumanMessage( - content=[{"type": "text", "text": text}], - ) - - return human_message - - return AIMessage(content=text) - - def __getattr__(self, key): - """ - Allows attribute-like access to the data dictionary. - """ - try: - if key.startswith("__"): - return self.__getattribute__(key) - if key in {"data", "text_key"} or key.startswith("_"): - return super().__getattr__(key) - - return self.data.get(key, self.default_value) - except KeyError: - # Fallback to default behavior to raise AttributeError for undefined attributes - raise AttributeError(f"'{type(self).__name__}' object has no attribute '{key}'") - - def __setattr__(self, key, value): - """ - Allows attribute-like setting of values in the data dictionary, - while still allowing direct assignment to class attributes. - """ - if key in {"data", "text_key"} or key.startswith("_"): - super().__setattr__(key, value) - else: - self.data[key] = value - - def __delattr__(self, key): - """ - Allows attribute-like deletion from the data dictionary. - """ - if key in {"data", "text_key"} or key.startswith("_"): - super().__delattr__(key) - else: - del self.data[key] - - def __deepcopy__(self, memo): - """ - Custom deepcopy implementation to handle copying of the Record object. - """ - # Create a new Record object with a deep copy of the data dictionary - return Record(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value) - - # check which attributes the Record has by checking the keys in the data dictionary - def __dir__(self): - return super().__dir__() + list(self.data.keys()) - - def __str__(self) -> str: - # return a JSON string representation of the Record atributes - try: - data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()} - return json.dumps(data, indent=4) - except Exception: - return str(self.data) - - def __contains__(self, key): - return key in self.data - - INPUT_FIELD_NAME = "input_value" InputType = Literal["chat", "text", "any"] diff --git a/src/backend/base/langflow/services/database/models/flow/model.py b/src/backend/base/langflow/services/database/models/flow/model.py index 4de1e0bc8..a3f9a055d 100644 --- a/src/backend/base/langflow/services/database/models/flow/model.py +++ b/src/backend/base/langflow/services/database/models/flow/model.py @@ -13,7 +13,7 @@ from pydantic import field_serializer, field_validator from sqlalchemy import UniqueConstraint from sqlmodel import JSON, Column, Field, Relationship, SQLModel -from langflow.schema.schema import Record +from langflow.schema import Record if TYPE_CHECKING: from langflow.services.database.models.folder import Folder diff --git a/src/backend/base/langflow/services/monitor/schema.py b/src/backend/base/langflow/services/monitor/schema.py index 4cb057ccc..ca267ac2b 100644 --- a/src/backend/base/langflow/services/monitor/schema.py +++ b/src/backend/base/langflow/services/monitor/schema.py @@ -1,11 +1,10 @@ import json from datetime import datetime -from typing import TYPE_CHECKING, Any, Optional +from typing import Any, Optional from pydantic import BaseModel, Field, field_serializer, field_validator -if TYPE_CHECKING: - from langflow.schema import Record +from langflow.schema.message import Message class TransactionModel(BaseModel): @@ -77,7 +76,7 @@ class MessageModel(BaseModel): sender: str sender_name: str session_id: str - message: str + text: str files: list[str] = [] class Config: @@ -91,18 +90,17 @@ class MessageModel(BaseModel): return v @classmethod - def from_record(cls, record: "Record", flow_id: Optional[str] = None): + def from_message(cls, message: Message, flow_id: Optional[str] = None): # first check if the record has all the required fields - if not record.data or ("sender" not in record.data and "sender_name" not in record.data): - raise ValueError("The record does not have the required fields 'sender' and 'sender_name' in the data.") + if not message.text or not message.sender or not message.sender_name: + raise ValueError("The message does not have the required fields 'sender' and 'sender_name' in the data.") return cls( - sender=record.sender, - sender_name=record.sender_name, - message=record.text, - session_id=record.session_id, - files=record.files or [], - artifacts=record.artifacts or {}, - timestamp=record.timestamp, + sender=message.sender, + sender_name=message.sender_name, + text=message.text, + session_id=message.session_id, + files=message.files or [], + timestamp=message.timestamp, flow_id=flow_id, ) @@ -121,7 +119,7 @@ class MessageModelResponse(MessageModel): class MessageModelRequest(MessageModel): - message: str = Field(default="") + text: str = Field(default="") sender: str = Field(default="") sender_name: str = Field(default="") session_id: str = Field(default="") diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index 6c37672af..2badabc1f 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -92,8 +92,6 @@ class MonitorService(Service): with duckdb.connect(str(self.db_path)) as conn: df = conn.execute(query).df() - print(query) - return df.to_dict(orient="records") def delete_vertex_builds(self, flow_id: Optional[str] = None): @@ -134,7 +132,7 @@ class MonitorService(Service): order: Optional[str] = "DESC", limit: Optional[int] = None, ): - query = "SELECT index, flow_id, sender_name, sender, session_id, message, timestamp FROM messages" + query = "SELECT index, flow_id, sender_name, sender, session_id, text, timestamp FROM messages" conditions = [] if sender: conditions.append(f"sender = '{sender}'") diff --git a/src/backend/base/langflow/template/field/prompt.py b/src/backend/base/langflow/template/field/prompt.py index ccc5d01a0..138b90131 100644 --- a/src/backend/base/langflow/template/field/prompt.py +++ b/src/backend/base/langflow/template/field/prompt.py @@ -10,5 +10,5 @@ class DefaultPromptField(TemplateField): advanced: bool = False multiline: bool = True - input_types: list[str] = ["Document", "Record", "Text"] + input_types: list[str] = ["Document", "Message", "Record", "Text"] value: str = "" # Set the value to empty string diff --git a/src/backend/base/langflow/utils/util.py b/src/backend/base/langflow/utils/util.py index bc7efc161..89b44bd0e 100644 --- a/src/backend/base/langflow/utils/util.py +++ b/src/backend/base/langflow/utils/util.py @@ -7,8 +7,7 @@ from typing import Any, Dict, List, Optional, Union from docstring_parser import parse - -from langflow.schema.schema import Record +from langflow.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 diff --git a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx index 21004dbc4..307c77c1a 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/components/switchOutputView/index.tsx @@ -24,6 +24,7 @@ export default function SwitchOutputView(nodeId): JSX.Element { const results = flowPoolNode?.data?.logs[0] ?? ""; const resultType = results?.type; let resultMessage = results?.message; + const RECORD_TYPES = ["record", "object", "array", "message"]; if (resultMessage.raw) { resultMessage = resultMessage.raw; } @@ -41,34 +42,20 @@ export default function SwitchOutputView(nodeId): JSX.Element { - + ).every((item) => item.data) + ? (resultMessage as Array).map((item) => item.data) + : resultMessage + : [resultMessage] + } pagination={true} columnMode="union" /> - - - - {Array.isArray(resultMessage) && ( - - ).every((item) => item.data) - ? (resultMessage as Array).map((item) => item.data) - : resultMessage - } - pagination={true} - columnMode="union" - /> - - )}
diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index fd3847e97..f9113594c 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -63,7 +63,7 @@ export async function sendAll(data: sendAllProps) { } export async function postValidateCode( - code: string, + code: string ): Promise> { return await api.post(`${BASE_URL_API}validate/code`, { code }); } @@ -78,7 +78,7 @@ export async function postValidateCode( export async function postValidatePrompt( name: string, template: string, - frontend_node: APIClassType, + frontend_node: APIClassType ): Promise> { return api.post(`${BASE_URL_API}validate/prompt`, { name, @@ -151,7 +151,7 @@ export async function saveFlowToDatabase(newFlow: { * @throws Will throw an error if the update fails. */ export async function updateFlowInDatabase( - updatedFlow: FlowType, + updatedFlow: FlowType ): Promise { try { const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, { @@ -329,7 +329,7 @@ export async function getHealth() { * */ export async function getBuildStatus( - flowId: string, + flowId: string ): Promise> { return await api.get(`${BASE_URL_API}build/${flowId}/status`); } @@ -342,7 +342,7 @@ export async function getBuildStatus( * */ export async function postBuildInit( - flow: FlowType, + flow: FlowType ): Promise> { return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow); } @@ -358,7 +358,7 @@ export async function postBuildInit( */ export async function uploadFile( file: File, - id: string, + id: string ): Promise> { const formData = new FormData(); formData.append("file", file); @@ -380,7 +380,7 @@ export async function getProfilePictures(): Promise> { // let template = apiClass.template; return await api.post(`${BASE_URL_API}custom_component`, { @@ -393,7 +393,7 @@ export async function postCustomComponentUpdate( code: string, template: APITemplateType, field: string, - field_value: any, + field_value: any ): Promise> { return await api.post(`${BASE_URL_API}custom_component/update`, { code, @@ -415,7 +415,7 @@ export async function onLogin(user: LoginType) { headers: { "Content-Type": "application/x-www-form-urlencoded", }, - }, + } ); if (response.status === 200) { @@ -477,11 +477,11 @@ export async function addUser(user: UserInputType): Promise> { export async function getUsersPage( skip: number, - limit: number, + limit: number ): Promise> { try { const res = await api.get( - `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`, + `${BASE_URL_API}users/?skip=${skip}&limit=${limit}` ); if (res.status === 200) { return res.data; @@ -518,7 +518,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) { try { const res = await api.patch( `${BASE_URL_API}users/${user_id}/reset-password`, - user, + user ); if (res.status === 200) { return res.data; @@ -592,7 +592,7 @@ export async function saveFlowStore( last_tested_version?: string; }, tags: string[], - publicFlow = false, + publicFlow = false ): Promise { try { const response = await api.post(`${BASE_URL_API}store/components/`, { @@ -721,7 +721,7 @@ export async function postStoreComponents(component: Component) { export async function getComponent(component_id: string) { try { const res = await api.get( - `${BASE_URL_API}store/components/${component_id}`, + `${BASE_URL_API}store/components/${component_id}` ); if (res.status === 200) { return res.data; @@ -736,7 +736,7 @@ export async function searchComponent( page?: number | null, limit?: number | null, status?: string | null, - tags?: string[], + tags?: string[] ): Promise { try { let url = `${BASE_URL_API}store/components/`; @@ -848,7 +848,7 @@ export async function updateFlowStore( }, tags: string[], publicFlow = false, - id: string, + id: string ): Promise { try { const response = await api.patch(`${BASE_URL_API}store/components/${id}`, { @@ -932,7 +932,7 @@ export async function deleteGlobalVariable(id: string) { export async function updateGlobalVariable( name: string, value: string, - id: string, + id: string ) { try { const response = api.patch(`${BASE_URL_API}variables/${id}`, { @@ -951,7 +951,7 @@ export async function getVerticesOrder( startNodeId?: string | null, stopNodeId?: string | null, nodes?: Node[], - Edges?: Edge[], + Edges?: Edge[] ): Promise> { // nodeId is optional and is a query parameter // if nodeId is not provided, the API will return all vertices @@ -971,7 +971,7 @@ export async function getVerticesOrder( return await api.post( `${BASE_URL_API}build/${flowId}/vertices`, data, - config, + config ); } @@ -979,16 +979,19 @@ export async function postBuildVertex( flowId: string, vertexId: string, input_value: string, - files?: string[], + files?: string[] ): Promise> { // input_value is optional and is a query parameter - const data = { inputs: { input_value: input_value ?? "" } }; + let data = {}; + if (typeof input_value !== "undefined") { + data["inputs"] = { input_value: input_value }; + } if (data && files) { data["files"] = files; } return await api.post( `${BASE_URL_API}build/${flowId}/vertices/${vertexId}`, - data, + data ); } @@ -1012,7 +1015,7 @@ export async function getFlowPool({ } export async function deleteFlowPool( - flowId: string, + flowId: string ): Promise> { const config = {}; config["params"] = { flow_id: flowId }; @@ -1026,7 +1029,7 @@ export async function deleteFlowPool( * @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses. */ export async function multipleDeleteFlowsComponents( - flowIds: string[], + flowIds: string[] ): Promise[]> { const batches: string[][] = []; @@ -1049,7 +1052,7 @@ export async function multipleDeleteFlowsComponents( // Execute all delete requests const responses: Promise>[] = batches.map((batch) => - deleteBatch(batch), + deleteBatch(batch) ); // Return the responses after all requests are completed @@ -1059,7 +1062,7 @@ export async function multipleDeleteFlowsComponents( export async function getTransactionTable( id: string, mode: "intersection" | "union", - params = {}, + params = {} ): Promise<{ rows: Array; columns: Array }> { const config = {}; config["params"] = { flow_id: id }; @@ -1075,7 +1078,7 @@ export async function getMessagesTable( mode: "intersection" | "union", id?: string, excludedFields?: string[], - params = {}, + params = {} ): Promise<{ rows: Array; columns: Array }> { const config = {}; if (id) { diff --git a/tests/test_data_components.py b/tests/test_data_components.py index 00b6eaa8a..975c81567 100644 --- a/tests/test_data_components.py +++ b/tests/test_data_components.py @@ -5,6 +5,7 @@ from unittest.mock import Mock, patch import httpx import pytest import respx +from dictdiffer import diff from httpx import Response from langflow.components import data @@ -164,8 +165,8 @@ def test_directory_without_mocks(): assert len(results) == len(projects) # each result is a Record that contains the content attribute # each are dict that are exactly the same as one of the projects - for result in results: - assert result.text in projects + for i, result in enumerate(results): + assert result.text in projects, list(diff(result.text, projects[i])) # in ../docs/docs/components there are many mdx files # check if the directory component can load them diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index 82c9ca598..4021022f8 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -448,7 +448,7 @@ def test_successful_run_no_payload(client, starter_project, created_api_key): assert all(["ChatOutput" in _id for _id in ids]) display_names = [output.get("component_display_name") for output in outputs_dict.get("outputs")] assert all([name in display_names for name in ["Chat Output"]]) - inner_results = [output.get("results").get("result") for output in outputs_dict.get("outputs")] + inner_results = [output.get("results").get("text") for output in outputs_dict.get("outputs")] assert all([result is not None for result in inner_results]), inner_results @@ -478,7 +478,7 @@ def test_successful_run_with_output_type_text(client, starter_project, created_a assert all(["ChatOutput" in _id for _id in ids]), ids display_names = [output.get("component_display_name") for output in outputs_dict.get("outputs")] assert all([name in display_names for name in ["Chat Output"]]), display_names - inner_results = [output.get("results").get("result") for output in outputs_dict.get("outputs")] + inner_results = [output.get("results").get("text") for output in outputs_dict.get("outputs")] expected_result = "" assert all([expected_result in result for result in inner_results]), inner_results @@ -509,7 +509,7 @@ def test_successful_run_with_output_type_any(client, starter_project, created_ap assert all(["ChatOutput" in _id or "TextOutput" in _id for _id in ids]), ids display_names = [output.get("component_display_name") for output in outputs_dict.get("outputs")] assert all([name in display_names for name in ["Chat Output"]]), display_names - inner_results = [output.get("results").get("result") for output in outputs_dict.get("outputs")] + inner_results = [output.get("results").get("text") for output in outputs_dict.get("outputs")] expected_result = "" assert all([expected_result in result for result in inner_results]), inner_results @@ -567,7 +567,7 @@ def test_successful_run_with_input_type_text(client, starter_project, created_ap text_input_outputs = [output for output in outputs_dict.get("outputs") if "TextInput" in output.get("component_id")] assert len(text_input_outputs) == 0 # Now we check if the input_value is correct - assert all([output.get("results").get("result") == "value1" for output in text_input_outputs]), text_input_outputs + assert all([output.get("results").get("text") == "value1" for output in text_input_outputs]), text_input_outputs # Now do the same for "chat" input type @@ -598,7 +598,7 @@ def test_successful_run_with_input_type_chat(client, starter_project, created_ap chat_input_outputs = [output for output in outputs_dict.get("outputs") if "ChatInput" in output.get("component_id")] assert len(chat_input_outputs) == 1 # Now we check if the input_value is correct - assert all([output.get("results").get("result") == "value1" for output in chat_input_outputs]), chat_input_outputs + assert all([output.get("results").get("text") == "value1" for output in chat_input_outputs]), chat_input_outputs def test_successful_run_with_input_type_any(client, starter_project, created_api_key): @@ -632,7 +632,7 @@ def test_successful_run_with_input_type_any(client, starter_project, created_api ] assert len(any_input_outputs) == 1 # Now we check if the input_value is correct - assert all([output.get("results").get("result") == "value1" for output in any_input_outputs]), any_input_outputs + assert all([output.get("results").get("text") == "value1" for output in any_input_outputs]), any_input_outputs @pytest.mark.api_key_required