diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..afe112a40 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.10-slim + +RUN apt-get update && apt-get install gcc g++ git make -y && apt-get clean \ + && rm -rf /var/lib/apt/lists/* +RUN useradd -m -u 1000 user +USER user +ENV HOME=/home/user \ + PATH=/home/user/.local/bin:$PATH + +WORKDIR $HOME/app + +COPY --chown=user . $HOME/app + +RUN pip install langflow>==0.0.86 -U --user +CMD ["python", "-m", "langflow", "--host", "0.0.0.0", "--port", "7860"] diff --git a/README.md b/README.md index 8e3930997..36ea5a20f 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ # ⛓️ LangFlow -~ A User Interface For [LangChain](https://github.com/hwchase17/langchain) ~ +~ An effortless way to experiment and prototype [LangChain](https://github.com/hwchase17/langchain) pipelines ~
+ +
-LangFlow is a GUI for [LangChain](https://github.com/hwchase17/langchain), designed with [react-flow](https://github.com/wbkd/react-flow) to provide an effortless way to experiment and prototype flows with drag-and-drop components and a chat box.
+
++
## 📦 Installation ### Locally @@ -178,6 +184,11 @@ flow("Hey, have you heard of LangFlow?") We welcome contributions from developers of all levels to our open-source project on GitHub. If you'd like to contribute, please check our [contributing guidelines](./CONTRIBUTING.md) and help make LangFlow more accessible. +Join our [Discord](https://discord.com/invite/EqksyE2EX9) server to ask questions, make suggestions and showcase your projects! 🦾 + ++
+ [](https://star-history.com/#logspace-ai/langflow&Date) diff --git a/poetry.lock b/poetry.lock index 1549c36b1..017fa2bd0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2381,21 +2381,21 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "langchain" -version = "0.0.202" +version = "0.0.208" description = "Building applications with LLMs through composability" category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.202-py3-none-any.whl", hash = "sha256:63ef3dba8df4326579aea30e8a209d8cb6cd199b8bd91f4eaf470c3f79ed5a57"}, - {file = "langchain-0.0.202.tar.gz", hash = "sha256:25f61952afe6c47e9eb4be8d6f23edf14a7a2dfa0ab74512f809a49bf34ef8e4"}, + {file = "langchain-0.0.208-py3-none-any.whl", hash = "sha256:c654c507dd60a6ac3d8b4c199b7c0dbc638d92a940900f6e1bf045abd400a23a"}, + {file = "langchain-0.0.208.tar.gz", hash = "sha256:8eb709d31379bcf4d7e5d1c5f92e62324aac47801efe60ce12e5b99d7bf5cd9b"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} dataclasses-json = ">=0.5.7,<0.6.0" -langchainplus-sdk = ">=0.0.9" +langchainplus-sdk = ">=0.0.13" numexpr = ">=2.8.4,<3.0.0" numpy = ">=1,<2" openapi-schema-pydantic = ">=1.2,<2.0" @@ -2406,12 +2406,12 @@ SQLAlchemy = ">=1.4,<3" tenacity = ">=8.1.0,<9.0.0" [package.extras] -all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.2.6,<0.3.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.2,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=3,<4)", "deeplake (>=3.3.0,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=2.8.6,<3.0.0)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jina (>=3.14,<4.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.1.dev3,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.1.2,<2.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.6.1,<0.7.0)", "spacy (>=3,<4)", "steamship (>=2.16.9,<3.0.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] +all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.2.6,<0.3.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.3,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=3,<4)", "deeplake (>=3.6.2,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jina (>=3.14,<4.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.1.dev3,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.1.2,<2.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "spacy (>=3,<4)", "steamship (>=2.16.9,<3.0.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"] azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0a20230509004)", "openai (>=0,<1)"] cohere = ["cohere (>=3,<4)"] docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] embeddings = ["sentence-transformers (>=2,<3)"] -extended-testing = ["atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "chardet (>=5.1.0,<6.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "openai (>=0,<1)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "psychicapi (>=0.5,<0.6)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "zep-python (>=0.31)"] +extended-testing = ["atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "chardet (>=5.1.0,<6.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "openai (>=0,<1)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.5,<0.6)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "telethon (>=1.28.5,<2.0.0)", "tqdm (>=4.48.0)", "zep-python (>=0.31)"] llms = ["anthropic (>=0.2.6,<0.3.0)", "cohere (>=3,<4)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"] qdrant = ["qdrant-client (>=1.1.2,<2.0.0)"] @@ -6354,4 +6354,4 @@ deploy = ["langchain-serve"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "6b382b428d0c1d43bd76917dccc88e524c5ae6ecbfea59d07ff977aa030fd7f4" +content-hash = "49c4252d510cda8418eb432e527180cb4b3581cbe8e67905150a6f86840704af" diff --git a/pyproject.toml b/pyproject.toml index 7aaceb868..e894da8d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ google-search-results = "^2.4.1" google-api-python-client = "^2.79.0" typer = "^0.9.0" gunicorn = "^20.1.0" -langchain = "^0.0.202" +langchain = "^0.0.208" openai = "^0.27.8" types-pyyaml = "^6.0.12.8" pandas = "^1.5.3" diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 262defed6..ed0caeba2 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -87,10 +87,16 @@ async def stream_build(flow_id: str): logger.debug("Building langchain object") graph = Graph.from_payload(graph_data) - for node in graph.generator_build(): + number_of_nodes = len(graph.nodes) + for i, vertex in enumerate(graph.generator_build(), 1): try: - node.build() - params = node._built_object_repr() + log_dict = { + "log": f"Building node {vertex.vertex_type}", + "progress": round(i / number_of_nodes, 2), + } + yield f"data: {json.dumps(log_dict)}\n\n" + vertex.build() + params = vertex._built_object_repr() valid = True logger.debug( f"Building node {params[:50]}{'...' if len(params) > 50 else ''}" @@ -103,7 +109,7 @@ async def stream_build(flow_id: str): { "valid": valid, "params": params, - "id": node.id, + "id": vertex.id, } ) yield f"data: {response}\n\n" diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index a5e952fc3..2c074c7bb 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -48,6 +48,7 @@ documentloaders: - ReadTheDocsLoader - SlackDirectoryLoader - NotionDirectoryLoader + - DirectoryLoader embeddings: - OpenAIEmbeddings - HuggingFaceEmbeddings diff --git a/src/backend/langflow/interface/agents/custom.py b/src/backend/langflow/interface/agents/custom.py index b0c794c2d..a4191a8b7 100644 --- a/src/backend/langflow/interface/agents/custom.py +++ b/src/backend/langflow/interface/agents/custom.py @@ -192,7 +192,7 @@ class SQLAgent(CustomAgentExecutor): from langchain.tools.sql_database.tool import ( InfoSQLDatabaseTool, ListSQLDatabaseTool, - QueryCheckerTool, + QuerySQLCheckerTool, QuerySQLDataBaseTool, ) @@ -207,7 +207,7 @@ class SQLAgent(CustomAgentExecutor): QuerySQLDataBaseTool(db=db), # type: ignore InfoSQLDatabaseTool(db=db), # type: ignore ListSQLDatabaseTool(db=db), # type: ignore - QueryCheckerTool(db=db, llm_chain=llmchain, llm=llm), # type: ignore + QuerySQLCheckerTool(db=db, llm_chain=llmchain, llm=llm), # type: ignore ] prefix = SQL_PREFIX.format(dialect=toolkit.dialect, top_k=10) diff --git a/src/backend/langflow/template/frontend_node/documentloaders.py b/src/backend/langflow/template/frontend_node/documentloaders.py index b8f26a9ca..52f37861d 100644 --- a/src/backend/langflow/template/frontend_node/documentloaders.py +++ b/src/backend/langflow/template/frontend_node/documentloaders.py @@ -51,6 +51,7 @@ class DocumentLoaderFrontNode(FrontendNode): def add_extra_fields(self) -> None: name = None + display_name = "Web Page" if self.template.type_name in self.file_path_templates: self.template.add_field(self.file_path_templates[self.template.type_name]) elif self.template.type_name in { @@ -64,8 +65,9 @@ class DocumentLoaderFrontNode(FrontendNode): name = "web_path" elif self.template.type_name in {"GitbookLoader"}: name = "web_page" - elif self.template.type_name in {"ReadTheDocsLoader"}: + elif self.template.type_name in {"DirectoryLoader", "ReadTheDocsLoader"}: name = "path" + display_name = "Local directory" if name: self.template.add_field( TemplateField( @@ -74,6 +76,17 @@ class DocumentLoaderFrontNode(FrontendNode): show=True, name=name, value="", - display_name="Web Page", + display_name=display_name, + ) + ) + if self.template.type_name in {"DirectoryLoader"}: + self.template.add_field( + TemplateField( + field_type="str", + required=True, + show=True, + name="glob", + value="**/*.txt", + display_name="glob", ) ) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 323cfdcc1..68f198dd6 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -80,7 +80,7 @@ "postcss": "^8.4.23", "tailwindcss": "^3.3.2", "typescript": "^5.0.2", - "vite": "^4.3.5" + "vite": "^4.3.9" } }, "node_modules/@adobe/css-tools": { @@ -5070,6 +5070,19 @@ "version": "1.0.0", "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "license": "MIT" @@ -9552,8 +9565,9 @@ } }, "node_modules/vite": { - "version": "4.3.5", - "license": "MIT", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dependencies": { "esbuild": "^0.17.5", "postcss": "^8.4.23", diff --git a/src/frontend/package.json b/src/frontend/package.json index c6177ebb0..07fdb32f5 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -101,6 +101,6 @@ "postcss": "^8.4.23", "tailwindcss": "^3.3.2", "typescript": "^5.0.2", - "vite": "^4.3.5" + "vite": "^4.3.9" } } diff --git a/src/frontend/src/components/chatComponent/buildTrigger/index.tsx b/src/frontend/src/components/chatComponent/buildTrigger/index.tsx index c9113dbd7..49ec2922f 100644 --- a/src/frontend/src/components/chatComponent/buildTrigger/index.tsx +++ b/src/frontend/src/components/chatComponent/buildTrigger/index.tsx @@ -1,4 +1,4 @@ -import { useState, useContext } from "react"; +import { useContext } from "react"; import { Transition } from "@headlessui/react"; import { Zap } from "lucide-react"; import { validateNodes } from "../../../utils"; @@ -22,7 +22,7 @@ export default function BuildTrigger({ }) { const { updateSSEData, isBuilding, setIsBuilding } = useSSE(); const { reactFlowInstance } = useContext(typesContext); - const { setErrorData } = useContext(alertContext); + const { setErrorData, setSuccessData } = useContext(alertContext); async function handleBuild(flow: FlowType) { try { @@ -81,10 +81,16 @@ export default function BuildTrigger({ eventSource.close(); return; + } else if (parsedData.log) { + // If the event is a log, log it + // TODO: implement the progress + setSuccessData({ title: parsedData.log }); + setSuccessData({ title: parsedData.progress }); + } else { + // Otherwise, process the data + const isValid = processStreamResult(parsedData); + validationResults.push(isValid); } - // Otherwise, process the data - const isValid = processStreamResult(parsedData); - validationResults.push(isValid); }; eventSource.onerror = (error) => { diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 0d9459f45..168f73465 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -1,4 +1,4 @@ -import { BellIcon, Home, Users2 } from "lucide-react"; +import { BellIcon, Home, MoonIcon, SunIcon, Users2 } from "lucide-react"; import { useContext, useEffect, useState } from "react"; import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa"; import { Button } from "../ui/button"; @@ -12,6 +12,7 @@ import MenuBar from "./components/menuBar"; import { Link, useLocation, useParams } from "react-router-dom"; import { USER_PROJECTS_HEADER } from "../../constants"; import { getRepoStars } from "../../controllers/API"; +import { Separator } from "../ui/separator"; export default function Header() { const { flows, addFlow, tabId } = useContext(TabsContext); @@ -73,7 +74,7 @@ export default function Header() { href="https://github.com/logspace-ai/langflow" target="_blank" rel="noreferrer" - className="inline-flex items-center justify-center text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background text-gray-600 dark:text-gray-300 border border-input hover:bg-accent hover:text-accent-foreground h-9 px-3 pr-0 rounded-md" + className="inline-flex shadow-sm items-center justify-center text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background text-gray-600 dark:text-gray-300 border border-input hover:bg-accent hover:text-accent-foreground h-9 px-3 pr-0 rounded-md" >