Merge branch 'dev' into NodeModal

This commit is contained in:
anovazzi1 2023-04-27 20:37:04 -03:00
commit 1f9cc38fd8
11 changed files with 768 additions and 593 deletions

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
``` ```

894
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"
@ -57,6 +57,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

@ -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

@ -166,7 +166,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.utils import compute_dict_hash, load_cache, memoize_dict from langflow.cache.utils import compute_dict_hash, load_cache, memoize_dict
from langflow.graph.graph import Graph from langflow.graph.graph import Graph

View file

@ -118,7 +118,6 @@ class ToolCreator(LangChainTypeCreator):
params = self.type_to_loader_dict[name]["params"] # type: ignore params = self.type_to_loader_dict[name]["params"] # type: ignore
base_classes += [name] base_classes += [name]
elif tool_type in OTHER_TOOLS: elif tool_type in OTHER_TOOLS:
print(tool_type)
tool_dict = build_template_from_class(tool_type, OTHER_TOOLS) tool_dict = build_template_from_class(tool_type, OTHER_TOOLS)
fields = tool_dict["template"] fields = tool_dict["template"]

View file

@ -226,11 +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(): if "kwargs" in field.name.lower():
field.advanced = True field.advanced = True
field.required = False field.required = False
field.show = 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

@ -445,7 +445,9 @@ class LLMFrontendNode(FrontendNode):
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
if field.name == "task": if field.name == "task":
field.required = True field.required = True

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

@ -83,7 +83,7 @@ def test_hugging_face_hub(client: TestClient):
"list": False, "list": False,
} }
assert template["huggingfacehub_api_token"] == { assert template["huggingfacehub_api_token"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,
@ -241,7 +241,7 @@ def test_openai(client: TestClient):
"list": False, "list": False,
} }
assert template["openai_api_key"] == { assert template["openai_api_key"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,
@ -371,7 +371,7 @@ def test_chat_open_ai(client: TestClient):
"list": False, "list": False,
} }
assert template["openai_api_key"] == { assert template["openai_api_key"] == {
"required": True, "required": False,
"placeholder": "", "placeholder": "",
"show": True, "show": True,
"multiline": False, "multiline": False,