Adds Info tooltips and links to docs, fixes component duplication (#554)

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-06-27 16:32:44 -03:00 committed by GitHub
commit a795632ed6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 670 additions and 395 deletions

View file

@ -13,8 +13,9 @@
<img alt="Github License" src="https://img.shields.io/github/license/logspace-ai/langflow" />
</p>
<p>
<a href="https://discord.gg/FUhJnnJ9"><img alt="Discord Server" src="https://dcbadge.vercel.app/api/server/FUhJnnJ9?compact=true&style=flat"/></a>
<a href="https://discord.gg/EqksyE2EX9"><img alt="Discord Server" src="https://dcbadge.vercel.app/api/server/EqksyE2EX9?compact=true&style=flat"/></a>
<a href="https://huggingface.co/spaces/Logspace/LangFlow"><img src="https://huggingface.co/datasets/huggingface/badges/raw/main/open-in-hf-spaces-sm.svg" alt="HuggingFace Spaces"></a>
</p>

12
poetry.lock generated
View file

@ -1565,14 +1565,14 @@ uritemplate = ">=3.0.1,<5"
[[package]]
name = "google-auth"
version = "2.20.0"
version = "2.21.0"
description = "Google Authentication Library"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "google-auth-2.20.0.tar.gz", hash = "sha256:030af34138909ccde0fbce611afc178f1d65d32fbff281f25738b1fe1c6f3eaa"},
{file = "google_auth-2.20.0-py2.py3-none-any.whl", hash = "sha256:23b7b0950fcda519bfb6692bf0d5289d2ea49fc143717cc7188458ec620e63fa"},
{file = "google-auth-2.21.0.tar.gz", hash = "sha256:b28e8048e57727e7cf0e5bd8e7276b212aef476654a09511354aa82753b45c66"},
{file = "google_auth-2.21.0-py2.py3-none-any.whl", hash = "sha256:da3f18d074fa0f5a7061d99b9af8cee3aa6189c987af7c1b07d94566b6b11268"},
]
[package.dependencies]
@ -4977,14 +4977,14 @@ files = [
[[package]]
name = "pywin32-ctypes"
version = "0.2.1"
version = "0.2.2"
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "pywin32-ctypes-0.2.1.tar.gz", hash = "sha256:934a2def1e5cbc472b2b6bf80680c0f03cd87df65dfd58bfd1846969de095b03"},
{file = "pywin32_ctypes-0.2.1-py3-none-any.whl", hash = "sha256:b9a53ef754c894a525469933ab2a447c74ec1ea6b9d2ef446f40ec50d3dcec9f"},
{file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
{file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
]
[[package]]

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "langflow"
version = "0.2.2"
version = "0.2.3"
description = "A Python package with a built-in web application"
authors = ["Logspace <contact@logspace.ai>"]
maintainers = [

View file

@ -1,6 +1,5 @@
import sys
import time
from fastapi import FastAPI
import httpx
from multiprocess import Process, cpu_count # type: ignore
import platform
@ -11,9 +10,7 @@ from rich.panel import Panel
from rich import box
from rich import print as rprint
import typer
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from langflow.main import create_app
from langflow.main import setup_app
from langflow.settings import settings
from langflow.utils.logger import configure, logger
import webbrowser
@ -144,15 +141,9 @@ def serve(
remove_api_keys=remove_api_keys,
cache=cache,
)
# get the directory of the current file
if not path:
frontend_path = Path(__file__).parent
static_files_dir = frontend_path / "frontend"
else:
static_files_dir = Path(path)
app = create_app()
setup_static_files(app, static_files_dir)
# create path object if path is provided
static_files_dir: Optional[Path] = Path(path) if path else None
app = setup_app(static_files_dir=static_files_dir)
# check if port is being used
if is_port_in_use(port, host):
port = get_free_port(port)
@ -200,29 +191,6 @@ def run_on_windows(host, port, log_level, options, app):
run_langflow(host, port, log_level, options, app)
def setup_static_files(app: FastAPI, static_files_dir: Path):
"""
Setup the static files directory.
Args:
app (FastAPI): FastAPI app.
path (str): Path to the static files directory.
"""
app.mount(
"/",
StaticFiles(directory=static_files_dir, html=True),
name="static",
)
@app.exception_handler(404)
async def custom_404_handler(request, __):
path = static_files_dir / "index.html"
if not path.exists():
raise RuntimeError(f"File at path {path} does not exist.")
return FileResponse(path)
def is_port_in_use(port, host="localhost"):
"""
Check if a port is in use.

View file

@ -0,0 +1,2 @@
class ChatConfig:
streaming: bool = True

View file

@ -1,141 +1,247 @@
---
agents:
- ZeroShotAgent
- JsonAgent
- CSVAgent
- AgentInitializer
- VectorStoreAgent
- VectorStoreRouterAgent
- SQLAgent
ZeroShotAgent:
documentation: "https://python.langchain.com/docs/modules/agents/how_to/custom_mrkl_agent"
JsonAgent:
documentation: "https://python.langchain.com/docs/modules/agents/toolkits/openapi"
CSVAgent:
documentation: "https://python.langchain.com/docs/modules/agents/toolkits/csv"
AgentInitializer:
documentation: "https://python.langchain.com/docs/modules/agents/agent_types/"
VectorStoreAgent:
documentation: ""
VectorStoreRouterAgent:
documentation: ""
SQLAgent:
documentation: ""
chains:
- LLMChain
- LLMMathChain
- LLMCheckerChain
- ConversationChain
- SeriesCharacterChain
- MidJourneyPromptChain
- TimeTravelGuideChain
- SQLDatabaseChain
- RetrievalQA
- RetrievalQAWithSourcesChain
- ConversationalRetrievalChain
- CombineDocsChain
LLMChain:
documentation: "https://python.langchain.com/docs/modules/chains/foundational/llm_chain"
LLMMathChain:
documentation: "https://python.langchain.com/docs/modules/chains/additional/llm_math"
LLMCheckerChain:
documentation: "https://python.langchain.com/docs/modules/chains/additional/llm_checker"
ConversationChain:
documentation: ""
SeriesCharacterChain:
documentation: ""
MidJourneyPromptChain:
documentation: ""
TimeTravelGuideChain:
documentation: ""
SQLDatabaseChain:
documentation: ""
RetrievalQA:
documentation: "https://python.langchain.com/docs/modules/chains/popular/vector_db_qa"
RetrievalQAWithSourcesChain:
documentation: ""
ConversationalRetrievalChain:
documentation: "https://python.langchain.com/docs/modules/chains/popular/chat_vector_db"
CombineDocsChain:
documentation: ""
documentloaders:
- AirbyteJSONLoader
- CoNLLULoader
- CSVLoader
- UnstructuredEmailLoader
- EverNoteLoader
- FacebookChatLoader
- GutenbergLoader
- BSHTMLLoader
- UnstructuredHTMLLoader
# - UnstructuredImageLoader # Issue with Python 3.11 (https://github.com/Unstructured-IO/unstructured-inference/issues/83)
- UnstructuredMarkdownLoader
- PyPDFLoader
- UnstructuredPowerPointLoader
- SRTLoader
- TelegramChatLoader
- TextLoader
- UnstructuredWordDocumentLoader
- WebBaseLoader
- AZLyricsLoader
- CollegeConfidentialLoader
- HNLoader
- IFixitLoader
- IMSDbLoader
- GitbookLoader
- ReadTheDocsLoader
- SlackDirectoryLoader
- NotionDirectoryLoader
- DirectoryLoader
- GitLoader
AirbyteJSONLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/airbyte_json"
CoNLLULoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/conll-u"
CSVLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/csv"
UnstructuredEmailLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/email"
EverNoteLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/evernote"
FacebookChatLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/facebook_chat"
GutenbergLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/gutenberg"
BSHTMLLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/how_to/html"
UnstructuredHTMLLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/how_to/html"
UnstructuredMarkdownLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/how_to/markdown"
PyPDFLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/how_to/pdf"
UnstructuredPowerPointLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/microsoft_powerpoint"
SRTLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/subtitle"
TelegramChatLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/telegram"
TextLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/"
UnstructuredWordDocumentLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/microsoft_word"
WebBaseLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/web_base"
AZLyricsLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/azlyrics"
CollegeConfidentialLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/college_confidential"
HNLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/hacker_news"
IFixitLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/ifixit"
IMSDbLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/imsdb"
GitbookLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/gitbook"
ReadTheDocsLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/readthedocs_documentation"
SlackDirectoryLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/slack"
NotionDirectoryLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/notion"
DirectoryLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/how_to/file_directory"
GitLoader:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/git"
embeddings:
- OpenAIEmbeddings
- HuggingFaceEmbeddings
- CohereEmbeddings
OpenAIEmbeddings:
documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/openai"
HuggingFaceEmbeddings:
documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/sentence_transformers"
CohereEmbeddings:
documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/cohere"
llms:
- OpenAI
# - AzureOpenAI
# - AzureChatOpenAI
- ChatOpenAI
- LlamaCpp
- CTransformers
- Cohere
- Anthropic
- ChatAnthropic
- HuggingFaceHub
OpenAI:
documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai"
ChatOpenAI:
documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/openai"
LlamaCpp:
documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/llamacpp"
CTransformers:
documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/ctransformers"
Cohere:
documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/cohere"
Anthropic:
documentation: ""
ChatAnthropic:
documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/anthropic"
HuggingFaceHub:
documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/huggingface_hub"
memories:
- ConversationBufferMemory
- ConversationSummaryMemory
- ConversationKGMemory
ConversationBufferMemory:
documentation: "https://python.langchain.com/docs/modules/memory/how_to/summary"
ConversationSummaryMemory:
documentation: "https://python.langchain.com/docs/modules/memory/how_to/summary"
ConversationKGMemory:
documentation: "https://python.langchain.com/docs/modules/memory/how_to/kg"
ConversationBufferWindowMemory:
documentation: "https://python.langchain.com/docs/modules/memory/how_to/buffer_window"
VectorStoreRetrieverMemory:
documentation: "https://python.langchain.com/docs/modules/memory/how_to/vectorstore_retriever_memory"
prompts:
- PromptTemplate
- FewShotPromptTemplate
- ZeroShotPrompt
PromptTemplate:
documentation: "https://python.langchain.com/docs/modules/model_io/prompts/prompt_templates/"
ZeroShotPrompt:
documentation: "https://python.langchain.com/docs/modules/agents/how_to/custom_mrkl_agent"
textsplitters:
- CharacterTextSplitter
- RecursiveCharacterTextSplitter
# - LatexTextSplitter
# - PythonCodeTextSplitter
CharacterTextSplitter:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter"
RecursiveCharacterTextSplitter:
documentation: "https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/recursive_text_splitter"
toolkits:
- OpenAPIToolkit
- JsonToolkit
- VectorStoreInfo
- VectorStoreRouterToolkit
- VectorStoreToolkit
OpenAPIToolkit:
documentation: ""
JsonToolkit:
documentation: ""
VectorStoreInfo:
documentation: ""
VectorStoreRouterToolkit:
documentation: ""
VectorStoreToolkit:
documentation: ""
tools:
- Search
- PAL-MATH
- Calculator
- Serper Search
- Tool
- PythonFunctionTool
- PythonFunction
- JsonSpec
- News API
- TMDB API
- Podcast API
- QuerySQLDataBaseTool
- InfoSQLDatabaseTool
- ListSQLDatabaseTool
# - QueryCheckerTool
- BingSearchRun
- GoogleSearchRun
- GoogleSearchResults
- GoogleSerperRun
- JsonListKeysTool
- JsonGetValueTool
- PythonREPLTool
- PythonAstREPLTool
- RequestsGetTool
- RequestsPostTool
- RequestsPatchTool
- RequestsPutTool
- RequestsDeleteTool
- WikipediaQueryRun
- WolframAlphaQueryRun
Search:
documentation: ""
PAL-MATH:
documentation: ""
Calculator:
documentation: ""
Serper Search:
documentation: ""
Tool:
documentation: ""
PythonFunctionTool:
documentation: ""
PythonFunction:
documentation: ""
JsonSpec:
documentation: ""
News API:
documentation: ""
TMDB API:
documentation: ""
Podcast API:
documentation: ""
QuerySQLDataBaseTool:
documentation: ""
InfoSQLDatabaseTool:
documentation: ""
ListSQLDatabaseTool:
documentation: ""
BingSearchRun:
documentation: ""
GoogleSearchRun:
documentation: ""
GoogleSearchResults:
documentation: ""
GoogleSerperRun:
documentation: ""
JsonListKeysTool:
documentation: ""
JsonGetValueTool:
documentation: ""
PythonREPLTool:
documentation: ""
PythonAstREPLTool:
documentation: ""
RequestsGetTool:
documentation: ""
RequestsPostTool:
documentation: ""
RequestsPatchTool:
documentation: ""
RequestsPutTool:
documentation: ""
RequestsDeleteTool:
documentation: ""
WikipediaQueryRun:
documentation: ""
WolframAlphaQueryRun:
documentation: ""
utilities:
- BingSearchAPIWrapper
- GoogleSearchAPIWrapper
- GoogleSerperAPIWrapper
- SearxResults
- SearxSearchWrapper
- SerpAPIWrapper
- WikipediaAPIWrapper
- WolframAlphaAPIWrapper
# - ZapierNLAWrapper
- SQLDatabase
BingSearchAPIWrapper:
documentation: ""
GoogleSearchAPIWrapper:
documentation: ""
GoogleSerperAPIWrapper:
documentation: ""
SearxResults:
documentation: ""
SearxSearchWrapper:
documentation: ""
SerpAPIWrapper:
documentation: ""
WikipediaAPIWrapper:
documentation: ""
WolframAlphaAPIWrapper:
documentation: ""
vectorstores:
- Chroma
- Qdrant
- Weaviate
- FAISS
- Pinecone
- SupabaseVectorStore
- MongoDBAtlasVectorSearch
Chroma:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/chroma"
Qdrant:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/qdrant"
Weaviate:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/weaviate"
FAISS:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/faiss"
Pinecone:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/pinecone"
SupabaseVectorStore:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/supabase"
MongoDBAtlasVectorSearch:
documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/mongodb_atlas_vector_search"
wrappers:
- RequestsWrapper
# - ChatPromptTemplate
# - SystemMessagePromptTemplate
# - HumanMessagePromptTemplate
RequestsWrapper:
documentation: ""

View file

@ -8,6 +8,7 @@ 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.logger import logger
from langflow.settings import settings
# Assuming necessary imports for Field, Template, and FrontendNode classes
@ -15,12 +16,29 @@ from langflow.utils.logger import logger
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."""
if self.name_docs_dict is None:
try:
type_settings = getattr(settings, self.type_name)
self.name_docs_dict = {
name: value_dict["documentation"]
for name, value_dict in type_settings.items()
}
except AttributeError as exc:
logger.error(exc)
self.name_docs_dict = {}
return self.name_docs_dict
@property
@abstractmethod
def type_to_loader_dict(self) -> Dict:
@ -83,7 +101,7 @@ class LangChainTypeCreator(BaseModel, ABC):
signature.add_extra_fields()
signature.add_extra_base_classes()
signature.set_documentation(self.docs_map.get(name, ""))
return signature

View file

@ -1,11 +1,12 @@
import json
from typing import Any, Callable, Dict, Sequence
from typing import Any, Callable, Dict, Sequence, Type
from langchain.agents import ZeroShotAgent
from langchain.agents import agent as agent_module
from langchain.agents.agent import AgentExecutor
from langchain.agents.agent_toolkits.base import BaseToolkit
from langchain.agents.tools import BaseTool
from langflow.interface.initialize.vector_store import vecstore_initializer
from pydantic import ValidationError
@ -16,6 +17,11 @@ from langflow.interface.toolkits.base import toolkits_creator
from langflow.interface.chains.base import chain_creator
from langflow.interface.utils import load_file_into_dict
from langflow.utils import validate
from langchain.chains.base import Chain
from langchain.vectorstores.base import VectorStore
from langchain.document_loaders.base import BaseLoader
from langchain.prompts.base import BasePromptTemplate
from langflow.chat.config import ChatConfig
def instantiate_class(node_type: str, base_type: str, params: Dict) -> Any:
@ -72,11 +78,22 @@ def instantiate_based_on_type(class_object, base_type, node_type, params):
return instantiate_utility(node_type, class_object, params)
elif base_type == "chains":
return instantiate_chains(node_type, class_object, params)
elif base_type == "llms":
return instantiate_llm(node_type, class_object, params)
else:
return class_object(**params)
def instantiate_chains(node_type, 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
ChatConfig.streaming = "jina" not in params.get("openai_api_base", "")
return class_object(**params)
def instantiate_chains(node_type, class_object: Type[Chain], params: Dict):
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:
@ -88,11 +105,11 @@ def instantiate_chains(node_type, class_object, params):
return class_object(**params)
def instantiate_agent(class_object, params):
def instantiate_agent(class_object: Type[agent_module.Agent], params: Dict):
return load_agent_executor(class_object, params)
def instantiate_prompt(node_type, class_object, params):
def instantiate_prompt(node_type, class_object: Type[BasePromptTemplate], params: Dict):
if node_type == "ZeroShotPrompt":
if "tools" not in params:
params["tools"] = []
@ -100,7 +117,7 @@ def instantiate_prompt(node_type, class_object, params):
return class_object(**params)
def instantiate_tool(node_type, class_object, params):
def instantiate_tool(node_type, class_object: Type[BaseTool], params: Dict):
if node_type == "JsonSpec":
params["dict_"] = load_file_into_dict(params.pop("path"))
return class_object(**params)
@ -118,7 +135,7 @@ def instantiate_tool(node_type, class_object, params):
return class_object(**params)
def instantiate_toolkit(node_type, 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):
@ -128,7 +145,7 @@ def instantiate_toolkit(node_type, class_object, params):
return loaded_toolkit
def instantiate_embedding(class_object, params):
def instantiate_embedding(class_object, params: Dict):
params.pop("model", None)
params.pop("headers", None)
try:
@ -142,7 +159,7 @@ def instantiate_embedding(class_object, params):
return class_object(**params)
def instantiate_vectorstore(class_object, params):
def instantiate_vectorstore(class_object: Type[VectorStore], params: Dict):
search_kwargs = params.pop("search_kwargs", {})
if initializer := vecstore_initializer.get(class_object.__name__):
vecstore = initializer(class_object, params)
@ -158,7 +175,7 @@ def instantiate_vectorstore(class_object, params):
return vecstore
def instantiate_documentloader(class_object, params):
def instantiate_documentloader(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
@ -187,19 +204,29 @@ def instantiate_documentloader(class_object, params):
return docs
def instantiate_textsplitter(class_object, params):
def instantiate_textsplitter(
class_object,
params: Dict,
):
try:
documents = params.pop("documents")
except KeyError as e:
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 e
text_splitter = class_object(**params)
) from exc
if "separator_type" in params and params["separator_type"] == "Text":
text_splitter = class_object(**params)
else:
params["language"] = params.pop("separator_type", None)
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):
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)

View file

@ -4,10 +4,12 @@ import os
from io import BytesIO
import re
import yaml
from langchain.base_language import BaseLanguageModel
from PIL.Image import Image
from langflow.utils.logger import logger
from langflow.chat.config import ChatConfig
def load_file_into_dict(file_path: str) -> dict:
@ -49,9 +51,9 @@ def try_setting_streaming_options(langchain_object, websocket):
if isinstance(llm, BaseLanguageModel):
if hasattr(llm, "streaming") and isinstance(llm.streaming, bool):
llm.streaming = True
llm.streaming = ChatConfig.streaming
elif hasattr(llm, "stream") and isinstance(llm.stream, bool):
llm.stream = True
llm.stream = ChatConfig.streaming
return langchain_object

View file

@ -1,5 +1,9 @@
from pathlib import Path
from typing import Optional
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from langflow.api import router
from langflow.database.base import create_db_and_tables
@ -33,6 +37,42 @@ def create_app():
return app
def setup_static_files(app: FastAPI, static_files_dir: Path):
"""
Setup the static files directory.
Args:
app (FastAPI): FastAPI app.
path (str): Path to the static files directory.
"""
app.mount(
"/",
StaticFiles(directory=static_files_dir, html=True),
name="static",
)
@app.exception_handler(404)
async def custom_404_handler(request, __):
path = static_files_dir / "index.html"
if not path.exists():
raise RuntimeError(f"File at path {path} does not exist.")
return FileResponse(path)
# app = create_app()
# setup_static_files(app, static_files_dir)
def setup_app(static_files_dir: Optional[Path]) -> FastAPI:
"""Setup the FastAPI app."""
# get the directory of the current file
if not static_files_dir:
frontend_path = Path(__file__).parent
static_files_dir = frontend_path / "frontend"
app = create_app()
setup_static_files(app, static_files_dir)
return app
app = create_app()

View file

@ -1,24 +1,23 @@
import os
from typing import List
import yaml
from pydantic import BaseSettings, root_validator
class Settings(BaseSettings):
chains: List[str] = []
agents: List[str] = []
prompts: List[str] = []
llms: List[str] = []
tools: List[str] = []
memories: List[str] = []
embeddings: List[str] = []
vectorstores: List[str] = []
documentloaders: List[str] = []
wrappers: List[str] = []
toolkits: List[str] = []
textsplitters: List[str] = []
utilities: List[str] = []
chains: dict = {}
agents: dict = {}
prompts: dict = {}
llms: dict = {}
tools: dict = {}
memories: dict = {}
embeddings: dict = {}
vectorstores: dict = {}
documentloaders: dict = {}
wrappers: dict = {}
toolkits: dict = {}
textsplitters: dict = {}
utilities: dict = {}
dev: bool = False
database_url: str = "sqlite:///./langflow.db"
cache: str = "InMemoryCache"
@ -38,16 +37,16 @@ class Settings(BaseSettings):
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.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.dev = dev
def update_settings(self, **kwargs):

View file

@ -21,6 +21,7 @@ class TemplateFieldCreator(BaseModel, ABC):
name: str = ""
display_name: Optional[str] = None
advanced: bool = False
info: Optional[str] = ""
def to_dict(self):
result = self.dict()

View file

@ -15,14 +15,21 @@ class FrontendNode(BaseModel):
base_classes: List[str]
name: str = ""
display_name: str = ""
documentation: str = ""
def set_documentation(self, documentation: str) -> None:
"""Sets the documentation of the frontend node."""
self.documentation = documentation
def to_dict(self) -> dict:
"""Returns a dict representation of the frontend node."""
return {
self.name: {
"template": self.template.to_dict(self.format_field),
"description": self.description,
"base_classes": self.base_classes,
"display_name": self.display_name or self.name,
"documentation": self.documentation,
},
}

View file

@ -32,3 +32,13 @@ You are a good listener and you can talk about anything.
HUMAN_PROMPT = "{input}"
QA_CHAIN_TYPES = ["stuff", "map_reduce", "map_rerank", "refine"]
# This variable is used to tell the user
# that it can be changed to use other APIs
# like Prem and LocalAI
OPENAI_API_BASE_INFO = """
The base URL of the OpenAI API. Defaults to https://api.openai.com/v1.
You can change this to use other APIs like JinaChat, LocalAI and Prem.
"""

View file

@ -2,6 +2,7 @@ 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 OPENAI_API_BASE_INFO
class LLMFrontendNode(FrontendNode):
@ -15,6 +16,9 @@ class LLMFrontendNode(FrontendNode):
if "key" not in field.name.lower() and "token" not in field.name.lower():
field.password = False
if field.name == "openai_api_base":
field.info = OPENAI_API_BASE_INFO
@staticmethod
def format_azure_field(field: TemplateField):
if field.name == "model_name":

View file

@ -1,5 +1,6 @@
from langflow.template.field.base import TemplateField
from langflow.template.frontend_node.base import FrontendNode
from langchain.text_splitter import Language
class TextSplittersFrontendNode(FrontendNode):
@ -17,6 +18,22 @@ class TextSplittersFrontendNode(FrontendNode):
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
self.template.add_field(
TemplateField(
field_type="str",
required=True,
show=True,
name="separator_type",
advanced=False,
is_list=True,
options=[x.value for x in Language],
value="Text",
display_name="Separator Type",
)
)
self.template.add_field(
TemplateField(
field_type="str",

View file

@ -200,7 +200,7 @@ class VectorStoreFrontendNode(FrontendNode):
self.template.add_field(field)
def add_extra_base_classes(self) -> None:
self.base_classes.append("BaseRetriever")
self.base_classes.extend(("BaseRetriever", "VectorStoreRetriever"))
@staticmethod
def format_field(field: TemplateField, name: Optional[str] = None) -> None:

View file

@ -1212,15 +1212,15 @@
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/@mui/system": {
"version": "5.13.5",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.5.tgz",
"integrity": "sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA==",
"version": "5.13.6",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.6.tgz",
"integrity": "sha512-G3Xr28uLqU3DyF6r2LQkHGw/ku4P0AHzlKVe7FGXOPl7X1u+hoe2xxj8Vdiq/69II/mh9OP21i38yBWgWb7WgQ==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@babel/runtime": "^7.22.5",
"@mui/private-theming": "^5.13.1",
"@mui/styled-engine": "^5.13.2",
"@mui/types": "^7.2.4",
"@mui/utils": "^5.13.1",
"@mui/utils": "^5.13.6",
"clsx": "^1.2.1",
"csstype": "^3.1.2",
"prop-types": "^15.8.1"
@ -1280,11 +1280,11 @@
}
},
"node_modules/@mui/utils": {
"version": "5.13.1",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz",
"integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==",
"version": "5.13.6",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.6.tgz",
"integrity": "sha512-ggNlxl5NPSbp+kNcQLmSig6WVB0Id+4gOxhx644987v4fsji+CSXc+MFYLocFB/x4oHtzCUlSzbVHlJfP/fXoQ==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@babel/runtime": "^7.22.5",
"@types/prop-types": "^15.7.5",
"@types/react-is": "^18.2.0",
"prop-types": "^15.8.1",
@ -3444,7 +3444,7 @@
"version": "16.18.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz",
"integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==",
"devOptional": true
"dev": true
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@ -3714,9 +3714,9 @@
}
},
"node_modules/aria-query": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.2.1.tgz",
"integrity": "sha512-7uFg4b+lETFgdaJyETnILsXgnnzVnkHcgRbwbPwevm5x/LmUlt3MjczMRe1zg824iBgXZNRPTBftNYyRSKLp2g==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"dependencies": {
"dequal": "^2.0.3"
@ -5010,9 +5010,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.438",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.438.tgz",
"integrity": "sha512-x94U0FhphEsHsOloCvlsujHCvoir0ZQ73ZAs/QN4PLx98uNvyEU79F75rq1db75Bx/atvuh7KPeuxelh+xfYJw=="
"version": "1.4.440",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.440.tgz",
"integrity": "sha512-r6dCgNpRhPwiWlxbHzZQ/d9swfPaEJGi8ekqRBwQYaR3WmA5VkqQfBWSDDjuJU1ntO+W9tHx8OHV/96Q8e0dVw=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@ -5504,6 +5504,7 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@ -6745,9 +6746,9 @@
}
},
"node_modules/katex": {
"version": "0.16.7",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.7.tgz",
"integrity": "sha512-Xk9C6oGKRwJTfqfIbtr0Kes9OSv6IFsuhFGc7tW4urlpMJtuh+7YhzU6YEG9n8gmWKcMAFzkp7nr+r69kV0zrA==",
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.8.tgz",
"integrity": "sha512-ftuDnJbcbOckGY11OO+zg3OofESlbR5DRl2cmN8HeWeeFIV7wTXvAOx8kEjZjobhA+9wh2fbKeO6cdcA9Mnovg==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"

View file

@ -25,6 +25,7 @@ import { nodeColors } from "../../../../utils";
import ShadTooltip from "../../../../components/ShadTooltipComponent";
import { PopUpContext } from "../../../../contexts/popUpContext";
import ToggleShadComponent from "../../../../components/toggleShadComponent";
import { Info } from "lucide-react";
export default function ParameterComponent({
left,
@ -36,9 +37,11 @@ export default function ParameterComponent({
type,
name = "",
required = false,
info = "",
}: ParameterComponentType) {
const ref = useRef(null);
const refHtml = useRef(null);
const infoHtml = useRef(null);
const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0);
const { closePopUp } = useContext(PopUpContext);
@ -79,6 +82,18 @@ export default function ParameterComponent({
});
};
useEffect(() => {
infoHtml.current = (
<div className="h-full w-full break-words">
{info.split("\n").map((line, i) => (
<p key={i} className="block">
{line}
</p>
))}
</div>
);
}, [info]);
useEffect(() => {
const groupedObj = groupByFamily(myData, tooltipTitle);
@ -126,9 +141,22 @@ export default function ParameterComponent({
className="w-full flex flex-wrap justify-between items-center bg-muted dark:bg-gray-800 dark:text-white mt-1 px-5 py-2"
>
<>
<div className={"text-sm truncate w-full " + (left ? "" : "text-end")}>
<div
className={
"text-sm truncate w-full" +
(left ? "" : " text-end") +
(info !== "" ? " flex items-center" : "")
}
>
{title}
<span className="text-red-600">{required ? " *" : ""}</span>
<div className="">
{info !== "" && (
<ShadTooltip content={infoHtml.current}>
<Info className="ml-2 relative bottom-0.5 w-3 h-3" />
</ShadTooltip>
)}
</div>
</div>
{left &&
(type === "str" ||

View file

@ -6,16 +6,7 @@ import {
} from "../../utils";
import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext";
import {
useContext,
useState,
useEffect,
useRef,
ForwardRefExoticComponent,
ComponentType,
SVGProps,
ReactNode,
} from "react";
import { useContext, useState, useEffect, useRef } from "react";
import { NodeDataType } from "../../types/flow";
import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
@ -23,10 +14,8 @@ import NodeModal from "../../modals/NodeModal";
import Tooltip from "../../components/TooltipComponent";
import { NodeToolbar } from "reactflow";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import ShadTooltip from "../../components/ShadTooltipComponent";
import { useSSE } from "../../contexts/SSEContext";
import { ReactElement } from "react-markdown/lib/react-markdown";
export default function GenericNode({
data,
@ -46,6 +35,7 @@ export default function GenericNode({
const [validationStatus, setValidationStatus] = useState(null);
// State for outline color
const { sseData, isBuilding } = useSSE();
const refHtml = useRef(null);
// useEffect(() => {
// if (reactFlowInstance) {
@ -103,11 +93,8 @@ export default function GenericNode({
color: nodeColors[types[data.type]] ?? nodeColors.unknown,
}}
/>
<div className="ml-2 truncate">
<ShadTooltip
delayDuration={1500}
content={data.node.display_name}
>
<div className="ml-2 truncate flex">
<ShadTooltip content={data.node.display_name}>
<div className="ml-2 truncate text-gray-800">
{data.node.display_name}
</div>
@ -214,6 +201,7 @@ export default function GenericNode({
? toTitleCase(data.node.template[t].name)
: toTitleCase(t)
}
info={data.node.template[t].info}
name={t}
tooltipTitle={data.node.template[t].type}
required={data.node.template[t].required}

View file

@ -1,3 +1,4 @@
import { ShadTooltipProps } from "../../types/components";
import {
Tooltip,
TooltipContent,
@ -5,18 +6,19 @@ import {
TooltipTrigger,
} from "../ui/tooltip";
const ShadTooltip = (props) => {
const ShadTooltip = ({
delayDuration = 500,
side,
content,
children,
}: ShadTooltipProps) => {
return (
<TooltipProvider>
<Tooltip delayDuration={props.delayDuration}>
<TooltipTrigger asChild>{props.children}</TooltipTrigger>
<Tooltip delayDuration={delayDuration}>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipContent
side={props.side}
avoidCollisions={false}
sticky="always"
>
{props.content}
<TooltipContent side={side} avoidCollisions={false} sticky="always">
{content}
</TooltipContent>
</Tooltip>
</TooltipProvider>

View file

@ -1,9 +1,11 @@
import { Listbox, Transition } from "@headlessui/react";
import { Fragment, useEffect, useState } from "react";
import { Fragment, useContext, useEffect, useState } from "react";
import { DropDownComponentType } from "../../types/components";
import { classNames } from "../../utils";
import { INPUT_STYLE } from "../../constants";
import { ChevronsUpDown, Check } from "lucide-react";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
export default function Dropdown({
value,
@ -12,12 +14,15 @@ export default function Dropdown({
editNode = false,
numberOfOptions = 0,
}: DropDownComponentType) {
const { closePopUp } = useContext(PopUpContext);
let [internalValue, setInternalValue] = useState(
value === "" || !value ? "Choose an option" : value
);
useEffect(() => {
setInternalValue(value === "" || !value ? "Choose an option" : value);
}, [value]);
}, [closePopUp]);
return (
<>

View file

@ -2,6 +2,7 @@ import { useContext, useEffect, useState } from "react";
import { FloatComponentType } from "../../types/components";
import { TabsContext } from "../../contexts/tabsContext";
import { INPUT_STYLE } from "../../constants";
import { PopUpContext } from "../../contexts/popUpContext";
export default function FloatComponent({
value,
@ -12,6 +13,7 @@ export default function FloatComponent({
}: FloatComponentType) {
const [myValue, setMyValue] = useState(value ?? "");
const { setDisableCopyPaste } = useContext(TabsContext);
const { closePopUp } = useContext(PopUpContext);
const step = 0.1;
const min = 0;
@ -26,7 +28,7 @@ export default function FloatComponent({
useEffect(() => {
setMyValue(value);
}, [value]);
}, [closePopUp]);
return (
<div

View file

@ -5,6 +5,7 @@ import { TabsContext } from "../../contexts/tabsContext";
import _ from "lodash";
import { INPUT_STYLE } from "../../constants";
import { X, Plus } from "lucide-react";
import { PopUpContext } from "../../contexts/popUpContext";
export default function InputListComponent({
value,
@ -13,12 +14,19 @@ export default function InputListComponent({
editNode = false,
}: InputListComponentType) {
const [inputList, setInputList] = useState(value ?? [""]);
const { closePopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
setInputList([""]);
onChange([""]);
}
}, [disabled, onChange]);
useEffect(() => {
setInputList(value);
}, [closePopUp]);
return (
<div
className={
@ -44,9 +52,9 @@ export default function InputListComponent({
setInputList((old) => {
let newInputList = _.cloneDeep(old);
newInputList[idx] = e.target.value;
onChange(newInputList);
return newInputList;
});
onChange(inputList);
}}
/>
{idx === inputList.length - 1 ? (

View file

@ -3,6 +3,7 @@ import { FloatComponentType } from "../../types/components";
import { TabsContext } from "../../contexts/tabsContext";
import { classNames } from "../../utils";
import { INPUT_STYLE } from "../../constants";
import { PopUpContext } from "../../contexts/popUpContext";
export default function IntComponent({
value,
@ -14,6 +15,7 @@ export default function IntComponent({
const [myValue, setMyValue] = useState(value ?? "");
const { setDisableCopyPaste } = useContext(TabsContext);
const min = 0;
const { closePopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
@ -24,7 +26,7 @@ export default function IntComponent({
useEffect(() => {
setMyValue(value);
}, [value]);
}, [closePopUp]);
return (
<div

View file

@ -192,39 +192,49 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function processFlowEdges(flow) {
if(!flow.data || !flow.data.edges) return;
if (!flow.data || !flow.data.edges) return;
flow.data.edges.forEach((edge) => {
edge.className = "";
edge.style = { stroke: "#555555" };
});
}
function updateDisplay_name(node:NodeType,template:APIClassType) {
node.data.node.display_name = template["display_name"]?template["display_name"]:node.data.type;
function updateDisplay_name(node: NodeType, template: APIClassType) {
node.data.node.display_name = template["display_name"] || node.data.type;
}
function updateNodeDocumentation(node: NodeType, template: APIClassType) {
node.data.node.documentation = template["documentation"];
}
function processFlowNodes(flow) {
if(!flow.data || !flow.data.nodes) return;
flow.data.nodes.forEach((node:NodeType) => {
if (!flow.data || !flow.data.nodes) return;
flow.data.nodes.forEach((node: NodeType) => {
const template = templates[node.data.type];
if (!template) {
setErrorData({ title: `Unknown node type: ${node.data.type}` });
return;
}
if (Object.keys(template["template"]).length > 0) {
updateDisplay_name(node,template);
updateDisplay_name(node, template);
updateNodeBaseClasses(node, template);
updateNodeEdges(flow, node, template);
updateNodeDescription(node, template);
updateNodeTemplate(node, template);
updateNodeDocumentation(node, template);
}
});
}
function updateNodeBaseClasses(node:NodeType,template:APIClassType) {
function updateNodeBaseClasses(node: NodeType, template: APIClassType) {
node.data.node.base_classes = template["base_classes"];
}
function updateNodeEdges(flow:FlowType, node:NodeType,template:APIClassType) {
function updateNodeEdges(
flow: FlowType,
node: NodeType,
template: APIClassType
) {
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle
@ -236,11 +246,11 @@ export function TabsProvider({ children }: { children: ReactNode }) {
});
}
function updateNodeDescription(node:NodeType,template:APIClassType) {
function updateNodeDescription(node: NodeType, template: APIClassType) {
node.data.node.description = template["description"];
}
function updateNodeTemplate(node:NodeType,template:APIClassType) {
function updateNodeTemplate(node: NodeType, template: APIClassType) {
node.data.node.template = updateTemplate(
template["template"] as unknown as APITemplateType,
node.data.node.template as APITemplateType
@ -404,7 +414,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
y: insidePosition.y + n.position.y - minimumY,
},
data: {
...n.data,
..._.cloneDeep(n.data),
id: newId,
},
};

View file

@ -103,7 +103,9 @@ export default function ApiModal({ flow }: { flow: FlowType }) {
<div className="flex items-center justify-between px-2">
<TabsList>
{tabs.map((tab, index) => (
<TabsTrigger key={index} value={index.toString()}>{tab.name}</TabsTrigger>
<TabsTrigger key={index} value={index.toString()}>
{tab.name}
</TabsTrigger>
))}
</TabsList>
<div className="float-right">

View file

@ -79,7 +79,7 @@ export default function EditNodeModal({ data }: { data: NodeDataType }) {
}
return (
<Dialog open={true} onOpenChange={setModalOpen} >
<Dialog open={true} onOpenChange={setModalOpen}>
<DialogTrigger asChild></DialogTrigger>
<DialogContent className="lg:max-w-[700px] ">
<DialogHeader>

View file

@ -62,7 +62,7 @@ export default function ExtraSidebar() {
return (
<div className="w-52 flex flex-col overflow-hidden scrollbar-hide h-full border-r">
<div className="mt-2 mb-2 w-full flex gap-2 justify-between px-2 items-center">
<ShadTooltip delayDuration={1000} content="Import" side="top">
<ShadTooltip content="Import" side="top">
<button
className="hover:dark:hover:bg-[#242f47] text-gray-700 w-full justify-center shadow-sm transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 relative inline-flex items-center rounded-md bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
onClick={() => {
@ -74,7 +74,7 @@ export default function ExtraSidebar() {
</button>
</ShadTooltip>
<ShadTooltip delayDuration={1000} content="Export" side="top">
<ShadTooltip content="Export" side="top">
<button
className={classNames(
"hover:dark:hover:bg-[#242f47] text-gray-700 w-full justify-center shadow-sm transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 relative inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 rounded-md"
@ -86,7 +86,7 @@ export default function ExtraSidebar() {
<FileDown className="w-5 h-5 dark:text-gray-300"></FileDown>
</button>
</ShadTooltip>
<ShadTooltip delayDuration={1000} content="Code" side="top">
<ShadTooltip content="Code" side="top">
<button
className={classNames(
"hover:dark:hover:bg-[#242f47] text-gray-700 w-full justify-center shadow-sm transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 relative inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 rounded-md"
@ -99,7 +99,7 @@ export default function ExtraSidebar() {
</button>
</ShadTooltip>
<ShadTooltip delayDuration={1000} content="Save" side="top">
<ShadTooltip content="Save" side="top">
<button
className="hover:dark:hover:bg-[#242f47] text-gray-700 w-full justify-center transition-all shadow-sm duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 relative inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 rounded-md"
onClick={(event) => {
@ -156,7 +156,6 @@ export default function ExtraSidebar() {
.map((t: string, k) => (
<ShadTooltip
content={data[d][t].display_name}
delayDuration={1500}
side="right"
key={data[d][t].display_name}
>

View file

@ -1,5 +1,5 @@
import { useContext, useState } from "react";
import { Settings2, Copy, Trash2 } from "lucide-react";
import { Settings2, Copy, Trash2, FileText } from "lucide-react";
import { classNames } from "../../../../utils";
import { TabsContext } from "../../../../contexts/tabsContext";
import { useReactFlow } from "reactflow";
@ -29,23 +29,21 @@ const NodeToolbarComponent = (props) => {
<>
<div className="h-10 w-26">
<span className="isolate inline-flex rounded-md shadow-sm">
<ShadTooltip delayDuration={1000} content="Delete" side="top">
<ShadTooltip content="Delete" side="top">
<button
className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative inline-flex items-center rounded-l-md bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10"
className="hover:dark:hover:bg-[#242f47] text-foreground transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-muted-foreground shadow-md relative inline-flex items-center rounded-l-md bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10"
onClick={() => {
props.deleteNode(props.data.id);
}}
>
<Trash2 className="w-4 h-4 dark:text-gray-300"></Trash2>
<Trash2 className="w-4 h-4 dark:text-muted-foreground"></Trash2>
</button>
</ShadTooltip>
<ShadTooltip delayDuration={1000} content="Duplicate" side="top">
<ShadTooltip content="Duplicate" side="top">
<button
className={classNames(
nodeLength > 0
? "hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10"
: "hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md"
"hover:dark:hover:bg-[#242f47] text-foreground transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-muted-foreground shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10"
)}
onClick={(event) => {
event.preventDefault();
@ -64,31 +62,64 @@ const NodeToolbarComponent = (props) => {
);
}}
>
<Copy className="w-4 h-4 dark:text-gray-300"></Copy>
<Copy className="w-4 h-4 dark:text-muted-foreground"></Copy>
</button>
</ShadTooltip>
{nodeLength > 0 && (
<ShadTooltip delayDuration={1000} content="Edit" side="top">
<button
className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md"
onClick={(event) => {
<ShadTooltip
content={
props.data.node.documentation === ""
? "Coming Soon"
: "Documentation"
}
side="top"
>
<a
className={classNames(
"hover:dark:hover:bg-[#242f47] transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-muted-foreground shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10" +
(props.data.node.documentation === ""
? " text-muted-foreground"
: " text-foreground")
)}
href={props.data.node.documentation}
// deactivate link if no documentation is provided
onClick={(event) => {
if (props.data.node.documentation === "") {
event.preventDefault();
props.openPopUp(<EditNodeModal data={props.data} />);
}}
>
<Settings2 className="w-4 h-4 dark:text-gray-300"></Settings2>
</button>
</ShadTooltip>
)}
}
}}
>
<FileText className="w-4 h-4 dark:text-muted-foreground"></FileText>
</a>
</ShadTooltip>
<ShadTooltip content="Edit" side="top">
<button
className={classNames(
"hover:dark:hover:bg-[#242f47] transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-muted-foreground shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md" +
(nodeLength == 0
? " text-muted-foreground"
: " text-foreground")
)}
onClick={(event) => {
if (nodeLength == 0) {
event.preventDefault();
}
event.preventDefault();
props.openPopUp(<EditNodeModal data={props.data} />);
}}
>
<Settings2 className="w-4 h-4 dark:text-muted-foreground"></Settings2>
</button>
</ShadTooltip>
{/*
<Menu as="div" className="relative inline-block text-left z-100">
<button className="hover:dark:hover:bg-[#242f47] text-gray-700 transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-gray-300 shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md">
<button className="hover:dark:hover:bg-[#242f47] text-foreground transition-all duration-500 ease-in-out dark:bg-gray-800 dark:text-muted-foreground shadow-md relative -ml-px inline-flex items-center bg-white px-2 py-2 ring-1 ring-inset ring-gray-300 hover:bg-muted focus:z-10 rounded-r-md">
<div>
<Menu.Button className="flex items-center">
<EllipsisVerticalIcon
className="w-5 h-5 dark:text-gray-300"
className="w-5 h-5 dark:text-muted-foreground"
aria-hidden="true"
/>
</Menu.Button>
@ -117,7 +148,7 @@ const NodeToolbarComponent = (props) => {
className={classNames(
active
? "bg-muted text-gray-900"
: "text-gray-700",
: "text-foreground",
"w-full group flex items-center px-4 py-2 text-sm"
)}
>
@ -157,7 +188,7 @@ const NodeToolbarComponent = (props) => {
className={classNames(
active
? "bg-muted text-gray-900"
: "text-gray-700",
: "text-foreground",
"w-full group flex items-center px-4 py-2 text-sm"
)}
>

View file

@ -12,6 +12,7 @@ export type APIClassType = {
description: string;
template: APITemplateType;
display_name: string;
documentation: string;
[key: string]: Array<string> | string | APITemplateType;
};
export type TemplateVariableType = {

View file

@ -1,10 +1,4 @@
import {
ComponentType,
ForwardRefExoticComponent,
ReactElement,
ReactNode,
SVGProps,
} from "react";
import { ReactElement, ReactNode } from "react";
import { NodeDataType } from "../flow/index";
import { typesContextType } from "../typesContext";
export type InputComponentType = {
@ -41,6 +35,7 @@ export type ParameterComponentType = {
name?: string;
tooltipTitle: string;
dataContext?: typesContextType;
info?: string;
};
export type InputListComponentType = {
value: string[];
@ -115,3 +110,12 @@ export type RadialProgressType = {
value?: number;
color?: string;
};
export type Side = "top" | "right" | "bottom" | "left";
export type ShadTooltipProps = {
delayDuration?: number;
side?: Side;
content: ReactNode;
children: ReactNode;
};

View file

@ -978,5 +978,5 @@ export function getRandomKeyByssmm(): string {
const now = new Date();
const seconds = String(now.getSeconds()).padStart(2, "0");
const milliseconds = String(now.getMilliseconds()).padStart(3, "0");
return seconds + milliseconds;
return seconds + milliseconds + Math.abs(Math.floor(Math.random() * 10001));
}

View file

@ -26,6 +26,7 @@ def test_zero_shot_agent(client: TestClient):
"type": "LLMChain",
"list": False,
"advanced": False,
"info": "",
}
assert template["allowed_tools"] == {
"required": False,
@ -37,6 +38,7 @@ def test_zero_shot_agent(client: TestClient):
"type": "Tool",
"list": True,
"advanced": False,
"info": "",
}
@ -60,6 +62,7 @@ def test_json_agent(client: TestClient):
"type": "BaseToolkit",
"list": False,
"advanced": False,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -72,6 +75,7 @@ def test_json_agent(client: TestClient):
"list": False,
"advanced": False,
"display_name": "LLM",
"info": "",
}
@ -99,6 +103,7 @@ def test_csv_agent(client: TestClient):
"list": False,
"file_path": None,
"advanced": False,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -111,6 +116,7 @@ def test_csv_agent(client: TestClient):
"list": False,
"advanced": False,
"display_name": "LLM",
"info": "",
}
@ -143,6 +149,7 @@ def test_initialize_agent(client: TestClient):
"type": "str",
"list": True,
"advanced": False,
"info": "",
}
assert template["memory"] == {
"required": False,
@ -154,6 +161,7 @@ def test_initialize_agent(client: TestClient):
"type": "BaseChatMemory",
"list": False,
"advanced": False,
"info": "",
}
assert template["tools"] == {
"required": False,
@ -165,6 +173,7 @@ def test_initialize_agent(client: TestClient):
"type": "Tool",
"list": True,
"advanced": False,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -177,4 +186,5 @@ def test_initialize_agent(client: TestClient):
"list": False,
"advanced": False,
"display_name": "LLM",
"info": "",
}

View file

@ -38,6 +38,7 @@ def test_conversation_chain(client: TestClient):
"type": "BaseMemory",
"list": False,
"advanced": False,
"info": "",
}
assert template["verbose"] == {
"required": False,
@ -49,6 +50,7 @@ def test_conversation_chain(client: TestClient):
"type": "bool",
"list": False,
"advanced": True,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -60,6 +62,7 @@ def test_conversation_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["input_key"] == {
"required": True,
@ -72,6 +75,7 @@ def test_conversation_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": True,
"info": "",
}
assert template["output_key"] == {
"required": True,
@ -84,6 +88,7 @@ def test_conversation_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": True,
"info": "",
}
assert template["_type"] == "ConversationChain"
@ -120,6 +125,7 @@ def test_llm_chain(client: TestClient):
"type": "BaseMemory",
"list": False,
"advanced": False,
"info": "",
}
assert template["verbose"] == {
"required": False,
@ -132,6 +138,7 @@ def test_llm_chain(client: TestClient):
"type": "bool",
"list": False,
"advanced": True,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -143,6 +150,7 @@ def test_llm_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["output_key"] == {
"required": True,
@ -155,6 +163,7 @@ def test_llm_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": True,
"info": "",
}
@ -184,6 +193,7 @@ def test_llm_checker_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["_type"] == "LLMCheckerChain"
@ -217,6 +227,7 @@ def test_llm_math_chain(client: TestClient):
"type": "BaseMemory",
"list": False,
"advanced": False,
"info": "",
}
assert template["verbose"] == {
"required": False,
@ -229,6 +240,7 @@ def test_llm_math_chain(client: TestClient):
"type": "bool",
"list": False,
"advanced": True,
"info": "",
}
assert template["llm"] == {
"required": True,
@ -240,6 +252,7 @@ def test_llm_math_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["input_key"] == {
"required": True,
@ -252,6 +265,7 @@ def test_llm_math_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": True,
"info": "",
}
assert template["output_key"] == {
"required": True,
@ -264,6 +278,7 @@ def test_llm_math_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": True,
"info": "",
}
assert template["_type"] == "LLMMathChain"
@ -304,6 +319,7 @@ def test_series_character_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["character"] == {
"required": True,
@ -315,6 +331,7 @@ def test_series_character_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": False,
"info": "",
}
assert template["series"] == {
"required": True,
@ -326,6 +343,7 @@ def test_series_character_chain(client: TestClient):
"type": "str",
"list": False,
"advanced": False,
"info": "",
}
assert template["_type"] == "SeriesCharacterChain"
@ -367,6 +385,7 @@ def test_mid_journey_prompt_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
# Test the description object
assert (
@ -406,6 +425,7 @@ def test_time_travel_guide_chain(client: TestClient):
"type": "BaseLanguageModel",
"list": False,
"advanced": False,
"info": "",
}
assert template["memory"] == {
"required": False,
@ -417,6 +437,7 @@ def test_time_travel_guide_chain(client: TestClient):
"type": "BaseChatMemory",
"list": False,
"advanced": False,
"info": "",
}
assert chain["description"] == "Time travel guide chain."

View file

@ -121,6 +121,7 @@ def test_openai(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
"info": "",
}
assert template["verbose"] == {
"required": False,
@ -132,6 +133,7 @@ def test_openai(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
"info": "",
}
assert template["client"] == {
"required": False,
@ -143,6 +145,7 @@ def test_openai(client: TestClient):
"type": "Any",
"list": False,
"advanced": False,
"info": "",
}
assert template["model_name"] == {
"required": False,
@ -162,6 +165,7 @@ def test_openai(client: TestClient):
"type": "str",
"list": True,
"advanced": False,
"info": "",
}
# Add more assertions for other properties here
assert template["temperature"] == {
@ -175,6 +179,7 @@ def test_openai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["max_tokens"] == {
"required": False,
@ -187,6 +192,7 @@ def test_openai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["top_p"] == {
"required": False,
@ -199,6 +205,7 @@ def test_openai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["frequency_penalty"] == {
"required": False,
@ -211,6 +218,7 @@ def test_openai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["presence_penalty"] == {
"required": False,
@ -223,6 +231,7 @@ def test_openai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["n"] == {
"required": False,
@ -235,6 +244,7 @@ def test_openai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["best_of"] == {
"required": False,
@ -247,6 +257,7 @@ def test_openai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["model_kwargs"] == {
"required": False,
@ -258,6 +269,7 @@ def test_openai(client: TestClient):
"type": "code",
"list": False,
"advanced": True,
"info": "",
}
assert template["openai_api_key"] == {
"required": False,
@ -271,6 +283,7 @@ def test_openai(client: TestClient):
"type": "str",
"list": False,
"advanced": False,
"info": "",
}
assert template["batch_size"] == {
"required": False,
@ -283,6 +296,7 @@ def test_openai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["request_timeout"] == {
"required": False,
@ -294,6 +308,7 @@ def test_openai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["logit_bias"] == {
"required": False,
@ -305,6 +320,7 @@ def test_openai(client: TestClient):
"type": "code",
"list": False,
"advanced": False,
"info": "",
}
assert template["max_retries"] == {
"required": False,
@ -317,6 +333,7 @@ def test_openai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["streaming"] == {
"required": False,
@ -329,6 +346,7 @@ def test_openai(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
"info": "",
}
@ -352,6 +370,7 @@ def test_chat_open_ai(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
"info": "",
}
assert template["client"] == {
"required": False,
@ -363,6 +382,7 @@ def test_chat_open_ai(client: TestClient):
"type": "Any",
"list": False,
"advanced": False,
"info": "",
}
assert template["model_name"] == {
"required": False,
@ -385,6 +405,7 @@ def test_chat_open_ai(client: TestClient):
"type": "str",
"list": True,
"advanced": False,
"info": "",
}
assert template["temperature"] == {
"required": False,
@ -397,6 +418,7 @@ def test_chat_open_ai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["model_kwargs"] == {
"required": False,
@ -408,6 +430,7 @@ def test_chat_open_ai(client: TestClient):
"type": "code",
"list": False,
"advanced": True,
"info": "",
}
assert template["openai_api_key"] == {
"required": False,
@ -421,6 +444,7 @@ def test_chat_open_ai(client: TestClient):
"type": "str",
"list": False,
"advanced": False,
"info": "",
}
assert template["request_timeout"] == {
"required": False,
@ -432,6 +456,7 @@ def test_chat_open_ai(client: TestClient):
"type": "float",
"list": False,
"advanced": False,
"info": "",
}
assert template["max_retries"] == {
"required": False,
@ -444,6 +469,7 @@ def test_chat_open_ai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["streaming"] == {
"required": False,
@ -456,6 +482,7 @@ def test_chat_open_ai(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
"info": "",
}
assert template["n"] == {
"required": False,
@ -468,6 +495,7 @@ def test_chat_open_ai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["max_tokens"] == {
@ -480,6 +508,7 @@ def test_chat_open_ai(client: TestClient):
"type": "int",
"list": False,
"advanced": False,
"info": "",
}
assert template["_type"] == "ChatOpenAI"
assert (

View file

@ -28,6 +28,7 @@ def test_prompt_template(client: TestClient):
"type": "str",
"list": True,
"advanced": False,
"info": "",
}
assert template["output_parser"] == {
"required": False,
@ -39,6 +40,7 @@ def test_prompt_template(client: TestClient):
"type": "BaseOutputParser",
"list": False,
"advanced": False,
"info": "",
}
assert template["partial_variables"] == {
"required": False,
@ -50,6 +52,7 @@ def test_prompt_template(client: TestClient):
"type": "code",
"list": False,
"advanced": False,
"info": "",
}
assert template["template"] == {
"required": True,
@ -61,6 +64,7 @@ def test_prompt_template(client: TestClient):
"type": "prompt",
"list": False,
"advanced": False,
"info": "",
}
assert template["template_format"] == {
"required": False,
@ -73,6 +77,7 @@ def test_prompt_template(client: TestClient):
"type": "str",
"list": False,
"advanced": False,
"info": "",
}
assert template["validate_template"] == {
"required": False,
@ -85,85 +90,7 @@ def test_prompt_template(client: TestClient):
"type": "bool",
"list": False,
"advanced": False,
}
def test_few_shot_prompt_template(client: TestClient):
response = client.get("api/v1/all")
assert response.status_code == 200
json_response = response.json()
prompts = json_response["prompts"]
prompt = prompts["FewShotPromptTemplate"]
template = prompt["template"]
# Test other fields in the template similar to PromptTemplate
assert template["examples"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": True,
"password": False,
"name": "examples",
"type": "prompt",
"list": True,
"advanced": False,
}
assert template["example_selector"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "example_selector",
"type": "BaseExampleSelector",
"list": False,
"advanced": False,
}
assert template["example_prompt"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"password": False,
"name": "example_prompt",
"type": "PromptTemplate",
"list": False,
"advanced": False,
}
assert template["suffix"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": True,
"password": False,
"name": "suffix",
"type": "prompt",
"list": False,
"advanced": False,
}
assert template["example_separator"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"value": "\n\n",
"password": False,
"name": "example_separator",
"type": "str",
"list": False,
"advanced": False,
}
assert template["prefix"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": True,
"value": "",
"password": False,
"name": "prefix",
"type": "prompt",
"list": False,
"advanced": False,
"info": "",
}
@ -185,6 +112,7 @@ def test_zero_shot_prompt(client: TestClient):
"type": "prompt",
"list": False,
"advanced": False,
"info": "",
}
assert template["suffix"] == {
"required": True,
@ -197,6 +125,7 @@ def test_zero_shot_prompt(client: TestClient):
"type": "prompt",
"list": False,
"advanced": False,
"info": "",
}
assert template["format_instructions"] == {
"required": True,
@ -209,4 +138,5 @@ def test_zero_shot_prompt(client: TestClient):
"type": "prompt",
"list": False,
"advanced": False,
"info": "",
}