diff --git a/poetry.lock b/poetry.lock index 243655b6f..fe56997ae 100644 --- a/poetry.lock +++ b/poetry.lock @@ -9295,6 +9295,20 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "vulture" +version = "2.11" +description = "Find dead code" +optional = false +python-versions = ">=3.8" +files = [ + {file = "vulture-2.11-py2.py3-none-any.whl", hash = "sha256:12d745f7710ffbf6aeb8279ba9068a24d4e52e8ed333b8b044035c9d6b823aba"}, + {file = "vulture-2.11.tar.gz", hash = "sha256:f0fbb60bce6511aad87ee0736c502456737490a82d919a44e6d92262cb35f1c2"}, +] + +[package.dependencies] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "watchfiles" version = "0.21.0" @@ -9991,4 +10005,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "33629727ceeb0aa86064658e89349c24fd786bb1bd3833f093651b70b264edb7" +content-hash = "90454066807e8ae6341a0b4e9569bfabb027b005081e94bbfb763ce8c72de10f" diff --git a/pyproject.toml b/pyproject.toml index 6a5401bea..230293411 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,7 @@ pytest-instafail = "^0.5.0" pytest-asyncio = "^0.23.0" pytest-profiling = "^1.7.0" pre-commit = "^3.7.0" +vulture = "^2.11" [tool.poetry.extras] deploy = ["celery", "redis", "flower"] diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index e7bb761ba..fdd04e571 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -18,9 +18,9 @@ from langflow.api.v1.schemas import ( UpdateCustomComponentRequest, UploadFileResponse, ) +from langflow.custom import CustomComponent +from langflow.custom.utils import build_custom_component_template from langflow.graph.graph.base import Graph -from langflow.interface.custom.custom_component import CustomComponent -from langflow.interface.custom.utils import build_custom_component_template from langflow.processing.process import process_tweaks, run_graph_internal from langflow.schema.graph import Tweaks from langflow.services.auth.utils import api_key_security, get_current_active_user diff --git a/src/backend/base/langflow/base/io/chat.py b/src/backend/base/langflow/base/io/chat.py index 14a09b3f5..6089f19ea 100644 --- a/src/backend/base/langflow/base/io/chat.py +++ b/src/backend/base/langflow/base/io/chat.py @@ -1,8 +1,8 @@ from typing import Optional, Union +from langflow.custom import CustomComponent from langflow.field_typing import Text from langflow.helpers.record import records_to_text -from langflow.interface.custom.custom_component import CustomComponent from langflow.memory import store_message from langflow.schema import Record diff --git a/src/backend/base/langflow/base/io/text.py b/src/backend/base/langflow/base/io/text.py index 5974e7d13..5ecfea11a 100644 --- a/src/backend/base/langflow/base/io/text.py +++ b/src/backend/base/langflow/base/io/text.py @@ -1,8 +1,8 @@ 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.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/base/memory/memory.py b/src/backend/base/langflow/base/memory/memory.py index 1bb2e22ff..0fb8cf209 100644 --- a/src/backend/base/langflow/base/memory/memory.py +++ b/src/backend/base/langflow/base/memory/memory.py @@ -1,6 +1,6 @@ from typing import Optional -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/components/agents/AgentInitializer.py b/src/backend/base/langflow/components/agents/AgentInitializer.py deleted file mode 100644 index d1f09d5cf..000000000 --- a/src/backend/base/langflow/components/agents/AgentInitializer.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Callable, List, Optional, Union - -from langchain.agents import AgentExecutor, AgentType, initialize_agent, types - -from langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool -from langflow.interface.custom.custom_component import CustomComponent - - -class AgentInitializerComponent(CustomComponent): - display_name: str = "Agent Initializer" - description: str = "Initialize a Langchain Agent." - documentation: str = "https://python.langchain.com/docs/modules/agents/agent_types/" - - def build_config(self): - agents = list(types.AGENT_TO_CLASS.keys()) - # field_type and required are optional - return { - "agent": {"options": agents, "value": agents[0], "display_name": "Agent Type"}, - "max_iterations": {"display_name": "Max Iterations", "value": 10}, - "memory": {"display_name": "Memory"}, - "tools": {"display_name": "Tools"}, - "llm": {"display_name": "Language Model"}, - "code": {"advanced": True}, - } - - def build( - self, - agent: str, - llm: BaseLanguageModel, - tools: List[Tool], - max_iterations: int, - memory: Optional[BaseChatMemory] = None, - ) -> Union[AgentExecutor, Callable]: - agent = AgentType(agent) - if memory: - return initialize_agent( - tools=tools, - llm=llm, - agent=agent, - memory=memory, - return_intermediate_steps=True, - handle_parsing_errors=True, - max_iterations=max_iterations, - ) - return initialize_agent( - tools=tools, - llm=llm, - agent=agent, - return_intermediate_steps=True, - handle_parsing_errors=True, - max_iterations=max_iterations, - ) diff --git a/src/backend/base/langflow/components/agents/JsonAgent.py b/src/backend/base/langflow/components/agents/JsonAgent.py index 51f20d71d..17826ef00 100644 --- a/src/backend/base/langflow/components/agents/JsonAgent.py +++ b/src/backend/base/langflow/components/agents/JsonAgent.py @@ -1,11 +1,9 @@ from langchain.agents import AgentExecutor +from langchain_community.agent_toolkits import create_json_agent from langchain_community.agent_toolkits.json.toolkit import JsonToolkit -from langflow.field_typing import ( - BaseLanguageModel, -) -from langflow.interface.custom.custom_component import CustomComponent -from langchain_community.agent_toolkits import create_json_agent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class JsonAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py b/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py deleted file mode 100644 index c4287569a..000000000 --- a/src/backend/base/langflow/components/agents/OpenAIConversationalAgent.py +++ /dev/null @@ -1,101 +0,0 @@ -from typing import List, Optional - -from langchain.agents.agent import AgentExecutor -from langchain.agents.agent_toolkits.conversational_retrieval.openai_functions import _get_default_system_message -from langchain.agents.openai_functions_agent.base import OpenAIFunctionsAgent -from langchain.memory.token_buffer import ConversationTokenBufferMemory -from langchain_openai import ChatOpenAI - -from langflow.field_typing.range_spec import RangeSpec -from langflow.interface.custom.custom_component import CustomComponent -from pydantic.v1 import SecretStr -from langchain_core.memory import BaseMemory -from langchain_core.prompts import MessagesPlaceholder, SystemMessagePromptTemplate -from langchain_core.tools import Tool - - -class ConversationalAgent(CustomComponent): - display_name: str = "OpenAI Conversational Agent" - description: str = "Conversational Agent that can use OpenAI's function calling API" - icon = "OpenAI" - - def build_config(self): - openai_function_models = [ - "gpt-4-turbo-preview", - "gpt-4-0125-preview", - "gpt-4-1106-preview", - "gpt-4-vision-preview", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-1106", - ] - return { - "tools": {"display_name": "Tools"}, - "memory": {"display_name": "Memory"}, - "system_message": {"display_name": "System Message"}, - "max_token_limit": {"display_name": "Max Token Limit"}, - "model_name": { - "display_name": "Model Name", - "options": openai_function_models, - "value": openai_function_models[0], - }, - "code": {"show": False}, - "temperature": { - "display_name": "Temperature", - "value": 0.2, - "rangeSpec": RangeSpec(min=0, max=2, step=0.1), - }, - } - - def build( - self, - model_name: str, - openai_api_key: str, - tools: List[Tool], - openai_api_base: Optional[str] = None, - memory: Optional[BaseMemory] = None, - system_message: Optional[SystemMessagePromptTemplate] = None, - max_token_limit: int = 2000, - temperature: float = 0.9, - ) -> AgentExecutor: - if openai_api_key: - api_key = SecretStr(openai_api_key) - else: - api_key = None - - llm = ChatOpenAI( - model=model_name, - api_key=api_key, - base_url=openai_api_base, - max_tokens=max_token_limit, - temperature=temperature, - ) - if not memory: - memory_key = "chat_history" - memory = ConversationTokenBufferMemory( - memory_key=memory_key, - return_messages=True, - output_key="output", - llm=llm, - max_token_limit=max_token_limit, - ) - else: - memory_key = memory.memory_key # type: ignore - - _system_message = system_message or _get_default_system_message() - prompt = OpenAIFunctionsAgent.create_prompt( - system_message=_system_message, # type: ignore - extra_prompt_messages=[MessagesPlaceholder(variable_name=memory_key)], - ) - agent = OpenAIFunctionsAgent( - llm=llm, - tools=tools, - prompt=prompt, # type: ignore - ) - return AgentExecutor( - agent=agent, - tools=tools, # type: ignore - memory=memory, - verbose=True, - return_intermediate_steps=True, - handle_parsing_errors=True, - ) diff --git a/src/backend/base/langflow/components/agents/SQLAgent.py b/src/backend/base/langflow/components/agents/SQLAgent.py index abde4ab94..cd6b03f94 100644 --- a/src/backend/base/langflow/components/agents/SQLAgent.py +++ b/src/backend/base/langflow/components/agents/SQLAgent.py @@ -1,12 +1,12 @@ from typing import Callable, Union from langchain.agents import AgentExecutor -from langchain_community.utilities import SQLDatabase from langchain_community.agent_toolkits import SQLDatabaseToolkit from langchain_community.agent_toolkits.sql.base import create_sql_agent +from langchain_community.utilities import SQLDatabase +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent class SQLAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/agents/VectorStoreAgent.py b/src/backend/base/langflow/components/agents/VectorStoreAgent.py index 095f9da41..3cba51a09 100644 --- a/src/backend/base/langflow/components/agents/VectorStoreAgent.py +++ b/src/backend/base/langflow/components/agents/VectorStoreAgent.py @@ -3,8 +3,8 @@ from typing import Callable, Union from langchain.agents import AgentExecutor, create_vectorstore_agent from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreToolkit +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent class VectorStoreAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/agents/VectorStoreRouterAgent.py b/src/backend/base/langflow/components/agents/VectorStoreRouterAgent.py index 514a9767c..e483f0d2c 100644 --- a/src/backend/base/langflow/components/agents/VectorStoreRouterAgent.py +++ b/src/backend/base/langflow/components/agents/VectorStoreRouterAgent.py @@ -4,7 +4,7 @@ from langchain.agents import create_vectorstore_router_agent from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreRouterToolkit from langchain_core.language_models.base import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class VectorStoreRouterAgentComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/agents/__init__.py b/src/backend/base/langflow/components/agents/__init__.py index f2a118b58..8bd64bab0 100644 --- a/src/backend/base/langflow/components/agents/__init__.py +++ b/src/backend/base/langflow/components/agents/__init__.py @@ -1,17 +1,13 @@ -from .AgentInitializer import AgentInitializerComponent from .CSVAgent import CSVAgentComponent from .JsonAgent import JsonAgentComponent -from .OpenAIConversationalAgent import ConversationalAgent from .SQLAgent import SQLAgentComponent from .VectorStoreAgent import VectorStoreAgentComponent from .VectorStoreRouterAgent import VectorStoreRouterAgentComponent from .XMLAgent import XMLAgentComponent __all__ = [ - "AgentInitializerComponent", "CSVAgentComponent", "JsonAgentComponent", - "ConversationalAgent", "SQLAgentComponent", "VectorStoreAgentComponent", "VectorStoreRouterAgentComponent", diff --git a/src/backend/base/langflow/components/chains/ConversationChain.py b/src/backend/base/langflow/components/chains/ConversationChain.py index 2b8dd09a3..0801f4623 100644 --- a/src/backend/base/langflow/components/chains/ConversationChain.py +++ b/src/backend/base/langflow/components/chains/ConversationChain.py @@ -2,8 +2,8 @@ from typing import Optional from langchain.chains import ConversationChain +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, BaseMemory, Text -from langflow.interface.custom.custom_component import CustomComponent class ConversationChainComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/chains/LLMChain.py b/src/backend/base/langflow/components/chains/LLMChain.py index 9fba051db..0387b50f3 100644 --- a/src/backend/base/langflow/components/chains/LLMChain.py +++ b/src/backend/base/langflow/components/chains/LLMChain.py @@ -1,11 +1,11 @@ from typing import Optional from langchain.chains.llm import LLMChain - -from langflow.field_typing import BaseLanguageModel, BaseMemory, Text -from langflow.interface.custom.custom_component import CustomComponent from langchain_core.prompts import PromptTemplate +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel, BaseMemory, Text + class LLMChainComponent(CustomComponent): display_name = "LLMChain" diff --git a/src/backend/base/langflow/components/chains/LLMCheckerChain.py b/src/backend/base/langflow/components/chains/LLMCheckerChain.py index 04e6fe67d..f413081b1 100644 --- a/src/backend/base/langflow/components/chains/LLMCheckerChain.py +++ b/src/backend/base/langflow/components/chains/LLMCheckerChain.py @@ -1,7 +1,7 @@ from langchain.chains import LLMCheckerChain +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, Text -from langflow.interface.custom.custom_component import CustomComponent class LLMCheckerChainComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/chains/LLMMathChain.py b/src/backend/base/langflow/components/chains/LLMMathChain.py index 0b7374da6..2bb573ef5 100644 --- a/src/backend/base/langflow/components/chains/LLMMathChain.py +++ b/src/backend/base/langflow/components/chains/LLMMathChain.py @@ -2,8 +2,8 @@ from typing import Optional from langchain.chains import LLMChain, LLMMathChain +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, BaseMemory, Text -from langflow.interface.custom.custom_component import CustomComponent class LLMMathChainComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/chains/RetrievalQA.py b/src/backend/base/langflow/components/chains/RetrievalQA.py index 7b6ba49e4..da77f89d4 100644 --- a/src/backend/base/langflow/components/chains/RetrievalQA.py +++ b/src/backend/base/langflow/components/chains/RetrievalQA.py @@ -3,8 +3,8 @@ from typing import Optional from langchain.chains.retrieval_qa.base import RetrievalQA from langchain_core.documents import Document +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, BaseMemory, BaseRetriever, Text -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/components/chains/RetrievalQAWithSourcesChain.py b/src/backend/base/langflow/components/chains/RetrievalQAWithSourcesChain.py index 75a9131f5..2e0fa4ced 100644 --- a/src/backend/base/langflow/components/chains/RetrievalQAWithSourcesChain.py +++ b/src/backend/base/langflow/components/chains/RetrievalQAWithSourcesChain.py @@ -3,8 +3,8 @@ from typing import Optional from langchain.chains import RetrievalQAWithSourcesChain from langchain_core.documents import Document +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, BaseMemory, BaseRetriever, Text -from langflow.interface.custom.custom_component import CustomComponent class RetrievalQAWithSourcesChainComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/chains/SQLGenerator.py b/src/backend/base/langflow/components/chains/SQLGenerator.py index 3b111ba71..a6ff0ee2f 100644 --- a/src/backend/base/langflow/components/chains/SQLGenerator.py +++ b/src/backend/base/langflow/components/chains/SQLGenerator.py @@ -5,8 +5,8 @@ from langchain_community.utilities.sql_database import SQLDatabase from langchain_core.prompts import PromptTemplate from langchain_core.runnables import Runnable +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, Text -from langflow.interface.custom.custom_component import CustomComponent class SQLGeneratorComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/data/APIRequest.py b/src/backend/base/langflow/components/data/APIRequest.py index 9f1ca703c..f4cf476f0 100644 --- a/src/backend/base/langflow/components/data/APIRequest.py +++ b/src/backend/base/langflow/components/data/APIRequest.py @@ -3,7 +3,8 @@ import json from typing import List, Optional import httpx -from langflow.interface.custom.custom_component import CustomComponent + +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/data/Directory.py b/src/backend/base/langflow/components/data/Directory.py index 87dc99287..4dfa51de3 100644 --- a/src/backend/base/langflow/components/data/Directory.py +++ b/src/backend/base/langflow/components/data/Directory.py @@ -1,7 +1,7 @@ from typing import Any, Dict, List, Optional from langflow.base.data.utils import parallel_load_records, parse_text_file_to_record, retrieve_file_paths -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/data/File.py b/src/backend/base/langflow/components/data/File.py index 70fe1dccc..5ebb94cff 100644 --- a/src/backend/base/langflow/components/data/File.py +++ b/src/backend/base/langflow/components/data/File.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import Any, Dict from langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/data/URL.py b/src/backend/base/langflow/components/data/URL.py index 2b286e126..f9e515205 100644 --- a/src/backend/base/langflow/components/data/URL.py +++ b/src/backend/base/langflow/components/data/URL.py @@ -2,7 +2,7 @@ from typing import Any, Dict from langchain_community.document_loaders.web_base import WebBaseLoader -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py b/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py index c8cf2a96b..e43c144b1 100644 --- a/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/AmazonBedrockEmbeddings.py @@ -1,9 +1,10 @@ from typing import Optional -from langchain_community.embeddings import BedrockEmbeddings -from langflow.interface.custom.custom_component import CustomComponent +from langchain_community.embeddings import BedrockEmbeddings from langchain_core.embeddings import Embeddings +from langflow.custom import CustomComponent + class AmazonBedrockEmeddingsComponent(CustomComponent): display_name: str = "Amazon Bedrock Embeddings" diff --git a/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py b/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py index 5e02890ff..dd40d64d5 100644 --- a/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/AzureOpenAIEmbeddings.py @@ -1,8 +1,9 @@ -from langflow.interface.custom.custom_component import CustomComponent from langchain_core.embeddings import Embeddings from langchain_openai import AzureOpenAIEmbeddings from pydantic.v1 import SecretStr +from langflow.custom import CustomComponent + class AzureOpenAIEmbeddingsComponent(CustomComponent): display_name: str = "Azure OpenAI Embeddings" diff --git a/src/backend/base/langflow/components/embeddings/HuggingFaceEmbeddings.py b/src/backend/base/langflow/components/embeddings/HuggingFaceEmbeddings.py index 849cd9bba..720dfa97f 100644 --- a/src/backend/base/langflow/components/embeddings/HuggingFaceEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/HuggingFaceEmbeddings.py @@ -2,7 +2,7 @@ from typing import Dict, Optional from langchain_community.embeddings.huggingface import HuggingFaceEmbeddings -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class HuggingFaceEmbeddingsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py b/src/backend/base/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py index 37a08ccc6..503a6a25a 100644 --- a/src/backend/base/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py @@ -3,7 +3,7 @@ from typing import Dict, Optional from langchain_community.embeddings.huggingface import HuggingFaceInferenceAPIEmbeddings from pydantic.v1.types import SecretStr -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class HuggingFaceInferenceAPIEmbeddingsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/embeddings/MistalAIEmbeddings.py b/src/backend/base/langflow/components/embeddings/MistalAIEmbeddings.py index 23d80132f..d24c9fb30 100644 --- a/src/backend/base/langflow/components/embeddings/MistalAIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/MistalAIEmbeddings.py @@ -1,7 +1,7 @@ +from langchain_mistralai.embeddings import MistralAIEmbeddings from pydantic.v1 import SecretStr -from langchain_mistralai.embeddings import MistralAIEmbeddings -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.field_typing import Embeddings diff --git a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py index 575df2d3f..8aad24735 100644 --- a/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/OllamaEmbeddings.py @@ -1,9 +1,10 @@ from typing import Optional -from langchain_community.embeddings import OllamaEmbeddings -from langflow.interface.custom.custom_component import CustomComponent +from langchain_community.embeddings import OllamaEmbeddings from langchain_core.embeddings import Embeddings +from langflow.custom import CustomComponent + class OllamaEmbeddingsComponent(CustomComponent): display_name: str = "Ollama Embeddings" diff --git a/src/backend/base/langflow/components/embeddings/OpenAIEmbeddings.py b/src/backend/base/langflow/components/embeddings/OpenAIEmbeddings.py index 0b8959101..2ff78d562 100644 --- a/src/backend/base/langflow/components/embeddings/OpenAIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/OpenAIEmbeddings.py @@ -1,10 +1,10 @@ -from typing import Any, Dict, List, Optional +from typing import Dict, List, Optional from langchain_openai.embeddings.base import OpenAIEmbeddings from pydantic.v1 import SecretStr +from langflow.custom import CustomComponent from langflow.field_typing import Embeddings, NestedDict -from langflow.interface.custom.custom_component import CustomComponent class OpenAIEmbeddingsComponent(CustomComponent): @@ -94,7 +94,6 @@ class OpenAIEmbeddingsComponent(CustomComponent): allowed_special: List[str] = [], disallowed_special: List[str] = ["all"], chunk_size: int = 1000, - client: Optional[Any] = None, deployment: str = "text-embedding-ada-002", embedding_ctx_length: int = 8191, max_retries: int = 6, @@ -126,7 +125,6 @@ class OpenAIEmbeddingsComponent(CustomComponent): allowed_special=set(allowed_special), disallowed_special="all", chunk_size=chunk_size, - client=client, deployment=deployment, embedding_ctx_length=embedding_ctx_length, max_retries=max_retries, diff --git a/src/backend/base/langflow/components/embeddings/VertexAIEmbeddings.py b/src/backend/base/langflow/components/embeddings/VertexAIEmbeddings.py index 4bfaa0003..c0d249326 100644 --- a/src/backend/base/langflow/components/embeddings/VertexAIEmbeddings.py +++ b/src/backend/base/langflow/components/embeddings/VertexAIEmbeddings.py @@ -2,7 +2,7 @@ from typing import List, Optional from langchain_google_vertexai import VertexAIEmbeddings -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class VertexAIEmbeddingsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/ClearMessageHistory.py b/src/backend/base/langflow/components/experimental/ClearMessageHistory.py index 3c62b7ea3..dacfaccb4 100644 --- a/src/backend/base/langflow/components/experimental/ClearMessageHistory.py +++ b/src/backend/base/langflow/components/experimental/ClearMessageHistory.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.memory import delete_messages, get_messages diff --git a/src/backend/base/langflow/components/experimental/ExtractDataFromRecord.py b/src/backend/base/langflow/components/experimental/ExtractDataFromRecord.py index 5d816f112..b1d6ecd40 100644 --- a/src/backend/base/langflow/components/experimental/ExtractDataFromRecord.py +++ b/src/backend/base/langflow/components/experimental/ExtractDataFromRecord.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/ListFlows.py b/src/backend/base/langflow/components/experimental/ListFlows.py index c7b421d15..07b4a4bbc 100644 --- a/src/backend/base/langflow/components/experimental/ListFlows.py +++ b/src/backend/base/langflow/components/experimental/ListFlows.py @@ -1,6 +1,6 @@ from typing import List -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/Listen.py b/src/backend/base/langflow/components/experimental/Listen.py index cab979f70..be7ddb8e3 100644 --- a/src/backend/base/langflow/components/experimental/Listen.py +++ b/src/backend/base/langflow/components/experimental/Listen.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/MergeRecords.py b/src/backend/base/langflow/components/experimental/MergeRecords.py index 60e5ffe20..c938b4473 100644 --- a/src/backend/base/langflow/components/experimental/MergeRecords.py +++ b/src/backend/base/langflow/components/experimental/MergeRecords.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/Notify.py b/src/backend/base/langflow/components/experimental/Notify.py index 9af7f8ec6..bf4391682 100644 --- a/src/backend/base/langflow/components/experimental/Notify.py +++ b/src/backend/base/langflow/components/experimental/Notify.py @@ -1,6 +1,6 @@ from typing import Optional -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/Pass.py b/src/backend/base/langflow/components/experimental/Pass.py index 9528f0591..3fdb438a0 100644 --- a/src/backend/base/langflow/components/experimental/Pass.py +++ b/src/backend/base/langflow/components/experimental/Pass.py @@ -1,7 +1,8 @@ from typing import Union -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema import Record + +from langflow.custom import CustomComponent from langflow.field_typing import Text +from langflow.schema import Record class PassComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/PythonFunction.py b/src/backend/base/langflow/components/experimental/PythonFunction.py index 28e902abe..d832e2f5c 100644 --- a/src/backend/base/langflow/components/experimental/PythonFunction.py +++ b/src/backend/base/langflow/components/experimental/PythonFunction.py @@ -1,8 +1,8 @@ from typing import Callable +from langflow.custom import CustomComponent +from langflow.custom.utils import get_function from langflow.field_typing import Code -from langflow.interface.custom.custom_component import CustomComponent -from langflow.interface.custom.utils import get_function class PythonFunctionComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/RunnableExecutor.py b/src/backend/base/langflow/components/experimental/RunnableExecutor.py index 0a3593a66..82260b76b 100644 --- a/src/backend/base/langflow/components/experimental/RunnableExecutor.py +++ b/src/backend/base/langflow/components/experimental/RunnableExecutor.py @@ -1,7 +1,7 @@ from langchain_core.runnables import Runnable +from langflow.custom import CustomComponent from langflow.field_typing import Text -from langflow.interface.custom.custom_component import CustomComponent class RunnableExecComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/SQLExecutor.py b/src/backend/base/langflow/components/experimental/SQLExecutor.py index a62ac187b..e03314514 100644 --- a/src/backend/base/langflow/components/experimental/SQLExecutor.py +++ b/src/backend/base/langflow/components/experimental/SQLExecutor.py @@ -1,8 +1,8 @@ from langchain_community.tools.sql_database.tool import QuerySQLDataBaseTool from langchain_community.utilities import SQLDatabase +from langflow.custom import CustomComponent from langflow.field_typing import Text -from langflow.interface.custom.custom_component import CustomComponent class SQLExecutorComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/experimental/SplitText.py b/src/backend/base/langflow/components/experimental/SplitText.py index bd2bc921f..5d71c8014 100644 --- a/src/backend/base/langflow/components/experimental/SplitText.py +++ b/src/backend/base/langflow/components/experimental/SplitText.py @@ -1,7 +1,7 @@ from typing import Optional +from langflow.custom import CustomComponent from langflow.field_typing import Text -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema import Record from langflow.utils.util import unescape_string diff --git a/src/backend/base/langflow/components/experimental/StoreMessage.py b/src/backend/base/langflow/components/experimental/StoreMessage.py index 9f3aa60e2..761646188 100644 --- a/src/backend/base/langflow/components/experimental/StoreMessage.py +++ b/src/backend/base/langflow/components/experimental/StoreMessage.py @@ -1,6 +1,6 @@ from typing import List, Optional -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.memory import get_messages, store_message from langflow.schema import Record diff --git a/src/backend/base/langflow/components/experimental/TextOperator.py b/src/backend/base/langflow/components/experimental/TextOperator.py index 89fba13b6..ea79e92e7 100644 --- a/src/backend/base/langflow/components/experimental/TextOperator.py +++ b/src/backend/base/langflow/components/experimental/TextOperator.py @@ -1,8 +1,8 @@ from typing import Optional, Union -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema import Record +from langflow.custom import CustomComponent from langflow.field_typing import Text +from langflow.schema import Record class TextOperatorComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/helpers/CombineText.py b/src/backend/base/langflow/components/helpers/CombineText.py index fcd23c188..bedc4293d 100644 --- a/src/backend/base/langflow/components/helpers/CombineText.py +++ b/src/backend/base/langflow/components/helpers/CombineText.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.field_typing import Text diff --git a/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py b/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py index 20cd4db29..67d315739 100644 --- a/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py +++ b/src/backend/base/langflow/components/helpers/CombineTextsUnsorted.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.field_typing import Text diff --git a/src/backend/base/langflow/components/helpers/CustomComponent.py b/src/backend/base/langflow/components/helpers/CustomComponent.py index ce3d8c62c..7313323a9 100644 --- a/src/backend/base/langflow/components/helpers/CustomComponent.py +++ b/src/backend/base/langflow/components/helpers/CustomComponent.py @@ -1,6 +1,6 @@ # from langflow.field_typing import Data +from langflow.custom import CustomComponent from langflow.schema import Record -from langflow.interface.custom.custom_component import CustomComponent class Component(CustomComponent): diff --git a/src/backend/base/langflow/components/helpers/DocumentToRecord.py b/src/backend/base/langflow/components/helpers/DocumentToRecord.py index 362c0a9c1..5adaf7ab4 100644 --- a/src/backend/base/langflow/components/helpers/DocumentToRecord.py +++ b/src/backend/base/langflow/components/helpers/DocumentToRecord.py @@ -2,7 +2,7 @@ from typing import List from langchain_core.documents import Document -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/helpers/IDGenerator.py b/src/backend/base/langflow/components/helpers/IDGenerator.py index d10574eef..1e4e223b1 100644 --- a/src/backend/base/langflow/components/helpers/IDGenerator.py +++ b/src/backend/base/langflow/components/helpers/IDGenerator.py @@ -1,7 +1,7 @@ import uuid from typing import Any, Optional -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class UUIDGeneratorComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/helpers/MessageHistory.py b/src/backend/base/langflow/components/helpers/MessageHistory.py index 0f208e6eb..221d90c4e 100644 --- a/src/backend/base/langflow/components/helpers/MessageHistory.py +++ b/src/backend/base/langflow/components/helpers/MessageHistory.py @@ -1,6 +1,6 @@ from typing import List, Optional -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.memory import get_messages from langflow.schema import Record diff --git a/src/backend/base/langflow/components/helpers/RecordsToText.py b/src/backend/base/langflow/components/helpers/RecordsToText.py index 8f4fed311..d3e418792 100644 --- a/src/backend/base/langflow/components/helpers/RecordsToText.py +++ b/src/backend/base/langflow/components/helpers/RecordsToText.py @@ -1,6 +1,6 @@ +from langflow.custom import CustomComponent from langflow.field_typing import Text from langflow.helpers.record import records_to_text -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/helpers/UpdateRecord.py b/src/backend/base/langflow/components/helpers/UpdateRecord.py index 9f165e146..e3153d6d7 100644 --- a/src/backend/base/langflow/components/helpers/UpdateRecord.py +++ b/src/backend/base/langflow/components/helpers/UpdateRecord.py @@ -1,4 +1,4 @@ -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/inputs/Prompt.py b/src/backend/base/langflow/components/inputs/Prompt.py index 3b44a6d12..2c76e6132 100644 --- a/src/backend/base/langflow/components/inputs/Prompt.py +++ b/src/backend/base/langflow/components/inputs/Prompt.py @@ -1,7 +1,7 @@ from langchain_core.prompts import PromptTemplate +from langflow.custom import CustomComponent from langflow.field_typing import Prompt, TemplateField, Text -from langflow.interface.custom.custom_component import CustomComponent class PromptComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py index 23eebee10..848d10985 100644 --- a/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/BingSearchAPIWrapper.py @@ -3,7 +3,7 @@ # We need to make sure this class is importable from the context where this code will be running. from langchain_community.utilities.bing_search import BingSearchAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class BingSearchAPIWrapperComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py index 3f2f67faf..5e45219cc 100644 --- a/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py @@ -2,7 +2,7 @@ from typing import Callable, Union from langchain_community.utilities.google_search import GoogleSearchAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class GoogleSearchAPIWrapperComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py index e70e85cf4..2b9a49458 100644 --- a/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py @@ -4,7 +4,7 @@ from typing import Dict # If this class does not exist, you would need to create it or import the appropriate class from another module from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class GoogleSerperAPIWrapperComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/JSONDocumentBuilder.py b/src/backend/base/langflow/components/langchain_utilities/JSONDocumentBuilder.py index df783470a..c0300cff0 100644 --- a/src/backend/base/langflow/components/langchain_utilities/JSONDocumentBuilder.py +++ b/src/backend/base/langflow/components/langchain_utilities/JSONDocumentBuilder.py @@ -13,7 +13,7 @@ from langchain_core.documents import Document -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.services.database.models.base import orjson_dumps diff --git a/src/backend/base/langflow/components/langchain_utilities/SQLDatabase.py b/src/backend/base/langflow/components/langchain_utilities/SQLDatabase.py index 7bbbdb870..93c46087d 100644 --- a/src/backend/base/langflow/components/langchain_utilities/SQLDatabase.py +++ b/src/backend/base/langflow/components/langchain_utilities/SQLDatabase.py @@ -1,6 +1,6 @@ from langchain_experimental.sql.base import SQLDatabase -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class SQLDatabaseComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py b/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py index d255f34b7..4fe0706f8 100644 --- a/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/SearxSearchWrapper.py @@ -2,7 +2,7 @@ from typing import Dict, Optional from langchain_community.utilities.searx_search import SearxSearchWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class SearxSearchWrapperComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py index c64a26e79..d8aa404cb 100644 --- a/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/SerpAPIWrapper.py @@ -2,7 +2,7 @@ from typing import Callable, Union from langchain_community.utilities.serpapi import SerpAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class SerpAPIWrapperComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py index 144792315..1c10dd4bd 100644 --- a/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/WikipediaAPIWrapper.py @@ -2,7 +2,7 @@ from typing import Callable, Union from langchain_community.utilities.wikipedia import WikipediaAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent # Assuming WikipediaAPIWrapper is a class that needs to be imported. # The import statement is not included as it is not provided in the JSON diff --git a/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py b/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py index bc224e83c..42be1f199 100644 --- a/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py +++ b/src/backend/base/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py @@ -2,7 +2,7 @@ from typing import Callable, Union from langchain_community.utilities.wolfram_alpha import WolframAlphaAPIWrapper -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent # Since all the fields in the JSON have show=False, we will only create a basic component # without any configurable fields. diff --git a/src/backend/base/langflow/components/memories/ZepMessageReader.py b/src/backend/base/langflow/components/memories/ZepMessageReader.py index bac6e9f1a..75b27091f 100644 --- a/src/backend/base/langflow/components/memories/ZepMessageReader.py +++ b/src/backend/base/langflow/components/memories/ZepMessageReader.py @@ -116,19 +116,18 @@ class ZepMessageReaderComponent(BaseMemoryComponent): url: Optional[Text] = None, api_key: Optional[Text] = None, query: Optional[Text] = None, - search_scope: SearchScope = SearchScope.messages, - search_type: SearchType = SearchType.similarity, + search_scope: str = SearchScope.messages, + search_type: str = SearchType.similarity, limit: Optional[int] = None, ) -> list[Record]: try: - from zep_python import ZepClient - from zep_python.langchain import ZepChatMessageHistory - # Monkeypatch API_BASE_PATH to # avoid 404 # This is a workaround for the local Zep instance # cloud Zep works with v2 import zep_python.zep_client + from zep_python import ZepClient + from zep_python.langchain import ZepChatMessageHistory zep_python.zep_client.API_BASE_PATH = api_base_path except ImportError: diff --git a/src/backend/base/langflow/components/model_specs/AmazonBedrockSpecs.py b/src/backend/base/langflow/components/model_specs/AmazonBedrockSpecs.py index ff36820f5..0e27e620f 100644 --- a/src/backend/base/langflow/components/model_specs/AmazonBedrockSpecs.py +++ b/src/backend/base/langflow/components/model_specs/AmazonBedrockSpecs.py @@ -1,8 +1,9 @@ from typing import Optional -from langflow.field_typing import BaseLanguageModel + from langchain_community.llms.bedrock import Bedrock -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class AmazonBedrockComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py index d83ad23a0..72a792aa7 100644 --- a/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py +++ b/src/backend/base/langflow/components/model_specs/AnthropicLLMSpecs.py @@ -1,9 +1,10 @@ from typing import Optional + from langchain_anthropic import ChatAnthropic +from langchain_core.language_models import BaseLanguageModel from pydantic.v1 import SecretStr -from langflow.interface.custom.custom_component import CustomComponent -from langchain_core.language_models import BaseLanguageModel +from langflow.custom import CustomComponent class ChatAntropicSpecsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py b/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py index c0fd2b779..c862047a4 100644 --- a/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/AzureChatOpenAISpecs.py @@ -1,10 +1,11 @@ from typing import Optional -from langflow.interface.custom.custom_component import CustomComponent from langchain_core.language_models import BaseLanguageModel from langchain_openai import AzureChatOpenAI from pydantic.v1 import SecretStr +from langflow.custom import CustomComponent + class AzureChatOpenAISpecsComponent(CustomComponent): display_name: str = "AzureChatOpenAI" diff --git a/src/backend/base/langflow/components/model_specs/BaiduQianfanChatEndpointsSpecs.py b/src/backend/base/langflow/components/model_specs/BaiduQianfanChatEndpointsSpecs.py index a60fb9a64..a353410ad 100644 --- a/src/backend/base/langflow/components/model_specs/BaiduQianfanChatEndpointsSpecs.py +++ b/src/backend/base/langflow/components/model_specs/BaiduQianfanChatEndpointsSpecs.py @@ -1,10 +1,11 @@ from typing import Optional from langchain_community.chat_models.baidu_qianfan_endpoint import QianfanChatEndpoint + from pydantic.v1 import SecretStr +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent class QianfanChatEndpointComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/BaiduQianfanLLMEndpointsSpecs.py b/src/backend/base/langflow/components/model_specs/BaiduQianfanLLMEndpointsSpecs.py index cc4ba3b9f..273bb5d98 100644 --- a/src/backend/base/langflow/components/model_specs/BaiduQianfanLLMEndpointsSpecs.py +++ b/src/backend/base/langflow/components/model_specs/BaiduQianfanLLMEndpointsSpecs.py @@ -2,7 +2,7 @@ from typing import Optional from langchain_community.llms.baidu_qianfan_endpoint import QianfanLLMEndpoint -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel diff --git a/src/backend/base/langflow/components/model_specs/ChatLiteLLMSpecs.py b/src/backend/base/langflow/components/model_specs/ChatLiteLLMSpecs.py index 840682f4d..54711184e 100644 --- a/src/backend/base/langflow/components/model_specs/ChatLiteLLMSpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatLiteLLMSpecs.py @@ -1,8 +1,9 @@ from typing import Any, Dict, Optional from langchain_community.chat_models.litellm import ChatLiteLLM, ChatLiteLLMException + +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent class ChatLiteLLMComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/ChatOllamaEndpointSpecs.py b/src/backend/base/langflow/components/model_specs/ChatOllamaEndpointSpecs.py index 6afde420c..610f4d110 100644 --- a/src/backend/base/langflow/components/model_specs/ChatOllamaEndpointSpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatOllamaEndpointSpecs.py @@ -1,11 +1,11 @@ -from typing import Any, Dict, List, Optional +from typing import Dict, List, Optional # from langchain_community.chat_models import ChatOllama from langchain_community.chat_models import ChatOllama from langchain_core.language_models.chat_models import BaseChatModel # from langchain.chat_models import ChatOllama -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent # from langchain.callbacks.manager import CallbackManager @@ -182,7 +182,7 @@ class ChatOllamaComponent(CustomComponent): num_ctx: Optional[int] = None, num_gpu: Optional[int] = None, format: Optional[str] = None, - metadata: Optional[Dict[str, Any]] = None, + metadata: Optional[Dict] = None, num_thread: Optional[int] = None, repeat_penalty: Optional[float] = None, stop: Optional[List[str]] = None, diff --git a/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py b/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py index 75f893582..5e53a44e4 100644 --- a/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatOpenAISpecs.py @@ -3,10 +3,9 @@ from typing import Optional from langchain_openai import ChatOpenAI from pydantic.v1 import SecretStr - from langflow.base.models.openai_constants import MODEL_NAMES +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, NestedDict -from langflow.interface.custom.custom_component import CustomComponent class ChatOpenAIComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/ChatVertexAISpecs.py b/src/backend/base/langflow/components/model_specs/ChatVertexAISpecs.py index f2c377546..0df7a0465 100644 --- a/src/backend/base/langflow/components/model_specs/ChatVertexAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/ChatVertexAISpecs.py @@ -1,10 +1,9 @@ -from typing import List, Optional +from typing import Optional from langchain_community.chat_models.vertexai import ChatVertexAI -from langchain_core.messages.base import BaseMessage +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent class ChatVertexAIComponent(CustomComponent): @@ -65,7 +64,6 @@ class ChatVertexAIComponent(CustomComponent): self, credentials: Optional[str], project: str, - examples: Optional[List[BaseMessage]] = [], location: str = "us-central1", max_output_tokens: int = 128, model_name: str = "chat-bison", @@ -76,7 +74,6 @@ class ChatVertexAIComponent(CustomComponent): ) -> BaseLanguageModel: return ChatVertexAI( credentials=credentials, - examples=examples, location=location, max_output_tokens=max_output_tokens, model_name=model_name, diff --git a/src/backend/base/langflow/components/model_specs/CohereSpecs.py b/src/backend/base/langflow/components/model_specs/CohereSpecs.py index eeda381a4..5513d07e2 100644 --- a/src/backend/base/langflow/components/model_specs/CohereSpecs.py +++ b/src/backend/base/langflow/components/model_specs/CohereSpecs.py @@ -1,7 +1,7 @@ from langchain_community.llms.cohere import Cohere from langchain_core.language_models.base import BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class CohereComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/GoogleGenerativeAISpecs.py b/src/backend/base/langflow/components/model_specs/GoogleGenerativeAISpecs.py index 8a3894292..534085938 100644 --- a/src/backend/base/langflow/components/model_specs/GoogleGenerativeAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/GoogleGenerativeAISpecs.py @@ -3,8 +3,8 @@ from typing import Optional from langchain_google_genai import ChatGoogleGenerativeAI # type: ignore from pydantic.v1.types import SecretStr +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, RangeSpec -from langflow.interface.custom.custom_component import CustomComponent class GoogleGenerativeAIComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/HuggingFaceEndpointsSpecs.py b/src/backend/base/langflow/components/model_specs/HuggingFaceEndpointsSpecs.py index c145105ea..4de68365f 100644 --- a/src/backend/base/langflow/components/model_specs/HuggingFaceEndpointsSpecs.py +++ b/src/backend/base/langflow/components/model_specs/HuggingFaceEndpointsSpecs.py @@ -1,9 +1,9 @@ from typing import Optional -from langflow.field_typing import BaseLanguageModel from langchain_community.llms.huggingface_endpoint import HuggingFaceEndpoint -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class HuggingFaceEndpointsComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/OllamaLLMSpecs.py b/src/backend/base/langflow/components/model_specs/OllamaLLMSpecs.py index 4ba5502d3..1c416f1b1 100644 --- a/src/backend/base/langflow/components/model_specs/OllamaLLMSpecs.py +++ b/src/backend/base/langflow/components/model_specs/OllamaLLMSpecs.py @@ -1,9 +1,9 @@ from typing import List, Optional -from langflow.field_typing import BaseLanguageModel from langchain_community.llms.ollama import Ollama -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class OllamaLLM(CustomComponent): diff --git a/src/backend/base/langflow/components/model_specs/VertexAISpecs.py b/src/backend/base/langflow/components/model_specs/VertexAISpecs.py index c9664408d..49b120d35 100644 --- a/src/backend/base/langflow/components/model_specs/VertexAISpecs.py +++ b/src/backend/base/langflow/components/model_specs/VertexAISpecs.py @@ -1,9 +1,9 @@ from typing import Dict, Optional -from langflow.field_typing import BaseLanguageModel from langchain_community.llms.vertexai import VertexAI -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class VertexAIComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/models/OllamaModel.py b/src/backend/base/langflow/components/models/OllamaModel.py index 41d75ba3e..d9ba48501 100644 --- a/src/backend/base/langflow/components/models/OllamaModel.py +++ b/src/backend/base/langflow/components/models/OllamaModel.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional +from typing import Dict, List, Optional # from langchain_community.chat_models import ChatOllama from langchain_community.chat_models import ChatOllama @@ -229,7 +229,7 @@ class ChatOllamaComponent(LCModelComponent): num_ctx: Optional[int] = None, num_gpu: Optional[int] = None, format: Optional[str] = None, - metadata: Optional[Dict[str, Any]] = None, + metadata: Optional[Dict] = None, num_thread: Optional[int] = None, repeat_penalty: Optional[float] = None, stop: Optional[List[str]] = None, diff --git a/src/backend/base/langflow/components/models/VertexAiModel.py b/src/backend/base/langflow/components/models/VertexAiModel.py index ff520e0d1..a992447f4 100644 --- a/src/backend/base/langflow/components/models/VertexAiModel.py +++ b/src/backend/base/langflow/components/models/VertexAiModel.py @@ -1,6 +1,5 @@ -from typing import List, Optional +from typing import Optional -from langchain_core.messages.base import BaseMessage from langflow.base.constants import STREAM_INFO_TEXT from langflow.base.models.model import LCModelComponent @@ -93,7 +92,6 @@ class ChatVertexAIComponent(LCModelComponent): input_value: Text, credentials: Optional[str], project: str, - examples: Optional[List[BaseMessage]] = [], location: str = "us-central1", max_output_tokens: int = 128, model_name: str = "chat-bison", @@ -112,7 +110,6 @@ class ChatVertexAIComponent(LCModelComponent): ) output = ChatVertexAI( credentials=credentials, - examples=examples, location=location, max_output_tokens=max_output_tokens, model_name=model_name, diff --git a/src/backend/base/langflow/components/retrievers/AmazonKendra.py b/src/backend/base/langflow/components/retrievers/AmazonKendra.py index 436f69d0f..23ab9191a 100644 --- a/src/backend/base/langflow/components/retrievers/AmazonKendra.py +++ b/src/backend/base/langflow/components/retrievers/AmazonKendra.py @@ -1,9 +1,10 @@ from typing import Optional -from langchain_community.retrievers import AmazonKendraRetriever -from langflow.interface.custom.custom_component import CustomComponent +from langchain_community.retrievers import AmazonKendraRetriever from langchain_core.retrievers import BaseRetriever +from langflow.custom import CustomComponent + class AmazonKendraRetrieverComponent(CustomComponent): display_name: str = "Amazon Kendra Retriever" diff --git a/src/backend/base/langflow/components/retrievers/MetalRetriever.py b/src/backend/base/langflow/components/retrievers/MetalRetriever.py index 4f1e71dd1..55fbcff0d 100644 --- a/src/backend/base/langflow/components/retrievers/MetalRetriever.py +++ b/src/backend/base/langflow/components/retrievers/MetalRetriever.py @@ -1,9 +1,10 @@ from typing import Optional + from langchain_community.retrievers import MetalRetriever +from langchain_core.retrievers import BaseRetriever from metal_sdk.metal import Metal # type: ignore -from langflow.interface.custom.custom_component import CustomComponent -from langchain_core.retrievers import BaseRetriever +from langflow.custom import CustomComponent class MetalRetrieverComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/retrievers/MultiQueryRetriever.py b/src/backend/base/langflow/components/retrievers/MultiQueryRetriever.py index 8dd6d8579..d9197ece2 100644 --- a/src/backend/base/langflow/components/retrievers/MultiQueryRetriever.py +++ b/src/backend/base/langflow/components/retrievers/MultiQueryRetriever.py @@ -2,8 +2,8 @@ from typing import Optional from langchain.retrievers import MultiQueryRetriever -from langflow.field_typing import BaseRetriever, PromptTemplate, BaseLanguageModel -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel, BaseRetriever, PromptTemplate, Text class MultiQueryRetrieverComponent(CustomComponent): @@ -41,10 +41,13 @@ class MultiQueryRetrieverComponent(CustomComponent): self, llm: BaseLanguageModel, retriever: BaseRetriever, - prompt: Optional[PromptTemplate] = None, + prompt: Optional[Text] = None, parser_key: str = "lines", ) -> MultiQueryRetriever: if not prompt: return MultiQueryRetriever.from_llm(llm=llm, retriever=retriever, parser_key=parser_key) else: - return MultiQueryRetriever.from_llm(llm=llm, retriever=retriever, prompt=prompt, parser_key=parser_key) + prompt_template = PromptTemplate.from_template(prompt) + return MultiQueryRetriever.from_llm( + llm=llm, retriever=retriever, prompt=prompt_template, parser_key=parser_key + ) diff --git a/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py b/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py index 0f5db6383..0c5c4fff5 100644 --- a/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py +++ b/src/backend/base/langflow/components/retrievers/VectaraSelfQueryRetriver.py @@ -1,13 +1,14 @@ import json from typing import List + from langchain.chains.query_constructor.base import AttributeInfo from langchain.retrievers.self_query.base import SelfQueryRetriever - -from langflow.interface.custom.custom_component import CustomComponent from langchain_core.language_models import BaseLanguageModel from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent + class VectaraSelfQueryRetriverComponent(CustomComponent): """ diff --git a/src/backend/base/langflow/components/retrievers/VectorStoreRetriever.py b/src/backend/base/langflow/components/retrievers/VectorStoreRetriever.py index 43f1aab71..6460e0458 100644 --- a/src/backend/base/langflow/components/retrievers/VectorStoreRetriever.py +++ b/src/backend/base/langflow/components/retrievers/VectorStoreRetriever.py @@ -1,7 +1,7 @@ from langchain_core.vectorstores import VectorStoreRetriever +from langflow.custom import CustomComponent from langflow.field_typing import VectorStore -from langflow.interface.custom.custom_component import CustomComponent class VectoStoreRetrieverComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py index 8c23720f2..ee340ab26 100644 --- a/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/CharacterTextSplitter.py @@ -1,9 +1,10 @@ from typing import List -from langflow.interface.custom.custom_component import CustomComponent +from langchain_text_splitters import CharacterTextSplitter + +from langflow.custom import CustomComponent from langflow.schema.schema import Record from langflow.utils.util import unescape_string -from langchain_text_splitters import CharacterTextSplitter class CharacterTextSplitterComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py index 19dc94686..7ef7d5c24 100644 --- a/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/LanguageRecursiveTextSplitter.py @@ -1,9 +1,10 @@ from typing import List, Optional -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record from langchain_text_splitters import Language, RecursiveCharacterTextSplitter +from langflow.custom import CustomComponent +from langflow.schema.schema import Record + class LanguageRecursiveTextSplitterComponent(CustomComponent): display_name: str = "Language Recursive Text Splitter" diff --git a/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py b/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py index 2bcde2232..77fcfa62a 100644 --- a/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py +++ b/src/backend/base/langflow/components/textsplitters/RecursiveCharacterTextSplitter.py @@ -1,10 +1,11 @@ from typing import Optional -from langchain_core.documents import Document -from langflow.interface.custom.custom_component import CustomComponent +from langchain_core.documents import Document +from langchain_text_splitters import RecursiveCharacterTextSplitter + +from langflow.custom import CustomComponent from langflow.schema import Record from langflow.utils.util import build_loader_repr_from_records, unescape_string -from langchain_text_splitters import RecursiveCharacterTextSplitter class RecursiveCharacterTextSplitterComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/toolkits/JsonToolkit.py b/src/backend/base/langflow/components/toolkits/JsonToolkit.py index 72fe17cde..09a613336 100644 --- a/src/backend/base/langflow/components/toolkits/JsonToolkit.py +++ b/src/backend/base/langflow/components/toolkits/JsonToolkit.py @@ -1,7 +1,10 @@ +from pathlib import Path + +import yaml from langchain_community.agent_toolkits.json.toolkit import JsonToolkit from langchain_community.tools.json.tool import JsonSpec -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class JsonToolkitComponent(CustomComponent): @@ -10,8 +13,17 @@ class JsonToolkitComponent(CustomComponent): def build_config(self): return { - "spec": {"display_name": "Spec", "type": JsonSpec}, + "path": { + "display_name": "Path", + "field_type": "file", + "file_types": ["json", "yaml", "yml"], + }, } - def build(self, spec: JsonSpec) -> JsonToolkit: + def build(self, path: str) -> JsonToolkit: + if path.endswith("yaml") or path.endswith("yml"): + yaml_dict = yaml.load(open(path, "r"), Loader=yaml.FullLoader) + spec = JsonSpec(dict_=yaml_dict) + else: + spec = JsonSpec.from_file(Path(path)) return JsonToolkit(spec=spec) diff --git a/src/backend/base/langflow/components/toolkits/Metaphor.py b/src/backend/base/langflow/components/toolkits/Metaphor.py index ba63416fb..9ebd4f771 100644 --- a/src/backend/base/langflow/components/toolkits/Metaphor.py +++ b/src/backend/base/langflow/components/toolkits/Metaphor.py @@ -1,9 +1,10 @@ from typing import List, Union -from metaphor_python import Metaphor # type: ignore -from langflow.interface.custom.custom_component import CustomComponent from langchain_community.agent_toolkits.base import BaseToolkit from langchain_core.tools import Tool, tool +from metaphor_python import Metaphor # type: ignore + +from langflow.custom import CustomComponent class MetaphorToolkit(CustomComponent): diff --git a/src/backend/base/langflow/components/toolkits/OpenAPIToolkit.py b/src/backend/base/langflow/components/toolkits/OpenAPIToolkit.py index b29feb291..a24798cef 100644 --- a/src/backend/base/langflow/components/toolkits/OpenAPIToolkit.py +++ b/src/backend/base/langflow/components/toolkits/OpenAPIToolkit.py @@ -1,8 +1,12 @@ +from pathlib import Path + +import yaml from langchain_community.agent_toolkits.openapi.toolkit import BaseToolkit, OpenAPIToolkit +from langchain_community.tools.json.tool import JsonSpec from langchain_community.utilities.requests import TextRequestsWrapper -from langflow.field_typing import AgentExecutor -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent +from langflow.field_typing import BaseLanguageModel class OpenAPIToolkitComponent(CustomComponent): @@ -15,9 +19,16 @@ class OpenAPIToolkitComponent(CustomComponent): "requests_wrapper": {"display_name": "Text Requests Wrapper"}, } - def build( - self, - json_agent: AgentExecutor, - requests_wrapper: TextRequestsWrapper, - ) -> BaseToolkit: - return OpenAPIToolkit(json_agent=json_agent, requests_wrapper=requests_wrapper) + def build(self, llm: BaseLanguageModel, path: str, allow_dangerous_requests: bool = False) -> BaseToolkit: + if path.endswith("yaml") or path.endswith("yml"): + yaml_dict = yaml.load(open(path, "r"), Loader=yaml.FullLoader) + spec = JsonSpec(dict_=yaml_dict) + else: + spec = JsonSpec.from_file(Path(path)) + requests_wrapper = TextRequestsWrapper() + return OpenAPIToolkit.from_llm( + llm=llm, + json_spec=spec, + requests_wrapper=requests_wrapper, + allow_dangerous_requests=allow_dangerous_requests, + ) diff --git a/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py b/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py index 78f00dc40..60bd6598e 100644 --- a/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py +++ b/src/backend/base/langflow/components/toolkits/VectorStoreInfo.py @@ -1,8 +1,8 @@ from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreInfo - -from langflow.interface.custom.custom_component import CustomComponent from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent + class VectorStoreInfoComponent(CustomComponent): display_name = "VectorStoreInfo" diff --git a/src/backend/base/langflow/components/toolkits/VectorStoreRouterToolkit.py b/src/backend/base/langflow/components/toolkits/VectorStoreRouterToolkit.py index 13ec1656f..13fff14a2 100644 --- a/src/backend/base/langflow/components/toolkits/VectorStoreRouterToolkit.py +++ b/src/backend/base/langflow/components/toolkits/VectorStoreRouterToolkit.py @@ -2,8 +2,8 @@ from typing import List, Union from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreInfo, VectorStoreRouterToolkit +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, Tool -from langflow.interface.custom.custom_component import CustomComponent class VectorStoreRouterToolkitComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/toolkits/VectorStoreToolkit.py b/src/backend/base/langflow/components/toolkits/VectorStoreToolkit.py index 8436ba58e..2f788fcb9 100644 --- a/src/backend/base/langflow/components/toolkits/VectorStoreToolkit.py +++ b/src/backend/base/langflow/components/toolkits/VectorStoreToolkit.py @@ -2,8 +2,8 @@ from typing import Union from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreInfo, VectorStoreToolkit +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel, Tool -from langflow.interface.custom.custom_component import CustomComponent class VectorStoreToolkitComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/tools/RetrieverTool.py b/src/backend/base/langflow/components/tools/RetrieverTool.py index 914ba3941..28829321e 100644 --- a/src/backend/base/langflow/components/tools/RetrieverTool.py +++ b/src/backend/base/langflow/components/tools/RetrieverTool.py @@ -1,7 +1,7 @@ from langchain.tools.retriever import create_retriever_tool +from langflow.custom import CustomComponent from langflow.field_typing import BaseRetriever, Tool -from langflow.interface.custom.custom_component import CustomComponent class RetrieverToolComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorsearch/__init__.py b/src/backend/base/langflow/components/vectorsearch/__init__.py index 4cdf5b83c..83ce34b26 100644 --- a/src/backend/base/langflow/components/vectorsearch/__init__.py +++ b/src/backend/base/langflow/components/vectorsearch/__init__.py @@ -9,7 +9,7 @@ from .SupabaseVectorStoreSearch import SupabaseSearchComponent from .VectaraSearch import VectaraSearchComponent from .WeaviateSearch import WeaviateSearchVectorStore from .pgvectorSearch import PGVectorSearchComponent -from .Couchbase import CouchbaseSearchComponent # type: ignore +from .Couchbase import CouchbaseSearchComponent # type: ignore __all__ = [ "AstraDBSearchComponent", diff --git a/src/backend/base/langflow/components/vectorstores/Chroma.py b/src/backend/base/langflow/components/vectorstores/Chroma.py index 8ea943a61..974412b81 100644 --- a/src/backend/base/langflow/components/vectorstores/Chroma.py +++ b/src/backend/base/langflow/components/vectorstores/Chroma.py @@ -2,13 +2,13 @@ from typing import List, Optional, Union import chromadb # type: ignore from langchain_community.vectorstores.chroma import Chroma - -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record from langchain_core.embeddings import Embeddings from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.schema.schema import Record + class ChromaComponent(CustomComponent): """ diff --git a/src/backend/base/langflow/components/vectorstores/FAISS.py b/src/backend/base/langflow/components/vectorstores/FAISS.py index 410ac6a87..9d9624919 100644 --- a/src/backend/base/langflow/components/vectorstores/FAISS.py +++ b/src/backend/base/langflow/components/vectorstores/FAISS.py @@ -1,12 +1,13 @@ from typing import List, Text, Union -from langchain_community.vectorstores.faiss import FAISS -from langflow.field_typing import Embeddings -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record +from langchain_community.vectorstores.faiss import FAISS from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.field_typing import Embeddings +from langflow.schema.schema import Record + class FAISSComponent(CustomComponent): display_name = "FAISS" diff --git a/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py b/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py index 6c800957a..8c045a1bd 100644 --- a/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py +++ b/src/backend/base/langflow/components/vectorstores/MongoDBAtlasVector.py @@ -1,8 +1,9 @@ from typing import List, Optional from langchain_community.vectorstores.mongodb_atlas import MongoDBAtlasVectorSearch + +from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/components/vectorstores/Pinecone.py b/src/backend/base/langflow/components/vectorstores/Pinecone.py index 31521dc10..2bc0e2252 100644 --- a/src/backend/base/langflow/components/vectorstores/Pinecone.py +++ b/src/backend/base/langflow/components/vectorstores/Pinecone.py @@ -1,13 +1,14 @@ from typing import List, Optional, Union + from langchain_core.documents import Document +from langchain_core.retrievers import BaseRetriever +from langchain_core.vectorstores import VectorStore from langchain_pinecone._utilities import DistanceStrategy from langchain_pinecone.vectorstores import PineconeVectorStore +from langflow.custom import CustomComponent from langflow.field_typing import Embeddings -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record -from langchain_core.retrievers import BaseRetriever -from langchain_core.vectorstores import VectorStore class PineconeComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Qdrant.py b/src/backend/base/langflow/components/vectorstores/Qdrant.py index 200d22770..dabaa17fc 100644 --- a/src/backend/base/langflow/components/vectorstores/Qdrant.py +++ b/src/backend/base/langflow/components/vectorstores/Qdrant.py @@ -1,12 +1,13 @@ from typing import Optional, Union -from langchain_community.vectorstores.qdrant import Qdrant -from langflow.field_typing import Embeddings -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record +from langchain_community.vectorstores.qdrant import Qdrant from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.field_typing import Embeddings +from langflow.schema.schema import Record + class QdrantComponent(CustomComponent): display_name = "Qdrant" diff --git a/src/backend/base/langflow/components/vectorstores/Redis.py b/src/backend/base/langflow/components/vectorstores/Redis.py index c72c11f4d..04d137538 100644 --- a/src/backend/base/langflow/components/vectorstores/Redis.py +++ b/src/backend/base/langflow/components/vectorstores/Redis.py @@ -1,12 +1,13 @@ from typing import Optional, Union -from langchain_community.vectorstores.redis import Redis -from langchain_core.retrievers import BaseRetriever -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record +from langchain_community.vectorstores.redis import Redis from langchain_core.embeddings import Embeddings +from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.schema.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 71bf78ec8..5e87a09ca 100644 --- a/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py +++ b/src/backend/base/langflow/components/vectorstores/SupabaseVectorStore.py @@ -1,12 +1,13 @@ from typing import List, Optional, Union -from langchain_community.vectorstores.supabase import SupabaseVectorStore -from supabase.client import Client, create_client -from langflow.field_typing import Embeddings -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record +from langchain_community.vectorstores.supabase import SupabaseVectorStore from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from supabase.client import Client, create_client + +from langflow.custom import CustomComponent +from langflow.field_typing import Embeddings +from langflow.schema.schema import Record class SupabaseComponent(CustomComponent): diff --git a/src/backend/base/langflow/components/vectorstores/Vectara.py b/src/backend/base/langflow/components/vectorstores/Vectara.py index 5c087875f..247614345 100644 --- a/src/backend/base/langflow/components/vectorstores/Vectara.py +++ b/src/backend/base/langflow/components/vectorstores/Vectara.py @@ -7,8 +7,8 @@ from langchain_community.embeddings import FakeEmbeddings from langchain_community.vectorstores.vectara import Vectara from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent from langflow.field_typing import BaseRetriever -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/components/vectorstores/Weaviate.py b/src/backend/base/langflow/components/vectorstores/Weaviate.py index 108c5a5da..e1a802000 100644 --- a/src/backend/base/langflow/components/vectorstores/Weaviate.py +++ b/src/backend/base/langflow/components/vectorstores/Weaviate.py @@ -3,13 +3,13 @@ from typing import Optional, Union import weaviate # type: ignore from langchain_community.vectorstores import Weaviate from langchain_core.documents import Document - -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record from langchain_core.embeddings import Embeddings from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.schema.schema import Record + class WeaviateVectorStoreComponent(CustomComponent): display_name: str = "Weaviate" diff --git a/src/backend/base/langflow/components/vectorstores/base/model.py b/src/backend/base/langflow/components/vectorstores/base/model.py index 668c5eff2..18a37c9cf 100644 --- a/src/backend/base/langflow/components/vectorstores/base/model.py +++ b/src/backend/base/langflow/components/vectorstores/base/model.py @@ -4,9 +4,9 @@ from langchain_core.documents import Document from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent from langflow.field_typing import Text from langflow.helpers.record import docs_to_records -from langflow.interface.custom.custom_component import CustomComponent from langflow.schema import Record diff --git a/src/backend/base/langflow/components/vectorstores/pgvector.py b/src/backend/base/langflow/components/vectorstores/pgvector.py index 1c46d1e51..75c833ded 100644 --- a/src/backend/base/langflow/components/vectorstores/pgvector.py +++ b/src/backend/base/langflow/components/vectorstores/pgvector.py @@ -1,12 +1,13 @@ from typing import Optional, Union -from langchain_community.vectorstores.pgvector import PGVector -from langchain_core.retrievers import BaseRetriever -from langflow.interface.custom.custom_component import CustomComponent -from langflow.schema.schema import Record +from langchain_community.vectorstores.pgvector import PGVector from langchain_core.embeddings import Embeddings +from langchain_core.retrievers import BaseRetriever from langchain_core.vectorstores import VectorStore +from langflow.custom import CustomComponent +from langflow.schema.schema import Record + class PGVectorComponent(CustomComponent): """ diff --git a/src/backend/base/langflow/custom.py b/src/backend/base/langflow/custom.py deleted file mode 100644 index ebe4c04e8..000000000 --- a/src/backend/base/langflow/custom.py +++ /dev/null @@ -1 +0,0 @@ -from langflow.interface.custom.custom_component import CustomComponent # noqa: F401 diff --git a/src/backend/base/langflow/custom/__init__.py b/src/backend/base/langflow/custom/__init__.py new file mode 100644 index 000000000..bd789498a --- /dev/null +++ b/src/backend/base/langflow/custom/__init__.py @@ -0,0 +1,3 @@ +from langflow.custom.custom_component import CustomComponent + +__all__ = ["CustomComponent"] diff --git a/src/backend/base/langflow/interface/custom/attributes.py b/src/backend/base/langflow/custom/attributes.py similarity index 100% rename from src/backend/base/langflow/interface/custom/attributes.py rename to src/backend/base/langflow/custom/attributes.py diff --git a/src/backend/base/langflow/interface/custom/code_parser/__init__.py b/src/backend/base/langflow/custom/code_parser/__init__.py similarity index 100% rename from src/backend/base/langflow/interface/custom/code_parser/__init__.py rename to src/backend/base/langflow/custom/code_parser/__init__.py diff --git a/src/backend/base/langflow/interface/custom/code_parser/code_parser.py b/src/backend/base/langflow/custom/code_parser/code_parser.py similarity index 98% rename from src/backend/base/langflow/interface/custom/code_parser/code_parser.py rename to src/backend/base/langflow/custom/code_parser/code_parser.py index 44dbbc1d9..17fe12896 100644 --- a/src/backend/base/langflow/interface/custom/code_parser/code_parser.py +++ b/src/backend/base/langflow/custom/code_parser/code_parser.py @@ -8,8 +8,8 @@ from cachetools import TTLCache, cachedmethod, keys from fastapi import HTTPException from loguru import logger -from langflow.interface.custom.eval import eval_custom_component_code -from langflow.interface.custom.schema import CallableCodeDetails, ClassCodeDetails, MissingDefault +from langflow.custom.eval import eval_custom_component_code +from langflow.custom.schema import CallableCodeDetails, ClassCodeDetails, MissingDefault class CodeSyntaxError(HTTPException): diff --git a/src/backend/base/langflow/interface/custom/code_parser/utils.py b/src/backend/base/langflow/custom/code_parser/utils.py similarity index 100% rename from src/backend/base/langflow/interface/custom/code_parser/utils.py rename to src/backend/base/langflow/custom/code_parser/utils.py diff --git a/src/backend/base/langflow/interface/custom/custom_component/__init__.py b/src/backend/base/langflow/custom/custom_component/__init__.py similarity index 100% rename from src/backend/base/langflow/interface/custom/custom_component/__init__.py rename to src/backend/base/langflow/custom/custom_component/__init__.py diff --git a/src/backend/base/langflow/interface/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py similarity index 93% rename from src/backend/base/langflow/interface/custom/custom_component/component.py rename to src/backend/base/langflow/custom/custom_component/component.py index 470ebcde8..d45b5daed 100644 --- a/src/backend/base/langflow/interface/custom/custom_component/component.py +++ b/src/backend/base/langflow/custom/custom_component/component.py @@ -5,9 +5,9 @@ from typing import Any, ClassVar, Optional from cachetools import TTLCache, cachedmethod from fastapi import HTTPException -from langflow.interface.custom.attributes import ATTR_FUNC_MAPPING -from langflow.interface.custom.code_parser import CodeParser -from langflow.interface.custom.eval import eval_custom_component_code +from langflow.custom.attributes import ATTR_FUNC_MAPPING +from langflow.custom.code_parser import CodeParser +from langflow.custom.eval import eval_custom_component_code from langflow.utils import validate diff --git a/src/backend/base/langflow/interface/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py similarity index 99% rename from src/backend/base/langflow/interface/custom/custom_component/custom_component.py rename to src/backend/base/langflow/custom/custom_component/custom_component.py index 1638ebb2c..aeac9cae6 100644 --- a/src/backend/base/langflow/interface/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -7,13 +7,12 @@ import yaml from cachetools import TTLCache, cachedmethod from langchain_core.documents import Document from pydantic import BaseModel - -from langflow.helpers.flow import list_flows, load_flow, run_flow -from langflow.interface.custom.code_parser.utils import ( +from langflow.custom.code_parser.utils import ( extract_inner_type_from_generic_alias, extract_union_types_from_generic_alias, ) -from langflow.interface.custom.custom_component.component import Component +from langflow.custom.custom_component.component import Component +from langflow.helpers.flow import list_flows, load_flow, run_flow from langflow.schema import Record from langflow.schema.dotdict import dotdict from langflow.services.deps import get_storage_service, get_variable_service, session_scope diff --git a/src/backend/base/langflow/interface/custom/directory_reader/__init__.py b/src/backend/base/langflow/custom/directory_reader/__init__.py similarity index 100% rename from src/backend/base/langflow/interface/custom/directory_reader/__init__.py rename to src/backend/base/langflow/custom/directory_reader/__init__.py diff --git a/src/backend/base/langflow/interface/custom/directory_reader/directory_reader.py b/src/backend/base/langflow/custom/directory_reader/directory_reader.py similarity index 98% rename from src/backend/base/langflow/interface/custom/directory_reader/directory_reader.py rename to src/backend/base/langflow/custom/directory_reader/directory_reader.py index e9f3f6ceb..b9f55f21f 100644 --- a/src/backend/base/langflow/interface/custom/directory_reader/directory_reader.py +++ b/src/backend/base/langflow/custom/directory_reader/directory_reader.py @@ -5,7 +5,7 @@ from pathlib import Path from loguru import logger -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent class CustomComponentPathValueError(ValueError): @@ -67,7 +67,7 @@ class DirectoryReader: return len(file_content.strip()) == 0 def filter_loaded_components(self, data: dict, with_errors: bool) -> dict: - from langflow.interface.custom.utils import build_component + from langflow.custom.utils import build_component items = [] for menu in data["menu"]: diff --git a/src/backend/base/langflow/interface/custom/directory_reader/utils.py b/src/backend/base/langflow/custom/directory_reader/utils.py similarity index 98% rename from src/backend/base/langflow/interface/custom/directory_reader/utils.py rename to src/backend/base/langflow/custom/directory_reader/utils.py index 2772cb78c..ddd24d8f3 100644 --- a/src/backend/base/langflow/interface/custom/directory_reader/utils.py +++ b/src/backend/base/langflow/custom/directory_reader/utils.py @@ -1,6 +1,6 @@ from loguru import logger -from langflow.interface.custom.directory_reader import DirectoryReader +from langflow.custom.directory_reader import DirectoryReader from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode diff --git a/src/backend/base/langflow/interface/custom/eval.py b/src/backend/base/langflow/custom/eval.py similarity index 80% rename from src/backend/base/langflow/interface/custom/eval.py rename to src/backend/base/langflow/custom/eval.py index b36f10d92..baa202402 100644 --- a/src/backend/base/langflow/interface/custom/eval.py +++ b/src/backend/base/langflow/custom/eval.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Type from langflow.utils import validate if TYPE_CHECKING: - from langflow.interface.custom.custom_component import CustomComponent + from langflow.custom import CustomComponent def eval_custom_component_code(code: str) -> Type["CustomComponent"]: diff --git a/src/backend/base/langflow/interface/custom/schema.py b/src/backend/base/langflow/custom/schema.py similarity index 100% rename from src/backend/base/langflow/interface/custom/schema.py rename to src/backend/base/langflow/custom/schema.py diff --git a/src/backend/base/langflow/interface/custom/utils.py b/src/backend/base/langflow/custom/utils.py similarity index 97% rename from src/backend/base/langflow/interface/custom/utils.py rename to src/backend/base/langflow/custom/utils.py index 2935a363a..5f7af956e 100644 --- a/src/backend/base/langflow/interface/custom/utils.py +++ b/src/backend/base/langflow/custom/utils.py @@ -10,17 +10,17 @@ from fastapi import HTTPException from loguru import logger from pydantic import BaseModel -from langflow.field_typing.range_spec import RangeSpec -from langflow.interface.custom.attributes import ATTR_FUNC_MAPPING -from langflow.interface.custom.code_parser.utils import extract_inner_type -from langflow.interface.custom.custom_component import CustomComponent -from langflow.interface.custom.directory_reader.utils import ( +from langflow.custom import CustomComponent +from langflow.custom.attributes import ATTR_FUNC_MAPPING +from langflow.custom.code_parser.utils import extract_inner_type +from langflow.custom.directory_reader.utils import ( build_custom_component_list_from_path, determine_component_name, merge_nested_dicts_with_renaming, ) -from langflow.interface.custom.eval import eval_custom_component_code -from langflow.interface.custom.schema import MissingDefault +from langflow.custom.eval import eval_custom_component_code +from langflow.custom.schema import MissingDefault +from langflow.field_typing.range_spec import RangeSpec from langflow.schema import dotdict from langflow.template.field.base import TemplateField from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode diff --git a/src/backend/base/langflow/graph/__init__.py b/src/backend/base/langflow/graph/__init__.py index e80dcaa5f..bb93f92cf 100644 --- a/src/backend/base/langflow/graph/__init__.py +++ b/src/backend/base/langflow/graph/__init__.py @@ -1,39 +1,6 @@ from langflow.graph.edge.base import Edge from langflow.graph.graph.base import Graph from langflow.graph.vertex.base import Vertex -from langflow.graph.vertex.types import ( - AgentVertex, - ChainVertex, - CustomComponentVertex, - DocumentLoaderVertex, - EmbeddingVertex, - LLMVertex, - MemoryVertex, - PromptVertex, - RetrieverVertex, - TextSplitterVertex, - ToolkitVertex, - ToolVertex, - VectorStoreVertex, - WrapperVertex, -) +from langflow.graph.vertex.types import CustomComponentVertex, InterfaceVertex, StateVertex -__all__ = [ - "Graph", - "Vertex", - "Edge", - "AgentVertex", - "ChainVertex", - "DocumentLoaderVertex", - "EmbeddingVertex", - "LLMVertex", - "MemoryVertex", - "PromptVertex", - "TextSplitterVertex", - "ToolVertex", - "ToolkitVertex", - "VectorStoreVertex", - "WrapperVertex", - "RetrieverVertex", - "CustomComponentVertex", -] +__all__ = ["Edge", "Graph", "Vertex", "CustomComponentVertex", "InterfaceVertex", "StateVertex"] diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index bd17d43f8..1712f84d2 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -14,8 +14,7 @@ from langflow.graph.graph.state_manager import GraphStateManager from langflow.graph.graph.utils import process_flow from langflow.graph.schema import InterfaceComponentTypes, RunOutputs from langflow.graph.vertex.base import Vertex -from langflow.graph.vertex.types import FileToolVertex, InterfaceVertex, LLMVertex, StateVertex, ToolkitVertex -from langflow.interface.tools.constants import FILE_TOOLS +from langflow.graph.vertex.types import InterfaceVertex, StateVertex from langflow.schema import Record from langflow.schema.schema import INPUT_FIELD_NAME, InputType from langflow.services.deps import get_chat_service @@ -687,16 +686,8 @@ class Graph: def _build_vertex_params(self) -> None: """Identifies and handles the LLM vertex within the graph.""" - llm_vertex = None for vertex in self.vertices: vertex._build_params() - if isinstance(vertex, LLMVertex): - llm_vertex = vertex - - if llm_vertex: - for vertex in self.vertices: - if isinstance(vertex, ToolkitVertex): - vertex.params["llm"] = llm_vertex def _validate_vertex(self, vertex: Vertex) -> bool: """Validates a vertex.""" @@ -1003,8 +994,6 @@ class Graph: elif node_name in lazy_load_vertex_dict.VERTEX_TYPE_MAP: return lazy_load_vertex_dict.VERTEX_TYPE_MAP[node_name] - if node_type in FILE_TOOLS: - return FileToolVertex if node_type in lazy_load_vertex_dict.VERTEX_TYPE_MAP: return lazy_load_vertex_dict.VERTEX_TYPE_MAP[node_type] return ( diff --git a/src/backend/base/langflow/graph/graph/constants.py b/src/backend/base/langflow/graph/graph/constants.py index 2ed42fbff..8f5840524 100644 --- a/src/backend/base/langflow/graph/graph/constants.py +++ b/src/backend/base/langflow/graph/graph/constants.py @@ -1,17 +1,5 @@ from langflow.graph.schema import CHAT_COMPONENTS from langflow.graph.vertex import types -from langflow.interface.agents.base import agent_creator -from langflow.interface.custom.base import custom_component_creator -from langflow.interface.document_loaders.base import documentloader_creator -from langflow.interface.embeddings.base import embedding_creator -from langflow.interface.llms.base import llm_creator -from langflow.interface.memories.base import memory_creator -from langflow.interface.prompts.base import prompt_creator -from langflow.interface.retrievers.base import retriever_creator -from langflow.interface.text_splitters.base import textsplitter_creator -from langflow.interface.toolkits.base import toolkits_creator -from langflow.interface.tools.base import tool_creator -from langflow.interface.wrappers.base import wrapper_creator from langflow.utils.lazy_load import LazyLoadDictBase @@ -32,20 +20,7 @@ class VertexTypesDict(LazyLoadDictBase): def get_type_dict(self): return { - **{t: types.PromptVertex for t in prompt_creator.to_list()}, - **{t: types.AgentVertex for t in agent_creator.to_list()}, - # **{t: types.ChainVertex for t in chain_creator.to_list()}, - **{t: types.ToolVertex for t in tool_creator.to_list()}, - **{t: types.ToolkitVertex for t in toolkits_creator.to_list()}, - **{t: types.WrapperVertex for t in wrapper_creator.to_list()}, - **{t: types.LLMVertex for t in llm_creator.to_list()}, - **{t: types.MemoryVertex for t in memory_creator.to_list()}, - **{t: types.EmbeddingVertex for t in embedding_creator.to_list()}, - # **{t: types.VectorStoreVertex for t in vectorstore_creator.to_list()}, - **{t: types.DocumentLoaderVertex for t in documentloader_creator.to_list()}, - **{t: types.TextSplitterVertex for t in textsplitter_creator.to_list()}, - **{t: types.CustomComponentVertex for t in custom_component_creator.to_list()}, - **{t: types.RetrieverVertex for t in retriever_creator.to_list()}, + **{t: types.CustomComponentVertex for t in ["CustomComponent"]}, **{t: types.InterfaceVertex for t in CHAT_COMPONENTS}, } diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py index e0dd0f4bf..561a91848 100644 --- a/src/backend/base/langflow/graph/vertex/base.py +++ b/src/backend/base/langflow/graph/vertex/base.py @@ -10,7 +10,7 @@ from loguru import logger from langflow.graph.schema import INPUT_COMPONENTS, OUTPUT_COMPONENTS, InterfaceComponentTypes, ResultData from langflow.graph.utils import UnbuiltObject, UnbuiltResult -from langflow.graph.vertex.utils import generate_result, log_transaction +from langflow.graph.vertex.utils import log_transaction from langflow.interface.initialize import loading from langflow.interface.listing import lazy_load_dict from langflow.schema.schema import INPUT_FIELD_NAME @@ -454,29 +454,6 @@ class Vertex: ) self.set_result(result_dict) - async def _run( - self, - user_id: str, - inputs: Optional[dict] = None, - session_id: Optional[str] = None, - ): - # user_id is just for compatibility with the other build methods - inputs = inputs or {} - # inputs = {key: value or "" for key, value in inputs.items()} - # if hasattr(self._built_object, "input_keys"): - # # test if all keys are in inputs - # # and if not add them with empty string - # # for key in self._built_object.input_keys: - # # if key not in inputs: - # # inputs[key] = "" - # if inputs == {} and hasattr(self._built_object, "prompt"): - # inputs = self._built_object.prompt.partial_variables - if isinstance(self._built_object, str): - self._built_result = self._built_object - - result = await generate_result(self._built_object, inputs, self.has_external_output, session_id) - self._built_result = result - async def _build_each_vertex_in_params_dict(self, user_id=None): """ Iterates over each vertex in the params dictionary and builds it. diff --git a/src/backend/base/langflow/graph/vertex/types.py b/src/backend/base/langflow/graph/vertex/types.py index 941f06036..590c38c24 100644 --- a/src/backend/base/langflow/graph/vertex/types.py +++ b/src/backend/base/langflow/graph/vertex/types.py @@ -1,15 +1,13 @@ -import ast import json -from typing import AsyncIterator, Callable, Dict, Iterator, List, Optional, Union +from typing import AsyncIterator, Dict, Iterator, List import yaml from langchain_core.messages import AIMessage from loguru import logger from langflow.graph.schema import CHAT_COMPONENTS, RECORDS_COMPONENTS, InterfaceComponentTypes -from langflow.graph.utils import UnbuiltObject, flatten_list, serialize_field +from langflow.graph.utils import UnbuiltObject, serialize_field from langflow.graph.vertex.base import Vertex -from langflow.interface.utils import extract_input_variables_from_prompt from langflow.schema import Record from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.monitor.utils import log_vertex_build @@ -17,289 +15,6 @@ from langflow.utils.schemas import ChatOutputResponse, RecordOutputResponse from langflow.utils.util import unescape_string -class AgentVertex(Vertex): - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="agents", params=params) - - self.tools: List[Union[ToolkitVertex, ToolVertex]] = [] - self.chains: List[ChainVertex] = [] - self.steps: List[Callable] = [self._custom_build] - - def __getstate__(self): - state = super().__getstate__() - state["tools"] = self.tools - state["chains"] = self.chains - return state - - def __setstate__(self, state): - self.tools = state["tools"] - self.chains = state["chains"] - super().__setstate__(state) - - def _set_tools_and_chains(self) -> None: - for edge in self.edges: - if not hasattr(edge, "source"): - continue - source_node = edge.source - if isinstance(source_node, (ToolVertex, ToolkitVertex)): - self.tools.append(source_node) - elif isinstance(source_node, ChainVertex): - self.chains.append(source_node) - - async def _custom_build(self, *args, **kwargs): - user_id = kwargs.get("user_id", None) - self._set_tools_and_chains() - # First, build the tools - for tool_node in self.tools: - await tool_node.build(user_id=user_id) - - # Next, build the chains and the rest - for chain_node in self.chains: - await chain_node.build(tools=self.tools, user_id=user_id) - - await self._build(user_id=user_id) - - -class ToolVertex(Vertex): - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="tools", params=params) - - -class LLMVertex(Vertex): - built_node_type = None - class_built_object = None - - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="models", params=params) - self.steps: List[Callable] = [self._custom_build] - - async def _custom_build(self, *args, **kwargs): - # LLM is different because some models might take up too much memory - # or time to load. So we only load them when we need them. - # Avoid deepcopying the LLM - # that are loaded from a file - force = kwargs.get("force", False) - user_id = kwargs.get("user_id", None) - if self.vertex_type == self.built_node_type: - self._built_object = self.class_built_object - if not self._built or force: - await self._build(user_id=user_id) - self.built_node_type = self.vertex_type - self.class_built_object = self._built_object - - -class ToolkitVertex(Vertex): - def __init__(self, data: Dict, graph, params=None): - super().__init__(data, graph=graph, base_type="toolkits", params=params) - - -class FileToolVertex(ToolVertex): - def __init__(self, data: Dict, graph, params=None): - super().__init__( - data, - params=params, - graph=graph, - ) - - -class WrapperVertex(Vertex): - def __init__(self, data: Dict, graph, params=None): - super().__init__(data, graph=graph, base_type="wrappers") - self.steps: List[Callable] = [self._custom_build] - - async def _custom_build(self, *args, **kwargs): - force = kwargs.get("force", False) - user_id = kwargs.get("user_id", None) - if not self._built or force: - if "headers" in self.params: - self.params["headers"] = ast.literal_eval(self.params["headers"]) - await self._build(user_id=user_id) - - -class DocumentLoaderVertex(Vertex): - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="documentloaders", params=params) - - def _built_object_repr(self): - # This built_object is a list of documents. Maybe we should - # show how many documents are in the list? - - if not isinstance(self._built_object, UnbuiltObject): - avg_length = sum(len(record.get_text()) for record in self._built_object if hasattr(record, "text")) / len( - self._built_object - ) - return f"""{self.display_name}({len(self._built_object)} records) - \nAvg. Record Length (characters): {int(avg_length)} - Records: {self._built_object[:3]}...""" - return f"{self.vertex_type}()" - - -class EmbeddingVertex(Vertex): - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="embeddings", params=params) - - -class VectorStoreVertex(Vertex): - def __init__(self, data: Dict, graph, params=None): - super().__init__(data, graph=graph, base_type="vectorstores") - - self.params = params or {} - - # VectorStores may contain databse connections - # so we need to define the __reduce__ method and the __setstate__ method - # to avoid pickling errors - def clean_edges_for_pickling(self): - # for each edge that has self as source - # we need to clear the _built_object of the target - # so that we don't try to pickle a database connection - for edge in self.edges: - if edge.source == self: - edge.target._built_object = None - edge.target._built = False - edge.target.params[edge.target_param] = self - - def remove_docs_and_texts_from_params(self): - # remove documents and texts from params - # so that we don't try to pickle a database connection - self.params.pop("documents", None) - self.params.pop("texts", None) - - def __getstate__(self): - # We want to save the params attribute - # and if "documents" or "texts" are in the params - # we want to remove them because they have already - # been processed. - params = self.params.copy() - params.pop("documents", None) - params.pop("texts", None) - self.clean_edges_for_pickling() - - return super().__getstate__() - - def __setstate__(self, state): - super().__setstate__(state) - self.remove_docs_and_texts_from_params() - - -class MemoryVertex(Vertex): - def __init__(self, data: Dict, graph): - super().__init__(data, graph=graph, base_type="memory") - - -class RetrieverVertex(Vertex): - def __init__(self, data: Dict, graph): - super().__init__(data, graph=graph, base_type="retrievers") - - -class TextSplitterVertex(Vertex): - def __init__(self, data: Dict, graph, params: Optional[Dict] = None): - super().__init__(data, graph=graph, base_type="textsplitters", params=params) - - def _built_object_repr(self): - # This built_object is a list of documents. Maybe we should - # show how many documents are in the list? - - if not isinstance(self._built_object, UnbuiltObject): - avg_length = sum(len(doc.page_content) for doc in self._built_object) / len(self._built_object) - return f"""{self.vertex_type}({len(self._built_object)} documents) - \nAvg. Document Length (characters): {int(avg_length)} - \nDocuments: {self._built_object[:3]}...""" - return f"{self.vertex_type}()" - - -class ChainVertex(Vertex): - def __init__(self, data: Dict, graph): - super().__init__(data, graph=graph, base_type="chains") - self.steps = [self._custom_build] - - async def _custom_build(self, *args, **kwargs): - force = kwargs.get("force", False) - user_id = kwargs.get("user_id", None) - # Remove this once LLMChain is CustomComponent - self.params.pop("code", None) - for key, value in self.params.items(): - if isinstance(value, PromptVertex): - # Build the PromptVertex, passing the tools if available - tools = kwargs.get("tools", None) - self.params[key] = value.build(tools=tools, frozen=force) - - await self._build(user_id=user_id) - - def set_artifacts(self) -> None: - if isinstance(self._built_object, UnbuiltObject): - return - if self._built_object and hasattr(self._built_object, "input_keys"): - self.artifacts = dict(input_keys=self._built_object.input_keys) - - def _built_object_repr(self): - if isinstance(self._built_object, str): - return self._built_object - return super()._built_object_repr() - - -class PromptVertex(Vertex): - def __init__(self, data: Dict, graph): - super().__init__(data, graph=graph, base_type="prompts") - self.steps: List[Callable] = [self._custom_build] - - async def _custom_build(self, *args, **kwargs): - force = kwargs.get("force", False) - user_id = kwargs.get("user_id", None) - tools = kwargs.get("tools", []) - if not self._built or force: - if "input_variables" not in self.params or self.params["input_variables"] is None: - self.params["input_variables"] = [] - # Check if it is a ZeroShotPrompt and needs a tool - if "ShotPrompt" in self.vertex_type: - tools = [tool_node.build(user_id=user_id) for tool_node in tools] if tools is not None else [] - # flatten the list of tools if it is a list of lists - # first check if it is a list - if tools and isinstance(tools, list) and isinstance(tools[0], list): - tools = flatten_list(tools) - self.params["tools"] = tools - prompt_params = [ - key for key, value in self.params.items() if isinstance(value, str) and key != "format_instructions" - ] - else: - prompt_params = ["template"] - - if "prompt" not in self.params and "messages" not in self.params: - for param in prompt_params: - prompt_text = self.params[param] - variables = extract_input_variables_from_prompt(prompt_text) - self.params["input_variables"].extend(variables) - self.params["input_variables"] = list(set(self.params["input_variables"])) - elif isinstance(self.params, dict): - self.params.pop("input_variables", None) - - await self._build(user_id=user_id) - - def _built_object_repr(self): - if not self.artifacts or self._built_object is None or not hasattr(self._built_object, "format"): - return super()._built_object_repr() - elif isinstance(self._built_object, UnbuiltObject): - return super()._built_object_repr() - # We'll build the prompt with the artifacts - # to show the user what the prompt looks like - # with the variables filled in - artifacts = self.artifacts.copy() - # Remove the handle_keys from the artifacts - # so the prompt format doesn't break - artifacts.pop("handle_keys", None) - try: - if not hasattr(self._built_object, "template") and hasattr(self._built_object, "prompt"): - template = self._built_object.prompt.template - else: - template = self._built_object.template - for key, value in artifacts.items(): - if value: - replace_key = "{" + key + "}" - template = template.replace(replace_key, value) - return template if isinstance(template, str) else f"{self.vertex_type}({template})" - except KeyError: - return str(self._built_object) - - class CustomComponentVertex(Vertex): def __init__(self, data: Dict, graph): super().__init__(data, graph=graph, base_type="custom_components") diff --git a/src/backend/base/langflow/graph/vertex/utils.py b/src/backend/base/langflow/graph/vertex/utils.py index b978424f2..59a1c1949 100644 --- a/src/backend/base/langflow/graph/vertex/utils.py +++ b/src/backend/base/langflow/graph/vertex/utils.py @@ -1,74 +1,13 @@ -from typing import Any, Optional, Union, TYPE_CHECKING +from typing import TYPE_CHECKING -from langchain_core.messages import BaseMessage -from langchain_core.runnables import Runnable from loguru import logger from langflow.services.deps import get_monitor_service -from langflow.utils.constants import PYTHON_BASIC_TYPES if TYPE_CHECKING: from langflow.graph.vertex.base import Vertex -def is_basic_type(obj): - return type(obj) in PYTHON_BASIC_TYPES - - -async def invoke_lc_runnable( - built_object: Runnable, inputs: dict, has_external_output: bool, session_id: Optional[str] = None, **kwargs -) -> Union[str, BaseMessage]: - # Setup callbacks for asynchronous execution - from langflow.processing.base import setup_callbacks - - callbacks = setup_callbacks(sync=False, trace_id=session_id, **kwargs) - - try: - if has_external_output and hasattr(built_object, "astream"): - # Asynchronous stream handling if supported and required - output = "" - async for chunk in built_object.astream(inputs, {"callbacks": callbacks}): - output += chunk - return output - else: - # Direct asynchronous invocation - return await built_object.ainvoke(inputs, {"callbacks": callbacks}) - except Exception as async_exc: - logger.debug(f"Async error, falling back to sync: {str(async_exc)}") - - # Setup synchronous callbacks for the fallback - sync_callbacks = setup_callbacks(sync=True, trace_id=session_id, **kwargs) - try: - # Synchronous fallback if asynchronous execution fails - if has_external_output and hasattr(built_object, "stream"): - # Synchronous stream handling if supported and required - output = "" - for chunk in built_object.stream(inputs, {"callbacks": sync_callbacks}): - output += chunk - return output - else: - # Direct synchronous invocation - return built_object.invoke(inputs, {"callbacks": sync_callbacks}) - except Exception as sync_exc: - logger.error(f"Sync error after async failure: {str(sync_exc)}") - # Handle or re-raise exception as appropriate for your application - raise sync_exc from async_exc - - -async def generate_result(built_object: Any, inputs: dict, has_external_output: bool, session_id: Optional[str] = None): - # If the built_object is instance of Runnable - # we can call `invoke` or `stream` on it - # if it has_external_outputl, we need to call `stream` if it has it - # if not, we call `invoke` if it has it - if isinstance(built_object, Runnable): - result = await invoke_lc_runnable( - built_object=built_object, inputs=inputs, has_external_output=has_external_output, session_id=session_id - ) - else: - result = built_object - return result - - def build_clean_params(target: "Vertex") -> dict: """ Cleans the parameters of the target vertex. diff --git a/src/backend/base/langflow/initial_setup/setup.py b/src/backend/base/langflow/initial_setup/setup.py index 3c976cb94..23ff02c93 100644 --- a/src/backend/base/langflow/initial_setup/setup.py +++ b/src/backend/base/langflow/initial_setup/setup.py @@ -159,7 +159,7 @@ def create_new_project( project_data, project_icon, project_icon_bg_color, - new_folder_id + new_folder_id, ): logger.debug(f"Creating starter project {project_name}") new_project = FlowCreate( @@ -247,5 +247,5 @@ def create_or_update_starter_projects(): project_data, project_icon, project_icon_bg_color, - new_folder.id + new_folder.id, ) 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 e001f8e41..631ebc21c 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,800 +1,886 @@ { - "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", - "data": { - "nodes": [ - { - "id": "Prompt-uxBqP", - "type": "genericNode", - "position": { - "x": 53.588791333410654, - "y": -107.07318910019967 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "template", - "display_name": "Template", - "advanced": false, - "input_types": ["Text"], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent", - "user_input": { - "field_type": "str", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "user_input", - "display_name": "user_input", - "advanced": false, - "input_types": [ - "Document", - "BaseOutputParser", - "Record", - "Text" - ], - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "type": "str" - } - }, - "description": "Create a prompt template with dynamic variables.", - "icon": "prompts", - "is_input": null, - "is_output": null, - "is_composition": null, - "base_classes": ["object", "str", "Text"], - "name": "", - "display_name": "Prompt", - "documentation": "", - "custom_fields": { - "template": ["user_input"] - }, - "output_types": ["Text"], - "full_path": null, - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false, - "error": null - }, - "id": "Prompt-uxBqP", - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt" - }, - "selected": true, - "width": 384, - "height": 383, - "dragging": false, - "positionAbsolute": { - "x": 53.588791333410654, - "y": -107.07318910019967 - } - }, - { - "id": "OpenAIModel-k39HS", - "type": "genericNode", - "position": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "c091a57f-43a7-4a5e-b352-035ae8d8379c", + "data": { + "nodes": [ + { + "id": "Prompt-uxBqP", + "type": "genericNode", + "position": { + "x": 53.588791333410654, + "y": -107.07318910019967 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: ", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "template", + "display_name": "Template", + "advanced": false, + "input_types": [ + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent", + "user_input": { + "field_type": "str", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "user_input", + "display_name": "user_input", + "advanced": false, + "input_types": [ + "Document", + "BaseOutputParser", + "Record", + "Text" + ], + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "type": "str" + } + }, + "description": "Create a prompt template with dynamic variables.", + "icon": "prompts", + "is_input": null, + "is_output": null, + "is_composition": null, + "base_classes": [ + "object", + "str", + "Text" + ], + "name": "", + "display_name": "Prompt", + "documentation": "", + "custom_fields": { + "template": [ + "user_input" + ] + }, + "output_types": [ + "Text" + ], + "full_path": null, + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false, + "error": null + }, + "id": "Prompt-uxBqP", + "description": "Create a prompt template with dynamic variables.", + "display_name": "Prompt" + }, + "selected": true, + "width": 384, + "height": 383, + "dragging": false, + "positionAbsolute": { + "x": 53.588791333410654, + "y": -107.07318910019967 + } }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "Text", "str"], - "display_name": "OpenAI", - "documentation": "", - "custom_fields": { - "input_value": null, - "openai_api_key": null, - "temperature": null, - "model_name": null, - "max_tokens": null, - "model_kwargs": null, - "openai_api_base": null, - "stream": null, - "system_message": null + { + "id": "OpenAIModel-k39HS", + "type": "genericNode", + "position": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "object", + "Text", + "str" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-k39HS", + "description": "Generates text using OpenAI LLMs.", + "display_name": "OpenAI" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 634.8148772766217, + "y": 27.035057029045305 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-k39HS", - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 634.8148772766217, - "y": 27.035057029045305 - }, - "dragging": false - }, - { - "id": "ChatOutput-njtka", - "type": "genericNode", - "position": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "data": { - "type": "ChatOutput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the 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 ) -> 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 )\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" + { + "id": "ChatOutput-njtka", + "type": "genericNode", + "position": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "data": { + "type": "ChatOutput", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the 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 ) -> 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 )\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": [ + "Record", + "Text", + "str", + "object" + ], + "display_name": "Chat Output", + "documentation": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "input_value": null, + "session_id": null, + "return_record": null, + "record_template": null + }, + "output_types": [ + "Text", + "Record" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "ChatOutput-njtka" + }, + "selected": false, + "width": 384, + "height": 383, + "positionAbsolute": { + "x": 1193.250417197867, + "y": 71.88476890163852 + }, + "dragging": false }, - "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 + { + "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 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 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": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}", + "target": "ChatOutput-njtka", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" }, - "output_types": ["Text", "Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "ChatOutput-njtka" - }, - "selected": false, - "width": 384, - "height": 383, - "positionAbsolute": { - "x": 1193.250417197867, - "y": 71.88476890163852 - }, - "dragging": false - }, - { - "id": "ChatInput-P3fgL", - "type": "genericNode", - "position": { - "x": -495.2223093083827, - "y": -232.56998443685862 - }, - "data": { - "type": "ChatInput", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the 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 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 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" + { + "source": "Prompt-uxBqP", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}", + "target": "OpenAIModel-k39HS", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" }, - "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": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}", - "target": "ChatOutput-njtka", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153}-ChatOutput-njtka{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-njtka\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-uxBqP", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}", - "target": "OpenAIModel-k39HS", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153}-OpenAIModel-k39HS{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-k39HS\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "ChatInput-P3fgL", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}", - "target": "Prompt-uxBqP", - "targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": 260.58251815500563, - "y": 318.2261172111936, - "zoom": 0.43514115784696294 - } - }, - "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", - "name": "Basic Prompting (Hello, World)", - "last_tested_version": "1.0.0a4", - "is_component": false + { + "source": "ChatInput-P3fgL", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}", + "target": "Prompt-uxBqP", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-P3fgL\u0153}-Prompt-uxBqP{\u0153fieldName\u0153:\u0153user_input\u0153,\u0153id\u0153:\u0153Prompt-uxBqP\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 260.58251815500563, + "y": 318.2261172111936, + "zoom": 0.43514115784696294 + } + }, + "description": "This flow will get you experimenting with the basics of the UI, the Chat and the Prompt component. \n\nTry changing the Template in it to see how the model behaves. \nYou can change it to this and a Text Input into the `type_of_person` variable : \"Answer the user as if you were a pirate.\n\nUser: {user_input}\n\nAnswer: \" ", + "name": "Basic Prompting (Hello, World)", + "last_tested_version": "1.0.0a4", + "is_component": false } 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 e70285000..42a28dd10 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,987 +1,1096 @@ { - "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", - "data": { - "nodes": [ - { - "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 PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "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 - } - }, - { - "id": "URL-HYPkR", - "type": "genericNode", - "position": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "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.interface.custom.custom_component 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": "", - "custom_fields": { - "urls": null - }, - "output_types": ["Record"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "URL-HYPkR" - }, - "selected": false, - "width": 384, - "height": 281, - "positionAbsolute": { - "x": 568.2971412887712, - "y": 700.9983368007821 - }, - "dragging": false - }, - { - "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 ) -> 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 )\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 - }, - { - "id": "OpenAIModel-gi29P", - "type": "genericNode", - "position": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "0.1", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "6ad5559d-fb66-4fdc-8f98-96f4ac12799d", + "data": { + "nodes": [ + { + "id": "Prompt-Rse03", + "type": "genericNode", + "position": { + "x": 1331.381712783371, + "y": 535.0279854229713 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "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 + } }, - "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 + { + "id": "URL-HYPkR", + "type": "genericNode", + "position": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "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/techniques/prompt_chaining" + ] + }, + "_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-HYPkR" + }, + "selected": false, + "width": 384, + "height": 281, + "positionAbsolute": { + "x": 568.2971412887712, + "y": 700.9983368007821 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-gi29P" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 1917.7089968570963, - "y": 575.9186499244129 - }, - "dragging": false - }, - { - "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.interface.custom.custom_component 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" + { + "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 ) -> 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 )\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 }, - "description": "Fetch content from one or more URLs.", - "icon": "layout-template", - "base_classes": ["Record"], - "display_name": "URL", - "documentation": "", - "custom_fields": { - "urls": null + { + "id": "OpenAIModel-gi29P", + "type": "genericNode", + "position": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "0.1", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "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 + }, + "id": "OpenAIModel-gi29P" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 1917.7089968570963, + "y": 575.9186499244129 + }, + "dragging": false }, - "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 - }, - { - "id": "TextInput-og8Or", - "type": "genericNode", - "position": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "data": { - "type": "TextInput", - "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" + { + "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 }, - "description": "Get text inputs from the Playground.", - "icon": "type", - "base_classes": ["object", "Text", "str"], - "display_name": "Instructions", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null + { + "id": "TextInput-og8Or", + "type": "genericNode", + "position": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "data": { + "type": "TextInput", + "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": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextInput-og8Or" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 569.9387927203336, + "y": 1095.3352160671316 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "URL-HYPkR", + "target": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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 }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextInput-og8Or" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 569.9387927203336, - "y": 1095.3352160671316 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "URL-HYPkR", - "target": "Prompt-Rse03", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}", - "targetHandle": "{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "id": "reactflow__edge-URL-HYPkR{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-HYPkR\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_2\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}", - "target": "ChatOutput-JPlxl", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "URL-2cX90", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}", - "target": "Prompt-Rse03", - "targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "TextInput-og8Or", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}", - "target": "Prompt-Rse03", - "targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-Rse03", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}", - "target": "OpenAIModel-gi29P", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - } - ], - "viewport": { - "x": -214.14726025721177, - "y": -35.83855793844168, - "zoom": 0.47344308394045925 - } - }, - "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", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "source": "OpenAIModel-gi29P", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}", + "target": "ChatOutput-JPlxl", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153}-ChatOutput-JPlxl{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-JPlxl\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "URL-2cX90", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153URL\u0153,\u0153id\u0153:\u0153URL-2cX90\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153reference_1\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "TextInput-og8Or", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}", + "target": "Prompt-Rse03", + "targetHandle": "{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-og8Or\u0153}-Prompt-Rse03{\u0153fieldName\u0153:\u0153instructions\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-Rse03", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}", + "target": "OpenAIModel-gi29P", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153Text\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-Rse03\u0153}-OpenAIModel-gi29P{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-gi29P\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + } + ], + "viewport": { + "x": -214.14726025721177, + "y": -35.83855793844168, + "zoom": 0.47344308394045925 + } + }, + "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", + "last_tested_version": "1.0.0a0", + "is_component": false } 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 5d3ab5a1b..f120b4e7d 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,933 +1,1029 @@ { - "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", - "data": { - "nodes": [ - { - "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 PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "Answer 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 - }, - { - "id": "File-6TEsD", - "type": "genericNode", - "position": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "data": { - "type": "File", - "node": { - "template": { - "path": { - "type": "file", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [ - ".txt", - ".md", - ".mdx", - ".csv", - ".json", - ".yaml", - ".yml", - ".xml", - ".html", - ".htm", - ".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", - "load_from_db": false, - "title_case": false, - "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, - "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.", - "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 - }, - "id": "File-6TEsD" - }, - "selected": false, - "width": 384, - "height": 282, - "positionAbsolute": { - "x": -18.636536329280602, - "y": 3.951948774836353 - }, - "dragging": false - }, - { - "id": "ChatInput-MsSJ9", - "type": "genericNode", - "position": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "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 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 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" - }, - "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 - }, - "id": "ChatInput-MsSJ9" - }, - "selected": true, - "width": 384, - "height": 377, - "positionAbsolute": { - "x": -28.80036300619821, - "y": 379.81180230285355 - }, - "dragging": false - }, - { - "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 ) -> 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 )\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 - }, - { - "id": "OpenAIModel-Bt067", - "type": "genericNode", - "position": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "fecbce42-6f11-454c-8ab2-db6eddbbbb0f", + "data": { + "nodes": [ + { + "id": "Prompt-tHwPf", + "type": "genericNode", + "position": { + "x": 585.7906101139403, + "y": 117.52115876762832 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "Answer 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 }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["object", "str", "Text"], - "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 + { + "id": "File-6TEsD", + "type": "genericNode", + "position": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "data": { + "type": "File", + "node": { + "template": { + "path": { + "type": "file", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [ + ".txt", + ".md", + ".mdx", + ".csv", + ".json", + ".yaml", + ".yml", + ".xml", + ".html", + ".htm", + ".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", + "load_from_db": false, + "title_case": false, + "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, + "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.", + "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 + }, + "id": "File-6TEsD" + }, + "selected": false, + "width": 384, + "height": 282, + "positionAbsolute": { + "x": -18.636536329280602, + "y": 3.951948774836353 + }, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-Bt067" - }, - "selected": false, - "width": 384, - "height": 642, - "positionAbsolute": { - "x": 1137.6078582863759, - "y": -14.41920034020356 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "ChatInput-MsSJ9", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}", - "target": "Prompt-tHwPf", - "targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "File-6TEsD", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}", - "target": "Prompt-tHwPf", - "targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-tHwPf", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}", - "target": "OpenAIModel-Bt067", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-Bt067", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}", - "target": "ChatOutput-F5Awj", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": 352.20899206064655, - "y": 56.054900898593075, - "zoom": 0.9023391400011 - } - }, - "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", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "id": "ChatInput-MsSJ9", + "type": "genericNode", + "position": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "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 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 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" + }, + "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 + }, + "id": "ChatInput-MsSJ9" + }, + "selected": true, + "width": 384, + "height": 377, + "positionAbsolute": { + "x": -28.80036300619821, + "y": 379.81180230285355 + }, + "dragging": false + }, + { + "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 ) -> 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 )\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 + }, + { + "id": "OpenAIModel-Bt067", + "type": "genericNode", + "position": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "object", + "str", + "Text" + ], + "display_name": "OpenAI", + "documentation": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-Bt067" + }, + "selected": false, + "width": 384, + "height": 642, + "positionAbsolute": { + "x": 1137.6078582863759, + "y": -14.41920034020356 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "ChatInput-MsSJ9", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Record\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-MsSJ9\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Question\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "File-6TEsD", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}", + "target": "Prompt-tHwPf", + "targetHandle": "{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153Record\u0153],\u0153dataType\u0153:\u0153File\u0153,\u0153id\u0153:\u0153File-6TEsD\u0153}-Prompt-tHwPf{\u0153fieldName\u0153:\u0153Document\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-tHwPf", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}", + "target": "OpenAIModel-Bt067", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-tHwPf\u0153}-OpenAIModel-Bt067{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-Bt067", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}", + "target": "ChatOutput-F5Awj", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-Bt067\u0153}-ChatOutput-F5Awj{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-F5Awj\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": 352.20899206064655, + "y": 56.054900898593075, + "zoom": 0.9023391400011 + } + }, + "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", + "last_tested_version": "1.0.0a0", + "is_component": false } 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 ef45db37d..f448de91b 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,1137 +1,1272 @@ { - "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", - "icon": "\ud83e\udd16", - "icon_bg_color": "#FFD700", - "data": { - "nodes": [ - { - "id": "ChatInput-t7F8v", - "type": "genericNode", - "position": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "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 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 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" - }, - "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 - }, - "id": "ChatInput-t7F8v" - }, - "selected": false, - "width": 384, - "height": 469, - "positionAbsolute": { - "x": 1283.2700598313072, - "y": 982.5953650473145 - }, - "dragging": false - }, - { - "id": "ChatOutput-P1jEe", - "type": "genericNode", - "position": { - "x": 3154.916355514023, - "y": 851.051882666333 - }, - "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 ) -> 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 )\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" - }, - "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 - }, - "id": "ChatOutput-P1jEe" - }, - "selected": false, - "width": 384, - "height": 477, - "dragging": false, - "positionAbsolute": { - "x": 3154.916355514023, - "y": 851.051882666333 - } - }, - { - "id": "MemoryComponent-cdA1J", - "type": "genericNode", - "position": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - }, - "data": { - "type": "MemoryComponent", - "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": "", - "custom_fields": { - "sender": null, - "sender_name": null, - "session_id": null, - "n_messages": null, - "order": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": true - }, - "id": "MemoryComponent-cdA1J", - "description": "Retrieves stored chat messages given a specific Session ID.", - "display_name": "Chat Memory" - }, - "selected": false, - "width": 384, - "height": 489, - "dragging": false, - "positionAbsolute": { - "x": 1289.9606870058817, - "y": 442.16804561053766 - } - }, - { - "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 PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "{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 - } - }, - { - "id": "OpenAIModel-9RykF", - "type": "genericNode", - "position": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": true, - "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 + "id": "08d5cccf-d098-4367-b14b-1078429c9ed9", + "icon": "\ud83e\udd16", + "icon_bg_color": "#FFD700", + "data": { + "nodes": [ + { + "id": "ChatInput-t7F8v", + "type": "genericNode", + "position": { + "x": 1283.2700598313072, + "y": 982.5953650473145 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "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 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 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" + }, + "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 + }, + "id": "ChatInput-t7F8v" + }, + "selected": false, + "width": 384, + "height": 469, + "positionAbsolute": { + "x": 1283.2700598313072, + "y": 982.5953650473145 + }, + "dragging": false }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["str", "object", "Text"], - "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 + { + "id": "ChatOutput-P1jEe", + "type": "genericNode", + "position": { + "x": 3154.916355514023, + "y": 851.051882666333 + }, + "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 ) -> 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 )\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" + }, + "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 + }, + "id": "ChatOutput-P1jEe" + }, + "selected": false, + "width": 384, + "height": 477, + "dragging": false, + "positionAbsolute": { + "x": 3154.916355514023, + "y": 851.051882666333 + } }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-9RykF" - }, - "selected": false, - "width": 384, - "height": 563, - "positionAbsolute": { - "x": 2561.5850334731617, - "y": 553.2745131130916 - }, - "dragging": false - }, - { - "id": "TextOutput-vrs6T", - "type": "genericNode", - "position": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "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" + { + "id": "MemoryComponent-cdA1J", + "type": "genericNode", + "position": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + }, + "data": { + "type": "MemoryComponent", + "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": "", + "custom_fields": { + "sender": null, + "sender_name": null, + "session_id": null, + "n_messages": null, + "order": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": true + }, + "id": "MemoryComponent-cdA1J", + "description": "Retrieves stored chat messages given a specific Session ID.", + "display_name": "Chat Memory" + }, + "selected": false, + "width": 384, + "height": 489, + "dragging": false, + "positionAbsolute": { + "x": 1289.9606870058817, + "y": 442.16804561053766 + } }, - "description": "Display a text output in the Playground.", - "icon": "type", - "base_classes": ["str", "object", "Text"], - "display_name": "Inspect Memory", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null + { + "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 PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "{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 + } }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-vrs6T" - }, - "selected": false, - "width": 384, - "height": 289, - "positionAbsolute": { - "x": 1911.4785906252087, - "y": 247.39079954376987 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", - "target": "Prompt-ODkUx", - "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - }, - { - "source": "ChatInput-t7F8v", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}", - "target": "Prompt-ODkUx", - "targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "selected": false - }, - { - "source": "Prompt-ODkUx", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}", - "target": "OpenAIModel-9RykF", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-9RykF", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}", - "target": "ChatOutput-P1jEe", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "MemoryComponent-cdA1J", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", - "target": "TextOutput-vrs6T", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": -569.862554459756, - "y": -42.08339711050985, - "zoom": 0.4868590524514978 - } - }, - "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", - "last_tested_version": "1.0.0a0", - "is_component": false + { + "id": "OpenAIModel-9RykF", + "type": "genericNode", + "position": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": true, + "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": "", + "custom_fields": { + "input_value": null, + "openai_api_key": null, + "temperature": null, + "model_name": null, + "max_tokens": null, + "model_kwargs": null, + "openai_api_base": null, + "stream": null, + "system_message": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [ + "max_tokens", + "model_kwargs", + "model_name", + "openai_api_base", + "openai_api_key", + "temperature", + "input_value", + "system_message", + "stream" + ], + "beta": false + }, + "id": "OpenAIModel-9RykF" + }, + "selected": false, + "width": 384, + "height": 563, + "positionAbsolute": { + "x": 2561.5850334731617, + "y": 553.2745131130916 + }, + "dragging": false + }, + { + "id": "TextOutput-vrs6T", + "type": "genericNode", + "position": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "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", + "object", + "Text" + ], + "display_name": "Inspect Memory", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-vrs6T" + }, + "selected": false, + "width": 384, + "height": 289, + "positionAbsolute": { + "x": 1911.4785906252087, + "y": 247.39079954376987 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153context\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "ChatInput-t7F8v", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}", + "target": "Prompt-ODkUx", + "targetHandle": "{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153object\u0153,\u0153Record\u0153,\u0153str\u0153],\u0153dataType\u0153:\u0153ChatInput\u0153,\u0153id\u0153:\u0153ChatInput-t7F8v\u0153}-Prompt-ODkUx{\u0153fieldName\u0153:\u0153user_message\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "selected": false + }, + { + "source": "Prompt-ODkUx", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}", + "target": "OpenAIModel-9RykF", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153Text\u0153,\u0153str\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-ODkUx\u0153}-OpenAIModel-9RykF{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-9RykF", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}", + "target": "ChatOutput-P1jEe", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153object\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-9RykF\u0153}-ChatOutput-P1jEe{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-P1jEe\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "MemoryComponent-cdA1J", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}", + "target": "TextOutput-vrs6T", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153MemoryComponent\u0153,\u0153id\u0153:\u0153MemoryComponent-cdA1J\u0153}-TextOutput-vrs6T{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-vrs6T\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -569.862554459756, + "y": -42.08339711050985, + "zoom": 0.4868590524514978 + } + }, + "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", + "last_tested_version": "1.0.0a0", + "is_component": false } 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 8563a442a..c12a3fb79 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,1586 +1,1769 @@ { - "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", - "data": { - "nodes": [ - { - "id": "Prompt-amqBu", - "type": "genericNode", - "position": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "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, - "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" - } - }, - "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" - }, - "selected": false, - "width": 384, - "height": 385, - "positionAbsolute": { - "x": 2191.5837146441663, - "y": 1047.9307944451873 - }, - "dragging": false - }, - { - "id": "Prompt-gTNiz", - "type": "genericNode", - "position": { - "x": 3731.0813766902447, - "y": 799.631909121391 - }, - "data": { - "type": "Prompt", - "node": { - "template": { - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "code", - "advanced": true, - "dynamic": true, - "info": "", - "load_from_db": false, - "title_case": false - }, - "template": { - "type": "prompt", - "required": false, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": "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, - "multiline": true, - "value": "", - "fileTypes": [], - "file_path": "", - "password": false, - "name": "summary", - "display_name": "summary", - "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": ["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" - }, - "selected": false, - "width": 384, - "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 ) -> 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 )\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 - }, - { - "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 ) -> 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 )\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 - }, - { - "id": "TextInput-sptaH", - "type": "genericNode", - "position": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "data": { - "type": "TextInput", - "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" - }, - "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 - }, - "id": "TextInput-sptaH" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 1700.5624822024752, - "y": 1039.603088937466 - }, - "dragging": false - }, - { - "id": "TextOutput-2MS4a", - "type": "genericNode", - "position": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "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": "First Prompt", - "documentation": "", - "custom_fields": { - "input_value": null, - "record_template": null - }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [], - "beta": false - }, - "id": "TextOutput-2MS4a" - }, - "selected": false, - "width": 384, - "height": 290, - "positionAbsolute": { - "x": 2917.216113690115, - "y": 513.0058511435552 - }, - "dragging": false - }, - { - "id": "OpenAIModel-uYXZJ", - "type": "genericNode", - "position": { - "x": 2925.784767523062, - "y": 933.6465680967775 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": 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": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 + "id": "85392e54-20f3-4ab5-a179-cb4bef16f639", + "data": { + "nodes": [ + { + "id": "Prompt-amqBu", + "type": "genericNode", + "position": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "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, + "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" + } + }, + "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" + }, + "selected": false, + "width": 384, + "height": 385, + "positionAbsolute": { + "x": 2191.5837146441663, + "y": 1047.9307944451873 + }, + "dragging": false }, - "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 + { + "id": "Prompt-gTNiz", + "type": "genericNode", + "position": { + "x": 3731.0813766902447, + "y": 799.631909121391 + }, + "data": { + "type": "Prompt", + "node": { + "template": { + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "code", + "advanced": true, + "dynamic": true, + "info": "", + "load_from_db": false, + "title_case": false + }, + "template": { + "type": "prompt", + "required": false, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": "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, + "multiline": true, + "value": "", + "fileTypes": [], + "file_path": "", + "password": false, + "name": "summary", + "display_name": "summary", + "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": [ + "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" + }, + "selected": false, + "width": 384, + "height": 385, + "dragging": false }, - "output_types": ["Text"], - "field_formatters": {}, - "frozen": false, - "field_order": [ - "max_tokens", - "model_kwargs", - "model_name", - "openai_api_base", - "openai_api_key", - "temperature", - "input_value", - "system_message", - "stream" - ], - "beta": false - }, - "id": "OpenAIModel-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" + { + "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 ) -> 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 )\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 }, - "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 + { + "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 ) -> 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 )\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 }, - "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": "TextInput-sptaH", + "type": "genericNode", + "position": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "data": { + "type": "TextInput", + "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" + }, + "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 + }, + "id": "TextInput-sptaH" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 1700.5624822024752, + "y": 1039.603088937466 + }, + "dragging": false + }, + { + "id": "TextOutput-2MS4a", + "type": "genericNode", + "position": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "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": "First Prompt", + "documentation": "", + "custom_fields": { + "input_value": null, + "record_template": null + }, + "output_types": [ + "Text" + ], + "field_formatters": {}, + "frozen": false, + "field_order": [], + "beta": false + }, + "id": "TextOutput-2MS4a" + }, + "selected": false, + "width": 384, + "height": 290, + "positionAbsolute": { + "x": 2917.216113690115, + "y": 513.0058511435552 + }, + "dragging": false + }, + { + "id": "OpenAIModel-uYXZJ", + "type": "genericNode", + "position": { + "x": 2925.784767523062, + "y": 933.6465680967775 + }, + "data": { + "type": "OpenAIModel", + "node": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": 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": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "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 + }, + "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": { + "template": { + "input_value": { + "type": "str", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "input_value", + "display_name": "Input", + "advanced": false, + "dynamic": false, + "info": "", + "load_from_db": false, + "title_case": false, + "input_types": [ + "Text" + ] + }, + "code": { + "type": "code", + "required": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": true, + "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", + "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": "" + }, + "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": true, + "placeholder": "", + "list": false, + "show": true, + "multiline": false, + "value": 0.1, + "fileTypes": [], + "file_path": "", + "password": false, + "name": "temperature", + "display_name": "Temperature", + "advanced": false, + "dynamic": false, + "info": "", + "rangeSpec": { + "step_type": "float", + "min": -1, + "max": 1, + "step": 0.1 + }, + "load_from_db": false, + "title_case": false + }, + "_type": "CustomComponent" + }, + "description": "Generates text using OpenAI LLMs.", + "icon": "OpenAI", + "base_classes": [ + "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 + }, + "id": "OpenAIModel-XawYB" + }, + "selected": false, + "width": 384, + "height": 565, + "positionAbsolute": { + "x": 4500.152018344182, + "y": 1027.7382026227656 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "TextInput-sptaH", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}", + "target": "Prompt-amqBu", + "targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "TextOutput-2MS4a", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-amqBu", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", + "target": "OpenAIModel-uYXZJ", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "Prompt-gTNiz", + "targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-uYXZJ", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", + "target": "ChatOutput-EJkG3", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "TextOutput-MUDOR", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "Prompt-gTNiz", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", + "target": "OpenAIModel-XawYB", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + }, + { + "source": "OpenAIModel-XawYB", + "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}", + "target": "ChatOutput-DNmvg", + "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", + "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" + } + ], + "viewport": { + "x": -383.7251879618552, + "y": 69.19813933800037, + "zoom": 0.3105753483695743 } - }, - { - "id": "OpenAIModel-XawYB", - "type": "genericNode", - "position": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "data": { - "type": "OpenAIModel", - "node": { - "template": { - "input_value": { - "type": "str", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "input_value", - "display_name": "Input", - "advanced": false, - "dynamic": false, - "info": "", - "load_from_db": false, - "title_case": false, - "input_types": ["Text"] - }, - "code": { - "type": "code", - "required": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": true, - "value": "from typing import Optional\n\nfrom langchain_openai import ChatOpenAI\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\"},\n \"max_tokens\": {\n \"display_name\": \"Max Tokens\",\n \"advanced\": True,\n },\n \"model_kwargs\": {\n \"display_name\": \"Model Kwargs\",\n \"advanced\": True,\n },\n \"model_name\": {\n \"display_name\": \"Model Name\",\n \"advanced\": False,\n \"options\": 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,\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,\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": "", - "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": "" - }, - "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": true, - "placeholder": "", - "list": false, - "show": true, - "multiline": false, - "value": 0.1, - "fileTypes": [], - "file_path": "", - "password": false, - "name": "temperature", - "display_name": "Temperature", - "advanced": false, - "dynamic": false, - "info": "", - "rangeSpec": { - "step_type": "float", - "min": -1, - "max": 1, - "step": 0.1 - }, - "load_from_db": false, - "title_case": false - }, - "_type": "CustomComponent" - }, - "description": "Generates text using OpenAI LLMs.", - "icon": "OpenAI", - "base_classes": ["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 - }, - "id": "OpenAIModel-XawYB" - }, - "selected": false, - "width": 384, - "height": 565, - "positionAbsolute": { - "x": 4500.152018344182, - "y": 1027.7382026227656 - }, - "dragging": false - } - ], - "edges": [ - { - "source": "TextInput-sptaH", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}", - "target": "Prompt-amqBu", - "targetHandle": "{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153TextInput\u0153,\u0153id\u0153:\u0153TextInput-sptaH\u0153}-Prompt-amqBu{\u0153fieldName\u0153:\u0153document\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", - "target": "TextOutput-2MS4a", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-TextOutput-2MS4a{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-2MS4a\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-amqBu", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}", - "target": "OpenAIModel-uYXZJ", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-amqBu\u0153}-OpenAIModel-uYXZJ{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", - "target": "Prompt-gTNiz", - "targetHandle": "{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-Prompt-gTNiz{\u0153fieldName\u0153:\u0153summary\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153,\u0153inputTypes\u0153:[\u0153Document\u0153,\u0153BaseOutputParser\u0153,\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-uYXZJ", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}", - "target": "ChatOutput-EJkG3", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-uYXZJ\u0153}-ChatOutput-EJkG3{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-EJkG3\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", - "target": "TextOutput-MUDOR", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-TextOutput-MUDOR{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153TextOutput-MUDOR\u0153,\u0153inputTypes\u0153:[\u0153Record\u0153,\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "Prompt-gTNiz", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}", - "target": "OpenAIModel-XawYB", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153object\u0153,\u0153str\u0153,\u0153Text\u0153],\u0153dataType\u0153:\u0153Prompt\u0153,\u0153id\u0153:\u0153Prompt-gTNiz\u0153}-OpenAIModel-XawYB{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - }, - { - "source": "OpenAIModel-XawYB", - "sourceHandle": "{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}", - "target": "ChatOutput-DNmvg", - "targetHandle": "{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}", - "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{\u0153baseClasses\u0153:[\u0153str\u0153,\u0153Text\u0153,\u0153object\u0153],\u0153dataType\u0153:\u0153OpenAIModel\u0153,\u0153id\u0153:\u0153OpenAIModel-XawYB\u0153}-ChatOutput-DNmvg{\u0153fieldName\u0153:\u0153input_value\u0153,\u0153id\u0153:\u0153ChatOutput-DNmvg\u0153,\u0153inputTypes\u0153:[\u0153Text\u0153],\u0153type\u0153:\u0153str\u0153}" - } - ], - "viewport": { - "x": -383.7251879618552, - "y": 69.19813933800037, - "zoom": 0.3105753483695743 - } - }, - "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", - "name": "Prompt Chaining", - "last_tested_version": "1.0.0a0", - "is_component": false + }, + "description": "The Prompt Chaining flow chains prompts with LLMs, refining outputs through iterative stages.", + "name": "Prompt Chaining", + "last_tested_version": "1.0.0a0", + "is_component": false } 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 097fdbbc2..fca035bd4 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 @@ -358,7 +358,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\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 client: Optional[Any] = None,\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 client=client,\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", + "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, @@ -1106,7 +1106,7 @@ "list": false, "show": true, "multiline": true, - "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.field_typing import Prompt, TemplateField, Text\nfrom langflow.interface.custom.custom_component import CustomComponent\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", + "value": "from langchain_core.prompts import PromptTemplate\n\nfrom langflow.custom import CustomComponent\nfrom langflow.field_typing import Prompt, TemplateField, Text\n\n\nclass PromptComponent(CustomComponent):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n\n def build_config(self):\n return {\n \"template\": TemplateField(display_name=\"Template\"),\n \"code\": TemplateField(advanced=True),\n }\n\n def build(\n self,\n template: Prompt,\n **kwargs,\n ) -> Text:\n from langflow.base.prompts.utils import dict_values_to_string\n\n prompt_template = PromptTemplate.from_template(Text(template))\n kwargs = dict_values_to_string(kwargs)\n kwargs = {k: \"\\n\".join(v) if isinstance(v, list) else v for k, v in kwargs.items()}\n try:\n formated_prompt = prompt_template.format(**kwargs)\n except Exception as exc:\n raise ValueError(f\"Error formatting prompt: {exc}\") from exc\n self.status = f'Prompt:\\n\"{formated_prompt}\"'\n return formated_prompt\n", "fileTypes": [], "file_path": "", "password": false, @@ -1491,7 +1491,7 @@ "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 = \"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", + "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, @@ -1631,7 +1631,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import Optional\nfrom langchain_core.documents import Document\n\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.schema import Record\nfrom langflow.utils.util import build_loader_repr_from_records, unescape_string\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\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", + "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, @@ -2632,7 +2632,7 @@ "list": false, "show": true, "multiline": true, - "value": "from typing import Any, Dict, List, Optional\n\nfrom langchain_openai.embeddings.base import OpenAIEmbeddings\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.field_typing import Embeddings, NestedDict\nfrom langflow.interface.custom.custom_component import CustomComponent\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 client: Optional[Any] = None,\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 client=client,\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", + "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, diff --git a/src/backend/base/langflow/interface/agents/__init__.py b/src/backend/base/langflow/interface/agents/__init__.py deleted file mode 100644 index df15bc39b..000000000 --- a/src/backend/base/langflow/interface/agents/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.agents.base import AgentCreator - -__all__ = ["AgentCreator"] diff --git a/src/backend/base/langflow/interface/agents/base.py b/src/backend/base/langflow/interface/agents/base.py deleted file mode 100644 index ee510580c..000000000 --- a/src/backend/base/langflow/interface/agents/base.py +++ /dev/null @@ -1,62 +0,0 @@ -from typing import ClassVar, Dict, List, Optional - -from langchain.agents import types -from langflow.interface.agents.custom import CUSTOM_AGENTS -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.utils import build_template_from_class -from langflow.legacy_custom.customs import get_custom_nodes -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.agents import AgentFrontendNode -from langflow.utils.util import build_template_from_method -from loguru import logger - - -class AgentCreator(LangChainTypeCreator): - type_name: str = "agents" - - from_method_nodes: ClassVar[Dict] = {"ZeroShotAgent": "from_llm_and_tools"} - - @property - def frontend_node_class(self) -> type[AgentFrontendNode]: - return AgentFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict = types.AGENT_TO_CLASS - # Add JsonAgent to the list of agents - for name, agent in CUSTOM_AGENTS.items(): - # TODO: validate AgentType - self.type_dict[name] = agent # type: ignore - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - elif name in self.from_method_nodes: - return build_template_from_method( - name, - type_to_cls_dict=self.type_to_loader_dict, - add_function=True, - method_name=self.from_method_nodes[name], - ) - return build_template_from_class(name, self.type_to_loader_dict, add_function=True) - except ValueError as exc: - raise ValueError("Agent not found") from exc - except AttributeError as exc: - logger.error(f"Agent {name} not loaded: {exc}") - return None - - # Now this is a generator - def to_list(self) -> List[str]: - names = [] - settings_service = get_settings_service() - for _, agent in self.type_to_loader_dict.items(): - agent_name = agent.function_name() if hasattr(agent, "function_name") else agent.__name__ - if agent_name in settings_service.settings.AGENTS or settings_service.settings.DEV: - names.append(agent_name) - return names - - -agent_creator = AgentCreator() diff --git a/src/backend/base/langflow/interface/agents/custom.py b/src/backend/base/langflow/interface/agents/custom.py deleted file mode 100644 index 36d9bd653..000000000 --- a/src/backend/base/langflow/interface/agents/custom.py +++ /dev/null @@ -1,265 +0,0 @@ -from typing import Any, Optional - -from langchain.agents import AgentExecutor, ZeroShotAgent -from langchain.agents.agent_toolkits import VectorStoreInfo, VectorStoreRouterToolkit, VectorStoreToolkit -from langchain.agents.agent_toolkits.vectorstore.prompt import PREFIX as VECTORSTORE_PREFIX -from langchain.agents.agent_toolkits.vectorstore.prompt import ROUTER_PREFIX as VECTORSTORE_ROUTER_PREFIX -from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS -from langchain.chains.llm import LLMChain -from langchain_community.utilities import SQLDatabase -from langchain.tools.sql_database.prompt import QUERY_CHECKER -from langchain_community.agent_toolkits import SQLDatabaseToolkit -from langchain_community.agent_toolkits.json.prompt import JSON_PREFIX, JSON_SUFFIX -from langchain_community.agent_toolkits.json.toolkit import JsonToolkit -from langchain_community.agent_toolkits.sql.prompt import SQL_PREFIX, SQL_SUFFIX -from langchain_experimental.agents.agent_toolkits.pandas.prompt import PREFIX as PANDAS_PREFIX -from langchain_experimental.agents.agent_toolkits.pandas.prompt import SUFFIX_WITH_DF as PANDAS_SUFFIX -from langchain_experimental.tools.python.tool import PythonAstREPLTool - -from langflow.interface.base import CustomAgentExecutor -from langchain_community.tools import ( - InfoSQLDatabaseTool, - ListSQLDatabaseTool, - QuerySQLCheckerTool, - QuerySQLDataBaseTool, -) -from langchain_core.language_models import BaseLanguageModel -from langchain_core.prompts import PromptTemplate - - -class JsonAgent(CustomAgentExecutor): - """Json agent""" - - @staticmethod - def function_name(): - return "JsonAgent" - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm(cls, toolkit: JsonToolkit, llm: BaseLanguageModel): - tools = toolkit if isinstance(toolkit, list) else toolkit.get_tools() - tool_names = list({tool.name for tool in tools}) - prompt = ZeroShotAgent.create_prompt( - tools, - prefix=JSON_PREFIX, - suffix=JSON_SUFFIX, - format_instructions=FORMAT_INSTRUCTIONS, - input_variables=None, - ) - llm_chain = LLMChain( - llm=llm, - prompt=prompt, - ) - agent = ZeroShotAgent( - llm_chain=llm_chain, - allowed_tools=tool_names, # type: ignore - ) - return cls.from_agent_and_tools(agent=agent, tools=tools, verbose=True) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -class CSVAgent(CustomAgentExecutor): - """CSV agent""" - - @staticmethod - def function_name(): - return "CSVAgent" - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm( - cls, path: str, llm: BaseLanguageModel, pandas_kwargs: Optional[dict] = None, **kwargs: Any - ): - import pandas as pd # type: ignore - - _kwargs = pandas_kwargs or {} - df = pd.read_csv(path, **_kwargs) - - tools = [PythonAstREPLTool(locals={"df": df})] # type: ignore - prompt = ZeroShotAgent.create_prompt( - tools, - prefix=PANDAS_PREFIX, - suffix=PANDAS_SUFFIX, - input_variables=["df_head", "input", "agent_scratchpad"], - ) - partial_prompt = prompt.partial(df_head=str(df.head())) - llm_chain = LLMChain( - llm=llm, - prompt=partial_prompt, - ) - tool_names = list({tool.name for tool in tools}) - agent = ZeroShotAgent( - llm_chain=llm_chain, - allowed_tools=tool_names, - **kwargs, # type: ignore - ) - - return cls.from_agent_and_tools(agent=agent, tools=tools, verbose=True) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -class VectorStoreAgent(CustomAgentExecutor): - """Vector store agent""" - - @staticmethod - def function_name(): - return "VectorStoreAgent" - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm(cls, llm: BaseLanguageModel, vectorstoreinfo: VectorStoreInfo, **kwargs: Any): - """Construct a vectorstore agent from an LLM and tools.""" - - toolkit = VectorStoreToolkit(vectorstore_info=vectorstoreinfo, llm=llm) - - tools = toolkit.get_tools() - prompt = ZeroShotAgent.create_prompt(tools, prefix=VECTORSTORE_PREFIX) - llm_chain = LLMChain( - llm=llm, - prompt=prompt, - ) - tool_names = list({tool.name for tool in tools}) - agent = ZeroShotAgent( - llm_chain=llm_chain, - allowed_tools=tool_names, - **kwargs, # type: ignore - ) - return AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -class SQLAgent(CustomAgentExecutor): - """SQL agent""" - - @staticmethod - def function_name(): - return "SQLAgent" - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm(cls, llm: BaseLanguageModel, database_uri: str, **kwargs: Any): - """Construct an SQL agent from an LLM and tools.""" - db = SQLDatabase.from_uri(database_uri) - toolkit = SQLDatabaseToolkit(db=db, llm=llm) - - llmchain = LLMChain( - llm=llm, - prompt=PromptTemplate(template=QUERY_CHECKER, input_variables=["query", "dialect"]), - ) - - tools = [ - QuerySQLDataBaseTool(db=db), # type: ignore - InfoSQLDatabaseTool(db=db), # type: ignore - ListSQLDatabaseTool(db=db), # type: ignore - QuerySQLCheckerTool(db=db, llm_chain=llmchain, llm=llm), # type: ignore - ] - - prefix = SQL_PREFIX.format(dialect=toolkit.dialect, top_k=10) - prompt = ZeroShotAgent.create_prompt( - tools=tools, # type: ignore - prefix=prefix, - suffix=SQL_SUFFIX, - format_instructions=FORMAT_INSTRUCTIONS, - ) - llm_chain = LLMChain( - llm=llm, - prompt=prompt, - ) - tool_names = list({tool.name for tool in tools}) # type: ignore - agent = ZeroShotAgent( - llm_chain=llm_chain, - allowed_tools=tool_names, - **kwargs, # type: ignore - ) - return AgentExecutor.from_agent_and_tools( - agent=agent, - tools=tools, # type: ignore - verbose=True, - max_iterations=15, - early_stopping_method="force", - handle_parsing_errors=True, - ) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -class VectorStoreRouterAgent(CustomAgentExecutor): - """Vector Store Router Agent""" - - @staticmethod - def function_name(): - return "VectorStoreRouterAgent" - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm( - cls, llm: BaseLanguageModel, vectorstoreroutertoolkit: VectorStoreRouterToolkit, **kwargs: Any - ): - """Construct a vector store router agent from an LLM and tools.""" - - tools = ( - vectorstoreroutertoolkit - if isinstance(vectorstoreroutertoolkit, list) - else vectorstoreroutertoolkit.get_tools() - ) - prompt = ZeroShotAgent.create_prompt(tools, prefix=VECTORSTORE_ROUTER_PREFIX) - llm_chain = LLMChain( - llm=llm, - prompt=prompt, - ) - tool_names = list({tool.name for tool in tools}) - agent = ZeroShotAgent( - llm_chain=llm_chain, - allowed_tools=tool_names, - **kwargs, # type: ignore - ) - return AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -CUSTOM_AGENTS = { - "JsonAgent": JsonAgent, - "CSVAgent": CSVAgent, - "VectorStoreAgent": VectorStoreAgent, - "VectorStoreRouterAgent": VectorStoreRouterAgent, - "SQLAgent": SQLAgent, -} diff --git a/src/backend/base/langflow/interface/agents/prebuilt.py b/src/backend/base/langflow/interface/agents/prebuilt.py deleted file mode 100644 index 9e59a76e1..000000000 --- a/src/backend/base/langflow/interface/agents/prebuilt.py +++ /dev/null @@ -1,45 +0,0 @@ -from langchain.chains.llm import LLMChain -from langchain.agents import AgentExecutor, ZeroShotAgent -from langchain.agents.agent_toolkits.json.prompt import JSON_PREFIX, JSON_SUFFIX -from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS -from langchain_community.agent_toolkits import JsonToolkit -from langchain_core.language_models import BaseLanguageModel - - -class MalfoyAgent(AgentExecutor): - """Json agent""" - - prefix = "Malfoy: " - - @classmethod - def initialize(cls, *args, **kwargs): - return cls.from_toolkit_and_llm(*args, **kwargs) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - @classmethod - def from_toolkit_and_llm(cls, toolkit: JsonToolkit, llm: BaseLanguageModel): - tools = toolkit.get_tools() - tool_names = {tool.name for tool in tools} - prompt = ZeroShotAgent.create_prompt( - tools, - prefix=JSON_PREFIX, - suffix=JSON_SUFFIX, - format_instructions=FORMAT_INSTRUCTIONS, - input_variables=None, - ) - llm_chain = LLMChain( - llm=llm, - prompt=prompt, - ) - agent = ZeroShotAgent(llm_chain=llm_chain, allowed_tools=tool_names) # type: ignore - return cls.from_agent_and_tools(agent=agent, tools=tools, verbose=True) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -PREBUILT_AGENTS = { - "MalfoyAgent": MalfoyAgent, -} diff --git a/src/backend/base/langflow/interface/base.py b/src/backend/base/langflow/interface/base.py deleted file mode 100644 index a300f12f2..000000000 --- a/src/backend/base/langflow/interface/base.py +++ /dev/null @@ -1,139 +0,0 @@ -from abc import ABC, abstractmethod -from typing import Any, Dict, List, Optional, Type, Union - -from langchain.agents import AgentExecutor -from langchain.chains.base import Chain -from loguru import logger -from pydantic import BaseModel - -from langflow.services.deps import get_settings_service -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.template.base import Template - -# Assuming necessary imports for Field, Template, and FrontendNode classes - - -class LangChainTypeCreator(BaseModel, ABC): - type_name: str - type_dict: Optional[Dict] = None - name_docs_dict: Optional[Dict[str, str]] = None - - @property - def frontend_node_class(self) -> Type[FrontendNode]: - """The class type of the FrontendNode created in frontend_node.""" - return FrontendNode - - @property - def docs_map(self) -> Dict[str, str]: - """A dict with the name of the component as key and the documentation link as value.""" - settings_service = get_settings_service() - if self.name_docs_dict is None: - try: - type_settings = getattr(settings_service.settings, self.type_name.upper()) - self.name_docs_dict = {name: value_dict["documentation"] for name, value_dict in type_settings.items()} - except AttributeError as exc: - logger.error(f"Error getting settings for {self.type_name}: {exc}") - - self.name_docs_dict = {} - return self.name_docs_dict - - @property - @abstractmethod - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - raise NotImplementedError - return self.type_dict - - @abstractmethod - def get_signature(self, name: str) -> Union[Optional[Dict[Any, Any]], FrontendNode]: - pass - - @abstractmethod - def to_list(self) -> List[str]: - pass - - def to_dict(self) -> Dict: - result: Dict = {self.type_name: {}} - - for name in self.to_list(): - # frontend_node.to_dict() returns a dict with the following structure: - # {name: {template: {fields}, description: str}} - # so we should update the result dict - node = self.frontend_node(name) - if node is not None: - node = node.to_dict() # type: ignore - result[self.type_name].update(node) - - return result - - def frontend_node(self, name) -> Union[FrontendNode, None]: - signature = self.get_signature(name) - if signature is None: - logger.error(f"Node {name} not loaded") - return signature - if not isinstance(signature, FrontendNode): - fields = [ - TemplateField( - name=key, - field_type=value["type"], - required=value.get("required", False), - placeholder=value.get("placeholder", ""), - is_list=value.get("list", False), - show=value.get("show", True), - multiline=value.get("multiline", False), - value=value.get("value", None), - file_types=value.get("fileTypes", []), - file_path=value.get("file_path", None), - ) - for key, value in signature["template"].items() - if key != "_type" - ] - template = Template(type_name=name, fields=fields) - signature = self.frontend_node_class( - template=template, - description=signature.get("description", ""), - base_classes=signature["base_classes"], - name=name, - ) - - signature.add_extra_fields() - signature.add_extra_base_classes() - signature.set_documentation(self.docs_map.get(name, "")) - return signature - - -class CustomChain(Chain, ABC): - """Custom chain""" - - @staticmethod - def function_name(): - return "CustomChain" - - @classmethod - def initialize(cls, *args, **kwargs): - pass - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -class CustomAgentExecutor(AgentExecutor, ABC): - """Custom chain""" - - @staticmethod - def function_name(): - return "CustomChain" - - @classmethod - def initialize(cls, *args, **kwargs): - pass - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) diff --git a/src/backend/base/langflow/interface/chains/__init__.py b/src/backend/base/langflow/interface/chains/__init__.py deleted file mode 100644 index 2e5570b3c..000000000 --- a/src/backend/base/langflow/interface/chains/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.chains.base import ChainCreator - -__all__ = ["ChainCreator"] diff --git a/src/backend/base/langflow/interface/chains/base.py b/src/backend/base/langflow/interface/chains/base.py deleted file mode 100644 index e69b93614..000000000 --- a/src/backend/base/langflow/interface/chains/base.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Any, ClassVar, Dict, List, Optional, Type - -from langchain import chains -from langchain_experimental.sql import SQLDatabaseChain -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class -from langflow.interface.utils import build_template_from_class -from langflow.legacy_custom.customs import get_custom_nodes -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.chains import ChainFrontendNode -from langflow.utils.util import build_template_from_method -from loguru import logger - -# Assuming necessary imports for Field, Template, and FrontendNode classes - - -class ChainCreator(LangChainTypeCreator): - type_name: str = "chains" - - @property - def frontend_node_class(self) -> Type[ChainFrontendNode]: - return ChainFrontendNode - - #! We need to find a better solution for this - from_method_nodes: ClassVar[Dict] = { - "ConversationalRetrievalChain": "from_llm", - "LLMCheckerChain": "from_llm", - "SQLDatabaseChain": "from_llm", - } - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - settings_service = get_settings_service() - self.type_dict: dict[str, Any] = { - chain_name: import_class(f"langchain.chains.{chain_name}") for chain_name in chains.__all__ - } - from langflow.interface.chains.custom import CUSTOM_CHAINS - - self.type_dict["SQLDatabaseChain"] = SQLDatabaseChain - - self.type_dict.update(CUSTOM_CHAINS) - # Filter according to settings.chains - self.type_dict = { - name: chain - for name, chain in self.type_dict.items() - if name in settings_service.settings.CHAINS or settings_service.settings.DEV - } - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - elif name in self.from_method_nodes.keys(): - return build_template_from_method( - name, - type_to_cls_dict=self.type_to_loader_dict, - method_name=self.from_method_nodes[name], - add_function=True, - ) - return build_template_from_class(name, self.type_to_loader_dict, add_function=True) - except ValueError as exc: - raise ValueError(f"Chain {name} not found: {exc}") from exc - except AttributeError as exc: - logger.error(f"Chain {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - names = [] - for _, chain in self.type_to_loader_dict.items(): - chain_name = chain.function_name() if hasattr(chain, "function_name") else chain.__name__ - names.append(chain_name) - return names - - -chain_creator = ChainCreator() diff --git a/src/backend/base/langflow/interface/chains/custom.py b/src/backend/base/langflow/interface/chains/custom.py deleted file mode 100644 index af5a84c54..000000000 --- a/src/backend/base/langflow/interface/chains/custom.py +++ /dev/null @@ -1,118 +0,0 @@ -from typing import Dict, Optional, Type, Union -from langchain.chains import ConversationChain -from langchain.chains.question_answering import load_qa_chain -from langchain.memory.buffer import ConversationBufferMemory -from pydantic.v1 import Field, root_validator - -from langflow.interface.base import CustomChain -from langflow.interface.utils import extract_input_variables_from_prompt -from langchain_core.language_models import BaseLanguageModel -from langchain_core.memory import BaseMemory - -DEFAULT_SUFFIX = """" -Current conversation: -{history} -Human: {input} -{ai_prefix}""" - - -class BaseCustomConversationChain(ConversationChain): - """BaseCustomChain is a chain you can use to have a conversation with a custom character.""" - - template: Optional[str] - - ai_prefix_value: Optional[str] - """Field to use as the ai_prefix. It needs to be set and has to be in the template""" - - @root_validator(pre=False) - def build_template(cls, values): - format_dict = {} - input_variables = extract_input_variables_from_prompt(values["template"]) - - if values.get("ai_prefix_value", None) is None: - values["ai_prefix_value"] = values["memory"].ai_prefix - - for key in input_variables: - new_value = values.get(key, f"{{{key}}}") - format_dict[key] = new_value - if key == values.get("ai_prefix_value", None): - values["memory"].ai_prefix = new_value - - values["template"] = values["template"].format(**format_dict) - - values["template"] = values["template"] - values["input_variables"] = extract_input_variables_from_prompt(values["template"]) - values["prompt"].template = values["template"] - values["prompt"].input_variables = values["input_variables"] - return values - - -class SeriesCharacterChain(BaseCustomConversationChain): - """SeriesCharacterChain is a chain you can use to have a conversation with a character from a series.""" - - character: str - series: str - template: Optional[str] = """I want you to act like {character} from {series}. -I want you to respond and answer like {character}. do not write any explanations. only answer like {character}. -You must know all of the knowledge of {character}. -Current conversation: -{history} -Human: {input} -{character}:""" - memory: BaseMemory = Field(default_factory=ConversationBufferMemory) - ai_prefix_value: Optional[str] = "character" - """Default memory store.""" - - -class MidJourneyPromptChain(BaseCustomConversationChain): - """MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts.""" - - template: Optional[ - str - ] = """I want you to act as a prompt generator for Midjourney's artificial intelligence program. - Your job is to provide detailed and creative descriptions that will inspire unique and interesting images from the AI. - Keep in mind that the AI is capable of understanding a wide range of language and can interpret abstract concepts, so feel free to be as imaginative and descriptive as possible. - For example, you could describe a scene from a futuristic city, or a surreal landscape filled with strange creatures. - The more detailed and imaginative your description, the more interesting the resulting image will be. Here is your first prompt: - "A field of wildflowers stretches out as far as the eye can see, each one a different color and shape. In the distance, a massive tree towers over the landscape, its branches reaching up to the sky like tentacles.\" - - Current conversation: - {history} - Human: {input} - AI:""" # noqa: E501 - - -class TimeTravelGuideChain(BaseCustomConversationChain): - template: Optional[ - str - ] = """I want you to act as my time travel guide. You are helpful and creative. I will provide you with the historical period or future time I want to visit and you will suggest the best events, sights, or people to experience. Provide the suggestions and any necessary information. - Current conversation: - {history} - Human: {input} - AI:""" # noqa: E501 - - -class CombineDocsChain(CustomChain): - """Implementation of load_qa_chain function""" - - @staticmethod - def function_name(): - return "load_qa_chain" - - @classmethod - def initialize(cls, llm: BaseLanguageModel, chain_type: str): - return load_qa_chain(llm=llm, chain_type=chain_type) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def run(self, *args, **kwargs): - return super().run(*args, **kwargs) - - -CUSTOM_CHAINS: Dict[str, Type[Union[ConversationChain, CustomChain]]] = { - "CombineDocsChain": CombineDocsChain, - "SeriesCharacterChain": SeriesCharacterChain, - "MidJourneyPromptChain": MidJourneyPromptChain, - "TimeTravelGuideChain": TimeTravelGuideChain, -} diff --git a/src/backend/base/langflow/interface/custom/__init__.py b/src/backend/base/langflow/interface/custom/__init__.py deleted file mode 100644 index 5b87e9fa3..000000000 --- a/src/backend/base/langflow/interface/custom/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from langflow.interface.custom.base import CustomComponentCreator -from langflow.interface.custom.custom_component import CustomComponent - -__all__ = ["CustomComponentCreator", "CustomComponent"] diff --git a/src/backend/base/langflow/interface/custom/base.py b/src/backend/base/langflow/interface/custom/base.py deleted file mode 100644 index 573eacba1..000000000 --- a/src/backend/base/langflow/interface/custom/base.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Any, Dict, List, Optional, Type - -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator - -# from langflow.interface.custom.custom import CustomComponent -from langflow.interface.custom.custom_component import CustomComponent -from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode - - -class CustomComponentCreator(LangChainTypeCreator): - type_name: str = "custom_components" - - @property - def frontend_node_class(self) -> Type[CustomComponentFrontendNode]: - return CustomComponentFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict: dict[str, Any] = { - "CustomComponent": CustomComponent, - } - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - from langflow.legacy_custom.customs import get_custom_nodes - - try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - except ValueError as exc: - raise ValueError(f"CustomComponent {name} not found: {exc}") from exc - except AttributeError as exc: - logger.error(f"CustomComponent {name} not loaded: {exc}") - return None - return None - - def to_list(self) -> List[str]: - return list(self.type_to_loader_dict.keys()) - - -custom_component_creator = CustomComponentCreator() diff --git a/src/backend/base/langflow/interface/custom_lists.py b/src/backend/base/langflow/interface/custom_lists.py deleted file mode 100644 index 27429e605..000000000 --- a/src/backend/base/langflow/interface/custom_lists.py +++ /dev/null @@ -1,66 +0,0 @@ -import inspect -from typing import Any - -from langchain import llms, memory, text_splitter -from langchain_community import agent_toolkits, document_loaders, embeddings -from langchain_community.chat_models import ChatVertexAI - -from langflow.interface.agents.custom import CUSTOM_AGENTS -from langflow.interface.chains.custom import CUSTOM_CHAINS -from langflow.interface.importing.utils import import_class -from langchain_anthropic import ChatAnthropic -from langchain_openai import AzureChatOpenAI, ChatOpenAI - -# LLMs -llm_type_to_cls_dict = {} - -for k, v in llms.get_type_to_cls_dict().items(): - try: - llm_type_to_cls_dict[k] = v() - except Exception: - pass -llm_type_to_cls_dict["anthropic-chat"] = ChatAnthropic # type: ignore -llm_type_to_cls_dict["azure-chat"] = AzureChatOpenAI # type: ignore -llm_type_to_cls_dict["openai-chat"] = ChatOpenAI # type: ignore -llm_type_to_cls_dict["vertexai-chat"] = ChatVertexAI # type: ignore - - -# Toolkits -toolkit_type_to_loader_dict: dict[str, Any] = { - toolkit_name: import_class(f"langchain_community.agent_toolkits.{toolkit_name}") - # if toolkit_name is lower case it is a loader - for toolkit_name in agent_toolkits.__all__ - if toolkit_name.islower() -} - -toolkit_type_to_cls_dict: dict[str, Any] = { - toolkit_name: import_class(f"langchain_community.agent_toolkits.{toolkit_name}") - # if toolkit_name is not lower case it is a class - for toolkit_name in agent_toolkits.__all__ - if not toolkit_name.islower() -} - -# Memories -memory_type_to_cls_dict: dict[str, Any] = { - memory_name: import_class(f"langchain.memory.{memory_name}") for memory_name in memory.__all__ -} - - -# Embeddings -embedding_type_to_cls_dict: dict[str, Any] = { - embedding_name: import_class(f"langchain_community.embeddings.{embedding_name}") - for embedding_name in embeddings.__all__ -} - - -# Document Loaders -documentloaders_type_to_cls_dict: dict[str, Any] = { - documentloader_name: import_class(f"langchain_community.document_loaders.{documentloader_name}") - for documentloader_name in document_loaders.__all__ -} - -# Text Splitters -textsplitter_type_to_cls_dict: dict[str, Any] = dict(inspect.getmembers(text_splitter, inspect.isclass)) - -# merge CUSTOM_AGENTS and CUSTOM_CHAINS -CUSTOM_NODES = {**CUSTOM_AGENTS, **CUSTOM_CHAINS} # type: ignore diff --git a/src/backend/base/langflow/interface/document_loaders/__init__.py b/src/backend/base/langflow/interface/document_loaders/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/document_loaders/base.py b/src/backend/base/langflow/interface/document_loaders/base.py deleted file mode 100644 index 11bf0db42..000000000 --- a/src/backend/base/langflow/interface/document_loaders/base.py +++ /dev/null @@ -1,42 +0,0 @@ -from typing import Dict, List, Optional, Type - -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.custom_lists import documentloaders_type_to_cls_dict -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.documentloaders import DocumentLoaderFrontNode - - -class DocumentLoaderCreator(LangChainTypeCreator): - type_name: str = "documentloaders" - - @property - def frontend_node_class(self) -> Type[DocumentLoaderFrontNode]: - return DocumentLoaderFrontNode - - @property - def type_to_loader_dict(self) -> Dict: - return documentloaders_type_to_cls_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of a document loader.""" - try: - return build_template_from_class(name, documentloaders_type_to_cls_dict) - except ValueError as exc: - raise ValueError(f"Documment Loader {name} not found") from exc - except AttributeError as exc: - logger.error(f"Documment Loader {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - documentloader.__name__ - for documentloader in self.type_to_loader_dict.values() - if documentloader.__name__ in settings_service.settings.DOCUMENTLOADERS or settings_service.settings.DEV - ] - - -documentloader_creator = DocumentLoaderCreator() diff --git a/src/backend/base/langflow/interface/embeddings/__init__.py b/src/backend/base/langflow/interface/embeddings/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/embeddings/base.py b/src/backend/base/langflow/interface/embeddings/base.py deleted file mode 100644 index 5fd7ad3b0..000000000 --- a/src/backend/base/langflow/interface/embeddings/base.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Dict, List, Optional, Type - -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.custom_lists import embedding_type_to_cls_dict -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.embeddings import EmbeddingFrontendNode - - -class EmbeddingCreator(LangChainTypeCreator): - type_name: str = "embeddings" - - @property - def type_to_loader_dict(self) -> Dict: - return embedding_type_to_cls_dict - - @property - def frontend_node_class(self) -> Type[FrontendNode]: - return EmbeddingFrontendNode - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of an embedding.""" - try: - return build_template_from_class(name, embedding_type_to_cls_dict) - except ValueError as exc: - raise ValueError(f"Embedding {name} not found") from exc - - except AttributeError as exc: - logger.error(f"Embedding {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - embedding.__name__ - for embedding in self.type_to_loader_dict.values() - if embedding.__name__ in settings_service.settings.EMBEDDINGS or settings_service.settings.DEV - ] - - -embedding_creator = EmbeddingCreator() diff --git a/src/backend/base/langflow/interface/importing/utils.py b/src/backend/base/langflow/interface/importing/utils.py index a4f4904ac..963a51ccb 100644 --- a/src/backend/base/langflow/interface/importing/utils.py +++ b/src/backend/base/langflow/interface/importing/utils.py @@ -1,16 +1,7 @@ # This module is used to import any langchain class by name. import importlib -from typing import Any, Type - -from langchain.agents import Agent -from langchain.chains.base import Chain -from langchain_core.language_models.chat_models import BaseChatModel - -from langflow.interface.wrappers.base import wrapper_creator -from langchain_core.language_models import BaseLanguageModel -from langchain_core.prompts import PromptTemplate -from langchain_core.tools import BaseTool +from typing import Any def import_module(module_path: str) -> Any: @@ -27,134 +18,8 @@ def import_module(module_path: str) -> Any: return getattr(module, object_name) -def import_by_type(_type: str, name: str) -> Any: - """Import class by type and name""" - if _type is None: - raise ValueError(f"Type cannot be None. Check if {name} is in the config file.") - func_dict = { - "agents": import_agent, - "prompts": import_prompt, - "models": {"llm": import_llm, "chat": import_chat_llm}, - "tools": import_tool, - "chains": import_chain, - "toolkits": import_toolkit, - "wrappers": import_wrapper, - "memory": import_memory, - "embeddings": import_embedding, - "vectorstores": import_vectorstore, - "documentloaders": import_documentloader, - "textsplitters": import_textsplitter, - "utilities": import_utility, - "retrievers": import_retriever, - } - if _type == "models": - key = "chat" if "chat" in name.lower() else "llm" - loaded_func = func_dict[_type][key] # type: ignore - else: - loaded_func = func_dict[_type] - - return loaded_func(name) - - -def import_chat_llm(llm: str) -> BaseChatModel: - """Import chat llm from llm name""" - return import_class(f"langchain_community.chat_models.{llm}") - - -def import_retriever(retriever: str) -> Any: - """Import retriever from retriever name""" - return import_module(f"from langchain.retrievers import {retriever}") - - -def import_memory(memory: str) -> Any: - """Import memory from memory name""" - return import_module(f"from langchain.memory import {memory}") - - def import_class(class_path: str) -> Any: """Import class from class path""" module_path, class_name = class_path.rsplit(".", 1) module = import_module(module_path) return getattr(module, class_name) - - -def import_prompt(prompt: str) -> Type[PromptTemplate]: - """Import prompt from prompt name""" - from langflow.interface.prompts.custom import CUSTOM_PROMPTS - - if prompt == "ZeroShotPrompt": - return import_class("langchain.prompts.PromptTemplate") - elif prompt in CUSTOM_PROMPTS: - return CUSTOM_PROMPTS[prompt] - return import_class(f"langchain.prompts.{prompt}") - - -def import_wrapper(wrapper: str) -> Any: - """Import wrapper from wrapper name""" - if isinstance(wrapper_creator.type_dict, dict) and wrapper in wrapper_creator.type_dict: - return wrapper_creator.type_dict.get(wrapper) - - -def import_toolkit(toolkit: str) -> Any: - """Import toolkit from toolkit name""" - return import_module(f"from langchain.agents.agent_toolkits import {toolkit}") - - -def import_agent(agent: str) -> Agent: - """Import agent from agent name""" - # check for custom agent - - return import_class(f"langchain.agents.{agent}") - - -def import_llm(llm: str) -> BaseLanguageModel: - """Import llm from llm name""" - return import_class(f"langchain.llms.{llm}") - - -def import_tool(tool: str) -> BaseTool: - """Import tool from tool name""" - from langflow.interface.tools.base import tool_creator - - if tool in tool_creator.type_to_loader_dict: - return tool_creator.type_to_loader_dict[tool]["fcn"] - - return import_class(f"langchain.tools.{tool}") - - -def import_chain(chain: str) -> Type[Chain]: - """Import chain from chain name""" - from langflow.interface.chains.custom import CUSTOM_CHAINS - - if chain in CUSTOM_CHAINS: - return CUSTOM_CHAINS[chain] - if chain == "SQLDatabaseChain": - return import_class("langchain_experimental.sql.SQLDatabaseChain") - return import_class(f"langchain.chains.{chain}") - - -def import_embedding(embedding: str) -> Any: - """Import embedding from embedding name""" - return import_class(f"langchain_community.embeddings.{embedding}") - - -def import_vectorstore(vectorstore: str) -> Any: - """Import vectorstore from vectorstore name""" - return import_class(f"langchain_community.vectorstores.{vectorstore}") - - -def import_documentloader(documentloader: str) -> Any: - """Import documentloader from documentloader name""" - return import_class(f"langchain_community.document_loaders.{documentloader}") - - -def import_textsplitter(textsplitter: str) -> Any: - """Import textsplitter from textsplitter name""" - return import_class(f"langchain.text_splitter.{textsplitter}") - - -def import_utility(utility: str) -> Any: - """Import utility from utility name""" - if utility == "SQLDatabase": - return import_class(f"langchain_community.sql_database.{utility}") - return import_class(f"langchain_community.utilities.{utility}") diff --git a/src/backend/base/langflow/interface/initialize/loading.py b/src/backend/base/langflow/interface/initialize/loading.py index d5ebf7260..03de827b3 100644 --- a/src/backend/base/langflow/interface/initialize/loading.py +++ b/src/backend/base/langflow/interface/initialize/loading.py @@ -1,33 +1,13 @@ import inspect import json import os -from typing import TYPE_CHECKING, Any, Callable, Dict, Sequence, Type +from typing import TYPE_CHECKING, Any, Type import orjson -from langchain.agents import agent as agent_module -from langchain.agents.agent import AgentExecutor -from langchain.chains.base import Chain -from langchain_core.documents import Document from loguru import logger -from pydantic import ValidationError -from langflow.interface.custom.eval import eval_custom_component_code -from langflow.interface.importing.utils import import_by_type -from langflow.interface.initialize.llm import initialize_vertexai -from langflow.interface.initialize.utils import handle_format_kwargs, handle_node_type, handle_partial_variables -from langflow.interface.initialize.vector_store import vecstore_initializer -from langflow.interface.retrievers.base import retriever_creator -from langflow.interface.toolkits.base import toolkits_creator -from langflow.interface.utils import load_file_into_dict -from langflow.interface.wrappers.base import wrapper_creator +from langflow.custom.eval import eval_custom_component_code from langflow.schema.schema import Record -from langflow.utils import validate -from langflow.utils.util import unescape_string -from langchain_community.agent_toolkits.base import BaseToolkit -from langchain_core.document_loaders import BaseLoader -from langchain_core.tools import BaseTool -from langchain_core.vectorstores import VectorStore -from langchain_text_splitters import Language if TYPE_CHECKING: from langflow.custom import CustomComponent @@ -40,36 +20,19 @@ async def instantiate_class( user_id=None, ) -> Any: """Instantiate class from module type and key, and params""" - from langflow.interface.custom_lists import CUSTOM_NODES vertex_type = vertex.vertex_type base_type = vertex.base_type params = vertex.params params = convert_params_to_sets(params) params = convert_kwargs(params) - - if vertex_type in CUSTOM_NODES: - if custom_node := CUSTOM_NODES.get(vertex_type): - if hasattr(custom_node, "initialize"): - return custom_node.initialize(**params) - if callable(custom_node): - return custom_node(**params) - raise ValueError(f"Custom node {vertex_type} is not callable") logger.debug(f"Instantiating {vertex_type} of type {base_type}") if not base_type: raise ValueError("No base type provided for vertex") if base_type == "custom_components": return await instantiate_custom_component(params, user_id, vertex, fallback_to_env_vars=fallback_to_env_vars) - class_object = import_by_type(_type=base_type, name=vertex_type) - return await instantiate_based_on_type( - class_object=class_object, - base_type=base_type, - node_type=vertex_type, - params=params, - user_id=user_id, - vertex=vertex, - fallback_to_env_vars=fallback_to_env_vars, - ) + else: + raise ValueError(f"Base type {base_type} not found.") def convert_params_to_sets(params): @@ -96,45 +59,6 @@ def convert_kwargs(params): return params -async def instantiate_based_on_type(class_object, base_type, node_type, params, user_id, vertex, fallback_to_env_vars): - if base_type == "agents": - return instantiate_agent(node_type, class_object, params) - elif base_type == "prompts": - return instantiate_prompt(node_type, class_object, params) - elif base_type == "tools": - tool = instantiate_tool(node_type, class_object, params) - if hasattr(tool, "name") and isinstance(tool, BaseTool): - # tool name shouldn't contain spaces - tool.name = tool.name.replace(" ", "_") - return tool - elif base_type == "toolkits": - return instantiate_toolkit(node_type, class_object, params) - elif base_type == "embeddings": - return instantiate_embedding(node_type, class_object, params) - elif base_type == "vectorstores": - return instantiate_vectorstore(class_object, params) - elif base_type == "documentloaders": - return instantiate_documentloader(node_type, class_object, params) - elif base_type == "textsplitters": - return instantiate_textsplitter(class_object, params) - elif base_type == "utilities": - return instantiate_utility(node_type, class_object, params) - elif base_type == "chains": - return instantiate_chains(node_type, class_object, params) - elif base_type == "models": - return instantiate_llm(node_type, class_object, params) - elif base_type == "retrievers": - return instantiate_retriever(node_type, class_object, params) - elif base_type == "memory": - return instantiate_memory(node_type, class_object, params) - elif base_type == "custom_components": - return await instantiate_custom_component(params, user_id, vertex, fallback_to_env_vars=fallback_to_env_vars) - elif base_type == "wrappers": - return instantiate_wrapper(node_type, class_object, params) - else: - return class_object(**params) - - def update_params_with_load_from_db_fields( custom_component: "CustomComponent", params, load_from_db_fields, fallback_to_env_vars=False ): @@ -201,349 +125,3 @@ async def instantiate_custom_component(params, user_id, vertex, fallback_to_env_ if not isinstance(custom_repr, str): custom_repr = str(custom_repr) return custom_component, build_result, {"repr": custom_repr} - - -def instantiate_wrapper(node_type, class_object, params): - if node_type in wrapper_creator.from_method_nodes: - method = wrapper_creator.from_method_nodes[node_type] - if class_method := getattr(class_object, method, None): - return class_method(**params) - raise ValueError(f"Method {method} not found in {class_object}") - return class_object(**params) - - -def instantiate_llm(node_type, class_object, params: Dict): - # This is a workaround so JinaChat works until streaming is implemented - # if "openai_api_base" in params and "jina" in params["openai_api_base"]: - # False if condition is True - if "VertexAI" in node_type: - return initialize_vertexai(class_object=class_object, params=params) - # max_tokens sometimes is a string and should be an int - if "max_tokens" in params: - if isinstance(params["max_tokens"], str) and params["max_tokens"].isdigit(): - params["max_tokens"] = int(params["max_tokens"]) - elif not isinstance(params.get("max_tokens"), int): - params.pop("max_tokens", None) - return class_object(**params) - - -def instantiate_memory(node_type, class_object, params): - # process input_key and output_key to remove them if - # they are empty strings - if node_type == "ConversationEntityMemory": - params.pop("memory_key", None) - - for key in ["input_key", "output_key"]: - if key in params and (params[key] == "" or not params[key]): - params.pop(key) - - try: - if "retriever" in params and hasattr(params["retriever"], "as_retriever"): - params["retriever"] = params["retriever"].as_retriever() - return class_object(**params) - # I want to catch a specific attribute error that happens - # when the object does not have a cursor attribute - except Exception as exc: - if "object has no attribute 'cursor'" in str(exc) or 'object has no field "conn"' in str(exc): - raise AttributeError( - ( - "Failed to build connection to database." - f" Please check your connection string and try again. Error: {exc}" - ) - ) from exc - raise exc - - -def instantiate_retriever(node_type, class_object, params): - if "retriever" in params and hasattr(params["retriever"], "as_retriever"): - params["retriever"] = params["retriever"].as_retriever() - if node_type in retriever_creator.from_method_nodes: - method = retriever_creator.from_method_nodes[node_type] - if class_method := getattr(class_object, method, None): - return class_method(**params) - raise ValueError(f"Method {method} not found in {class_object}") - return class_object(**params) - - -def instantiate_chains(node_type, class_object: Type[Chain], params: Dict): - from langflow.interface.chains.base import chain_creator - - if "retriever" in params and hasattr(params["retriever"], "as_retriever"): - params["retriever"] = params["retriever"].as_retriever() - if node_type in chain_creator.from_method_nodes: - method = chain_creator.from_method_nodes[node_type] - if class_method := getattr(class_object, method, None): - return class_method(**params) - raise ValueError(f"Method {method} not found in {class_object}") - - return class_object(**params) - - -def instantiate_agent(node_type, class_object: Type[agent_module.Agent], params: Dict): - from langflow.interface.agents.base import agent_creator - - if node_type in agent_creator.from_method_nodes: - method = agent_creator.from_method_nodes[node_type] - if class_method := getattr(class_object, method, None): - agent = class_method(**params) - tools = params.get("tools", []) - return AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, handle_parsing_errors=True) - return load_agent_executor(class_object, params) - - -def instantiate_prompt(node_type, class_object, params: Dict): - params, prompt = handle_node_type(node_type, class_object, params) - format_kwargs = handle_format_kwargs(prompt, params) - # Now we'll use partial_format to format the prompt - if format_kwargs: - prompt = handle_partial_variables(prompt, format_kwargs) - return prompt, format_kwargs - - -def instantiate_tool(node_type, class_object: Type[BaseTool], params: Dict): - if node_type == "JsonSpec": - if file_dict := load_file_into_dict(params.pop("path")): - params["dict_"] = file_dict - else: - raise ValueError("Invalid file") - return class_object(**params) - elif node_type == "PythonFunctionTool": - from langflow.interface.custom.utils import get_function - - params["func"] = get_function(params.get("code")) - return class_object(**params) - elif node_type == "PythonFunction": - function_string = params["code"] - if isinstance(function_string, str): - return validate.eval_function(function_string) - raise ValueError("Function should be a string") - elif node_type.lower() == "tool": - return class_object(**params) - return class_object(**params) - - -def instantiate_toolkit(node_type, class_object: Type[BaseToolkit], params: Dict): - loaded_toolkit = class_object(**params) - # Commenting this out for now to use toolkits as normal tools - # if toolkits_creator.has_create_function(node_type): - # return load_toolkits_executor(node_type, loaded_toolkit, params) - if isinstance(loaded_toolkit, BaseToolkit): - return loaded_toolkit.get_tools() - return loaded_toolkit - - -def instantiate_embedding(node_type, class_object, params: Dict): - params.pop("model", None) - params.pop("headers", None) - - if "VertexAI" in node_type: - return initialize_vertexai(class_object=class_object, params=params) - - if "OpenAIEmbedding" in node_type: - params["disallowed_special"] = () - - try: - return class_object(**params) - except ValidationError: - params = {key: value for key, value in params.items() if key in class_object.model_fields} - return class_object(**params) - - -def instantiate_vectorstore(class_object: Type[VectorStore], params: Dict): - search_kwargs = params.pop("search_kwargs", {}) - if search_kwargs == {"yourkey": "value"}: - search_kwargs = {} - # clean up docs or texts to have only documents - if "texts" in params: - params["documents"] = params.pop("texts") - if "documents" in params: - params["documents"] = [doc for doc in params["documents"] if isinstance(doc, Document)] - if initializer := vecstore_initializer.get(class_object.__name__): - vecstore = initializer(class_object, params) - else: - if "texts" in params: - params["documents"] = params.pop("texts") - vecstore = class_object.from_documents(**params) - - # ! This might not work. Need to test - if search_kwargs and hasattr(vecstore, "as_retriever"): - vecstore = vecstore.as_retriever(search_kwargs=search_kwargs) - - return vecstore - - -def instantiate_documentloader(node_type: str, class_object: Type[BaseLoader], params: Dict): - if "file_filter" in params: - # file_filter will be a string but we need a function - # that will be used to filter the files using file_filter - # like lambda x: x.endswith(".txt") but as we don't know - # anything besides the string, we will simply check if the string is - # in x and if it is, we will return True - file_filter = params.pop("file_filter") - extensions = file_filter.split(",") - params["file_filter"] = lambda x: any(extension.strip() in x for extension in extensions) - metadata = params.pop("metadata", None) - if metadata and isinstance(metadata, str): - try: - metadata = orjson.loads(metadata) - except json.JSONDecodeError as exc: - raise ValueError("The metadata you provided is not a valid JSON string.") from exc - - if node_type == "WebBaseLoader": - if web_path := params.pop("web_path", None): - params["web_paths"] = [web_path] - - docs = class_object(**params).load() - # Now if metadata is an empty dict, we will not add it to the documents - if metadata: - for doc in docs: - # If the document already has metadata, we will not overwrite it - if not doc.metadata: - doc.metadata = metadata - else: - doc.metadata.update(metadata) - - return docs - - -def instantiate_textsplitter( - class_object, - params: Dict, -): - try: - documents = params.pop("documents") - if not isinstance(documents, list): - documents = [documents] - except KeyError as exc: - raise ValueError( - "The source you provided did not load correctly or was empty." - "Try changing the chunk_size of the Text Splitter." - ) from exc - - if ("separator_type" in params and params["separator_type"] == "Text") or "separator_type" not in params: - params.pop("separator_type", None) - # separators might come in as an escaped string like \\n - # so we need to convert it to a string - if "separators" in params: - if isinstance(params["separators"], str): - params["separators"] = unescape_string(params["separators"]) - elif isinstance(params["separators"], list): - params["separators"] = [unescape_string(separator) for separator in params["separators"]] - text_splitter = class_object(**params) - else: - language = params.pop("separator_type", None) - params["language"] = Language(language) - params.pop("separators", None) - - text_splitter = class_object.from_language(**params) - return text_splitter.split_documents(documents) - - -def instantiate_utility(node_type, class_object, params: Dict): - if node_type == "SQLDatabase": - return class_object.from_uri(params.pop("uri")) - return class_object(**params) - - -def replace_zero_shot_prompt_with_prompt_template(nodes): - """Replace ZeroShotPrompt with PromptTemplate""" - for node in nodes: - if node["data"]["type"] == "ZeroShotPrompt": - # Build Prompt Template - tools = [ - tool - for tool in nodes - if tool["type"] != "chatOutputNode" and "Tool" in tool["data"]["node"]["base_classes"] - ] - node["data"] = build_prompt_template(prompt=node["data"], tools=tools) - break - return nodes - - -def load_agent_executor(agent_class: type[agent_module.Agent], params, **kwargs): - """Load agent executor from agent class, tools and chain""" - allowed_tools: Sequence[BaseTool] = params.get("allowed_tools", []) - llm_chain = params["llm_chain"] - # agent has hidden args for memory. might need to be support - # memory = params["memory"] - # if allowed_tools is not a list or set, make it a list - if not isinstance(allowed_tools, (list, set)) and isinstance(allowed_tools, BaseTool): - allowed_tools = [allowed_tools] - tool_names = [tool.name for tool in allowed_tools] - # Agent class requires an output_parser but Agent classes - # have a default output_parser. - agent = agent_class(allowed_tools=tool_names, llm_chain=llm_chain) # type: ignore - return AgentExecutor.from_agent_and_tools( - agent=agent, - tools=allowed_tools, - handle_parsing_errors=True, - # memory=memory, - **kwargs, - ) - - -def load_toolkits_executor(node_type: str, toolkit: BaseToolkit, params: dict): - create_function: Callable = toolkits_creator.get_create_function(node_type) - if llm := params.get("llm"): - return create_function(llm=llm, toolkit=toolkit) - - -def build_prompt_template(prompt, tools): - """Build PromptTemplate from ZeroShotPrompt""" - prefix = prompt["node"]["template"]["prefix"]["value"] - suffix = prompt["node"]["template"]["suffix"]["value"] - format_instructions = prompt["node"]["template"]["format_instructions"]["value"] - - tool_strings = "\n".join( - [f"{tool['data']['node']['name']}: {tool['data']['node']['description']}" for tool in tools] - ) - tool_names = ", ".join([tool["data"]["node"]["name"] for tool in tools]) - format_instructions = format_instructions.format(tool_names=tool_names) - value = "\n\n".join([prefix, tool_strings, format_instructions, suffix]) - - prompt["type"] = "PromptTemplate" - - prompt["node"] = { - "template": { - "_type": "prompt", - "input_variables": { - "type": "str", - "required": True, - "placeholder": "", - "list": True, - "show": False, - "multiline": False, - }, - "template": { - "type": "str", - "required": True, - "placeholder": "", - "list": False, - "show": True, - "multiline": True, - "value": value, - }, - "template_format": { - "type": "str", - "required": False, - "placeholder": "", - "list": False, - "show": False, - "multline": False, - "value": "f-string", - }, - "validate_template": { - "type": "bool", - "required": False, - "placeholder": "", - "list": False, - "show": False, - "multline": False, - "value": True, - }, - }, - "description": "Schema to represent a prompt for an LLM.", - "base_classes": ["BasePromptTemplate"], - } - - return prompt diff --git a/src/backend/base/langflow/interface/llms/__init__.py b/src/backend/base/langflow/interface/llms/__init__.py deleted file mode 100644 index c5d7186fb..000000000 --- a/src/backend/base/langflow/interface/llms/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.llms.base import LLMCreator - -__all__ = ["LLMCreator"] diff --git a/src/backend/base/langflow/interface/llms/base.py b/src/backend/base/langflow/interface/llms/base.py deleted file mode 100644 index b7d91d674..000000000 --- a/src/backend/base/langflow/interface/llms/base.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import Dict, List, Optional, Type - -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.custom_lists import llm_type_to_cls_dict -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.llms import LLMFrontendNode - - -class LLMCreator(LangChainTypeCreator): - type_name: str = "models" - - @property - def frontend_node_class(self) -> Type[LLMFrontendNode]: - return LLMFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict = llm_type_to_cls_dict - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of an llm.""" - try: - return build_template_from_class(name, llm_type_to_cls_dict) - except ValueError as exc: - raise ValueError("LLM not found") from exc - - except AttributeError as exc: - logger.error(f"LLM {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - llm.__name__ - for llm in self.type_to_loader_dict.values() - if llm.__name__ in settings_service.settings.LLMS or settings_service.settings.DEV - ] - - -llm_creator = LLMCreator() diff --git a/src/backend/base/langflow/interface/memories/__init__.py b/src/backend/base/langflow/interface/memories/__init__.py deleted file mode 100644 index 845eb29fe..000000000 --- a/src/backend/base/langflow/interface/memories/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.memories.base import MemoryCreator - -__all__ = ["MemoryCreator"] diff --git a/src/backend/base/langflow/interface/memories/base.py b/src/backend/base/langflow/interface/memories/base.py deleted file mode 100644 index ea0eabbf1..000000000 --- a/src/backend/base/langflow/interface/memories/base.py +++ /dev/null @@ -1,60 +0,0 @@ -from typing import ClassVar, Dict, List, Optional, Type - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.custom_lists import memory_type_to_cls_dict -from langflow.interface.utils import build_template_from_class -from langflow.legacy_custom.customs import get_custom_nodes -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.memories import MemoryFrontendNode -from langflow.utils.util import build_template_from_method -from loguru import logger - - -class MemoryCreator(LangChainTypeCreator): - type_name: str = "memories" - - from_method_nodes: ClassVar[Dict] = { - "ZepChatMessageHistory": "__init__", - "SQLiteEntityStore": "__init__", - } - - @property - def frontend_node_class(self) -> Type[FrontendNode]: - """The class type of the FrontendNode created in frontend_node.""" - return MemoryFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict = memory_type_to_cls_dict - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of a memory.""" - try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - elif name in self.from_method_nodes: - return build_template_from_method( - name, - type_to_cls_dict=memory_type_to_cls_dict, - method_name=self.from_method_nodes[name], - ) - return build_template_from_class(name, memory_type_to_cls_dict) - except ValueError as exc: - raise ValueError("Memory not found") from exc - except AttributeError as exc: - logger.error(f"Memory {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - memory.__name__ - for memory in self.type_to_loader_dict.values() - if memory.__name__ in settings_service.settings.MEMORIES or settings_service.settings.DEV - ] - - -memory_creator = MemoryCreator() diff --git a/src/backend/base/langflow/interface/prompts/__init__.py b/src/backend/base/langflow/interface/prompts/__init__.py deleted file mode 100644 index 2a81e8bf0..000000000 --- a/src/backend/base/langflow/interface/prompts/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.prompts.base import PromptCreator - -__all__ = ["PromptCreator"] diff --git a/src/backend/base/langflow/interface/prompts/base.py b/src/backend/base/langflow/interface/prompts/base.py deleted file mode 100644 index b9662e0cd..000000000 --- a/src/backend/base/langflow/interface/prompts/base.py +++ /dev/null @@ -1,64 +0,0 @@ -from typing import Dict, List, Optional, Type - -from langchain import prompts -from loguru import logger -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class -from langflow.interface.utils import build_template_from_class -from langflow.legacy_custom.customs import get_custom_nodes -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.prompts import PromptFrontendNode - - -class PromptCreator(LangChainTypeCreator): - type_name: str = "prompts" - - @property - def frontend_node_class(self) -> Type[PromptFrontendNode]: - return PromptFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - settings_service = get_settings_service() - if self.type_dict is None: - self.type_dict = { - prompt_name: import_class(f"langchain.prompts.{prompt_name}") - # if prompt_name is not lower case it is a class - for prompt_name in prompts.__all__ - } - # Merge CUSTOM_PROMPTS into self.type_dict - from langflow.interface.prompts.custom import CUSTOM_PROMPTS - - self.type_dict.update(CUSTOM_PROMPTS) - # Now filter according to settings.prompts - self.type_dict = { - name: prompt - for name, prompt in self.type_dict.items() - if name in settings_service.settings.PROMPTS or settings_service.settings.DEV - } - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - try: - if name in get_custom_nodes(self.type_name).keys(): - return get_custom_nodes(self.type_name)[name] - return build_template_from_class(name, self.type_to_loader_dict) - except ValueError as exc: - # raise ValueError("Prompt not found") from exc - logger.error(f"Prompt {name} not found: {exc}") - except AttributeError as exc: - logger.error(f"Prompt {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - custom_prompts = get_custom_nodes("prompts") - # library_prompts = [ - # prompt.__annotations__["return"].__name__ - # for prompt in self.type_to_loader_dict.values() - # if prompt.__annotations__["return"].__name__ in settings.prompts - # or settings.dev - # ] - return list(self.type_to_loader_dict.keys()) + list(custom_prompts.keys()) - - -prompt_creator = PromptCreator() diff --git a/src/backend/base/langflow/interface/prompts/custom.py b/src/backend/base/langflow/interface/prompts/custom.py deleted file mode 100644 index e90ce8812..000000000 --- a/src/backend/base/langflow/interface/prompts/custom.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import Dict, List, Optional, Type -from pydantic.v1 import root_validator - -from langflow.interface.utils import extract_input_variables_from_prompt -from langchain_core.prompts import PromptTemplate - -# Steps to create a BaseCustomPrompt: -# 1. Create a prompt template that endes with: -# Current conversation: -# {history} -# Human: {input} -# {ai_prefix}: -# 2. Create a class that inherits from BaseCustomPrompt -# 3. Add the following class attributes: -# template: str = "" -# description: Optional[str] -# ai_prefix: Optional[str] = "{ai_prefix}" -# 3.1. The ai_prefix should be a value in input_variables -# SeriesCharacterPrompt is a working example -# If used in a LLMChain, with a Memory module, it will work as expected -# We should consider creating ConversationalChains that expose custom parameters -# That way it will be easier to create custom prompts - - -class BaseCustomPrompt(PromptTemplate): - template: str = "" - description: Optional[str] - ai_prefix: Optional[str] - - @root_validator(pre=False) - def build_template(cls, values): - format_dict = {} - ai_prefix_format_dict = {} - for key in values.get("input_variables", []): - new_value = values.get(key, f"{{{key}}}") - format_dict[key] = new_value - if key in values["ai_prefix"]: - ai_prefix_format_dict[key] = new_value - - values["ai_prefix"] = values["ai_prefix"].format(**ai_prefix_format_dict) - values["template"] = values["template"].format(**format_dict) - - values["template"] = values["template"] - values["input_variables"] = extract_input_variables_from_prompt(values["template"]) - return values - - -class SeriesCharacterPrompt(BaseCustomPrompt): - # Add a very descriptive description for the prompt generator - description: Optional[str] = "A prompt that asks the AI to act like a character from a series." - character: str - series: str - template: str = """I want you to act like {character} from {series}. -I want you to respond and answer like {character}. do not write any explanations. only answer like {character}. -You must know all of the knowledge of {character}. - -Current conversation: -{history} -Human: {input} -{character}:""" - - ai_prefix: str = "{character}" - input_variables: List[str] = ["character", "series"] - - -CUSTOM_PROMPTS: Dict[str, Type[BaseCustomPrompt]] = {"SeriesCharacterPrompt": SeriesCharacterPrompt} diff --git a/src/backend/base/langflow/interface/retrievers/__init__.py b/src/backend/base/langflow/interface/retrievers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/retrievers/base.py b/src/backend/base/langflow/interface/retrievers/base.py deleted file mode 100644 index 6eefe18db..000000000 --- a/src/backend/base/langflow/interface/retrievers/base.py +++ /dev/null @@ -1,60 +0,0 @@ -from typing import Any, ClassVar, Dict, List, Optional, Type - -from langchain_community import retrievers -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.retrievers import RetrieverFrontendNode -from langflow.utils.util import build_template_from_method -from loguru import logger - - -class RetrieverCreator(LangChainTypeCreator): - type_name: str = "retrievers" - - from_method_nodes: ClassVar[Dict] = { - "MultiQueryRetriever": "from_llm", - "ZepRetriever": "__init__", - } - - @property - def frontend_node_class(self) -> Type[RetrieverFrontendNode]: - return RetrieverFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict: dict[str, Any] = { - retriever_name: import_class(f"langchain_community.retrievers.{retriever_name}") - for retriever_name in retrievers.__all__ - } - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of an embedding.""" - try: - if name in self.from_method_nodes: - return build_template_from_method( - name, - type_to_cls_dict=self.type_to_loader_dict, - method_name=self.from_method_nodes[name], - ) - else: - return build_template_from_class(name, type_to_cls_dict=self.type_to_loader_dict) - except ValueError as exc: - raise ValueError(f"Retriever {name} not found") from exc - except AttributeError as exc: - logger.error(f"Retriever {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - retriever - for retriever in self.type_to_loader_dict.keys() - if retriever in settings_service.settings.RETRIEVERS or settings_service.settings.DEV - ] - - -retriever_creator = RetrieverCreator() diff --git a/src/backend/base/langflow/interface/text_splitters/__init__.py b/src/backend/base/langflow/interface/text_splitters/__init__.py deleted file mode 100644 index 4bb9dd1b0..000000000 --- a/src/backend/base/langflow/interface/text_splitters/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.text_splitters.base import TextSplitterCreator - -__all__ = ["TextSplitterCreator"] diff --git a/src/backend/base/langflow/interface/text_splitters/base.py b/src/backend/base/langflow/interface/text_splitters/base.py deleted file mode 100644 index 69d9799b3..000000000 --- a/src/backend/base/langflow/interface/text_splitters/base.py +++ /dev/null @@ -1,42 +0,0 @@ -from typing import Dict, List, Optional, Type - -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.custom_lists import textsplitter_type_to_cls_dict -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.textsplitters import TextSplittersFrontendNode - - -class TextSplitterCreator(LangChainTypeCreator): - type_name: str = "textsplitters" - - @property - def frontend_node_class(self) -> Type[TextSplittersFrontendNode]: - return TextSplittersFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - return textsplitter_type_to_cls_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of a text splitter.""" - try: - return build_template_from_class(name, textsplitter_type_to_cls_dict) - except ValueError as exc: - raise ValueError(f"Text Splitter {name} not found") from exc - except AttributeError as exc: - logger.error(f"Text Splitter {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - textsplitter.__name__ - for textsplitter in self.type_to_loader_dict.values() - if textsplitter.__name__ in settings_service.settings.TEXTSPLITTERS or settings_service.settings.DEV - ] - - -textsplitter_creator = TextSplitterCreator() diff --git a/src/backend/base/langflow/interface/toolkits/__init__.py b/src/backend/base/langflow/interface/toolkits/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/toolkits/base.py b/src/backend/base/langflow/interface/toolkits/base.py deleted file mode 100644 index eca7ae3b7..000000000 --- a/src/backend/base/langflow/interface/toolkits/base.py +++ /dev/null @@ -1,71 +0,0 @@ -import warnings -from typing import Callable, Dict, List, Optional - -from langchain.agents import agent_toolkits -from loguru import logger -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class, import_module -from langflow.interface.utils import build_template_from_class -from langflow.services.deps import get_settings_service - - -class ToolkitCreator(LangChainTypeCreator): - type_name: str = "toolkits" - all_types: List[str] = agent_toolkits.__all__ - create_functions: Dict = { - "JsonToolkit": [], - "SQLDatabaseToolkit": [], - "OpenAPIToolkit": ["create_openapi_agent"], - "VectorStoreToolkit": [ - "create_vectorstore_agent", - "create_vectorstore_router_agent", - "VectorStoreInfo", - ], - "ZapierToolkit": [], - "PandasToolkit": ["create_pandas_dataframe_agent"], - "CSVToolkit": ["create_csv_agent"], - } - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - settings_service = get_settings_service() - self.type_dict = { - toolkit_name: import_class(f"langchain.agents.agent_toolkits.{toolkit_name}") - # if toolkit_name is not lower case it is a class - for toolkit_name in agent_toolkits.__all__ - if not toolkit_name.islower() and toolkit_name in settings_service.settings.TOOLKITS - } - - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - try: - template = build_template_from_class(name, self.type_to_loader_dict) - # add Tool to base_classes - if "toolkit" in name.lower() and template: - template["base_classes"].append("Tool") - return template - except ValueError as exc: - raise ValueError("Toolkit not found") from exc - except AttributeError as exc: - logger.error(f"Toolkit {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - return list(self.type_to_loader_dict.keys()) - - def get_create_function(self, name: str) -> Callable: - if loader_name := self.create_functions.get(name): - return import_module(f"from langchain.agents.agent_toolkits import {loader_name[0]}") - else: - raise ValueError("Toolkit not found") - - def has_create_function(self, name: str) -> bool: - # check if the function list is not empty - return bool(self.create_functions.get(name, None)) - - -toolkits_creator = ToolkitCreator() diff --git a/src/backend/base/langflow/interface/toolkits/custom.py b/src/backend/base/langflow/interface/toolkits/custom.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/tools/__init__.py b/src/backend/base/langflow/interface/tools/__init__.py deleted file mode 100644 index 148892e90..000000000 --- a/src/backend/base/langflow/interface/tools/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from langflow.interface.tools.base import ToolCreator - -__all__ = ["ToolCreator"] diff --git a/src/backend/base/langflow/interface/tools/base.py b/src/backend/base/langflow/interface/tools/base.py deleted file mode 100644 index f64192a3b..000000000 --- a/src/backend/base/langflow/interface/tools/base.py +++ /dev/null @@ -1,170 +0,0 @@ -from typing import Dict, List, Optional - -from langchain.agents.load_tools import _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.tools.constants import ALL_TOOLS_NAMES, CUSTOM_TOOLS, FILE_TOOLS, OTHER_TOOLS -from langflow.interface.tools.util import get_tool_params -from langflow.legacy_custom import customs -from langflow.services.deps import get_settings_service -from langflow.template.field.base import TemplateField -from langflow.template.template.base import Template -from langflow.utils import util -from langflow.utils.logger import logger -from langflow.interface.utils import build_template_from_class - -TOOL_INPUTS = { - "str": TemplateField( - field_type="str", - required=True, - is_list=False, - show=True, - placeholder="", - value="", - ), - "llm": TemplateField(field_type="BaseLanguageModel", required=True, is_list=False, show=True), - "func": TemplateField( - field_type="Callable", - required=True, - is_list=False, - show=True, - multiline=True, - ), - "code": TemplateField( - field_type="str", - required=True, - is_list=False, - show=True, - value="", - multiline=True, - ), - "path": TemplateField( - field_type="file", - required=True, - is_list=False, - show=True, - value="", - file_types=[".json", ".yaml", ".yml"], - ), -} - - -class ToolCreator(LangChainTypeCreator): - type_name: str = "tools" - tools_dict: Optional[Dict] = None - - @property - def type_to_loader_dict(self) -> Dict: - settings_service = get_settings_service() - if self.tools_dict is None: - all_tools = {} - - for tool, tool_fcn in ALL_TOOLS_NAMES.items(): - try: - tool_params = get_tool_params(tool_fcn) - except Exception: - logger.error(f"Error getting params for tool {tool}") - continue - - tool_name = tool_params.get("name") or tool - - if tool_name in settings_service.settings.TOOLS or settings_service.settings.DEV: - if tool_name == "JsonSpec": - tool_params["path"] = tool_params.pop("dict_") # type: ignore - all_tools[tool_name] = { - "type": tool, - "params": tool_params, - "fcn": tool_fcn, - } - - self.tools_dict = all_tools - - return self.tools_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of a tool.""" - - base_classes = ["Tool", "BaseTool"] - fields = [] - params = [] - tool_params = {} - - # Raise error if name is not in tools - if name not in self.type_to_loader_dict.keys(): - raise ValueError("Tool not found") - - tool_type: str = self.type_to_loader_dict[name]["type"] # type: ignore - - # if tool_type in _BASE_TOOLS.keys(): - # params = [] - if tool_type in _LLM_TOOLS.keys(): - params = ["llm"] - elif tool_type in _EXTRA_LLM_TOOLS.keys(): - extra_keys = _EXTRA_LLM_TOOLS[tool_type][1] - params = ["llm"] + extra_keys - elif tool_type in _EXTRA_OPTIONAL_TOOLS.keys(): - extra_keys = _EXTRA_OPTIONAL_TOOLS[tool_type][1] - params = extra_keys - # elif tool_type == "Tool": - # params = ["name", "description", "func"] - elif tool_type in CUSTOM_TOOLS: - # Get custom tool params - params = self.type_to_loader_dict[name]["params"] # type: ignore - base_classes = ["Callable"] - if node := customs.get_custom_nodes("tools").get(tool_type): - return node - elif tool_type in FILE_TOOLS: - params = self.type_to_loader_dict[name]["params"] # type: ignore - base_classes += [name] - elif tool_type in OTHER_TOOLS: - tool_dict = build_template_from_class(tool_type, OTHER_TOOLS) - fields = tool_dict["template"] - - # _type is the only key in fields - # return None - if len(fields) == 1 and "_type" in fields: - return None - - # Pop unnecessary fields and add name - fields.pop("_type") # type: ignore - fields.pop("return_direct", None) # type: ignore - fields.pop("verbose", None) # type: ignore - - tool_params = { - "name": fields.pop("name")["value"], # type: ignore - "description": fields.pop("description")["value"], # type: ignore - } - - fields = [ - TemplateField(name=name, field_type=field["type"], **field) - for name, field in fields.items() # type: ignore - ] - base_classes += tool_dict["base_classes"] - - # Copy the field and add the name - for param in params: - field = TOOL_INPUTS.get(param, TOOL_INPUTS["str"]).copy() - field.name = param - field.advanced = False - if param == "aiosession": - field.show = False - field.required = False - - fields.append(field) - - template = Template(fields=fields, type_name=tool_type) - - tool_params = {**tool_params, **self.type_to_loader_dict[name]["params"]} - return { - "template": util.format_dict(template.to_dict()), - **tool_params, - "base_classes": base_classes, - } - - def to_list(self) -> List[str]: - """List all load tools""" - - return list(self.type_to_loader_dict.keys()) - - -tool_creator = ToolCreator() diff --git a/src/backend/base/langflow/interface/tools/constants.py b/src/backend/base/langflow/interface/tools/constants.py deleted file mode 100644 index 39e3b7465..000000000 --- a/src/backend/base/langflow/interface/tools/constants.py +++ /dev/null @@ -1,25 +0,0 @@ -from langchain import tools -from langchain.agents.load_tools import _BASE_TOOLS, _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS -from langchain_community.tools.json.tool import JsonSpec - -from langflow.interface.importing.utils import import_class -from langflow.interface.tools.custom import PythonFunctionTool -from langchain_core.tools import Tool - -FILE_TOOLS = {"JsonSpec": JsonSpec} -CUSTOM_TOOLS = { - "Tool": Tool, - "PythonFunctionTool": PythonFunctionTool, -} - -OTHER_TOOLS = {tool: import_class(f"langchain_community.tools.{tool}") for tool in tools.__all__} - -ALL_TOOLS_NAMES = { - **_BASE_TOOLS, - **_LLM_TOOLS, # type: ignore - **{k: v[0] for k, v in _EXTRA_LLM_TOOLS.items()}, # type: ignore - **{k: v[0] for k, v in _EXTRA_OPTIONAL_TOOLS.items()}, - **CUSTOM_TOOLS, - **FILE_TOOLS, # type: ignore - **OTHER_TOOLS, -} diff --git a/src/backend/base/langflow/interface/tools/custom.py b/src/backend/base/langflow/interface/tools/custom.py deleted file mode 100644 index 8afaa10da..000000000 --- a/src/backend/base/langflow/interface/tools/custom.py +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Callable, Optional -from pydantic.v1 import BaseModel, validator - -from langflow.interface.custom.utils import get_function -from langflow.utils import validate -from langchain_core.tools import Tool - - -class Function(BaseModel): - code: str - function: Optional[Callable] = None - imports: Optional[str] = None - - # Eval code and store the function - def __init__(self, **data): - super().__init__(**data) - - # Validate the function - @validator("code") - def validate_func(cls, v): - try: - validate.eval_function(v) - except Exception as e: - raise e - - return v - - def get_function(self): - """Get the function""" - function_name = validate.extract_function_name(self.code) - - return validate.create_function(self.code, function_name) - - -class PythonFunctionTool(Function, Tool): - name: str = "Custom Tool" - description: str - code: str - - def ___init__(self, name: str, description: str, code: str): - self.name = name - self.description = description - self.code = code - self.func = get_function(self.code) - super().__init__(name=name, description=description, func=self.func) - - -class PythonFunction(Function): - code: str diff --git a/src/backend/base/langflow/interface/tools/util.py b/src/backend/base/langflow/interface/tools/util.py deleted file mode 100644 index f572efe5e..000000000 --- a/src/backend/base/langflow/interface/tools/util.py +++ /dev/null @@ -1,99 +0,0 @@ -import ast -import inspect -import textwrap -from typing import Dict, Union -from langchain_core.tools import Tool - - -def get_func_tool_params(func, **kwargs) -> Union[Dict, None]: - tree = ast.parse(textwrap.dedent(inspect.getsource(func))) - - # Iterate over the statements in the abstract syntax tree - for node in ast.walk(tree): - # Find the first return statement - if isinstance(node, ast.Return): - tool = node.value - if isinstance(tool, ast.Call): - if isinstance(tool.func, ast.Name) and tool.func.id == "Tool": - if tool.keywords: - tool_params = {} - for keyword in tool.keywords: - if keyword.arg == "name": - try: - tool_params["name"] = ast.literal_eval(keyword.value) - except ValueError: - break - elif keyword.arg == "description": - try: - tool_params["description"] = ast.literal_eval(keyword.value) - except ValueError: - continue - - return tool_params - return { - "name": ast.literal_eval(tool.args[0]), - "description": ast.literal_eval(tool.args[2]), - } - # - else: - # get the class object from the return statement - try: - class_obj = eval(compile(ast.Expression(tool), "", "eval")) - except Exception: - return None - - return { - "name": getattr(class_obj, "name"), - "description": getattr(class_obj, "description"), - } - # Return None if no return statement was found - return None - - -def get_class_tool_params(cls, **kwargs) -> Union[Dict, None]: - tree = ast.parse(textwrap.dedent(inspect.getsource(cls))) - - tool_params = {} - - # Iterate over the statements in the abstract syntax tree - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef): - # Find the class definition and look for methods - for stmt in node.body: - if isinstance(stmt, ast.FunctionDef) and stmt.name == "__init__": - # There is no assignment statements in the __init__ method - # So we need to get the params from the function definition - for arg in stmt.args.args: - if arg.arg == "name": - # It should be the name of the class - tool_params[arg.arg] = cls.__name__ - elif arg.arg == "self": - continue - # If there is not default value, set it to an empty string - else: - try: - annotation = ast.literal_eval(arg.annotation) # type: ignore - tool_params[arg.arg] = annotation - except ValueError: - tool_params[arg.arg] = "" - # Get the attribute name and the annotation - elif cls != Tool and isinstance(stmt, ast.AnnAssign): - # Get the attribute name and the annotation - tool_params[stmt.target.id] = "" # type: ignore - - return tool_params - - -def get_tool_params(tool, **kwargs) -> Dict: - # Parse the function code into an abstract syntax tree - # Define if it is a function or a class - if inspect.isfunction(tool): - return get_func_tool_params(tool, **kwargs) or {} - elif inspect.isclass(tool): - # Get the parameters necessary to - # instantiate the class - - return get_class_tool_params(tool, **kwargs) or {} - - else: - raise ValueError("Tool must be a function or class.") diff --git a/src/backend/base/langflow/interface/types.py b/src/backend/base/langflow/interface/types.py index 46fa44a37..a092a7d19 100644 --- a/src/backend/base/langflow/interface/types.py +++ b/src/backend/base/langflow/interface/types.py @@ -1,69 +1,10 @@ -from cachetools import LRUCache, cached - -from langflow.interface.agents.base import agent_creator -from langflow.interface.chains.base import chain_creator -from langflow.interface.custom.directory_reader.utils import merge_nested_dicts_with_renaming -from langflow.interface.custom.utils import build_custom_components -from langflow.interface.document_loaders.base import documentloader_creator -from langflow.interface.embeddings.base import embedding_creator -from langflow.interface.llms.base import llm_creator -from langflow.interface.memories.base import memory_creator -from langflow.interface.retrievers.base import retriever_creator -from langflow.interface.text_splitters.base import textsplitter_creator -from langflow.interface.toolkits.base import toolkits_creator -from langflow.interface.tools.base import tool_creator -from langflow.interface.wrappers.base import wrapper_creator - - -# Used to get the base_classes list -def get_type_list(): - """Get a list of all langchain types""" - all_types = build_langchain_types_dict() - - # all_types.pop("tools") - - for key, value in all_types.items(): - all_types[key] = [item["template"]["_type"] for item in value.values()] - - return all_types - - -@cached(LRUCache(maxsize=1)) -def build_langchain_types_dict(): # sourcery skip: dict-assign-update-to-union - """Build a dictionary of all langchain types""" - all_types = {} - - creators = [ - chain_creator, - agent_creator, - # prompt_creator, - llm_creator, - memory_creator, - tool_creator, - toolkits_creator, - wrapper_creator, - embedding_creator, - # vectorstore_creator, - documentloader_creator, - textsplitter_creator, - # utility_creator, - retriever_creator, - ] - - all_types = {} - for creator in creators: - created_types = creator.to_dict() - if created_types[creator.type_name].values(): - all_types.update(created_types) - - return all_types +from langflow.custom.utils import build_custom_components def get_all_types_dict(components_paths): """Get all types dictionary combining native and custom components.""" - native_components = build_langchain_types_dict() custom_components_from_file = build_custom_components(components_paths=components_paths) - return merge_nested_dicts_with_renaming(native_components, custom_components_from_file) + return custom_components_from_file def get_all_components(components_paths, as_dict=False): diff --git a/src/backend/base/langflow/interface/utilities/__init__.py b/src/backend/base/langflow/interface/utilities/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/utilities/base.py b/src/backend/base/langflow/interface/utilities/base.py deleted file mode 100644 index 474bf8ca2..000000000 --- a/src/backend/base/langflow/interface/utilities/base.py +++ /dev/null @@ -1,65 +0,0 @@ -from typing import Dict, List, Optional, Type - -from langchain_community import utilities -from loguru import logger -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class -from langflow.interface.utils import build_template_from_class -from langflow.legacy_custom.customs import get_custom_nodes -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.utilities import UtilitiesFrontendNode - - -class UtilityCreator(LangChainTypeCreator): - type_name: str = "utilities" - - @property - def frontend_node_class(self) -> Type[UtilitiesFrontendNode]: - return UtilitiesFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - """ - Returns a dictionary mapping utility names to their corresponding loader classes. - If the dictionary has not been created yet, it is created by importing all utility classes - from the langchain.chains module and filtering them according to the settings.utilities list. - """ - if self.type_dict is None: - settings_service = get_settings_service() - self.type_dict = {} - for utility_name in utilities.__all__: - try: - imported = import_class(f"langchain_community.utilities.{utility_name}") - self.type_dict[utility_name] = imported - except Exception: - pass - - self.type_dict["SQLDatabase"] = utilities.SQLDatabase - # Filter according to settings.utilities - self.type_dict = { - name: utility - for name, utility in self.type_dict.items() - if name in settings_service.settings.UTILITIES or settings_service.settings.DEV - } - - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of a utility.""" - try: - custom_nodes = get_custom_nodes(self.type_name) - if name in custom_nodes.keys(): - return custom_nodes[name] - return build_template_from_class(name, self.type_to_loader_dict) - except ValueError as exc: - raise ValueError(f"Utility {name} not found") from exc - - except AttributeError as exc: - logger.error(f"Utility {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - return list(self.type_to_loader_dict.keys()) - - -utility_creator = UtilityCreator() diff --git a/src/backend/base/langflow/interface/vector_store/__init__.py b/src/backend/base/langflow/interface/vector_store/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/vector_store/base.py b/src/backend/base/langflow/interface/vector_store/base.py deleted file mode 100644 index 893c78fca..000000000 --- a/src/backend/base/langflow/interface/vector_store/base.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Any, Dict, List, Optional, Type - -from langchain import vectorstores -from loguru import logger - -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.importing.utils import import_class -from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.vectorstores import VectorStoreFrontendNode -from langflow.utils.util import build_template_from_method - - -class VectorstoreCreator(LangChainTypeCreator): - type_name: str = "vectorstores" - - @property - def frontend_node_class(self) -> Type[VectorStoreFrontendNode]: - return VectorStoreFrontendNode - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict: dict[str, Any] = { - vectorstore_name: import_class(f"langchain_community.vectorstores.{vectorstore_name}") - for vectorstore_name in vectorstores.__all__ - } - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - """Get the signature of an embedding.""" - try: - return build_template_from_method( - name, - type_to_cls_dict=self.type_to_loader_dict, - method_name="from_texts", - ) - except ValueError as exc: - raise ValueError(f"Vector Store {name} not found") from exc - except AttributeError as exc: - logger.error(f"Vector Store {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - settings_service = get_settings_service() - return [ - vectorstore - for vectorstore in self.type_to_loader_dict.keys() - if vectorstore in settings_service.settings.VECTORSTORES or settings_service.settings.DEV - ] - - -vectorstore_creator = VectorstoreCreator() diff --git a/src/backend/base/langflow/interface/wrappers/__init__.py b/src/backend/base/langflow/interface/wrappers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/backend/base/langflow/interface/wrappers/base.py b/src/backend/base/langflow/interface/wrappers/base.py deleted file mode 100644 index b850d345f..000000000 --- a/src/backend/base/langflow/interface/wrappers/base.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Dict, List, Optional - -from langchain_community.utilities import requests -from langflow.interface.base import LangChainTypeCreator -from langflow.interface.utils import build_template_from_class -from loguru import logger - - -class WrapperCreator(LangChainTypeCreator): - type_name: str = "wrappers" - - @property - def type_to_loader_dict(self) -> Dict: - if self.type_dict is None: - self.type_dict = {wrapper.__name__: wrapper for wrapper in [requests.TextRequestsWrapper]} - return self.type_dict - - def get_signature(self, name: str) -> Optional[Dict]: - try: - return build_template_from_class(name, self.type_to_loader_dict) - except ValueError as exc: - raise ValueError("Wrapper not found") from exc - except AttributeError as exc: - logger.error(f"Wrapper {name} not loaded: {exc}") - return None - - def to_list(self) -> List[str]: - return list(self.type_to_loader_dict.keys()) - - -wrapper_creator = WrapperCreator() diff --git a/src/backend/base/langflow/legacy_custom/customs.py b/src/backend/base/langflow/legacy_custom/customs.py index ff69064ff..26e5e33fa 100644 --- a/src/backend/base/langflow/legacy_custom/customs.py +++ b/src/backend/base/langflow/legacy_custom/customs.py @@ -2,33 +2,6 @@ from langflow.template import frontend_node # These should always be instantiated CUSTOM_NODES: dict[str, dict[str, frontend_node.base.FrontendNode]] = { - # "prompts": { - # "ZeroShotPrompt": frontend_node.prompts.ZeroShotPromptNode(), - # }, - "tools": { - "PythonFunctionTool": frontend_node.tools.PythonFunctionToolNode(), - "Tool": frontend_node.tools.ToolNode(), - }, - "agents": { - "JsonAgent": frontend_node.agents.JsonAgentNode(), - "CSVAgent": frontend_node.agents.CSVAgentNode(), - "VectorStoreAgent": frontend_node.agents.VectorStoreAgentNode(), - "VectorStoreRouterAgent": frontend_node.agents.VectorStoreRouterAgentNode(), - "SQLAgent": frontend_node.agents.SQLAgentNode(), - }, - "utilities": { - "SQLDatabase": frontend_node.agents.SQLDatabaseNode(), - }, - "memories": { - "PostgresChatMessageHistory": frontend_node.memories.PostgresChatMessageHistoryFrontendNode(), - "MongoDBChatMessageHistory": frontend_node.memories.MongoDBChatMessageHistoryFrontendNode(), - }, - "chains": { - "SeriesCharacterChain": frontend_node.chains.SeriesCharacterChainNode(), - "TimeTravelGuideChain": frontend_node.chains.TimeTravelGuideChainNode(), - "MidJourneyPromptChain": frontend_node.chains.MidJourneyPromptChainNode(), - "load_qa_chain": frontend_node.chains.CombineDocsChainNode(), - }, "custom_components": { "CustomComponent": frontend_node.custom_components.CustomComponentFrontendNode(), }, diff --git a/src/backend/base/langflow/load.py b/src/backend/base/langflow/load.py deleted file mode 100644 index 1262ac4b9..000000000 --- a/src/backend/base/langflow/load.py +++ /dev/null @@ -1 +0,0 @@ -from langflow.processing.load import load_flow_from_json, run_flow_from_json # noqa: F401 diff --git a/src/backend/base/langflow/load/__init__.py b/src/backend/base/langflow/load/__init__.py new file mode 100644 index 000000000..2002e8bb1 --- /dev/null +++ b/src/backend/base/langflow/load/__init__.py @@ -0,0 +1,3 @@ +from .load import load_flow_from_json, run_flow_from_json # noqa: F401 + +__all__ = ["load_flow_from_json", "run_flow_from_json"] diff --git a/src/backend/base/langflow/processing/load.py b/src/backend/base/langflow/load/load.py similarity index 100% rename from src/backend/base/langflow/processing/load.py rename to src/backend/base/langflow/load/load.py diff --git a/src/backend/base/langflow/processing/base.py b/src/backend/base/langflow/processing/base.py index 35e46a3b2..26da99842 100644 --- a/src/backend/base/langflow/processing/base.py +++ b/src/backend/base/langflow/processing/base.py @@ -1,11 +1,9 @@ from typing import TYPE_CHECKING, List, Union -from langchain.agents.agent import AgentExecutor +from langchain_core.callbacks import BaseCallbackHandler from loguru import logger -from langflow.processing.process import fix_memory_inputs, format_actions from langflow.services.deps import get_plugins_service -from langchain_core.callbacks import BaseCallbackHandler if TYPE_CHECKING: from langfuse.callback import CallbackHandler # type: ignore @@ -44,48 +42,3 @@ def flush_langfuse_callback_if_present(callbacks: List[Union[BaseCallbackHandler if hasattr(callback, "langfuse") and hasattr(callback.langfuse, "flush"): callback.langfuse.flush() break - - -async def get_result_and_steps(langchain_object, inputs: Union[dict, str], **kwargs): - """Get result and thought from extracted json""" - - try: - if hasattr(langchain_object, "verbose"): - langchain_object.verbose = True - - if hasattr(langchain_object, "return_intermediate_steps"): - # https://github.com/hwchase17/langchain/issues/2068 - # Deactivating until we have a frontend solution - # to display intermediate steps - langchain_object.return_intermediate_steps = True - try: - if not isinstance(langchain_object, AgentExecutor): - fix_memory_inputs(langchain_object) - except Exception as exc: - logger.error(f"Error fixing memory inputs: {exc}") - - trace_id = kwargs.pop("session_id", None) - try: - callbacks = setup_callbacks(sync=False, trace_id=trace_id, **kwargs) - output = await langchain_object.acall(inputs, callbacks=callbacks) - except Exception as exc: - # make the error message more informative - logger.debug(f"Error: {str(exc)}") - callbacks = setup_callbacks(sync=True, trace_id=trace_id, **kwargs) - output = langchain_object(inputs, callbacks=callbacks) - - # if langfuse callback is present, run callback.langfuse.flush() - flush_langfuse_callback_if_present(callbacks) - - intermediate_steps = output.get("intermediate_steps", []) if isinstance(output, dict) else [] - - result = output.get(langchain_object.output_keys[0]) if isinstance(output, dict) else output - try: - thought = format_actions(intermediate_steps) if intermediate_steps else "" - except Exception as exc: - logger.exception(exc) - thought = "" - except Exception as exc: - logger.exception(exc) - raise ValueError(f"Error: {str(exc)}") from exc - return result, thought, output diff --git a/src/backend/base/langflow/processing/process.py b/src/backend/base/langflow/processing/process.py index 326e8ca3d..d53b5e25f 100644 --- a/src/backend/base/langflow/processing/process.py +++ b/src/backend/base/langflow/processing/process.py @@ -1,127 +1,19 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union - -from langchain.agents import AgentExecutor from loguru import logger from pydantic import BaseModel from langflow.graph.graph.base import Graph from langflow.graph.schema import RunOutputs from langflow.graph.vertex.base import Vertex -from langflow.interface.run import get_memory_key, update_memory_keys from langflow.schema.graph import InputValue, Tweaks from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.session.service import SessionService -from langchain_core.agents import AgentAction - if TYPE_CHECKING: from langflow.api.v1.schemas import InputValueRequest -def fix_memory_inputs(langchain_object): - """ - Given a LangChain object, this function checks if it has a memory attribute and if that memory key exists in the - object's input variables. If so, it does nothing. Otherwise, it gets a possible new memory key using the - get_memory_key function and updates the memory keys using the update_memory_keys function. - """ - if not hasattr(langchain_object, "memory") or langchain_object.memory is None: - return - try: - if ( - hasattr(langchain_object.memory, "memory_key") - and langchain_object.memory.memory_key in langchain_object.input_variables - ): - return - except AttributeError: - input_variables = ( - langchain_object.prompt.input_variables - if hasattr(langchain_object, "prompt") - else langchain_object.input_keys - ) - if langchain_object.memory.memory_key in input_variables: - return - - possible_new_mem_key = get_memory_key(langchain_object) - if possible_new_mem_key is not None: - update_memory_keys(langchain_object, possible_new_mem_key) - - -def format_actions(actions: List[Tuple[AgentAction, str]]) -> str: - """Format a list of (AgentAction, answer) tuples into a string.""" - output = [] - for action, answer in actions: - log = action.log - tool = action.tool - tool_input = action.tool_input - output.append(f"Log: {log}") - if "Action" not in log and "Action Input" not in log: - output.append(f"Tool: {tool}") - output.append(f"Tool Input: {tool_input}") - output.append(f"Answer: {answer}") - output.append("") # Add a blank line - return "\n".join(output) - - -def get_result_and_thought(langchain_object: Any, inputs: dict): - """Get result and thought from extracted json""" - try: - if hasattr(langchain_object, "verbose"): - langchain_object.verbose = True - - if hasattr(langchain_object, "return_intermediate_steps"): - langchain_object.return_intermediate_steps = False - - try: - if not isinstance(langchain_object, AgentExecutor): - fix_memory_inputs(langchain_object) - except Exception as exc: - logger.error(f"Error fixing memory inputs: {exc}") - - try: - output = langchain_object(inputs, return_only_outputs=True) - except ValueError as exc: - # make the error message more informative - logger.debug(f"Error: {str(exc)}") - output = langchain_object.run(inputs) - - except Exception as exc: - raise ValueError(f"Error: {str(exc)}") from exc - return output - - -def get_input_str_if_only_one_input(inputs: dict) -> Optional[str]: - """Get input string if only one input is provided""" - return list(inputs.values())[0] if len(inputs) == 1 else None - - -def process_inputs( - inputs: Optional[Union[dict, List[dict]]] = None, - artifacts: Optional[Dict[str, Any]] = None, -) -> Union[dict, List[dict]]: - if inputs is None: - inputs = {} - if artifacts is None: - artifacts = {} - - if isinstance(inputs, dict): - inputs = update_inputs_dict(inputs, artifacts) - elif isinstance(inputs, List): - inputs = [update_inputs_dict(inp, artifacts) for inp in inputs] - - return inputs - - -def update_inputs_dict(inputs: dict, artifacts: Dict[str, Any]) -> dict: - for key, value in artifacts.items(): - if key == "repr": - continue - elif key not in inputs or not inputs[key]: - inputs[key] = value - - return inputs - - class Result(BaseModel): result: Any session_id: str diff --git a/src/backend/base/langflow/services/chat/utils.py b/src/backend/base/langflow/services/chat/utils.py deleted file mode 100644 index 271c0e85b..000000000 --- a/src/backend/base/langflow/services/chat/utils.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Any - -from langchain.agents import AgentExecutor -from langchain.chains.base import Chain -from langchain_core.runnables import Runnable -from loguru import logger - -from langflow.api.v1.schemas import ChatMessage -from langflow.interface.utils import try_setting_streaming_options -from langflow.processing.base import get_result_and_steps - -LANGCHAIN_RUNNABLES = (Chain, Runnable, AgentExecutor) - - -async def process_graph( - build_result, - chat_inputs: ChatMessage, - client_id: str, - session_id: str, -): - build_result = try_setting_streaming_options(build_result) - logger.debug("Loaded langchain object") - - if build_result is None: - # Raise user facing error - raise ValueError("There was an error loading the langchain_object. Please, check all the nodes and try again.") - - # Generate result and thought - try: - if chat_inputs.message is None: - logger.debug("No message provided") - chat_inputs.message = {} - - logger.debug("Generating result and thought") - if isinstance(build_result, LANGCHAIN_RUNNABLES): - result, intermediate_steps, raw_output = await get_result_and_steps( - build_result, - chat_inputs.message, - client_id=client_id, - session_id=session_id, - ) - else: - raise TypeError(f"Unknown type {type(build_result)}") - logger.debug("Generated result and intermediate_steps") - return result, intermediate_steps, raw_output - except Exception as e: - # Log stack trace - logger.exception(e) - raise e - - -async def run_build_result(build_result: Any, chat_inputs: ChatMessage, client_id: str, session_id: str): - return build_result(inputs=chat_inputs.message) diff --git a/src/backend/base/langflow/settings.py b/src/backend/base/langflow/settings.py deleted file mode 100644 index 3f340df95..000000000 --- a/src/backend/base/langflow/settings.py +++ /dev/null @@ -1,166 +0,0 @@ -import contextlib -import json -import os -from pathlib import Path -from typing import List, Optional - -import yaml -from pydantic import model_validator, validator -from pydantic_settings import BaseSettings - -from langflow.utils.logger import logger - -BASE_COMPONENTS_PATH = str(Path(__file__).parent / "components") - - -class Settings(BaseSettings): - CHAINS: dict = {} - AGENTS: dict = {} - PROMPTS: dict = {} - LLMS: dict = {} - TOOLS: dict = {} - MEMORIES: dict = {} - EMBEDDINGS: dict = {} - VECTORSTORES: dict = {} - DOCUMENTLOADERS: dict = {} - WRAPPERS: dict = {} - RETRIEVERS: dict = {} - TOOLKITS: dict = {} - TEXTSPLITTERS: dict = {} - UTILITIES: dict = {} - CUSTOM_COMPONENTS: dict = {} - - DEV: bool = False - DATABASE_URL: Optional[str] = None - CACHE: str = "InMemoryCache" - REMOVE_API_KEYS: bool = False - COMPONENTS_PATH: List[str] = [] - - @validator("DATABASE_URL", pre=True) - def set_database_url(cls, value): - if not value: - logger.debug("No database_url provided, trying LANGFLOW_DATABASE_URL env variable") - if langflow_database_url := os.getenv("LANGFLOW_DATABASE_URL"): - value = langflow_database_url - logger.debug("Using LANGFLOW_DATABASE_URL env variable.") - else: - logger.debug("No DATABASE_URL env variable, using sqlite database") - value = "sqlite:///./langflow.db" - return value - - @validator("COMPONENTS_PATH", pre=True) - def set_components_path(cls, value): - if os.getenv("LANGFLOW_COMPONENTS_PATH"): - logger.debug("Adding LANGFLOW_COMPONENTS_PATH to components_path") - langflow_component_path = os.getenv("LANGFLOW_COMPONENTS_PATH") - if Path(langflow_component_path).exists() and langflow_component_path not in value: - if isinstance(langflow_component_path, list): - for path in langflow_component_path: - if path not in value: - value.append(path) - logger.debug(f"Extending {langflow_component_path} to components_path") - elif langflow_component_path not in value: - value.append(langflow_component_path) - logger.debug(f"Appending {langflow_component_path} to components_path") - - if not value: - value = [BASE_COMPONENTS_PATH] - logger.debug("Setting default components path to components_path") - elif BASE_COMPONENTS_PATH not in value: - value.append(BASE_COMPONENTS_PATH) - logger.debug("Adding default components path to components_path") - - logger.debug(f"Components path: {value}") - return value - - class Config: - validate_assignment = True - extra = "ignore" - env_prefix = "LANGFLOW_" - - @model_validator(mode="after") - def validate_lists(cls, values): - for key, value in values.items(): - if key != "dev" and not value: - values[key] = [] - return values - - def update_from_yaml(self, file_path: str, dev: bool = False): - new_settings = load_settings_from_yaml(file_path) - self.CHAINS = new_settings.CHAINS or {} - self.AGENTS = new_settings.AGENTS or {} - self.PROMPTS = new_settings.PROMPTS or {} - self.LLMS = new_settings.LLMS or {} - self.TOOLS = new_settings.TOOLS or {} - self.MEMORIES = new_settings.MEMORIES or {} - self.WRAPPERS = new_settings.WRAPPERS or {} - self.TOOLKITS = new_settings.TOOLKITS or {} - self.TEXTSPLITTERS = new_settings.TEXTSPLITTERS or {} - self.UTILITIES = new_settings.UTILITIES or {} - self.EMBEDDINGS = new_settings.EMBEDDINGS or {} - self.VECTORSTORES = new_settings.VECTORSTORES or {} - self.DOCUMENTLOADERS = new_settings.DOCUMENTLOADERS or {} - self.RETRIEVERS = new_settings.RETRIEVERS or {} - self.CUSTOM_COMPONENTS = new_settings.CUSTOM_COMPONENTS or {} - self.COMPONENTS_PATH = new_settings.COMPONENTS_PATH or [] - self.DEV = dev - - def update_settings(self, **kwargs): - logger.debug("Updating settings") - for key, value in kwargs.items(): - # value may contain sensitive information, so we don't want to log it - if not hasattr(self, key): - logger.debug(f"Key {key} not found in settings") - continue - logger.debug(f"Updating {key}") - if isinstance(getattr(self, key), list): - # value might be a '[something]' string - with contextlib.suppress(json.decoder.JSONDecodeError): - value = json.loads(str(value)) - if isinstance(value, list): - for item in value: - if isinstance(item, Path): - item = str(item) - if item not in getattr(self, key): - getattr(self, key).append(item) - logger.debug(f"Extended {key}") - else: - if isinstance(value, Path): - value = str(value) - if value not in getattr(self, key): - getattr(self, key).append(value) - logger.debug(f"Appended {key}") - - else: - setattr(self, key, value) - logger.debug(f"Updated {key}") - logger.debug(f"{key}: {getattr(self, key)}") - - -def save_settings_to_yaml(settings: Settings, file_path: str): - with open(file_path, "w") as f: - settings_dict = settings.model_dump() - yaml.dump(settings_dict, f) - - -def load_settings_from_yaml(file_path: str) -> Settings: - # Check if a string is a valid path or a file name - if "/" not in file_path: - # Get current path - current_path = os.path.dirname(os.path.abspath(__file__)) - - file_path = os.path.join(current_path, file_path) - - with open(file_path, "r") as f: - settings_dict = yaml.safe_load(f) - settings_dict = {k.upper(): v for k, v in settings_dict.items()} - - for key in settings_dict: - if key not in Settings.model_fields.keys(): - raise KeyError(f"Key {key} not found in settings") - logger.debug(f"Loading {len(settings_dict[key])} {key} from {file_path}") - - return Settings(**settings_dict) - - -settings = load_settings_from_yaml("config.yaml") diff --git a/src/backend/base/langflow/template/frontend_node/__init__.py b/src/backend/base/langflow/template/frontend_node/__init__.py index ceb2e0cb9..98c6fdb01 100644 --- a/src/backend/base/langflow/template/frontend_node/__init__.py +++ b/src/backend/base/langflow/template/frontend_node/__init__.py @@ -1,29 +1,6 @@ -from langflow.template.frontend_node import ( - agents, - chains, - custom_components, - documentloaders, - embeddings, - llms, - memories, - prompts, - textsplitters, - tools, - vectorstores, - base, -) +from langflow.template.frontend_node import base, custom_components __all__ = [ - "agents", "base", - "chains", - "embeddings", - "memories", - "tools", - "llms", - "prompts", - "vectorstores", - "documentloaders", - "textsplitters", "custom_components", ] diff --git a/src/backend/base/langflow/template/frontend_node/agents.py b/src/backend/base/langflow/template/frontend_node/agents.py deleted file mode 100644 index 0993c1736..000000000 --- a/src/backend/base/langflow/template/frontend_node/agents.py +++ /dev/null @@ -1,172 +0,0 @@ -from typing import Optional - -from langchain.agents import types - - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.template.base import Template - -NON_CHAT_AGENTS = { - agent_type: agent_class - for agent_type, agent_class in types.AGENT_TO_CLASS.items() - if "chat" not in agent_type.value -} - - -class AgentFrontendNode(FrontendNode): - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - if field.name in ["suffix", "prefix"]: - field.show = True - if field.name == "Tools" and name == "ZeroShotAgent": - field.field_type = "BaseTool" - field.is_list = True - - -class SQLAgentNode(FrontendNode): - name: str = "SQLAgent" - template: Template = Template( - type_name="sql_agent", - fields=[ - TemplateField( - field_type="str", # pyright: ignore - required=True, - placeholder="", - is_list=False, # pyright: ignore - show=True, - multiline=False, - value="", - name="database_uri", - ), - TemplateField( - field_type="BaseLanguageModel", # pyright: ignore - required=True, - show=True, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = """Construct an SQL agent from an LLM and tools.""" - base_classes: list[str] = ["AgentExecutor"] - - -class VectorStoreRouterAgentNode(FrontendNode): - name: str = "VectorStoreRouterAgent" - template: Template = Template( - type_name="vectorstorerouter_agent", - fields=[ - TemplateField( - field_type="VectorStoreRouterToolkit", # pyright: ignore - required=True, - show=True, - name="vectorstoreroutertoolkit", - display_name="Vector Store Router Toolkit", - ), - TemplateField( - field_type="BaseLanguageModel", # pyright: ignore - required=True, - show=True, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = """Construct an agent from a Vector Store Router.""" - base_classes: list[str] = ["AgentExecutor"] - - -class VectorStoreAgentNode(FrontendNode): - name: str = "VectorStoreAgent" - template: Template = Template( - type_name="vectorstore_agent", - fields=[ - TemplateField( - field_type="VectorStoreInfo", # pyright: ignore - required=True, - show=True, - name="vectorstoreinfo", - display_name="Vector Store Info", - ), - TemplateField( - field_type="BaseLanguageModel", # pyright: ignore - required=True, - show=True, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = """Construct an agent from a Vector Store.""" - base_classes: list[str] = ["AgentExecutor"] - - -class SQLDatabaseNode(FrontendNode): - name: str = "SQLDatabase" - template: Template = Template( - type_name="sql_database", - fields=[ - TemplateField( - field_type="str", # pyright: ignore - required=True, - is_list=False, # pyright: ignore - show=True, - multiline=False, - value="", - name="uri", - ), - ], - ) - description: str = """SQLAlchemy wrapper around a database.""" - base_classes: list[str] = ["SQLDatabase"] - - -class CSVAgentNode(FrontendNode): - name: str = "CSVAgent" - template: Template = Template( - type_name="csv_agent", - fields=[ - TemplateField( - field_type="file", # pyright: ignore - required=True, - show=True, - name="path", - value="", - file_types=[".csv"], # pyright: ignore - ), - TemplateField( - field_type="BaseLanguageModel", # pyright: ignore - required=True, - show=True, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = """Construct a CSV agent from a CSV and tools.""" - base_classes: list[str] = ["AgentExecutor"] - - -class JsonAgentNode(FrontendNode): - name: str = "JsonAgent" - template: Template = Template( - type_name="json_agent", - fields=[ - TemplateField( - field_type="BaseToolkit", # pyright: ignore - required=True, - show=True, - name="toolkit", - ), - TemplateField( - field_type="BaseLanguageModel", # pyright: ignore - required=True, - show=True, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = """Construct a json agent from an LLM and tools.""" - base_classes: list[str] = ["AgentExecutor"] diff --git a/src/backend/base/langflow/template/frontend_node/chains.py b/src/backend/base/langflow/template/frontend_node/chains.py deleted file mode 100644 index 4ce23a316..000000000 --- a/src/backend/base/langflow/template/frontend_node/chains.py +++ /dev/null @@ -1,265 +0,0 @@ -from typing import Optional - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.constants import QA_CHAIN_TYPES -from langflow.template.template.base import Template - - -class ChainFrontendNode(FrontendNode): - output_type: str = "Chain" - - def add_extra_base_classes(self) -> None: - self.base_classes.append("Text") - - def add_extra_fields(self) -> None: - if self.template.type_name == "ConversationalRetrievalChain": - # add memory - self.template.add_field( - TemplateField( - field_type="BaseChatMemory", - required=True, - show=True, - name="memory", - advanced=False, - ) - ) - # add return_source_documents - self.template.add_field( - TemplateField( - field_type="bool", - required=False, - show=True, - name="return_source_documents", - advanced=False, - value=True, - display_name="Return source documents", - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=True, - is_list=True, - show=True, - multiline=False, - options=QA_CHAIN_TYPES, - value=QA_CHAIN_TYPES[0], - name="chain_type", - advanced=False, - ) - ) - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - - if "name" == "RetrievalQA" and field.name == "memory": - field.show = False - field.required = False - - field.advanced = False - if "key" in str(field.name): - field.password = False - field.show = False - if field.name in ["input_key", "output_key"]: - field.required = True - field.show = True - field.advanced = True - - # We should think of a way to deal with this later - # if field.field_type == "PromptTemplate": - # field.field_type = "str" - # field.multiline = True - # field.show = True - # field.advanced = False - # field.value = field.value.template - - # Separated for possible future changes - if field.name == "prompt" and field.value is None: - field.required = True - field.show = True - field.advanced = False - if field.name == "memory": - # field.required = False - field.show = True - field.advanced = False - if field.name == "verbose": - field.required = False - field.show = False - field.advanced = True - if field.name == "llm": - field.required = True - field.show = True - field.advanced = False - field.field_type = "BaseLanguageModel" - field.is_list = False - - if field.name == "return_source_documents": - field.required = False - field.show = True - field.advanced = True - field.value = True - - -class SeriesCharacterChainNode(FrontendNode): - output_type: str = "Chain" - name: str = "SeriesCharacterChain" - template: Template = Template( - type_name="SeriesCharacterChain", - fields=[ - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - advanced=False, - multiline=False, - name="character", - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - advanced=False, - multiline=False, - name="series", - ), - TemplateField( - field_type="BaseLanguageModel", - required=True, - placeholder="", - is_list=False, - show=True, - advanced=False, - multiline=False, - name="llm", - display_name="LLM", - ), - ], - ) - description: str = ( - "SeriesCharacterChain is a chain you can use to have a conversation with a character from a series." # noqa - ) - base_classes: list[str] = [ - "LLMChain", - "BaseCustomChain", - "Chain", - "ConversationChain", - "SeriesCharacterChain", - "function", - ] - - -class TimeTravelGuideChainNode(FrontendNode): - output_type: str = "Chain" - name: str = "TimeTravelGuideChain" - template: Template = Template( - type_name="TimeTravelGuideChain", - fields=[ - TemplateField( - field_type="BaseLanguageModel", - required=True, - placeholder="", - is_list=False, - show=True, - advanced=False, - multiline=False, - name="llm", - display_name="LLM", - ), - TemplateField( - field_type="BaseChatMemory", - required=False, - show=True, - name="memory", - advanced=False, - ), - ], - ) - description: str = "Time travel guide chain." - base_classes: list[str] = [ - "LLMChain", - "BaseCustomChain", - "TimeTravelGuideChain", - "Chain", - "ConversationChain", - ] - - -class MidJourneyPromptChainNode(FrontendNode): - output_type: str = "Chain" - name: str = "MidJourneyPromptChain" - template: Template = Template( - type_name="MidJourneyPromptChain", - fields=[ - TemplateField( - field_type="BaseLanguageModel", - required=True, - placeholder="", - is_list=False, - show=True, - advanced=False, - multiline=False, - name="llm", - display_name="LLM", - ), - TemplateField( - field_type="BaseChatMemory", - required=False, - show=True, - name="memory", - advanced=False, - ), - ], - ) - description: str = "MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts." - base_classes: list[str] = [ - "LLMChain", - "BaseCustomChain", - "Chain", - "ConversationChain", - "MidJourneyPromptChain", - ] - - -class CombineDocsChainNode(FrontendNode): - output_type: str = "Chain" - name: str = "CombineDocsChain" - template: Template = Template( - type_name="load_qa_chain", - fields=[ - TemplateField( - field_type="str", - required=True, - is_list=True, - show=True, - multiline=False, - options=QA_CHAIN_TYPES, - value=QA_CHAIN_TYPES[0], - name="chain_type", - advanced=False, - ), - TemplateField( - field_type="BaseLanguageModel", - required=True, - show=True, - name="llm", - display_name="LLM", - advanced=False, - ), - ], - ) - description: str = """Load question answering chain.""" - base_classes: list[str] = ["BaseCombineDocumentsChain", "function"] - - def to_dict(self): - return super().to_dict() - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - # do nothing and don't return anything - pass diff --git a/src/backend/base/langflow/template/frontend_node/custom_components.py b/src/backend/base/langflow/template/frontend_node/custom_components.py index 577c89684..932d30799 100644 --- a/src/backend/base/langflow/template/frontend_node/custom_components.py +++ b/src/backend/base/langflow/template/frontend_node/custom_components.py @@ -4,7 +4,7 @@ from langflow.template.field.base import TemplateField from langflow.template.frontend_node.base import FrontendNode from langflow.template.template.base import Template -DEFAULT_CUSTOM_COMPONENT_CODE = """from langflow.interface.custom.custom_component import CustomComponent +DEFAULT_CUSTOM_COMPONENT_CODE = """from langflow.custom import CustomComponent from typing import Optional, List, Dict, Union from langflow.field_typing import ( diff --git a/src/backend/base/langflow/template/frontend_node/documentloaders.py b/src/backend/base/langflow/template/frontend_node/documentloaders.py deleted file mode 100644 index 31e13894a..000000000 --- a/src/backend/base/langflow/template/frontend_node/documentloaders.py +++ /dev/null @@ -1,301 +0,0 @@ -from typing import ClassVar, Dict, Optional - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode - - -def build_file_field(fileTypes: list, name: str = "file_path") -> TemplateField: - """Build a template field for a document loader.""" - return TemplateField( - field_type="file", - required=True, - show=True, - name=name, - value="", - file_types=fileTypes, - ) - - -class DocumentLoaderFrontNode(FrontendNode): - def add_extra_base_classes(self) -> None: - self.base_classes = ["Document"] - self.output_types = ["Document"] - - file_path_templates: ClassVar[Dict] = { - "AirbyteJSONLoader": build_file_field( - fileTypes=[".json"], - ), - "CoNLLULoader": build_file_field( - fileTypes=[".csv"], - ), - "CSVLoader": build_file_field( - fileTypes=[".csv"], - ), - "UnstructuredEmailLoader": build_file_field( - fileTypes=[".eml"], - ), - "EverNoteLoader": build_file_field( - fileTypes=[".xml"], - ), - "FacebookChatLoader": build_file_field( - fileTypes=[".json"], - ), - "BSHTMLLoader": build_file_field( - fileTypes=[".html"], - ), - "UnstructuredHTMLLoader": build_file_field(fileTypes=[".html"]), - "UnstructuredImageLoader": build_file_field( - fileTypes=[".jpg", ".jpeg", ".png", ".gif", ".bmp"], - ), - "UnstructuredMarkdownLoader": build_file_field( - fileTypes=[".md"], - ), - "PyPDFLoader": build_file_field( - fileTypes=[".pdf"], - ), - "UnstructuredPowerPointLoader": build_file_field( - fileTypes=[".pptx", ".ppt"], - ), - "SRTLoader": build_file_field( - fileTypes=[".srt"], - ), - "TelegramChatLoader": build_file_field( - fileTypes=[".json"], - ), - "TextLoader": build_file_field( - fileTypes=[".txt"], - ), - "UnstructuredWordDocumentLoader": build_file_field( - fileTypes=[".docx", ".doc"], - ), - } - - def add_extra_fields(self) -> None: - name = None - display_name = "Web Page" - if self.template.type_name in {"GitLoader"}: - # Add fields repo_path, clone_url, branch and file_filter - self.template.add_field( - TemplateField( - field_type="str", - required=True, - show=True, - name="repo_path", - value="", - display_name="Path to repository", - advanced=False, - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=False, - show=True, - name="clone_url", - value="", - display_name="Clone URL", - advanced=False, - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=True, - show=True, - name="branch", - value="", - display_name="Branch", - advanced=False, - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=False, - show=True, - name="file_filter", - value="", - display_name="File extensions (comma-separated)", - advanced=False, - ) - ) - elif self.template.type_name in {"SlackDirectoryLoader"}: - self.template.add_field( - TemplateField( - field_type="file", - required=True, - show=True, - name="zip_path", - value="", - display_name="Path to zip file", - file_types=[".zip"], - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=False, - show=True, - name="workspace_url", - value="", - display_name="Workspace URL", - advanced=False, - ) - ) - elif self.template.type_name in self.file_path_templates: - self.template.add_field(self.file_path_templates[self.template.type_name]) - elif self.template.type_name in { - "WebBaseLoader", - "AZLyricsLoader", - "CollegeConfidentialLoader", - "HNLoader", - "IFixitLoader", - "IMSDbLoader", - "GutenbergLoader", - }: - name = "web_path" - elif self.template.type_name in {"GutenbergLoader"}: - name = "file_path" - elif self.template.type_name in {"GitbookLoader"}: - name = "web_page" - elif self.template.type_name in { - "DirectoryLoader", - "ReadTheDocsLoader", - "NotionDirectoryLoader", - "PyPDFDirectoryLoader", - }: - name = "path" - display_name = "Local directory" - if name: - if self.template.type_name in {"DirectoryLoader"}: - for field in build_directory_loader_fields(): - self.template.add_field(field) - else: - self.template.add_field( - TemplateField( - field_type="str", - required=True, - show=True, - name=name, - value="", - display_name=display_name, - ) - ) - # add a metadata field of type dict - self.template.add_field( - TemplateField( - field_type="dict", - required=False, - show=True, - name="metadata", - value={}, - display_name="Metadata", - multiline=False, - ) - ) - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - if field.name == "metadata": - field.show = True - field.advanced = False - field.show = True - - -def build_directory_loader_fields(): - # if loader_kwargs is None: - # loader_kwargs = {} - # self.path = path - # self.glob = glob - # self.load_hidden = load_hidden - # self.loader_cls = loader_cls - # self.loader_kwargs = loader_kwargs - # self.silent_errors = silent_errors - # self.recursive = recursive - # self.show_progress = show_progress - # self.use_multithreading = use_multithreading - # self.max_concurrency = max_concurrency - # Based on the above fields, we can build the following fields: - # path, glob, load_hidden, silent_errors, recursive, show_progress, use_multithreading, max_concurrency - # path - path = TemplateField( - field_type="str", - required=True, - show=True, - name="path", - value="", - display_name="Local directory", - advanced=False, - ) - # glob - glob = TemplateField( - field_type="str", - required=True, - show=True, - name="glob", - value="**/*.txt", - display_name="glob", - advanced=False, - ) - # load_hidden - load_hidden = TemplateField( - field_type="bool", - required=False, - show=True, - name="load_hidden", - value="False", - display_name="Load hidden files", - advanced=True, - ) - # silent_errors - silent_errors = TemplateField( - field_type="bool", - required=False, - show=True, - name="silent_errors", - value="False", - display_name="Silent errors", - advanced=True, - ) - # recursive - recursive = TemplateField( - field_type="bool", - required=False, - show=True, - name="recursive", - value="True", - display_name="Recursive", - advanced=True, - ) - - # use_multithreading - use_multithreading = TemplateField( - field_type="bool", - required=False, - show=True, - name="use_multithreading", - value="True", - display_name="Use multithreading", - advanced=True, - ) - # max_concurrency - max_concurrency = TemplateField( - field_type="int", - required=False, - show=True, - name="max_concurrency", - value=10, - display_name="Max concurrency", - advanced=True, - ) - - return ( - path, - glob, - load_hidden, - silent_errors, - recursive, - use_multithreading, - max_concurrency, - ) diff --git a/src/backend/base/langflow/template/frontend_node/embeddings.py b/src/backend/base/langflow/template/frontend_node/embeddings.py deleted file mode 100644 index a2974487e..000000000 --- a/src/backend/base/langflow/template/frontend_node/embeddings.py +++ /dev/null @@ -1,119 +0,0 @@ -from typing import Optional - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode - - -class EmbeddingFrontendNode(FrontendNode): - def add_extra_fields(self) -> None: - if "VertexAI" in self.template.type_name: - # Add credentials field which should of type file. - self.template.add_field( - TemplateField( - field_type="file", - required=False, - show=True, - name="credentials", - value="", - file_types=[".json"], - ) - ) - - @staticmethod - def format_vertex_field(field: TemplateField, name: str): - if "VertexAI" in name: - key = field.name or "" - advanced_fields = [ - "verbose", - "top_p", - "top_k", - "max_output_tokens", - ] - if key in advanced_fields: - field.advanced = True - show_fields = [ - "verbose", - "project", - "location", - "credentials", - "max_output_tokens", - "model_name", - "temperature", - "top_p", - "top_k", - ] - - if key in show_fields: - field.show = True - - @staticmethod - def format_jina_fields(field: TemplateField): - name = field.name or "" - if "jina" in name: - field.show = True - field.advanced = False - - if "auth" in name or "token" in name: - field.password = True - field.show = True - field.advanced = False - - if name == "jina_api_url": - field.show = True - field.advanced = True - field.display_name = "Jina API URL" - field.password = False - - @staticmethod - def format_openai_fields(field: TemplateField): - name = field.name or "" - if "openai" in name: - field.show = True - field.advanced = True - split_name = name.split("_") - title_name = " ".join([s.capitalize() for s in split_name]) - field.display_name = title_name.replace("Openai", "OpenAI").replace("Api", "API") - - if "api_key" in name: - field.password = True - field.show = True - field.advanced = False - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - if name and "vertex" in name.lower(): - EmbeddingFrontendNode.format_vertex_field(field, name) - field.advanced = not field.required - field.show = True - key = field.name or "" - if key == "headers": - field.show = False - if key == "model_kwargs": - field.field_type = "dict" - field.advanced = True - field.show = True - elif key in [ - "model_name", - "temperature", - "model_file", - "model_type", - "deployment_name", - "credentials", - ]: - field.advanced = False - field.show = True - if key == "credentials": - field.field_type = "file" - if name == "VertexAI" and key not in [ - "callbacks", - "client", - "stop", - "tags", - "cache", - ]: - field.show = True - - # Format Jina fields - EmbeddingFrontendNode.format_jina_fields(field) - EmbeddingFrontendNode.format_openai_fields(field) diff --git a/src/backend/base/langflow/template/frontend_node/llms.py b/src/backend/base/langflow/template/frontend_node/llms.py deleted file mode 100644 index 7bf5a8cb6..000000000 --- a/src/backend/base/langflow/template/frontend_node/llms.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import Optional - -from langflow.services.database.models.base import orjson_dumps -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.constants import CTRANSFORMERS_DEFAULT_CONFIG, OPENAI_API_BASE_INFO - - -class LLMFrontendNode(FrontendNode): - def add_extra_fields(self) -> None: - if "VertexAI" in self.template.type_name: - # Add credentials field which should of type file. - self.template.add_field( - TemplateField( - field_type="file", - required=False, - show=True, - name="credentials", - value="", - file_types=[".json"], - ) - ) - - @staticmethod - def format_vertex_field(field: TemplateField, name: str): - key = field.name or "" - if "VertexAI" in name: - advanced_fields = [ - "tuned_model_name", - "verbose", - "top_p", - "top_k", - "max_output_tokens", - ] - if key in advanced_fields: - field.advanced = True - show_fields = [ - "tuned_model_name", - "verbose", - "project", - "location", - "credentials", - "max_output_tokens", - "model_name", - "temperature", - "top_p", - "top_k", - ] - - if key in show_fields: - field.show = True - - @staticmethod - def format_openai_field(field: TemplateField): - key = field.name or "" - if "openai" in key.lower(): - field.display_name = (key.title().replace("Openai", "OpenAI").replace("_", " ")).replace("Api", "API") - - if "key" not in key.lower() and "token" not in key.lower(): - field.password = False - - if key == "openai_api_base": - field.info = OPENAI_API_BASE_INFO - - def add_extra_base_classes(self) -> None: - if "BaseLanguageModel" not in self.base_classes: - self.base_classes.append("BaseLanguageModel") - - @staticmethod - def format_azure_field(field: TemplateField): - key = field.name or "" - if key == "model_name": - field.show = False # Azure uses deployment_name instead of model_name. - elif key == "openai_api_type": - field.show = False - field.password = False - field.value = "azure" - elif key == "openai_api_version": - field.password = False - - @staticmethod - def format_llama_field(field: TemplateField): - field.show = True - field.advanced = not field.required - - @staticmethod - def format_ctransformers_field(field: TemplateField): - key = field.name or "" - if key == "config": - field.show = True - field.advanced = True - field.value = orjson_dumps(CTRANSFORMERS_DEFAULT_CONFIG, indent_2=True) - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - display_names_dict = { - "huggingfacehub_api_token": "HuggingFace Hub API Token", - } - FrontendNode.format_field(field, name) - LLMFrontendNode.format_openai_field(field) - LLMFrontendNode.format_ctransformers_field(field) - if name and "azure" in name.lower(): - LLMFrontendNode.format_azure_field(field) - if name and "llama" in name.lower(): - LLMFrontendNode.format_llama_field(field) - if name and "vertex" in name.lower(): - LLMFrontendNode.format_vertex_field(field, name) - SHOW_FIELDS = ["repo_id"] - key = field.name or "" - if key in SHOW_FIELDS: - field.show = True - - if "api" in key and ("key" in key or ("token" in key and "tokens" not in key)): - field.password = True - field.show = True - # Required should be False to support - # loading the API key from environment variables - field.required = False - field.advanced = False - - if key == "task": - field.required = True - field.show = True - field.is_list = True - field.options = ["text-generation", "text2text-generation", "summarization"] - field.value = field.options[0] - field.advanced = True - - if display_name := display_names_dict.get(key): - field.display_name = display_name - if key == "model_kwargs": - field.field_type = "dict" - field.advanced = True - field.show = True - elif key in [ - "model_name", - "temperature", - "model_file", - "model_type", - "deployment_name", - "credentials", - ]: - field.advanced = False - field.show = True - if key == "credentials": - field.field_type = "file" - if name == "VertexAI" and key not in [ - "callbacks", - "client", - "stop", - "tags", - "cache", - ]: - field.show = True diff --git a/src/backend/base/langflow/template/frontend_node/memories.py b/src/backend/base/langflow/template/frontend_node/memories.py deleted file mode 100644 index 1cdc8febb..000000000 --- a/src/backend/base/langflow/template/frontend_node/memories.py +++ /dev/null @@ -1,190 +0,0 @@ -from typing import Optional - -from langchain_community.chat_message_histories.mongodb import DEFAULT_COLLECTION_NAME, DEFAULT_DBNAME -from langchain_community.chat_message_histories.postgres import DEFAULT_CONNECTION_STRING - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.constants import INPUT_KEY_INFO, OUTPUT_KEY_INFO -from langflow.template.template.base import Template - - -class MemoryFrontendNode(FrontendNode): - frozen: bool = True - - def add_extra_fields(self) -> None: - # chat history should have another way to add common field? - # prevent adding incorect field in ChatMessageHistory - base_message_classes = ["BaseEntityStore", "BaseChatMessageHistory"] - if any(base_class in self.base_classes for base_class in base_message_classes): - return - - # add return_messages field - self.template.add_field( - TemplateField( - field_type="bool", - required=False, - show=True, - name="return_messages", - advanced=False, - value=False, - ) - ) - # add input_key and output_key str fields - self.template.add_field( - TemplateField( - field_type="str", - required=False, - show=True, - name="input_key", - advanced=True, - value="", - ) - ) - if self.template.type_name not in {"VectorStoreRetrieverMemory"}: - self.template.add_field( - TemplateField( - field_type="str", - required=False, - show=True, - name="output_key", - advanced=True, - value="", - ) - ) - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - - if not isinstance(field.value, str): - field.value = None - if field.name == "k": - field.required = True - field.show = True - field.field_type = "int" - field.value = 10 - field.display_name = "Memory Size" - field.password = False - if field.name == "return_messages": - field.required = False - field.show = True - field.advanced = False - if field.name in {"input_key", "output_key"}: - field.required = False - field.show = True - field.advanced = False - field.value = "" - field.info = INPUT_KEY_INFO if field.name == "input_key" else OUTPUT_KEY_INFO - - if field.name == "memory_key": - field.value = "chat_history" - if field.name == "chat_memory": - field.show = True - field.advanced = False - field.required = False - if field.name == "url": - field.show = True - if field.name == "entity_store": - field.show = False - if name == "ConversationEntityMemory" and field.name == "memory_key": - field.show = False - field.required = False - - if name == "MotorheadMemory": - if field.name == "chat_memory": - field.show = False - field.required = False - elif field.name == "client_id": - field.show = True - field.advanced = False - - -class PostgresChatMessageHistoryFrontendNode(MemoryFrontendNode): - name: str = "PostgresChatMessageHistory" - template: Template = Template( - type_name="PostgresChatMessageHistory", - fields=[ - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - name="session_id", - ), - TemplateField( - field_type="str", - required=True, - show=True, - name="connection_string", - value=DEFAULT_CONNECTION_STRING, - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value="message_store", - name="table_name", - ), - ], - ) - description: str = "Memory store with Postgres" - base_classes: list[str] = ["PostgresChatMessageHistory", "BaseChatMessageHistory"] - - -class MongoDBChatMessageHistoryFrontendNode(MemoryFrontendNode): - name: str = "MongoDBChatMessageHistory" - template: Template = Template( - # langchain/memory/chat_message_histories/mongodb.py - # connection_string: str, - # session_id: str, - # database_name: str = DEFAULT_DBNAME, - # collection_name: str = DEFAULT_COLLECTION_NAME, - type_name="MongoDBChatMessageHistory", - fields=[ - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - name="session_id", - ), - TemplateField( - field_type="str", - required=True, - show=True, - name="connection_string", - value="", - info="MongoDB connection string (e.g mongodb://mongo_user:password123@mongo:27017)", - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value=DEFAULT_DBNAME, - name="database_name", - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value=DEFAULT_COLLECTION_NAME, - name="collection_name", - ), - ], - ) - description: str = "Memory store with MongoDB" - base_classes: list[str] = ["MongoDBChatMessageHistory", "BaseChatMessageHistory"] diff --git a/src/backend/base/langflow/template/frontend_node/prompts.py b/src/backend/base/langflow/template/frontend_node/prompts.py deleted file mode 100644 index 03445f753..000000000 --- a/src/backend/base/langflow/template/frontend_node/prompts.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import Optional - -from langchain.agents.mrkl import prompt - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.frontend_node.constants import DEFAULT_PROMPT, HUMAN_PROMPT, SYSTEM_PROMPT -from langflow.template.template.base import Template - - -class PromptFrontendNode(FrontendNode): - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - # if field.field_type == "StringPromptTemplate" - # change it to str - PROMPT_FIELDS = [ - "template", - "suffix", - "prefix", - "examples", - "format_instructions", - ] - key = field.name or "" - if field.field_type == "StringPromptTemplate" and "Message" in str(name): - field.field_type = "prompt" - field.multiline = True - field.value = HUMAN_PROMPT if "Human" in key else SYSTEM_PROMPT - if key == "template" and field.value == "": - field.value = DEFAULT_PROMPT - - if key and key in PROMPT_FIELDS: - field.field_type = "prompt" - field.advanced = False - - if "Union" in field.field_type and "BaseMessagePromptTemplate" in field.field_type: - field.field_type = "BaseMessagePromptTemplate" - - # All prompt fields should be password=False - field.password = False - field.dynamic = True - - -class PromptTemplateNode(FrontendNode): - name: str = "PromptTemplate" - template: Template - description: str - base_classes: list[str] = ["BasePromptTemplate"] - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - - if (field.name or "") == "examples": - field.advanced = False - - -class BasePromptFrontendNode(FrontendNode): - name: str - template: Template - description: str - base_classes: list[str] - - -class ZeroShotPromptNode(BasePromptFrontendNode): - name: str = "ZeroShotPrompt" - template: Template = Template( - type_name="ZeroShotPrompt", - fields=[ - TemplateField( - field_type="str", - required=False, - placeholder="", - is_list=False, - show=True, - multiline=True, - value=prompt.PREFIX, - name="prefix", - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=True, - value=prompt.FORMAT_INSTRUCTIONS, - name="format_instructions", - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=True, - value=prompt.SUFFIX, - name="suffix", - ), - ], - ) - description: str = "Prompt template for Zero Shot Agent." - base_classes: list[str] = ["BasePromptTemplate"] - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - PromptFrontendNode.format_field(field, name) diff --git a/src/backend/base/langflow/template/frontend_node/retrievers.py b/src/backend/base/langflow/template/frontend_node/retrievers.py deleted file mode 100644 index b482c8b84..000000000 --- a/src/backend/base/langflow/template/frontend_node/retrievers.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Optional - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode - - -class RetrieverFrontendNode(FrontendNode): - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - # Define common field attributes - field.show = True - if field.name == "parser_key": - field.display_name = "Parser Key" - field.password = False diff --git a/src/backend/base/langflow/template/frontend_node/textsplitters.py b/src/backend/base/langflow/template/frontend_node/textsplitters.py deleted file mode 100644 index 8fc5620d2..000000000 --- a/src/backend/base/langflow/template/frontend_node/textsplitters.py +++ /dev/null @@ -1,73 +0,0 @@ -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langchain_text_splitters import Language - - -class TextSplittersFrontendNode(FrontendNode): - def add_extra_base_classes(self) -> None: - self.base_classes = ["Document"] - self.output_types = ["Document"] - - def add_extra_fields(self) -> None: - self.template.add_field( - TemplateField( - field_type="Document", - required=True, - show=True, - name="documents", - is_list=True, - ) - ) - name = "separator" - if self.template.type_name == "CharacterTextSplitter": - name = "separator" - elif self.template.type_name == "RecursiveCharacterTextSplitter": - name = "separators" - # Add a field for type of separator - # which will have Text or any value from the - # Language enum - options = [x.value for x in Language] + ["Text"] - options.sort() - self.template.add_field( - TemplateField( - field_type="str", - required=True, - show=True, - name="separator_type", - advanced=False, - is_list=True, - options=options, - value="Text", - display_name="Separator Type", - ) - ) - self.template.add_field( - TemplateField( - field_type="str", - required=True, - show=True, - value="\\n", - name=name, - display_name="Separator", - ) - ) - self.template.add_field( - TemplateField( - field_type="int", - required=True, - show=True, - value=1000, - name="chunk_size", - display_name="Chunk Size", - ) - ) - self.template.add_field( - TemplateField( - field_type="int", - required=True, - show=True, - value=200, - name="chunk_overlap", - display_name="Chunk Overlap", - ) - ) diff --git a/src/backend/base/langflow/template/frontend_node/tools.py b/src/backend/base/langflow/template/frontend_node/tools.py deleted file mode 100644 index 5bed90c05..000000000 --- a/src/backend/base/langflow/template/frontend_node/tools.py +++ /dev/null @@ -1,130 +0,0 @@ -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode -from langflow.template.template.base import Template -from langflow.utils.constants import DEFAULT_PYTHON_FUNCTION - - -class ToolNode(FrontendNode): - name: str = "Tool" - template: Template = Template( - type_name="Tool", - fields=[ - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=True, - value="", - name="name", - advanced=False, - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=True, - value="", - name="description", - advanced=False, - ), - TemplateField( - name="func", - field_type="Callable", - required=True, - is_list=False, - show=True, - multiline=True, - advanced=False, - ), - TemplateField( - field_type="bool", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value=False, - name="return_direct", - ), - ], - ) - description: str = "Converts a chain, agent or function into a tool." - base_classes: list[str] = ["Tool", "BaseTool"] - - -class PythonFunctionToolNode(FrontendNode): - name: str = "PythonFunctionTool" - template: Template = Template( - type_name="PythonFunctionTool", - fields=[ - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value="", - name="name", - advanced=False, - ), - TemplateField( - field_type="str", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value="", - name="description", - advanced=False, - ), - TemplateField( - field_type="code", - required=True, - placeholder="", - is_list=False, - show=True, - value=DEFAULT_PYTHON_FUNCTION, - name="code", - advanced=False, - ), - TemplateField( - field_type="bool", - required=True, - placeholder="", - is_list=False, - show=True, - multiline=False, - value=False, - name="return_direct", - ), - ], - ) - description: str = "Python function to be executed." - base_classes: list[str] = ["BaseTool", "Tool"] - - -class PythonFunctionNode(FrontendNode): - name: str = "PythonFunction" - template: Template = Template( - type_name="PythonFunction", - fields=[ - TemplateField( - field_type="code", - required=True, - placeholder="", - is_list=False, - show=True, - value=DEFAULT_PYTHON_FUNCTION, - name="code", - advanced=False, - ) - ], - ) - description: str = "Python function to be executed." - base_classes: list[str] = ["Callable"] diff --git a/src/backend/base/langflow/template/frontend_node/utilities.py b/src/backend/base/langflow/template/frontend_node/utilities.py deleted file mode 100644 index 51849189c..000000000 --- a/src/backend/base/langflow/template/frontend_node/utilities.py +++ /dev/null @@ -1,24 +0,0 @@ -import ast -from typing import Optional - -from langflow.services.database.models.base import orjson_dumps -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode - - -class UtilitiesFrontendNode(FrontendNode): - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - # field.field_type could be "Literal['news', 'search', 'places', 'images'] - # we need to convert it to a list - # It seems it could also be like "typing_extensions.['news', 'search', 'places', 'images']" - if "Literal" in field.field_type: - field_type = field.field_type.replace("typing_extensions.", "") - field_type = field_type.replace("Literal", "") - field.options = ast.literal_eval(field_type) - field.is_list = True - field.field_type = "str" - - if isinstance(field.value, dict): - field.value = orjson_dumps(field.value) diff --git a/src/backend/base/langflow/template/frontend_node/vectorstores.py b/src/backend/base/langflow/template/frontend_node/vectorstores.py deleted file mode 100644 index 1f49f76a9..000000000 --- a/src/backend/base/langflow/template/frontend_node/vectorstores.py +++ /dev/null @@ -1,369 +0,0 @@ -from typing import List, Optional - -from langflow.template.field.base import TemplateField -from langflow.template.frontend_node.base import FrontendNode - -BASIC_FIELDS = [ - "work_dir", - "collection_name", - "api_key", - "location", - "persist_directory", - "persist", - "weaviate_url", - "es_url", - "index_name", - "namespace", - "folder_path", - "table_name", - "query_name", - "supabase_url", - "supabase_service_key", - "mongodb_atlas_cluster_uri", - "collection_name", - "db_name", -] -ADVANCED_FIELDS = [ - "n_dim", - "key", - "prefix", - "distance_func", - "content_payload_key", - "metadata_payload_key", - "timeout", - "host", - "path", - "url", - "port", - "https", - "prefer_grpc", - "grpc_port", - "pinecone_api_key", - "pinecone_env", - "client_kwargs", - "search_kwargs", - "chroma_server_host", - "chroma_server_http_port", - "chroma_server_ssl_enabled", - "chroma_server_grpc_port", - "chroma_server_cors_allow_origins", -] - - -class VectorStoreFrontendNode(FrontendNode): - def add_extra_fields(self) -> None: - extra_fields: List[TemplateField] = [] - # Add search_kwargs field - extra_field = TemplateField( - name="search_kwargs", - field_type="NestedDict", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="{}", - ) - extra_fields.append(extra_field) - if self.template.type_name == "Weaviate": - extra_field = TemplateField( - name="weaviate_url", - field_type="str", - required=True, - placeholder="http://localhost:8080", - show=True, - advanced=False, - multiline=False, - value="http://localhost:8080", - ) - # Add client_kwargs field - extra_field2 = TemplateField( - name="client_kwargs", - field_type="code", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="{}", - ) - extra_fields.extend((extra_field, extra_field2)) - - elif self.template.type_name == "Chroma": - # New bool field for persist parameter - chroma_fields = [ - TemplateField( - name="persist", - field_type="bool", - required=False, - show=True, - advanced=False, - value=False, - display_name="Persist", - ), - # chroma_server_grpc_port: str | None = None, - TemplateField( - name="chroma_server_host", - field_type="str", - required=False, - show=True, - advanced=True, - display_name="Chroma Server Host", - ), - TemplateField( - name="chroma_server_http_port", - field_type="str", - required=False, - show=True, - advanced=True, - display_name="Chroma Server HTTP Port", - ), - TemplateField( - name="chroma_server_ssl_enabled", - field_type="bool", - required=False, - show=True, - advanced=True, - value=False, - display_name="Chroma Server SSL Enabled", - ), - TemplateField( - name="chroma_server_grpc_port", - field_type="str", - required=False, - show=True, - advanced=True, - display_name="Chroma Server GRPC Port", - ), - TemplateField( - name="chroma_server_cors_allow_origins", - field_type="str", - required=False, - is_list=True, - show=True, - advanced=True, - display_name="Chroma Server CORS Allow Origins", - ), - ] - - extra_fields.extend(chroma_fields) - elif self.template.type_name == "Pinecone": - # add pinecone_api_key and pinecone_env - extra_field = TemplateField( - name="pinecone_api_key", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - password=True, - value="", - ) - extra_field2 = TemplateField( - name="pinecone_env", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="", - ) - extra_fields.extend((extra_field, extra_field2)) - - elif self.template.type_name == "ElasticsearchStore": - # add elastic and elastic credentials - extra_field = TemplateField( - name="es_url", - field_type="str", - required=True, - placeholder="http://localhost:9200", - show=True, - advanced=False, - multiline=False, - value="http://localhost:9200", - display_name="Elasticsearch URL", - ) - extra_field2 = TemplateField( - name="index_name", - field_type="str", - required=True, - placeholder="test-index", - show=True, - advanced=False, - multiline=False, - value="test-index", - display_name="Index Name", - ) - extra_fields.extend((extra_field, extra_field2)) - - elif self.template.type_name == "FAISS": - extra_field = TemplateField( - name="folder_path", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - display_name="Local Path", - value="", - ) - extra_field2 = TemplateField( - name="index_name", - field_type="str", - required=False, - show=True, - advanced=False, - value="", - display_name="Index Name", - ) - extra_fields.extend((extra_field, extra_field2)) - elif self.template.type_name == "SupabaseVectorStore": - self.display_name = "Supabase" - # Add table_name and query_name - extra_field = TemplateField( - name="table_name", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="", - ) - extra_field2 = TemplateField( - name="query_name", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="", - ) - # Add supabase_url and supabase_service_key - extra_field3 = TemplateField( - name="supabase_url", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - value="", - ) - extra_field4 = TemplateField( - name="supabase_service_key", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - password=True, - value="", - ) - extra_fields.extend((extra_field, extra_field2, extra_field3, extra_field4)) - - elif self.template.type_name == "MongoDBAtlasVectorSearch": - self.display_name = "MongoDB Atlas" - - extra_field = TemplateField( - name="mongodb_atlas_cluster_uri", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - display_name="MongoDB Atlas Cluster URI", - value="", - ) - extra_field2 = TemplateField( - name="collection_name", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - display_name="Collection Name", - value="", - ) - extra_field3 = TemplateField( - name="db_name", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - display_name="Database Name", - value="", - ) - extra_field4 = TemplateField( - name="index_name", - field_type="str", - required=False, - placeholder="", - show=True, - advanced=True, - multiline=False, - display_name="Index Name", - value="", - ) - extra_fields.extend((extra_field, extra_field2, extra_field3, extra_field4)) - - if extra_fields: - for field in extra_fields: - self.template.add_field(field) - - def add_extra_base_classes(self) -> None: - self.base_classes.extend(("BaseRetriever", "VectorStoreRetriever")) - - @staticmethod - def format_field(field: TemplateField, name: Optional[str] = None) -> None: - FrontendNode.format_field(field, name) - # Define common field attributes - - # Check and set field attributes - if field.name == "texts": - # if field.name is "texts" it has to be replaced - # when instantiating the vectorstores - field.name = "documents" - - field.field_type = "Document" - field.display_name = "Documents" - field.required = False - field.show = True - field.advanced = False - field.is_list = True - elif field.name and "embedding" in field.name: - # for backwards compatibility - field.name = "embedding" - field.required = True - field.show = True - field.advanced = False - field.display_name = "Embedding" - field.field_type = "Embeddings" - - elif field.name in BASIC_FIELDS: - field.show = True - field.advanced = False - if field.name == "api_key": - field.display_name = "API Key" - field.password = True - elif field.name == "location": - field.value = ":memory:" - field.placeholder = ":memory:" - - elif field.name in ADVANCED_FIELDS: - field.show = True - field.advanced = True - if "key" in field.name: - field.password = False - - elif field.name == "text_key": - field.show = False diff --git a/tests/test_creators.py b/tests/test_creators.py deleted file mode 100644 index 177dd4105..000000000 --- a/tests/test_creators.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Dict, List - -import pytest -from langflow.interface.agents.base import AgentCreator -from langflow.interface.base import LangChainTypeCreator - - -@pytest.fixture -def sample_lang_chain_type_creator() -> LangChainTypeCreator: - class SampleLangChainTypeCreator(LangChainTypeCreator): - type_name: str = "test_type" - - def type_to_loader_dict(self) -> Dict: # type: ignore - return {"test_type": "TestClass"} - - def to_list(self) -> List[str]: - return ["node1", "node2"] - - def get_signature(self, name: str) -> Dict: - return { - "template": {"test_field": {"type": "str"}}, - "description": "test description", - "base_classes": ["base_class1", "base_class2"], - } - - return SampleLangChainTypeCreator() - - -@pytest.fixture -def sample_agent_creator() -> AgentCreator: - return AgentCreator() - - -def test_lang_chain_type_creator_to_dict( - client, - sample_lang_chain_type_creator: LangChainTypeCreator, -): - type_dict = sample_lang_chain_type_creator.to_dict() - - assert len(type_dict) == 1 - assert "test_type" in type_dict - assert "node1" in type_dict["test_type"] - assert "node2" in type_dict["test_type"] - assert "template" in type_dict["test_type"]["node1"] - assert "description" in type_dict["test_type"]["node1"] - assert "base_classes" in type_dict["test_type"]["node1"] - - -def test_agent_creator_type_to_loader_dict(sample_agent_creator: AgentCreator): - type_to_loader_dict = sample_agent_creator.type_to_loader_dict - assert len(type_to_loader_dict) > 0 - assert "JsonAgent" diff --git a/tests/test_custom_component.py b/tests/test_custom_component.py index 07796c540..0b64f2c1a 100644 --- a/tests/test_custom_component.py +++ b/tests/test_custom_component.py @@ -5,14 +5,14 @@ from uuid import uuid4 import pytest from langchain_core.documents import Document -from langflow.interface.custom.base import CustomComponent -from langflow.interface.custom.code_parser.code_parser import CodeParser, CodeSyntaxError -from langflow.interface.custom.custom_component.component import Component, ComponentCodeNullError +from langflow.custom import CustomComponent +from langflow.custom.code_parser.code_parser import CodeParser, CodeSyntaxError +from langflow.custom.custom_component.component import Component, ComponentCodeNullError from langflow.services.database.models.flow import Flow, FlowCreate code_default = """ from langflow.field_typing import Prompt -from langflow.interface.custom.custom_component import CustomComponent +from langflow.custom import CustomComponent from langflow.field_typing import BaseLanguageModel from langchain.chains import LLMChain diff --git a/tests/test_custom_types.py b/tests/test_custom_types.py deleted file mode 100644 index 33c854ba3..000000000 --- a/tests/test_custom_types.py +++ /dev/null @@ -1,33 +0,0 @@ -# Test this: -import pytest -from langflow.interface.custom.utils import get_function -from langflow.interface.tools.custom import PythonFunction, PythonFunctionTool -from langflow.utils import constants - - -def test_python_function_tool(): - """Test Python function""" - code = constants.DEFAULT_PYTHON_FUNCTION - func = get_function(code) - func = PythonFunctionTool(name="Test", description="Testing", code=code, func=func) - assert func("text") == "text" - # the tool decorator should raise an error if - # the function is not str -> str - - # This raises ValidationError - with pytest.raises(SyntaxError): - code = pytest.CODE_WITH_SYNTAX_ERROR - func = get_function(code) - func = PythonFunctionTool(name="Test", description="Testing", code=code, func=func) - - -def test_python_function(): - """Test Python function""" - func = PythonFunction(code=constants.DEFAULT_PYTHON_FUNCTION) - assert get_function(func.code)("text") == "text" - # the tool decorator should raise an error if - # the function is not str -> str - - # This raises ValidationError - with pytest.raises(SyntaxError): - func = PythonFunction(code=pytest.CODE_WITH_SYNTAX_ERROR) diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index 893b2b6d3..a01e45bb2 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -4,10 +4,8 @@ from uuid import UUID, uuid4 import pytest from fastapi import status from fastapi.testclient import TestClient - -from langflow.interface.custom.directory_reader.directory_reader import DirectoryReader +from langflow.custom.directory_reader.directory_reader import DirectoryReader from langflow.services.deps import get_settings_service -from langflow.template.frontend_node.chains import TimeTravelGuideChainNode def run_post(client, flow_id, headers, post_data): @@ -271,7 +269,7 @@ def test_get_all(client: TestClient, logged_in_headers): all_names = [component_name for _, components in response.json().items() for component_name in components] json_response = response.json() # We need to test the custom nodes - assert len(all_names) > len(files) + assert len(all_names) == len(files) assert "ChatInput" in json_response["inputs"] assert "Prompt" in json_response["inputs"] assert "ChatOutput" in json_response["outputs"] @@ -385,7 +383,6 @@ def test_invalid_prompt(client: TestClient): ], ) def test_various_prompts(client, prompt, expected_input_variables): - TimeTravelGuideChainNode().to_dict() PROMPT_REQUEST["template"] = prompt response = client.post("api/v1/validate/prompt", json=PROMPT_REQUEST) assert response.status_code == 200 diff --git a/tests/test_helper_components.py b/tests/test_helper_components.py index 8414cdac5..01a69de74 100644 --- a/tests/test_helper_components.py +++ b/tests/test_helper_components.py @@ -1,6 +1,7 @@ from langchain_core.documents import Document + from langflow.components import helpers -from langflow.interface.custom.utils import build_custom_component_template +from langflow.custom.utils import build_custom_component_template from langflow.schema import Record diff --git a/tests/test_loading.py b/tests/test_loading.py index 884a6a94a..5872d060f 100644 --- a/tests/test_loading.py +++ b/tests/test_loading.py @@ -2,7 +2,7 @@ import pytest from langflow.graph import Graph from langflow.graph.schema import RunOutputs from langflow.initial_setup.setup import load_starter_projects -from langflow.processing.load import load_flow_from_json, run_flow_from_json +from langflow.load import load_flow_from_json, run_flow_from_json @pytest.mark.noclient