merged chat_and_cache into dev

This commit is contained in:
anovazzi1 2023-04-29 01:26:44 -03:00
commit 8a169c9782
35 changed files with 1632 additions and 966 deletions

View file

@ -0,0 +1,15 @@
# LangFlow Demo Codespace Readme
These instructions will walk you through the process of running a LangFlow demo via GitHub Codespaces.
## Setup
### Create a Codespace in GitHub
To setup the demo, simply navigate to the Langflow repo, click the "+" button, and select "Create new Codespace". This will automatically create a new codespace in your browser, which you can use for the demo.
### Wait for everything to install
After the codespace is opened, you should see a new Terminal window in VS Code where langflow is installed. Once the install completes, `langflow` will launch the webserver and your application will be available via devcontainer port.
Note: VS Code should prompt you with a button to push once the port is available.

View file

@ -0,0 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
{
"name": "LangChain Demo Container",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/python:3.10",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker": {},
"ghcr.io/devcontainers/features/node": {}
},
"customizations": {
"vscode": {
"extensions": [
"actboy168.tasks",
"GitHub.copilot",
"ms-python.python",
"eamodio.gitlens"
]
}
},
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pipx install 'langflow>=0.0.33' && langflow --host 0.0.0.0"
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View file

@ -1,11 +1,12 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the // For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/universal // README at: https://github.com/devcontainers/templates/tree/main/src/universal
{ {
"name": "Default Linux Universal", "name": "LangChain Dev Container",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/universal:2-linux", "image": "mcr.microsoft.com/devcontainers/universal:2-linux",
"features": { "features": {
"ghcr.io/devcontainers/features/aws-cli:1": {} "ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker": {}
}, },
"customizations": { "customizations": {
"vscode": {"extensions": [ "vscode": {"extensions": [
@ -15,7 +16,7 @@
"sourcery.sourcery", "sourcery.sourcery",
"eamodio.gitlens" "eamodio.gitlens"
]} ]}
} },
// Features to add to the dev container. More info: https://containers.dev/features. // Features to add to the dev container. More info: https://containers.dev/features.
// "features": {}, // "features": {},
@ -24,7 +25,7 @@
// "forwardPorts": [], // "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created. // Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "uname -a", "postCreateCommand": "poetry install"
// Configure tool-specific properties. // Configure tool-specific properties.
// "customizations": {}, // "customizations": {},

View file

@ -5,6 +5,7 @@
~ A User Interface For [LangChain](https://github.com/hwchase17/langchain) ~ ~ A User Interface For [LangChain](https://github.com/hwchase17/langchain) ~
<p> <p>
<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>
<img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/logspace-ai/langflow" /> <img alt="GitHub Contributors" src="https://img.shields.io/github/contributors/logspace-ai/langflow" />
<img alt="GitHub Last Commit" src="https://img.shields.io/github/last-commit/logspace-ai/langflow" /> <img alt="GitHub Last Commit" src="https://img.shields.io/github/last-commit/logspace-ai/langflow" />
<img alt="" src="https://img.shields.io/github/repo-size/logspace-ai/langflow" /> <img alt="" src="https://img.shields.io/github/repo-size/logspace-ai/langflow" />
@ -31,7 +32,7 @@ Next, run:
```shell ```shell
python -m langflow python -m langflow
``` ```
or or
```shell ```shell
langflow langflow
``` ```

764
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "langflow" name = "langflow"
version = "0.0.57" version = "0.0.59"
description = "A Python package with a built-in web application" description = "A Python package with a built-in web application"
authors = ["Logspace <contact@logspace.ai>"] authors = ["Logspace <contact@logspace.ai>"]
maintainers = [ maintainers = [
@ -29,7 +29,7 @@ google-search-results = "^2.4.1"
google-api-python-client = "^2.79.0" google-api-python-client = "^2.79.0"
typer = "^0.7.0" typer = "^0.7.0"
gunicorn = "^20.1.0" gunicorn = "^20.1.0"
langchain = "^0.0.131" langchain = "~0.0.150"
openai = "^0.27.2" openai = "^0.27.2"
types-pyyaml = "^6.0.12.8" types-pyyaml = "^6.0.12.8"
dill = "^0.3.6" dill = "^0.3.6"
@ -58,6 +58,8 @@ httpx = "^0.23.3"
pytest = "^7.2.2" pytest = "^7.2.2"
types-requests = "^2.28.11" types-requests = "^2.28.11"
requests = "^2.28.0" requests = "^2.28.0"
pytest-cov = "^4.0.0"
[tool.ruff] [tool.ruff]
line-length = 120 line-length = 120

View file

@ -15,6 +15,11 @@ CUSTOM_NODES = {
"utilities": { "utilities": {
"SQLDatabase": nodes.SQLDatabaseNode(), "SQLDatabase": nodes.SQLDatabaseNode(),
}, },
"chains": {
"SeriesCharacterChain": nodes.SeriesCharacterChainNode(),
"TimeTravelGuideChain": nodes.TimeTravelGuideChainNode(),
"MidJourneyPromptChain": nodes.MidJourneyPromptChainNode(),
},
} }

View file

@ -174,7 +174,7 @@ class SQLAgent(AgentExecutor):
def from_toolkit_and_llm(cls, llm: BaseLLM, database_uri: str, **kwargs: Any): def from_toolkit_and_llm(cls, llm: BaseLLM, database_uri: str, **kwargs: Any):
"""Construct a sql agent from an LLM and tools.""" """Construct a sql agent from an LLM and tools."""
db = SQLDatabase.from_uri(database_uri) db = SQLDatabase.from_uri(database_uri)
toolkit = SQLDatabaseToolkit(db=db) toolkit = SQLDatabaseToolkit(db=db, llm=llm)
# The right code should be this, but there is a problem with tools = toolkit.get_tools() # The right code should be this, but there is a problem with tools = toolkit.get_tools()
# related to `OPENAI_API_KEY` # related to `OPENAI_API_KEY`
@ -274,7 +274,11 @@ class InitializeAgent(AgentExecutor):
@classmethod @classmethod
def initialize( def initialize(
cls, llm: BaseLLM, tools: List[Tool], agent: str, memory: BaseChatMemory cls,
llm: BaseLLM,
tools: List[Tool],
agent: str,
memory: Optional[BaseChatMemory] = None,
): ):
return initialize_agent( return initialize_agent(
tools=tools, tools=tools,

View file

@ -186,7 +186,9 @@ def load_agent_executor(agent_class: type[agent_module.Agent], params, **kwargs)
allowed_tools = params["allowed_tools"] allowed_tools = params["allowed_tools"]
llm_chain = params["llm_chain"] llm_chain = params["llm_chain"]
tool_names = [tool.name for tool in allowed_tools] tool_names = [tool.name for tool in allowed_tools]
agent = agent_class(allowed_tools=tool_names, llm_chain=llm_chain) # 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( return AgentExecutor.from_agent_and_tools(
agent=agent, agent=agent,
tools=allowed_tools, tools=allowed_tools,

View file

@ -1,7 +1,7 @@
import contextlib import contextlib
import io import io
from typing import Any, Dict from typing import Any, Dict
from chromadb.errors import NotEnoughElementsException from chromadb.errors import NotEnoughElementsException # type: ignore
from langflow.cache.base import compute_dict_hash, load_cache, memoize_dict from langflow.cache.base import compute_dict_hash, load_cache, memoize_dict
from langflow.graph.graph import Graph from langflow.graph.graph import Graph

View file

@ -23,6 +23,7 @@ class TemplateFieldCreator(BaseModel, ABC):
options: list[str] = [] options: list[str] = []
name: str = "" name: str = ""
display_name: Optional[str] = None display_name: Optional[str] = None
advanced: bool = True
def to_dict(self): def to_dict(self):
result = self.dict() result = self.dict()
@ -225,6 +226,19 @@ class FrontendNode(BaseModel):
field.is_list = True field.is_list = True
if "api_key" in key and "OpenAI" in str(name): if "api_key" in key and "OpenAI" in str(name):
field.display_name = "OpenAI API Key" field.display_name = "OpenAI API Key"
field.required = True field.required = False
if field.value is None: if field.value is None:
field.value = "" field.value = ""
# If the field.name contains api or api and key, then it might be an api key
# other conditions are to make sure that it is not an input or output variable
if "api" in key.lower() and "key" in key.lower():
field.required = False
if "kwargs" in field.name.lower():
field.advanced = True
field.required = False
field.show = False
# If the field.name contains api or api and key, then it might be an api key
# other conditions are to make sure that it is not an input or output variable
if "api" in key.lower() and "key" in key.lower():
field.required = False

View file

@ -101,6 +101,107 @@ class PythonFunctionNode(FrontendNode):
return super().to_dict() return super().to_dict()
class MidJourneyPromptChainNode(FrontendNode):
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",
),
],
)
description: str = "MidJourneyPromptChain is a chain you can use to generate new MidJourney prompts."
base_classes: list[str] = [
"LLMChain",
"BaseCustomChain",
"Chain",
"ConversationChain",
"MidJourneyPromptChain",
]
class TimeTravelGuideChainNode(FrontendNode):
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",
),
],
)
description: str = "Time travel guide chain to be used in the flow."
base_classes: list[str] = [
"LLMChain",
"BaseCustomChain",
"TimeTravelGuideChain",
"Chain",
"ConversationChain",
]
class SeriesCharacterChainNode(FrontendNode):
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",
),
],
)
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",
]
class ToolNode(FrontendNode): class ToolNode(FrontendNode):
name: str = "Tool" name: str = "Tool"
template: Template = Template( template: Template = Template(
@ -418,17 +519,29 @@ class ChainFrontendNode(FrontendNode):
def format_field(field: TemplateField, name: Optional[str] = None) -> None: def format_field(field: TemplateField, name: Optional[str] = None) -> None:
FrontendNode.format_field(field, name) FrontendNode.format_field(field, name)
field.advanced = False
if "key" in field.name: if "key" in field.name:
field.password = False field.password = False
field.show = False field.show = False
if field.name in ["input_key", "output_key"]: if field.name in ["input_key", "output_key"]:
field.required = True field.required = True
field.show = True field.show = True
field.advanced = True
# Separated for possible future changes # Separated for possible future changes
if field.name == "prompt" and field.value is None: if field.name == "prompt" and field.value is None:
# if no prompt is provided, use the default prompt # if no prompt is provided, use the default prompt
field.required = False field.required = False
field.show = 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 = True
field.advanced = True
class LLMFrontendNode(FrontendNode): class LLMFrontendNode(FrontendNode):
@ -438,22 +551,31 @@ class LLMFrontendNode(FrontendNode):
"huggingfacehub_api_token": "HuggingFace Hub API Token", "huggingfacehub_api_token": "HuggingFace Hub API Token",
} }
FrontendNode.format_field(field, name) FrontendNode.format_field(field, name)
SHOW_FIELDS = ["repo_id", "task", "model_kwargs"] SHOW_FIELDS = ["repo_id"]
if field.name in SHOW_FIELDS: if field.name in SHOW_FIELDS:
field.show = True field.show = True
if "api" in field.name and ("key" in field.name or "token" in field.name): if "api" in field.name and ("key" in field.name or "token" in field.name):
field.password = True field.password = True
field.show = True field.show = True
field.required = True # Required should be False to support
# loading the API key from environment variables
field.required = False
field.advanced = False
if field.name == "task": if field.name == "task":
field.required = True field.required = True
field.show = True field.show = True
field.is_list = True field.is_list = True
field.options = ["text-generation", "text2text-generation"] field.options = ["text-generation", "text2text-generation"]
field.advanced = True
if display_name := display_names_dict.get(field.name): if display_name := display_names_dict.get(field.name):
field.display_name = display_name field.display_name = display_name
if field.name == "model_kwargs": if field.name == "model_kwargs":
field.field_type = "code" field.field_type = "code"
field.advanced = True
field.show = True
elif field.name in ["model_name", "temperature"]:
field.advanced = False
field.show = True

View file

@ -1,4 +1,4 @@
import { TrashIcon } from "@heroicons/react/24/outline"; import { Cog6ToothIcon, TrashIcon } from "@heroicons/react/24/outline";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
import { import {
classNames, classNames,
@ -11,6 +11,8 @@ import { typesContext } from "../../contexts/typesContext";
import { useContext, useState, useEffect, useRef } from "react"; import { useContext, useState, useEffect, useRef } from "react";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
import NodeModal from "../../modals/NodeModal";
import { useCallback } from "react"; import { useCallback } from "react";
import { TabsContext } from "../../contexts/tabsContext"; import { TabsContext } from "../../contexts/tabsContext";
export default function GenericNode({ export default function GenericNode({
@ -23,6 +25,7 @@ export default function GenericNode({
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const showError = useRef(true); const showError = useRef(true);
const { types, deleteNode } = useContext(typesContext); const { types, deleteNode } = useContext(typesContext);
const { openPopUp } = useContext(PopUpContext);
const Icon = nodeIcons[types[data.type]]; const Icon = nodeIcons[types[data.type]];
const [validationStatus, setValidationStatus] = useState("idle"); const [validationStatus, setValidationStatus] = useState("idle");
// State for outline color // State for outline color
@ -101,17 +104,46 @@ export default function GenericNode({
/> />
<div className="truncate">{data.type}</div> <div className="truncate">{data.type}</div>
</div> </div>
<button <div className="flex gap-3">
onClick={() => { <button
deleteNode(data.id); className="relative"
}} onClick={(event) => {
> event.preventDefault();
<TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-500"></TrashIcon> openPopUp(<NodeModal data={data} />);
</button> }}
>
<div className=" absolute text-red-600 -top-2 -right-1">
{Object.keys(data.node.template).some(
(t) =>
data.node.template[t].advanced &&
data.node.template[t].required
)
? " *"
: ""}
</div>
<Cog6ToothIcon
className={classNames(
Object.keys(data.node.template).some(
(t) => data.node.template[t].advanced && data.node.template[t].show
)
? ""
: "hidden",
"w-6 h-6 dark:text-gray-500 hover:animate-spin"
)}
></Cog6ToothIcon>
</button>
<button
onClick={() => {
deleteNode(data.id);
}}
>
<TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-500"></TrashIcon>
</button>
</div>
</div> </div>
<div className="w-full h-full py-5"> <div className="w-full h-full py-5">
<div className="w-full text-gray-500 px-5 text-sm"> <div className="w-full text-gray-500 px-5 pb-3 text-sm">
{data.node.description} {data.node.description}
</div> </div>
@ -120,7 +152,7 @@ export default function GenericNode({
.filter((t) => t.charAt(0) !== "_") .filter((t) => t.charAt(0) !== "_")
.map((t: string, idx) => ( .map((t: string, idx) => (
<div key={idx}> <div key={idx}>
{idx === 0 ? ( {/* {idx === 0 ? (
<div <div
className={classNames( className={classNames(
"px-5 py-2 mt-2 dark:text-white text-center", "px-5 py-2 mt-2 dark:text-white text-center",
@ -138,8 +170,8 @@ export default function GenericNode({
</div> </div>
) : ( ) : (
<></> <></>
)} )} */}
{data.node.template[t].show ? ( {data.node.template[t].show && !data.node.template[t].advanced ? (
<ParameterComponent <ParameterComponent
data={data} data={data}
color={ color={
@ -169,9 +201,17 @@ export default function GenericNode({
)} )}
</div> </div>
))} ))}
<div className="px-5 py-2 mt-2 dark:text-white text-center"> <div
Output className={classNames(
Object.keys(data.node.template).length < 1 ? "hidden" : "",
"w-full flex justify-center"
)}
>
{" "}
</div> </div>
{/* <div className="px-5 py-2 mt-2 dark:text-white text-center">
Output
</div> */}
<ParameterComponent <ParameterComponent
data={data} data={data}
color={nodeColors[types[data.type]] ?? nodeColors.unknown} color={nodeColors[types[data.type]] ?? nodeColors.unknown}

View file

@ -19,9 +19,24 @@ export default function CodeAreaComponent({
} }
}, [disabled, onChange]); }, [disabled, onChange]);
return ( return (
<div className={disabled ? "pointer-events-none cursor-not-allowed w-full" : "w-full"}> <div
className={
disabled ? "pointer-events-none cursor-not-allowed w-full" : "w-full"
}
>
<div className="w-full flex items-center gap-3"> <div className="w-full flex items-center gap-3">
<span <span
onClick={() => {
openPopUp(
<CodeAreaModal
value={myValue}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
/>
);
}}
className={ className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "") (disabled ? " bg-gray-200" : "")

View file

@ -69,6 +69,7 @@ export default function InputFileComponent({
> >
<div className="w-full flex items-center gap-3"> <div className="w-full flex items-center gap-3">
<span <span
onClick={handleButtonClick}
className={ className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "") (disabled ? " bg-gray-200" : "")

View file

@ -6,30 +6,61 @@ import TextAreaModal from "../../modals/textAreaModal";
import { TextAreaComponentType } from "../../types/components"; import { TextAreaComponentType } from "../../types/components";
import PromptAreaModal from "../../modals/promptModal"; import PromptAreaModal from "../../modals/promptModal";
export default function PromptAreaComponent({ value, onChange, disabled }:TextAreaComponentType) { export default function PromptAreaComponent({
const [myValue, setMyValue] = useState(value); value,
const { openPopUp } = useContext(PopUpContext); onChange,
useEffect(() => { disabled,
if (disabled) { }: TextAreaComponentType) {
setMyValue(""); const [myValue, setMyValue] = useState(value);
onChange(""); const { openPopUp } = useContext(PopUpContext);
} useEffect(() => {
}, [disabled, onChange]); if (disabled) {
return ( setMyValue("");
<div className={disabled ? "pointer-events-none cursor-not-allowed w-full" : " w-full"}> onChange("");
<div className="w-full flex items-center gap-3"> }
<span }, [disabled, onChange]);
className={ return (
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + <div
(disabled ? " bg-gray-200" : "") className={
} disabled ? "pointer-events-none cursor-not-allowed w-full" : " w-full"
> }
{myValue !== "" ? myValue : 'Text empty'} >
</span> <div className="w-full flex items-center gap-3">
<button onClick={()=>{openPopUp(<PromptAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}}> <span
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600" /> onClick={() => {
</button> openPopUp(
</div> <PromptAreaModal
</div> value={myValue}
); setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
/>
);
}}
className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "")
}
>
{myValue !== "" ? myValue : "Text empty"}
</span>
<button
onClick={() => {
openPopUp(
<PromptAreaModal
value={myValue}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
/>
);
}}
>
<ArrowTopRightOnSquareIcon className="w-6 h-6 hover:text-blue-600" />
</button>
</div>
</div>
);
} }

View file

@ -1,7 +1,6 @@
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline"; import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
import CodeAreaModal from "../../modals/codeAreaModal";
import TextAreaModal from "../../modals/textAreaModal"; import TextAreaModal from "../../modals/textAreaModal";
import { TextAreaComponentType } from "../../types/components"; import { TextAreaComponentType } from "../../types/components";
@ -17,7 +16,7 @@ export default function TextAreaComponent({ value, onChange, disabled }:TextArea
return ( return (
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}> <div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
<div className="w-full flex items-center gap-3"> <div className="w-full flex items-center gap-3">
<span <span onClick={()=>{openPopUp(<TextAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}}
className={ className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + "truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "") (disabled ? " bg-gray-200" : "")

View file

@ -11,15 +11,15 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
return ( return (
<> <>
<DarkProvider> <DarkProvider>
<LocationProvider> <TypesProvider>
<AlertProvider> <LocationProvider>
<TabsProvider> <AlertProvider>
<TypesProvider> <TabsProvider>
<PopUpProvider>{children}</PopUpProvider> <PopUpProvider>{children}</PopUpProvider>
</TypesProvider> </TabsProvider>
</TabsProvider> </AlertProvider>
</AlertProvider> </LocationProvider>
</LocationProvider> </TypesProvider>
</DarkProvider> </DarkProvider>
</> </>
); );

View file

@ -1,33 +1,33 @@
import { createContext } from "react"; import { createContext } from "react";
import React, { useState } from "react"; import React, { useState } from "react";
//context to set JSX element on the DOM // context to set JSX element on the DOM
export const PopUpContext = createContext({ export const PopUpContext = createContext({
openPopUp: (popUpElement: JSX.Element) => {}, openPopUp: (popUpElement: JSX.Element) => {},
closePopUp: () => {}, closePopUp: () => {},
}); });
interface PopUpProviderProps { interface PopUpProviderProps {
children: React.ReactNode; children: React.ReactNode;
} }
const PopUpProvider = ({ children }: PopUpProviderProps) => { const PopUpProvider = ({ children }: PopUpProviderProps) => {
const [popUpElement, setPopUpElement] = useState<JSX.Element | null>(null); const [popUpElements, setPopUpElements] = useState<JSX.Element[]>([]);
const openPopUp = (element: JSX.Element) => { const openPopUp = (element: JSX.Element) => {
setPopUpElement(element); setPopUpElements(prevPopUps => [element, ...prevPopUps]);
}; };
const closePopUp = () => { const closePopUp = () => {
setPopUpElement(null); setPopUpElements(prevPopUps => prevPopUps.slice(1));
}; };
return ( return (
<PopUpContext.Provider value={{ openPopUp, closePopUp }}> <PopUpContext.Provider value={{ openPopUp, closePopUp }}>
{children} {children}
{popUpElement} {popUpElements[0]}
</PopUpContext.Provider> </PopUpContext.Provider>
); );
}; };
export default PopUpProvider; export default PopUpProvider;

View file

@ -7,9 +7,11 @@ import {
useContext, useContext,
} from "react"; } from "react";
import { FlowType } from "../types/flow"; import { FlowType } from "../types/flow";
import { TabsContextType } from "../types/tabs"; import { LangFlowState, TabsContextType } from "../types/tabs";
import { normalCaseToSnakeCase } from "../utils"; import { normalCaseToSnakeCase, updateObject } from "../utils";
import { alertContext } from "./alertContext"; import { alertContext } from "./alertContext";
import { typesContext } from "./typesContext";
import { TemplateVariableType } from "../types/api";
const { v4: uuidv4 } = require('uuid'); const { v4: uuidv4 } = require('uuid');
const TabsContextInitialValue: TabsContextType = { const TabsContextInitialValue: TabsContextType = {
@ -35,6 +37,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const [tabIndex, setTabIndex] = useState(0); const [tabIndex, setTabIndex] = useState(0);
const [flows, setFlows] = useState<Array<FlowType>>([]); const [flows, setFlows] = useState<Array<FlowType>>([]);
const [id, setId] = useState(""); const [id, setId] = useState("");
const { templates } = useContext(typesContext);
const newNodeId = useRef(0); const newNodeId = useRef(0);
function incrementNodeId() { function incrementNodeId() {
@ -56,19 +59,31 @@ export function TabsProvider({ children }: { children: ReactNode }) {
useEffect(() => { useEffect(() => {
//get tabs locally saved //get tabs locally saved
let cookie = window.localStorage.getItem("tabsData"); let cookie = window.localStorage.getItem("tabsData");
if (cookie) { if (cookie && Object.keys(templates).length > 0) {
let cookieObject = JSON.parse(cookie); let cookieObject: LangFlowState = JSON.parse(cookie);
cookieObject.flows.forEach((flow) => {
flow.data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length>0) {
node.data.node.template = updateObject(
node.data.node.template as TemplateVariableType,
templates[node.data.type][
"template"
] as unknown as TemplateVariableType
);
}
});
});
setTabIndex(cookieObject.tabIndex); setTabIndex(cookieObject.tabIndex);
setFlows(cookieObject.flows); setFlows(cookieObject.flows);
setId(cookieObject.id); setId(cookieObject.id);
newNodeId.current = cookieObject.nodeId; newNodeId.current = cookieObject.nodeId;
} }
}, []); }, [templates]);
function hardReset() { function hardReset() {
newNodeId.current = 0; newNodeId.current = 0;
setTabIndex(0); setTabIndex(0);
setFlows([]); setFlows([]);
setId(uuidv4()); setId("");
} }
/** /**
@ -110,7 +125,19 @@ export function TabsProvider({ children }: { children: ReactNode }) {
// read the file as text // read the file as text
file.text().then((text) => { file.text().then((text) => {
// parse the text into a JSON object // parse the text into a JSON object
addFlow(JSON.parse(text)); let flow: FlowType = JSON.parse(text);
flow.data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length>0) {
node.data.node.template = updateObject(
node.data.node.template as TemplateVariableType,
templates[node.data.type][
"template"
] as unknown as TemplateVariableType
);
}
});
addFlow();
}); });
} }
}; };

View file

@ -1,6 +1,8 @@
import { createContext, ReactNode, useState } from "react"; import { createContext, ReactNode, useEffect, useState } from "react";
import { Node} from "reactflow"; import { Node} from "reactflow";
import { typesContextType } from "../types/typesContext"; import { typesContextType } from "../types/typesContext";
import { getAll } from "../controllers/API";
import { APIKindType } from "../types/api";
//context to share types adn functions from nodes to flow //context to share types adn functions from nodes to flow
@ -10,6 +12,10 @@ const initialValue:typesContextType = {
deleteNode: () => {}, deleteNode: () => {},
types: {}, types: {},
setTypes: () => {}, setTypes: () => {},
templates: {},
setTemplates: () => {},
data:{},
setData:()=>{}
}; };
export const typesContext = createContext<typesContextType>(initialValue); export const typesContext = createContext<typesContextType>(initialValue);
@ -17,6 +23,42 @@ export const typesContext = createContext<typesContextType>(initialValue);
export function TypesProvider({ children }:{children:ReactNode}) { export function TypesProvider({ children }:{children:ReactNode}) {
const [types, setTypes] = useState({}); const [types, setTypes] = useState({});
const [reactFlowInstance, setReactFlowInstance] = useState(null); const [reactFlowInstance, setReactFlowInstance] = useState(null);
const [templates, setTemplates] = useState({});
const [data, setData] = useState({});
useEffect(() => {
async function getTypes(): Promise<void> {
// Make an asynchronous API call to retrieve all data.
let result = await getAll();
// Update the state of the component with the retrieved data.
setData(result.data);
setTemplates(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType)=>{
acc[c] = result.data[curr][c]
})
return acc;
},{})
);
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
});
return acc;
}, {})
);
}
// Call the getTypes function.
getTypes();
}, [setTypes]);
function deleteNode(idx:string) { function deleteNode(idx:string) {
reactFlowInstance.setNodes( reactFlowInstance.setNodes(
reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx) reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx)
@ -31,6 +73,10 @@ export function TypesProvider({ children }:{children:ReactNode}) {
reactFlowInstance, reactFlowInstance,
setReactFlowInstance, setReactFlowInstance,
deleteNode, deleteNode,
setTemplates,
templates,
data,
setData
}} }}
> >
{children} {children}

View file

@ -0,0 +1,166 @@
import { useContext, useState } from "react";
import { TabsContext } from "../../../../contexts/tabsContext";
import InputListComponent from "../../../../components/inputListComponent";
import Dropdown from "../../../../components/dropdownComponent";
import TextAreaComponent from "../../../../components/textAreaComponent";
import InputComponent from "../../../../components/inputComponent";
import ToggleComponent from "../../../../components/toggleComponent";
import FloatComponent from "../../../../components/floatComponent";
import IntComponent from "../../../../components/intComponent";
import InputFileComponent from "../../../../components/inputFileComponent";
import PromptAreaComponent from "../../../../components/promptComponent";
import CodeAreaComponent from "../../../../components/codeAreaComponent";
import { classNames } from "../../../../utils";
export default function ModalField({ data, title, required, id, name, type }) {
const { save } = useContext(TabsContext);
const [enabled, setEnabled] = useState(
data.node.template[name]?.value ?? false
);
const display =
type === "str" ||
type === "int" ||
type === "prompt" ||
type === "bool" ||
type === "float" ||
type === "file" ||
type === "code";
return (
<div
className={classNames(
"flex flex-row w-full items-center justify-between",
display ? "" : "hidden"
)}
>
{display && (
<div>
<span className="mx-2">{title}</span>
<span className="text-red-600">{required ? " *" : ""}</span>
</div>
)}
{type === "str" && !data.node.template[name].options ? (
<div className="w-1/2">
{data.node.template[name].list ? (
<InputListComponent
disabled={false}
value={
!data.node.template[name].value ||
data.node.template[name].value === ""
? [""]
: data.node.template[name].value
}
onChange={(t: string[]) => {
data.node.template[name].value = t;
save();
}}
/>
) : data.node.template[name].multiline ? (
<TextAreaComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
save();
}}
/>
) : (
<InputComponent
disabled={false}
password={data.node.template[name].password ?? false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
save();
}}
/>
)}
</div>
) : type === "bool" ? (
<div className="ml-auto">
{" "}
<ToggleComponent
disabled={false}
enabled={enabled}
setEnabled={(t) => {
data.node.template[name].value = t;
setEnabled(t);
save();
}}
/>
</div>
) : type === "float" ? (
<div className="w-1/2">
<FloatComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
save();
}}
/>
</div>
) : type === "str" && data.node.template[name].options ? (
<div className="w-1/2">
<Dropdown
options={data.node.template[name].options}
onSelect={(newValue) => (data.node.template[name].value = newValue)}
value={data.node.template[name].value ?? "Choose an option"}
></Dropdown>
</div>
) : type === "int" ? (
<div className="w-1/2">
<IntComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t) => {
data.node.template[name].value = t;
save();
}}
/>
</div>
) : type === "file" ? (
<div className="w-1/2">
<InputFileComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
}}
fileTypes={data.node.template[name].fileTypes}
suffixes={data.node.template[name].suffixes}
onFileChange={(t: string) => {
data.node.template[name].content = t;
save();
}}
></InputFileComponent>
</div>
) : type === "prompt" ? (
<div className="w-1/2">
<PromptAreaComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
save();
}}
/>
</div>
) : type === "code" ? (
<div className="w-1/2">
<CodeAreaComponent
disabled={false}
value={data.node.template[name].value ?? ""}
onChange={(t: string) => {
data.node.template[name].value = t;
save();
}}
/>
</div>
) : (
<div className="hidden"></div>
)}
</div>
);
}

View file

@ -0,0 +1,144 @@
import { Dialog, Transition } from "@headlessui/react";
import { XMarkIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { NodeDataType } from "../../types/flow";
import { nodeColors, nodeIcons, snakeToNormalCase } from "../../utils";
import { typesContext } from "../../contexts/typesContext";
import ModalField from "./components/ModalField";
export default function NodeModal({ data }: { data: NodeDataType }) {
const [open, setOpen] = useState(true);
const { closePopUp } = useContext(PopUpContext);
const { types } = useContext(typesContext);
const ref = useRef();
function setModalOpen(x: boolean) {
setOpen(x);
if (x === false) {
setTimeout(() => {
closePopUp();
}, 300);
}
}
const Icon = nodeIcons[types[data.type]];
return (
<Transition.Root show={open} appear={true} as={Fragment}>
<Dialog
as="div"
className="relative z-10"
onClose={setModalOpen}
initialFocus={ref}
>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button
type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => {
setModalOpen(false);
}}
>
<span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button>
</div>
<div className="h-full w-full flex flex-col justify-center items-center">
<div className="flex w-full pb-4 z-10 justify-center shadow-sm">
<Icon
className="w-10 mt-4 h-10 p-1 rounded"
style={{
color:
nodeColors[types[data.type]] ?? nodeColors.unknown,
}}
/>
<div className="mt-4 text-center sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium dark:text-white leading-10 text-gray-900"
>
{data.type}
</Dialog.Title>
</div>
</div>
<div className="h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
<div className="flex h-full w-full">
<div className="overflow-hidden px-4 sm:p-4 w-full rounded-lg bg-white dark:bg-gray-800 shadow">
<div className="flex flex-col h-full gap-5">
{
Object.keys(data.node.template)
.filter((t) => t.charAt(0) !== "_"&& data.node.template[t].advanced && data.node.template[t].show)
.map((t: string, idx) => {
return (
<ModalField
key={idx}
data={data}
title={
data.node.template[t].display_name
? data.node.template[t].display_name
: data.node.template[t].name
? snakeToNormalCase(
data.node.template[t].name
)
: snakeToNormalCase(t)
}
required={data.node.template[t].required}
id={
data.node.template[t].type +
"|" +
t +
"|" +
data.id
}
name={t}
type={data.node.template[t].type}
/>
);
})
}
</div>
</div>
</div>
</div>
<div className="bg-gray-200 dark:bg-gray-900 w-full pb-3 flex flex-row-reverse px-4">
<button
type="button"
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => {
setModalOpen(false);
}}
>
Done
</button>
</div>
</div>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}

View file

@ -1,11 +1,11 @@
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { import {
XMarkIcon, XMarkIcon,
ArrowDownTrayIcon, ArrowDownTrayIcon,
DocumentDuplicateIcon, DocumentDuplicateIcon,
ComputerDesktopIcon, ComputerDesktopIcon,
ArrowUpTrayIcon, ArrowUpTrayIcon,
ArrowLeftIcon, ArrowLeftIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react"; import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
@ -19,211 +19,214 @@ import { FlowType } from "../../types/flow";
import { classNames } from "../../utils"; import { classNames } from "../../utils";
export default function ImportModal() { export default function ImportModal() {
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const { closePopUp } = useContext(PopUpContext); const { closePopUp } = useContext(PopUpContext);
const ref = useRef(); const ref = useRef();
const [showExamples, setShowExamples] = useState(false); const [showExamples, setShowExamples] = useState(false);
const [loadingExamples, setLoadingExamples] = useState(false); const [loadingExamples, setLoadingExamples] = useState(false);
const [examples, setExamples] = useState<FlowType[]>([]); const [examples, setExamples] = useState<FlowType[]>([]);
const { uploadFlow, addFlow } = useContext(TabsContext); const { uploadFlow, addFlow } = useContext(TabsContext);
function setModalOpen(x: boolean) { function setModalOpen(x: boolean) {
setOpen(x); setOpen(x);
if (x === false) { if (x === false) {
setTimeout(() => { setTimeout(() => {
closePopUp(); closePopUp();
}, 300); }, 300);
} }
} }
function handleExamples() { function handleExamples() {
setLoadingExamples(true); setLoadingExamples(true);
getExamples() getExamples()
.then((result) => { .then((result) => {
setLoadingExamples(false); setLoadingExamples(false);
setExamples(result); setExamples(result);
}) })
.catch((error) => .catch((error) =>
setErrorData({ setErrorData({
title: "there was an error loading examples, please try again", title: "there was an error loading examples, please try again",
list: [error.message], list: [error.message],
}) })
); );
} }
return ( return (
<Transition.Root show={open} appear={true} as={Fragment}> <Transition.Root show={open} appear={true} as={Fragment}>
<Dialog <Dialog
as="div" as="div"
className="relative z-10" className="relative z-10"
onClose={setModalOpen} onClose={setModalOpen}
initialFocus={ref} initialFocus={ref}
> >
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter="ease-out duration-300" enter="ease-out duration-300"
enterFrom="opacity-0" enterFrom="opacity-0"
enterTo="opacity-100" enterTo="opacity-100"
leave="ease-in duration-200" leave="ease-in duration-200"
leaveFrom="opacity-100" leaveFrom="opacity-100"
leaveTo="opacity-0" leaveTo="opacity-0"
> >
<div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" /> <div className="fixed inset-0 bg-gray-500 dark:bg-gray-600 dark:bg-opacity-75 bg-opacity-75 transition-opacity" />
</Transition.Child> </Transition.Child>
<div className="fixed inset-0 z-10 overflow-y-auto"> <div className="fixed inset-0 z-10 overflow-y-auto">
<div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"> <div className="flex h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter="ease-out duration-300" enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100" enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200" leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
> >
<Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]"> <Dialog.Panel className="relative flex flex-col justify-between transform h-[600px] overflow-hidden rounded-lg bg-white dark:bg-gray-800 text-left shadow-xl transition-all sm:my-8 w-[700px]">
<div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block"> <div className=" z-50 absolute top-0 right-0 hidden pt-4 pr-4 sm:block">
<button <button
type="button" type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => { onClick={() => {
setModalOpen(false); setModalOpen(false);
}} }}
> >
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
<XMarkIcon className="h-6 w-6" aria-hidden="true" /> <XMarkIcon className="h-6 w-6" aria-hidden="true" />
</button> </button>
</div> </div>
{showExamples && ( {showExamples && (
<> <>
<div className="z-50 absolute top-2 left-0 hidden pt-4 pl-4 sm:block"> <div className="z-50 absolute top-2 left-0 hidden pt-4 pl-4 sm:block">
<button <button
type="button" type="button"
className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" className="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
onClick={() => { onClick={() => {
setShowExamples(false); setShowExamples(false);
}} }}
> >
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
<ArrowLeftIcon className="h-6 w-6" aria-hidden="true" /> <ArrowLeftIcon className="h-6 w-6" aria-hidden="true" />
</button> </button>
</div> </div>
<div className="z-50 absolute bottom-2 left-0 hidden pt-4 pl-2 sm:block"> <div className="z-50 absolute bottom-2 left-1/2 transform -translate-x-1/2 hidden pt-4 pl-2 sm:block text-center">
<a <a
href="https://github.com/logspace-ai/langflow_examples" href="https://github.com/logspace-ai/langflow_examples"
target="_blank" target="_blank"
> className="flex items-center justify-center"
<svg rel="noreferrer"
width="24" >
viewBox="0 0 98 96" <svg
xmlns="http://www.w3.org/2000/svg" width="24"
> viewBox="0 0 98 96"
<path xmlns="http://www.w3.org/2000/svg"
fill-rule="evenodd" >
clip-rule="evenodd" <path
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill-rule="evenodd"
fill="#24292f" clip-rule="evenodd"
/> d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
</svg> fill="#24292f"
</a> />
</div> </svg>
</> <span className="ml-2">LangFlow Examples</span>
)} </a>
<div className="h-full w-full flex flex-col justify-center items-center"> </div>
<div className="flex w-full pb-4 z-10 justify-center shadow-sm"> </>
<div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10"> )}
<ArrowUpTrayIcon <div className="h-full w-full flex flex-col justify-center items-center">
className="h-6 w-6 text-blue-600" <div className="flex w-full pb-4 z-10 justify-center shadow-sm">
aria-hidden="true" <div className="mx-auto mt-4 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-gray-900 sm:mx-0 sm:h-10 sm:w-10">
/> <ArrowUpTrayIcon
</div> className="h-6 w-6 text-blue-600"
<div className="mt-4 text-center sm:ml-4 sm:text-left"> aria-hidden="true"
<Dialog.Title />
as="h3" </div>
className="text-lg font-medium dark:text-white leading-10 text-gray-900" <div className="mt-4 text-center sm:ml-4 sm:text-left">
> <Dialog.Title
{showExamples ?"Select an example":"Import from"} as="h3"
</Dialog.Title> className="text-lg font-medium dark:text-white leading-10 text-gray-900"
</div> >
</div> {showExamples ? "Select an example" : "Import from"}
<div </Dialog.Title>
className={classNames( </div>
"h-full w-full bg-gray-200 dark:bg-gray-900 gap-4", </div>
showExamples && !loadingExamples <div
? "flex flex-row start justify-start items-start p-9 flex-wrap overflow-auto" className={classNames(
: "flex flex-row justify-center items-center p-4" "h-full w-full bg-gray-200 dark:bg-gray-900 gap-4",
)} showExamples && !loadingExamples
> ? "flex flex-row start justify-start items-start p-9 flex-wrap overflow-auto"
{!showExamples && ( : "flex flex-row justify-center items-center p-4"
<div className="flex h-full w-full justify-evenly items-center"> )}
<ButtonBox >
size="big" {!showExamples && (
bgColor="bg-emerald-500" <div className="flex h-full w-full justify-evenly items-center">
description="Prebuilt Examples" <ButtonBox
icon={ size="big"
<DocumentDuplicateIcon className="h-10 w-10 flex-shrink-0" /> bgColor="bg-emerald-500"
} description="Prebuilt Examples"
onClick={() => { icon={
setShowExamples(true); <DocumentDuplicateIcon className="h-10 w-10 flex-shrink-0" />
handleExamples(); }
}} onClick={() => {
textColor="text-emerald-400" setShowExamples(true);
title="Examples" handleExamples();
></ButtonBox> }}
<ButtonBox textColor="text-emerald-400"
size="big" title="Examples"
bgColor="bg-blue-500" ></ButtonBox>
description="Import from Local" <ButtonBox
icon={ size="big"
<ComputerDesktopIcon className="h-10 w-10 flex-shrink-0" /> bgColor="bg-blue-500"
} description="Import from Local"
onClick={() => { icon={
uploadFlow(); <ComputerDesktopIcon className="h-10 w-10 flex-shrink-0" />
setModalOpen(false); }
}} onClick={() => {
textColor="text-blue-500" uploadFlow();
title="Local file" setModalOpen(false);
></ButtonBox> }}
</div> textColor="text-blue-500"
)} title="Local file"
{showExamples && loadingExamples && ( ></ButtonBox>
<div className="flex align-middle justify-center items-center"> </div>
<LoadingComponent remSize={30} /> )}
</div> {showExamples && loadingExamples && (
)} <div className="flex align-middle justify-center items-center">
{showExamples && <LoadingComponent remSize={30} />
!loadingExamples && </div>
examples.map((example, index) => { )}
return ( {showExamples &&
<div id="index"> !loadingExamples &&
{" "} examples.map((example, index) => {
<ButtonBox return (
size="small" <div id="index">
bgColor="bg-emerald-500" {" "}
description={ <ButtonBox
example.description ?? "Prebuilt Examples" size="small"
} bgColor="bg-emerald-500"
icon={ description={
<DocumentDuplicateIcon className="h-6 w-6 flex-shrink-0" /> example.description ?? "Prebuilt Examples"
} }
onClick={() => { icon={
addFlow(example); <DocumentDuplicateIcon className="h-6 w-6 flex-shrink-0" />
setModalOpen(false); }
}} onClick={() => {
textColor="text-emerald-400" addFlow(example);
title={example.name} setModalOpen(false);
></ButtonBox> }}
</div> textColor="text-emerald-400"
); title={example.name}
})} ></ButtonBox>
</div> </div>
</div> );
</Dialog.Panel> })}
</Transition.Child> </div>
</div> </div>
</div> </Dialog.Panel>
</Dialog> </Transition.Child>
</Transition.Root> </div>
); </div>
</Dialog>
</Transition.Root>
);
} }

View file

@ -2,43 +2,14 @@ import { Bars2Icon } from "@heroicons/react/24/outline";
import DisclosureComponent from "../DisclosureComponent"; import DisclosureComponent from "../DisclosureComponent";
import { nodeColors, nodeIcons, nodeNames } from "../../../../utils"; import { nodeColors, nodeIcons, nodeNames } from "../../../../utils";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { getAll } from "../../../../controllers/API";
import { typesContext } from "../../../../contexts/typesContext"; import { typesContext } from "../../../../contexts/typesContext";
import { import {
APIClassType, APIClassType,
APIKindType,
APIObjectType, APIObjectType,
} from "../../../../types/api"; } from "../../../../types/api";
export default function ExtraSidebar() { export default function ExtraSidebar() {
const [data, setData] = useState({}); const {data} = useContext(typesContext)
const { setTypes } = useContext(typesContext);
useEffect(() => {
async function getTypes(): Promise<void> {
// Make an asynchronous API call to retrieve all data.
let result = await getAll();
// Update the state of the component with the retrieved data.
setData(result.data);
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
});
return acc;
}, {})
);
}
// Call the getTypes function.
getTypes();
}, [setTypes]);
function onDragStart( function onDragStart(
event: React.DragEvent<any>, event: React.DragEvent<any>,
@ -84,7 +55,9 @@ export default function ExtraSidebar() {
</div> </div>
</div> </div>
))} ))}
{Object.keys(data[d]).length===0 && <div className="text-gray-400 text-center">Coming soon</div>} {Object.keys(data[d]).length === 0 && (
<div className="text-gray-400 text-center">Coming soon</div>
)}
</div> </div>
</DisclosureComponent> </DisclosureComponent>
))} ))}

View file

@ -16,21 +16,23 @@ import AlertDropdown from "../../../../alerts/alertDropDown";
import { alertContext } from "../../../../contexts/alertContext"; import { alertContext } from "../../../../contexts/alertContext";
import ImportModal from "../../../../modals/importModal"; import ImportModal from "../../../../modals/importModal";
import ExportModal from "../../../../modals/exportModal"; import ExportModal from "../../../../modals/exportModal";
import { typesContext } from "../../../../contexts/typesContext";
export default function TabsManagerComponent() { export default function TabsManagerComponent() {
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } =
useContext(TabsContext); useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext); const { openPopUp } = useContext(PopUpContext);
const AlertWidth = 256; const {templates} = useContext(typesContext)
const { dark, setDark } = useContext(darkContext); const AlertWidth = 256;
const { notificationCenter, setNotificationCenter } = const { dark, setDark } = useContext(darkContext);
useContext(alertContext); const { notificationCenter, setNotificationCenter } =
useEffect(() => { useContext(alertContext);
//create the first flow useEffect(() => {
if (flows.length === 0) { //create the first flow
addFlow(); if (flows.length === 0&& Object.keys(templates).length>0) {
} addFlow();
}, [addFlow, flows.length]); }
}, [addFlow, flows.length,templates]);
return ( return (
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col">

View file

@ -29,11 +29,12 @@ const nodeTypes = {
var _ = require("lodash"); var _ = require("lodash");
export default function FlowPage({ flow }: { flow: FlowType }) { export default function FlowPage({ flow }:{flow:FlowType}) {
let { updateFlow, incrementNodeId } = useContext(TabsContext); let { updateFlow, incrementNodeId} =
const { types, reactFlowInstance, setReactFlowInstance } = useContext(TabsContext);
useContext(typesContext); const { types, reactFlowInstance, setReactFlowInstance, templates } =
const reactFlowWrapper = useRef(null); useContext(typesContext);
const reactFlowWrapper = useRef(null);
const { setExtraComponent, setExtraNavigation } = useContext(locationContext); const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
@ -176,46 +177,47 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
[] []
); );
const onEdgeUpdateEnd = useCallback((_, edge) => { const onEdgeUpdateEnd = useCallback((_, edge) => {
if (!edgeUpdateSuccessful.current) { if (!edgeUpdateSuccessful.current) {
setEdges((eds) => eds.filter((e) => e.id !== edge.id)); setEdges((eds) => eds.filter((e) => e.id !== edge.id));
} }
edgeUpdateSuccessful.current = true; edgeUpdateSuccessful.current = true;
}, []); }, []);
return ( return (
<div className="w-full h-full" ref={reactFlowWrapper}> <div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(types).length > 0 ? ( {Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
<> <>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
onMove={() => onMove={() =>
updateFlow({ ...flow, data: reactFlowInstance.toObject() }) updateFlow({ ...flow, data: reactFlowInstance.toObject() })
} }
edges={edges} edges={edges}
onNodesChange={onNodesChange} onNodesChange={onNodesChange}
onEdgesChange={onEdgesChangeMod} onEdgesChange={onEdgesChangeMod}
onConnect={onConnect} onConnect={onConnect}
onLoad={setReactFlowInstance} onLoad={setReactFlowInstance}
onInit={setReactFlowInstance} onInit={setReactFlowInstance}
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
onEdgeUpdate={onEdgeUpdate} onEdgeUpdate={onEdgeUpdate}
onEdgeUpdateStart={onEdgeUpdateStart} onEdgeUpdateStart={onEdgeUpdateStart}
onEdgeUpdateEnd={onEdgeUpdateEnd} onEdgeUpdateEnd={onEdgeUpdateEnd}
connectionLineComponent={ConnectionLineComponent} connectionLineComponent={ConnectionLineComponent}
onDragOver={onDragOver} onDragOver={onDragOver}
onDrop={onDrop} onDrop={onDrop}
onNodesDelete={onDelete} onNodesDelete={onDelete}
> >
<Background className="dark:bg-gray-900" /> <Background className="dark:bg-gray-900"/>
<Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600"></Controls> <Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600">
</ReactFlow> </Controls>
<Chat flow={flow} reactFlowInstance={reactFlowInstance} /> </ReactFlow>
</> <Chat flow={flow} reactFlowInstance={reactFlowInstance} />
) : ( </>
<></> ) : (
)} <></>
</div> )}
); </div>
);
} }

View file

@ -13,3 +13,5 @@ export type TabsContextType = {
uploadFlow: () => void; uploadFlow: () => void;
hardReset: () => void; hardReset: () => void;
}; };
export type LangFlowState={ tabIndex:number, flows:FlowType[], id:string, nodeId:number }

View file

@ -0,0 +1,7 @@
const template:{[char: string]: string}={}
export type TemplateContextType = {
templates: typeof template;
setTemplates: (newState: {}) => void;
};

View file

@ -1,11 +1,18 @@
import { ReactFlowInstance } from "reactflow"; import { ReactFlowInstance } from "reactflow";
const types: { [char: string]: string } = {}; const types:{[char: string]: string}={};
const template:{[char: string]: string}={}
const data:{[char: string]: string}={}
export type typesContextType = { export type typesContextType = {
reactFlowInstance: ReactFlowInstance | null; reactFlowInstance: ReactFlowInstance|null;
setReactFlowInstance: any; setReactFlowInstance: any;
deleteNode: (idx: string) => void; deleteNode: (idx: string) => void;
types: typeof types; types: typeof types;
setTypes: (newState: {}) => void; setTypes: (newState: {}) => void;
templates: typeof template;
setTemplates: (newState: {}) => void;
data: typeof data;
setData: (newState: {}) => void;
}; };

View file

@ -398,3 +398,22 @@ export function removeApiKeys(flow: FlowType): FlowType {
}); });
return cleanFLow; return cleanFLow;
} }
export function updateObject<T extends Record<string, any>>(reference: T, objectToUpdate: T): T {
let clonedObject = _.cloneDeep(objectToUpdate)
// Loop through each key in the object to update
for (const key in clonedObject) {
// If the key is not in the reference object, delete it
if (!(key in reference)) {
delete clonedObject[key];
}
}
// Loop through each key in the reference object
for (const key in reference) {
// If the key is not in the object to update, add it
if (!(key in clonedObject)) {
clonedObject[key] = reference[key];
}
}
return clonedObject;
}

View file

@ -36,6 +36,7 @@ def test_zero_shot_agent(client: TestClient):
"name": "llm_chain", "name": "llm_chain",
"type": "LLMChain", "type": "LLMChain",
"list": False, "list": False,
"advanced": True,
} }
assert template["allowed_tools"] == { assert template["allowed_tools"] == {
"required": False, "required": False,
@ -46,6 +47,7 @@ def test_zero_shot_agent(client: TestClient):
"name": "allowed_tools", "name": "allowed_tools",
"type": "Tool", "type": "Tool",
"list": True, "list": True,
"advanced": True,
} }
@ -68,6 +70,7 @@ def test_json_agent(client: TestClient):
"name": "toolkit", "name": "toolkit",
"type": "BaseToolkit", "type": "BaseToolkit",
"list": False, "list": False,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -78,6 +81,7 @@ def test_json_agent(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": True,
} }
@ -104,6 +108,7 @@ def test_csv_agent(client: TestClient):
"type": "file", "type": "file",
"list": False, "list": False,
"content": None, "content": None,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -114,6 +119,7 @@ def test_csv_agent(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": True,
} }
@ -143,6 +149,7 @@ def test_initialize_agent(client: TestClient):
"name": "agent", "name": "agent",
"type": "str", "type": "str",
"list": True, "list": True,
"advanced": True,
} }
assert template["memory"] == { assert template["memory"] == {
"required": False, "required": False,
@ -153,6 +160,7 @@ def test_initialize_agent(client: TestClient):
"name": "memory", "name": "memory",
"type": "BaseChatMemory", "type": "BaseChatMemory",
"list": False, "list": False,
"advanced": True,
} }
assert template["tools"] == { assert template["tools"] == {
"required": False, "required": False,
@ -163,6 +171,7 @@ def test_initialize_agent(client: TestClient):
"name": "tools", "name": "tools",
"type": "Tool", "type": "Tool",
"list": True, "list": True,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -173,4 +182,5 @@ def test_initialize_agent(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": True,
} }

View file

@ -31,16 +31,18 @@ def test_conversation_chain(client: TestClient):
"name": "memory", "name": "memory",
"type": "BaseMemory", "type": "BaseMemory",
"list": False, "list": False,
"advanced": False,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
"placeholder": "", "placeholder": "",
"show": False, "show": True,
"multiline": False, "multiline": False,
"password": False, "password": False,
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -51,6 +53,7 @@ def test_conversation_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": False,
} }
assert template["input_key"] == { assert template["input_key"] == {
"required": True, "required": True,
@ -62,6 +65,7 @@ def test_conversation_chain(client: TestClient):
"name": "input_key", "name": "input_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["output_key"] == { assert template["output_key"] == {
"required": True, "required": True,
@ -73,6 +77,7 @@ def test_conversation_chain(client: TestClient):
"name": "output_key", "name": "output_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["_type"] == "ConversationChain" assert template["_type"] == "ConversationChain"
@ -102,17 +107,19 @@ def test_llm_chain(client: TestClient):
"name": "memory", "name": "memory",
"type": "BaseMemory", "type": "BaseMemory",
"list": False, "list": False,
"advanced": False,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
"placeholder": "", "placeholder": "",
"show": False, "show": True,
"multiline": False, "multiline": False,
"value": False, "value": False,
"password": False, "password": False,
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -123,6 +130,7 @@ def test_llm_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": False,
} }
assert template["output_key"] == { assert template["output_key"] == {
"required": True, "required": True,
@ -134,6 +142,7 @@ def test_llm_chain(client: TestClient):
"name": "output_key", "name": "output_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
@ -156,17 +165,19 @@ def test_llm_checker_chain(client: TestClient):
"name": "memory", "name": "memory",
"type": "BaseMemory", "type": "BaseMemory",
"list": False, "list": False,
"advanced": False,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
"placeholder": "", "placeholder": "",
"show": False, "show": True,
"multiline": False, "multiline": False,
"value": False, "value": False,
"password": False, "password": False,
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -177,6 +188,7 @@ def test_llm_checker_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLLM", "type": "BaseLLM",
"list": False, "list": False,
"advanced": False,
} }
assert template["input_key"] == { assert template["input_key"] == {
"required": True, "required": True,
@ -188,6 +200,7 @@ def test_llm_checker_chain(client: TestClient):
"name": "input_key", "name": "input_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["output_key"] == { assert template["output_key"] == {
"required": True, "required": True,
@ -199,6 +212,7 @@ def test_llm_checker_chain(client: TestClient):
"name": "output_key", "name": "output_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["_type"] == "LLMCheckerChain" assert template["_type"] == "LLMCheckerChain"
@ -228,17 +242,19 @@ def test_llm_math_chain(client: TestClient):
"name": "memory", "name": "memory",
"type": "BaseMemory", "type": "BaseMemory",
"list": False, "list": False,
"advanced": False,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
"placeholder": "", "placeholder": "",
"show": False, "show": True,
"multiline": False, "multiline": False,
"value": False, "value": False,
"password": False, "password": False,
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
@ -249,6 +265,7 @@ def test_llm_math_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
"advanced": False,
} }
assert template["input_key"] == { assert template["input_key"] == {
"required": True, "required": True,
@ -260,6 +277,7 @@ def test_llm_math_chain(client: TestClient):
"name": "input_key", "name": "input_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["output_key"] == { assert template["output_key"] == {
"required": True, "required": True,
@ -271,6 +289,7 @@ def test_llm_math_chain(client: TestClient):
"name": "output_key", "name": "output_key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["_type"] == "LLMMathChain" assert template["_type"] == "LLMMathChain"
@ -298,35 +317,7 @@ def test_series_character_chain(client: TestClient):
"SeriesCharacterChain", "SeriesCharacterChain",
} }
template = chain["template"] template = chain["template"]
assert template["memory"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": False,
"value": {
"chat_memory": {"messages": []},
"output_key": None,
"input_key": None,
"return_messages": False,
"human_prefix": "Human",
"ai_prefix": "AI",
"memory_key": "history",
},
"password": False,
"name": "memory",
"type": "BaseMemory",
"list": False,
}
assert template["verbose"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "verbose",
"type": "bool",
"list": False,
}
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
"placeholder": "", "placeholder": "",
@ -336,50 +327,7 @@ def test_series_character_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
} "advanced": False,
assert template["input_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "input",
"password": False,
"name": "input_key",
"type": "str",
"list": False,
}
assert template["output_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "response",
"password": False,
"name": "output_key",
"type": "str",
"list": False,
}
assert template["template"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": True,
"value": "I want you to act like {character} from {series}.\nI want you to respond and answer like {character}. do not write any explanations. only answer like {character}.\nYou must know all of the knowledge of {character}.\nCurrent conversation:\n{history}\nHuman: {input}\n{character}:", # noqa: E501
"password": False,
"name": "template",
"type": "str",
"list": False,
}
assert template["ai_prefix_value"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"value": "character",
"password": False,
"name": "ai_prefix_value",
"type": "str",
"list": False,
} }
assert template["character"] == { assert template["character"] == {
"required": True, "required": True,
@ -390,6 +338,7 @@ def test_series_character_chain(client: TestClient):
"name": "character", "name": "character",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": False,
} }
assert template["series"] == { assert template["series"] == {
"required": True, "required": True,
@ -400,6 +349,7 @@ def test_series_character_chain(client: TestClient):
"name": "series", "name": "series",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": False,
} }
assert template["_type"] == "SeriesCharacterChain" assert template["_type"] == "SeriesCharacterChain"
@ -429,55 +379,7 @@ def test_mid_journey_prompt_chain(client: TestClient):
# Test the template object # Test the template object
template = chain["template"] template = chain["template"]
assert template["memory"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": False,
"value": {
"chat_memory": {"messages": []},
"output_key": None,
"input_key": None,
"return_messages": False,
"human_prefix": "Human",
"ai_prefix": "AI",
"memory_key": "history",
},
"password": False,
"name": "memory",
"type": "BaseMemory",
"list": False,
}
assert template["verbose"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "verbose",
"type": "bool",
"list": False,
}
# Continue with other template object assertions
assert template["prompt"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"value": {
"input_variables": ["history", "input"],
"output_parser": None,
"partial_variables": {},
"template": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n\nCurrent conversation:\n{history}\nHuman: {input}\nAI:", # noqa: E501
"template_format": "f-string",
"validate_template": True,
"_type": "prompt",
},
"password": False,
"name": "prompt",
"type": "BasePromptTemplate",
"list": False,
}
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
"placeholder": "", "placeholder": "",
@ -487,49 +389,7 @@ def test_mid_journey_prompt_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
} "advanced": False,
assert template["output_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "response",
"password": False,
"name": "output_key",
"type": "str",
"list": False,
}
assert template["input_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "input",
"password": False,
"name": "input_key",
"type": "str",
"list": False,
}
assert template["template"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": True,
"value": 'I want you to act as a prompt generator for Midjourney\'s artificial intelligence program.\n Your job is to provide detailed and creative descriptions that will inspire unique and interesting images from the AI.\n 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.\n For example, you could describe a scene from a futuristic city, or a surreal landscape filled with strange creatures.\n The more detailed and imaginative your description, the more interesting the resulting image will be. Here is your first prompt:\n "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."\n\n Current conversation:\n {history}\n Human: {input}\n AI:', # noqa: E501
"password": False,
"name": "template",
"type": "str",
"list": False,
}
assert template["ai_prefix_value"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "ai_prefix_value",
"type": "str",
"list": False,
} }
# Test the description object # Test the description object
assert ( assert (
@ -557,55 +417,7 @@ def test_time_travel_guide_chain(client: TestClient):
# Test the template object # Test the template object
template = chain["template"] template = chain["template"]
assert template["memory"] == {
"required": False,
"placeholder": "",
"show": True,
"multiline": False,
"value": {
"chat_memory": {"messages": []},
"output_key": None,
"input_key": None,
"return_messages": False,
"human_prefix": "Human",
"ai_prefix": "AI",
"memory_key": "history",
},
"password": False,
"name": "memory",
"type": "BaseMemory",
"list": False,
}
assert template["verbose"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "verbose",
"type": "bool",
"list": False,
}
assert template["prompt"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"value": {
"input_variables": ["history", "input"],
"output_parser": None,
"partial_variables": {},
"template": "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n\nCurrent conversation:\n{history}\nHuman: {input}\nAI:", # noqa: E501
"template_format": "f-string",
"validate_template": True,
"_type": "prompt",
},
"password": False,
"name": "prompt",
"type": "BasePromptTemplate",
"list": False,
}
assert template["llm"] == { assert template["llm"] == {
"required": True, "required": True,
"placeholder": "", "placeholder": "",
@ -615,50 +427,7 @@ def test_time_travel_guide_chain(client: TestClient):
"name": "llm", "name": "llm",
"type": "BaseLanguageModel", "type": "BaseLanguageModel",
"list": False, "list": False,
} "advanced": False,
assert template["output_key"] == {
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "response",
"password": False,
"name": "output_key",
"type": "str",
"list": False,
} }
assert template["input_key"] == { assert chain["description"] == "Time travel guide chain to be used in the flow."
"required": True,
"placeholder": "",
"show": True,
"multiline": False,
"value": "input",
"password": False,
"name": "input_key",
"type": "str",
"list": False,
}
assert template["template"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": True,
"value": "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.\n Current conversation:\n {history}\n Human: {input}\n AI:", # noqa: E501
"password": False,
"name": "template",
"type": "str",
"list": False,
}
assert template["ai_prefix_value"] == {
"required": False,
"placeholder": "",
"show": False,
"multiline": False,
"password": False,
"name": "ai_prefix_value",
"type": "str",
"list": False,
}
assert chain["description"] == ""

View file

@ -28,6 +28,7 @@ def test_hugging_face_hub(client: TestClient):
"name": "cache", "name": "cache",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
@ -39,6 +40,7 @@ def test_hugging_face_hub(client: TestClient):
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["client"] == { assert template["client"] == {
"required": False, "required": False,
@ -49,6 +51,7 @@ def test_hugging_face_hub(client: TestClient):
"name": "client", "name": "client",
"type": "Any", "type": "Any",
"list": False, "list": False,
"advanced": True,
} }
assert template["repo_id"] == { assert template["repo_id"] == {
"required": False, "required": False,
@ -60,6 +63,7 @@ def test_hugging_face_hub(client: TestClient):
"name": "repo_id", "name": "repo_id",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["task"] == { assert template["task"] == {
"required": True, "required": True,
@ -71,6 +75,7 @@ def test_hugging_face_hub(client: TestClient):
"name": "task", "name": "task",
"type": "str", "type": "str",
"list": True, "list": True,
"advanced": True,
} }
assert template["model_kwargs"] == { assert template["model_kwargs"] == {
"required": False, "required": False,
@ -81,9 +86,10 @@ def test_hugging_face_hub(client: TestClient):
"name": "model_kwargs", "name": "model_kwargs",
"type": "code", "type": "code",
"list": False, "list": False,
"advanced": True,
} }
assert template["huggingfacehub_api_token"] == { assert template["huggingfacehub_api_token"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,
@ -92,6 +98,7 @@ def test_hugging_face_hub(client: TestClient):
"display_name": "HuggingFace Hub API Token", "display_name": "HuggingFace Hub API Token",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": False,
} }
@ -113,6 +120,7 @@ def test_openai(client: TestClient):
"name": "cache", "name": "cache",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["verbose"] == { assert template["verbose"] == {
"required": False, "required": False,
@ -123,6 +131,7 @@ def test_openai(client: TestClient):
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["client"] == { assert template["client"] == {
"required": False, "required": False,
@ -133,6 +142,7 @@ def test_openai(client: TestClient):
"name": "client", "name": "client",
"type": "Any", "type": "Any",
"list": False, "list": False,
"advanced": True,
} }
assert template["model_name"] == { assert template["model_name"] == {
"required": False, "required": False,
@ -151,6 +161,7 @@ def test_openai(client: TestClient):
"name": "model_name", "name": "model_name",
"type": "str", "type": "str",
"list": True, "list": True,
"advanced": False,
} }
# Add more assertions for other properties here # Add more assertions for other properties here
assert template["temperature"] == { assert template["temperature"] == {
@ -163,6 +174,7 @@ def test_openai(client: TestClient):
"name": "temperature", "name": "temperature",
"type": "float", "type": "float",
"list": False, "list": False,
"advanced": False,
} }
assert template["max_tokens"] == { assert template["max_tokens"] == {
"required": False, "required": False,
@ -174,6 +186,7 @@ def test_openai(client: TestClient):
"name": "max_tokens", "name": "max_tokens",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["top_p"] == { assert template["top_p"] == {
"required": False, "required": False,
@ -185,6 +198,7 @@ def test_openai(client: TestClient):
"name": "top_p", "name": "top_p",
"type": "float", "type": "float",
"list": False, "list": False,
"advanced": True,
} }
assert template["frequency_penalty"] == { assert template["frequency_penalty"] == {
"required": False, "required": False,
@ -196,6 +210,7 @@ def test_openai(client: TestClient):
"name": "frequency_penalty", "name": "frequency_penalty",
"type": "float", "type": "float",
"list": False, "list": False,
"advanced": True,
} }
assert template["presence_penalty"] == { assert template["presence_penalty"] == {
"required": False, "required": False,
@ -207,6 +222,7 @@ def test_openai(client: TestClient):
"name": "presence_penalty", "name": "presence_penalty",
"type": "float", "type": "float",
"list": False, "list": False,
"advanced": True,
} }
assert template["n"] == { assert template["n"] == {
"required": False, "required": False,
@ -218,6 +234,7 @@ def test_openai(client: TestClient):
"name": "n", "name": "n",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["best_of"] == { assert template["best_of"] == {
"required": False, "required": False,
@ -229,6 +246,7 @@ def test_openai(client: TestClient):
"name": "best_of", "name": "best_of",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["model_kwargs"] == { assert template["model_kwargs"] == {
"required": False, "required": False,
@ -239,9 +257,10 @@ def test_openai(client: TestClient):
"name": "model_kwargs", "name": "model_kwargs",
"type": "code", "type": "code",
"list": False, "list": False,
"advanced": True,
} }
assert template["openai_api_key"] == { assert template["openai_api_key"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,
@ -251,6 +270,7 @@ def test_openai(client: TestClient):
"display_name": "OpenAI API Key", "display_name": "OpenAI API Key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": False,
} }
assert template["batch_size"] == { assert template["batch_size"] == {
"required": False, "required": False,
@ -262,6 +282,7 @@ def test_openai(client: TestClient):
"name": "batch_size", "name": "batch_size",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["request_timeout"] == { assert template["request_timeout"] == {
"required": False, "required": False,
@ -272,6 +293,7 @@ def test_openai(client: TestClient):
"name": "request_timeout", "name": "request_timeout",
"type": "Union[float, Tuple[float, float], NoneType]", "type": "Union[float, Tuple[float, float], NoneType]",
"list": False, "list": False,
"advanced": True,
} }
assert template["logit_bias"] == { assert template["logit_bias"] == {
"required": False, "required": False,
@ -282,6 +304,7 @@ def test_openai(client: TestClient):
"name": "logit_bias", "name": "logit_bias",
"type": "code", "type": "code",
"list": False, "list": False,
"advanced": True,
} }
assert template["max_retries"] == { assert template["max_retries"] == {
"required": False, "required": False,
@ -293,6 +316,7 @@ def test_openai(client: TestClient):
"name": "max_retries", "name": "max_retries",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["streaming"] == { assert template["streaming"] == {
"required": False, "required": False,
@ -304,6 +328,7 @@ def test_openai(client: TestClient):
"name": "streaming", "name": "streaming",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
@ -326,6 +351,7 @@ def test_chat_open_ai(client: TestClient):
"name": "verbose", "name": "verbose",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["client"] == { assert template["client"] == {
"required": False, "required": False,
@ -336,6 +362,7 @@ def test_chat_open_ai(client: TestClient):
"name": "client", "name": "client",
"type": "Any", "type": "Any",
"list": False, "list": False,
"advanced": True,
} }
assert template["model_name"] == { assert template["model_name"] == {
"required": False, "required": False,
@ -348,6 +375,7 @@ def test_chat_open_ai(client: TestClient):
"name": "model_name", "name": "model_name",
"type": "str", "type": "str",
"list": True, "list": True,
"advanced": False,
} }
assert template["temperature"] == { assert template["temperature"] == {
"required": False, "required": False,
@ -359,6 +387,7 @@ def test_chat_open_ai(client: TestClient):
"name": "temperature", "name": "temperature",
"type": "float", "type": "float",
"list": False, "list": False,
"advanced": False,
} }
assert template["model_kwargs"] == { assert template["model_kwargs"] == {
"required": False, "required": False,
@ -369,9 +398,10 @@ def test_chat_open_ai(client: TestClient):
"name": "model_kwargs", "name": "model_kwargs",
"type": "code", "type": "code",
"list": False, "list": False,
"advanced": True,
} }
assert template["openai_api_key"] == { assert template["openai_api_key"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,
@ -381,6 +411,7 @@ def test_chat_open_ai(client: TestClient):
"display_name": "OpenAI API Key", "display_name": "OpenAI API Key",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": False,
} }
assert template["request_timeout"] == { assert template["request_timeout"] == {
"required": False, "required": False,
@ -392,6 +423,7 @@ def test_chat_open_ai(client: TestClient):
"name": "request_timeout", "name": "request_timeout",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["max_retries"] == { assert template["max_retries"] == {
"required": False, "required": False,
@ -403,6 +435,7 @@ def test_chat_open_ai(client: TestClient):
"name": "max_retries", "name": "max_retries",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["streaming"] == { assert template["streaming"] == {
"required": False, "required": False,
@ -414,6 +447,7 @@ def test_chat_open_ai(client: TestClient):
"name": "streaming", "name": "streaming",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
assert template["n"] == { assert template["n"] == {
"required": False, "required": False,
@ -425,6 +459,7 @@ def test_chat_open_ai(client: TestClient):
"name": "n", "name": "n",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["max_tokens"] == { assert template["max_tokens"] == {
@ -436,6 +471,7 @@ def test_chat_open_ai(client: TestClient):
"name": "max_tokens", "name": "max_tokens",
"type": "int", "type": "int",
"list": False, "list": False,
"advanced": True,
} }
assert template["_type"] == "ChatOpenAI" assert template["_type"] == "ChatOpenAI"
assert ( assert (

View file

@ -27,6 +27,7 @@ def test_prompt_template(client: TestClient):
"name": "input_variables", "name": "input_variables",
"type": "str", "type": "str",
"list": True, "list": True,
"advanced": True,
} }
assert template["output_parser"] == { assert template["output_parser"] == {
"required": False, "required": False,
@ -37,6 +38,7 @@ def test_prompt_template(client: TestClient):
"name": "output_parser", "name": "output_parser",
"type": "BaseOutputParser", "type": "BaseOutputParser",
"list": False, "list": False,
"advanced": True,
} }
assert template["partial_variables"] == { assert template["partial_variables"] == {
"required": False, "required": False,
@ -47,6 +49,7 @@ def test_prompt_template(client: TestClient):
"name": "partial_variables", "name": "partial_variables",
"type": "code", "type": "code",
"list": False, "list": False,
"advanced": True,
} }
assert template["template"] == { assert template["template"] == {
"required": True, "required": True,
@ -57,6 +60,7 @@ def test_prompt_template(client: TestClient):
"name": "template", "name": "template",
"type": "prompt", "type": "prompt",
"list": False, "list": False,
"advanced": True,
} }
assert template["template_format"] == { assert template["template_format"] == {
"required": False, "required": False,
@ -68,6 +72,7 @@ def test_prompt_template(client: TestClient):
"name": "template_format", "name": "template_format",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["validate_template"] == { assert template["validate_template"] == {
"required": False, "required": False,
@ -79,6 +84,7 @@ def test_prompt_template(client: TestClient):
"name": "validate_template", "name": "validate_template",
"type": "bool", "type": "bool",
"list": False, "list": False,
"advanced": True,
} }
@ -100,6 +106,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "examples", "name": "examples",
"type": "prompt", "type": "prompt",
"list": True, "list": True,
"advanced": True,
} }
assert template["example_selector"] == { assert template["example_selector"] == {
"required": False, "required": False,
@ -110,6 +117,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "example_selector", "name": "example_selector",
"type": "BaseExampleSelector", "type": "BaseExampleSelector",
"list": False, "list": False,
"advanced": True,
} }
assert template["example_prompt"] == { assert template["example_prompt"] == {
"required": True, "required": True,
@ -120,6 +128,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "example_prompt", "name": "example_prompt",
"type": "PromptTemplate", "type": "PromptTemplate",
"list": False, "list": False,
"advanced": True,
} }
assert template["suffix"] == { assert template["suffix"] == {
"required": True, "required": True,
@ -130,6 +139,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "suffix", "name": "suffix",
"type": "prompt", "type": "prompt",
"list": False, "list": False,
"advanced": True,
} }
assert template["example_separator"] == { assert template["example_separator"] == {
"required": False, "required": False,
@ -141,6 +151,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "example_separator", "name": "example_separator",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["prefix"] == { assert template["prefix"] == {
"required": False, "required": False,
@ -152,6 +163,7 @@ def test_few_shot_prompt_template(client: TestClient):
"name": "prefix", "name": "prefix",
"type": "prompt", "type": "prompt",
"list": False, "list": False,
"advanced": True,
} }
@ -172,6 +184,7 @@ def test_zero_shot_prompt(client: TestClient):
"name": "prefix", "name": "prefix",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["suffix"] == { assert template["suffix"] == {
"required": True, "required": True,
@ -183,6 +196,7 @@ def test_zero_shot_prompt(client: TestClient):
"name": "suffix", "name": "suffix",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }
assert template["format_instructions"] == { assert template["format_instructions"] == {
"required": False, "required": False,
@ -194,4 +208,5 @@ def test_zero_shot_prompt(client: TestClient):
"name": "format_instructions", "name": "format_instructions",
"type": "str", "type": "str",
"list": False, "list": False,
"advanced": True,
} }