From e01993b7f19c67b6187427e22ba85428f59b68a2 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 09:55:29 -0300 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=90=9B=20fix(=5F=5Fmain=5F=5F.py):?= =?UTF-8?q?=20add=20support=20for=20running=20Langflow=20on=20Windows=20?= =?UTF-8?q?=E2=9C=A8=20feat(=5F=5Fmain=5F=5F.py):=20add=20support=20for=20?= =?UTF-8?q?running=20Langflow=20on=20MacOS=20and=20Linux=20using=20gunicor?= =?UTF-8?q?n=20The=20changes=20add=20support=20for=20running=20Langflow=20?= =?UTF-8?q?on=20Windows=20by=20using=20uvicorn=20instead=20of=20gunicorn.?= =?UTF-8?q?=20This=20is=20because=20Windows=20doesn't=20support=20gunicorn?= =?UTF-8?q?.=20The=20changes=20also=20add=20support=20for=20running=20Lang?= =?UTF-8?q?flow=20on=20MacOS=20and=20Linux=20using=20gunicorn.=20This=20is?= =?UTF-8?q?=20because=20MacOS=20requires=20an=20env=20variable=20to=20be?= =?UTF-8?q?=20set=20to=20use=20gunicorn.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/__main__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index 5598fb78c..29f60ed23 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -152,6 +152,17 @@ def serve( "timeout": timeout, } + if platform.system() in ["Windows"]: + # Run using uvicorn on MacOS and Windows + # Windows doesn't support gunicorn + # MacOS requires an env variable to be set to use gunicorn + run_on_windows(host, port, log_level, options, app) + else: + # Run using gunicorn on Linux + run_on_mac_or_linux(host, port, log_level, options, app, open_browser) + + +def run_on_mac_or_linux(host, port, log_level, options, app, open_browser=True): webapp_process = Process( target=run_langflow, args=(host, port, log_level, options, app) ) @@ -169,6 +180,14 @@ def serve( webbrowser.open(f"http://{host}:{port}") +def run_on_windows(host, port, log_level, options, app): + """ + Run the Langflow server on Windows. + """ + print_banner(host, port) + run_langflow(host, port, log_level, options, app) + + def setup_static_files(app: FastAPI, static_files_dir: Path): """ Setup the static files directory. From a3f902d479cc7952018072b2a206f8d668e250dd Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 09:59:10 -0300 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=94=96=20chore(pyproject.toml):=20b?= =?UTF-8?q?ump=20version=20to=200.1.3=20The=20version=20number=20has=20bee?= =?UTF-8?q?n=20updated=20from=200.1.2=20to=200.1.3=20to=20reflect=20the=20?= =?UTF-8?q?changes=20made=20in=20the=20package.=20This=20is=20a=20chore=20?= =?UTF-8?q?commit=20as=20it=20does=20not=20add=20any=20new=20features=20or?= =?UTF-8?q?=20fix=20any=20bugs,=20but=20rather=20updates=20the=20version?= =?UTF-8?q?=20number.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 26 +++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 015f3caaf..c8843ccba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -909,14 +909,14 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "ctransformers" -version = "0.2.8" +version = "0.2.9" description = "Python bindings for the Transformer models implemented in C/C++ using GGML library." category = "main" optional = false python-versions = "*" files = [ - {file = "ctransformers-0.2.8-py3-none-any.whl", hash = "sha256:9804640364c13d93d58bfb6a9a1fa90d34b6438955d842c68ab05e5f8f15e023"}, - {file = "ctransformers-0.2.8.tar.gz", hash = "sha256:81c0436d8b5315211496566294d51e7bbd07cf6e4305608262eab04603b74b65"}, + {file = "ctransformers-0.2.9-py3-none-any.whl", hash = "sha256:ff0183ccf2bf157102cffacea13476cb78b8a2ffc2e1fdd46b57f8682a8da8ac"}, + {file = "ctransformers-0.2.9.tar.gz", hash = "sha256:2165c512ee153f763c3d4ab133d666f86460010330d6bc75c0a6db6310ec9fc8"}, ] [package.dependencies] @@ -2444,14 +2444,14 @@ test = ["psutil", "pytest", "pytest-asyncio"] [[package]] name = "langchainplus-sdk" -version = "0.0.10" +version = "0.0.11" description = "Client library to connect to the LangChainPlus LLM Tracing and Evaluation Platform." category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchainplus_sdk-0.0.10-py3-none-any.whl", hash = "sha256:6ea4013a92a4c33a61d22deb49620577c592a79ee44038b2c751032a71cbc7b6"}, - {file = "langchainplus_sdk-0.0.10.tar.gz", hash = "sha256:4f810b38df74a99d01e5723e653da02f05df3ee922971cccabc365d00c33dbf6"}, + {file = "langchainplus_sdk-0.0.11-py3-none-any.whl", hash = "sha256:fbe3482ffe253e439ec8386a2904594a875b590e29e4adcbd938452a69a6c7c6"}, + {file = "langchainplus_sdk-0.0.11.tar.gz", hash = "sha256:e50679309a31d9526f467aa13d4dbcfba0dc00a295cea72ffcc9972865ecac1b"}, ] [package.dependencies] @@ -3812,14 +3812,14 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- [[package]] name = "pluggy" -version = "1.0.0" +version = "1.1.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-1.1.0-py3-none-any.whl", hash = "sha256:d81d19a3a88d82ed06998353ce5d5c02587ef07ee2d808ae63904ab0ccef0087"}, + {file = "pluggy-1.1.0.tar.gz", hash = "sha256:c500b592c5512df35622e4faf2135aa0b7e989c7d31344194b4afb9d5e47b1bf"}, ] [package.extras] @@ -4265,14 +4265,14 @@ files = [ [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pyparsing-3.1.0-py3-none-any.whl", hash = "sha256:d554a96d1a7d3ddaf7183104485bc19fd80543ad6ac5bdb6426719d766fb06c1"}, + {file = "pyparsing-3.1.0.tar.gz", hash = "sha256:edb662d6fe322d6e990b1594b5feaeadf806803359e3d4d42f11e295e588f0ea"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index 4a383f6fc..dd2cdda71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow" -version = "0.1.2" +version = "0.1.3" description = "A Python package with a built-in web application" authors = ["Logspace "] maintainers = [ From 5ea20aa2f011050ecec899231f789ca2bf9ecfa6 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 10:55:18 -0300 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=94=A8=20refactor(constants.tsx):?= =?UTF-8?q?=20remove=20unnecessary=20indentation=20in=20getPythonCode=20fu?= =?UTF-8?q?nction=20The=20indentation=20of=20the=20commented=20line=20in?= =?UTF-8?q?=20the=20getPythonCode=20function=20was=20unnecessary=20and=20h?= =?UTF-8?q?as=20been=20removed=20to=20improve=20code=20readability.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/constants.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/constants.tsx b/src/frontend/src/constants.tsx index 34d20211a..0e9a9ad3d 100644 --- a/src/frontend/src/constants.tsx +++ b/src/frontend/src/constants.tsx @@ -123,9 +123,9 @@ export const getPythonCode = (flow: FlowType): string => { const flowName = flow.name; return `from langflow import load_flow_from_json - flow = load_flow_from_json("${flowName}.json") - # Now you can use it like any chain - flow("Hey, have you heard of LangFlow?")`; +flow = load_flow_from_json("${flowName}.json") +# Now you can use it like any chain +flow("Hey, have you heard of LangFlow?")`; }; /** From 6886828ddd020fed9a533ed84da7cc6f2f0e54b1 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 11:36:43 -0300 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=94=80=20refactor(process.py):=20ch?= =?UTF-8?q?ange=20load=5Fflow=5Ffrom=5Fjson=20function=20signature=20to=20?= =?UTF-8?q?accept=20either=20a=20JSON=20file=20path=20or=20a=20JSON=20obje?= =?UTF-8?q?ct=20=F0=9F=94=80=20refactor(base.py):=20import=20Chain=20from?= =?UTF-8?q?=20langchain.chains.base=20instead=20of=20importing=20it=20from?= =?UTF-8?q?=20langflow.graph.vertex.types=20=F0=9F=94=80=20refactor(proces?= =?UTF-8?q?s.py):=20remove=20print=20statement=20from=20process=5Ftweaks?= =?UTF-8?q?=20function=20=F0=9F=94=80=20refactor(process.py):=20change=20l?= =?UTF-8?q?oad=5Fflow=5Ffrom=5Fjson=20function=20signature=20to=20accept?= =?UTF-8?q?=20optional=20tweaks=20parameter=20=F0=9F=94=80=20refactor(proc?= =?UTF-8?q?ess.py):=20change=20return=20type=20of=20build=20method=20in=20?= =?UTF-8?q?Graph=20class=20from=20List[Vertex]=20to=20Chain=20=F0=9F=A7=AA?= =?UTF-8?q?=20test(loading.py):=20add=20test=20case=20for=20loading=20a=20?= =?UTF-8?q?flow=20from=20a=20JSON=20file=20and=20applying=20tweaks=20?= =?UTF-8?q?=F0=9F=A7=AA=20test(loading.py):=20remove=20unused=20import=20s?= =?UTF-8?q?tatement=20The=20import=20statement=20for=20Chain=20in=20base.p?= =?UTF-8?q?y=20is=20now=20more=20explicit=20and=20imports=20it=20from=20la?= =?UTF-8?q?ngchain.chains.base=20instead=20of=20importing=20it=20from=20la?= =?UTF-8?q?ngflow.graph.vertex.types.=20The=20load=5Fflow=5Ffrom=5Fjson=20?= =?UTF-8?q?function=20in=20process.py=20now=20accepts=20either=20a=20JSON?= =?UTF-8?q?=20file=20path=20or=20a=20JSON=20object.=20The=20print=20statem?= =?UTF-8?q?ent=20in=20process=5Ftweaks=20function=20has=20been=20removed.?= =?UTF-8?q?=20The=20load=5Fflow=5Ffrom=5Fjson=20function=20in=20process.py?= =?UTF-8?q?=20now=20accepts=20an=20optional=20tweaks=20parameter.=20The=20?= =?UTF-8?q?return=20type=20of=20the=20build=20method=20in=20the=20Graph=20?= =?UTF-8?q?class=20has=20been=20changed=20from=20List[Vertex]=20to=20Chain?= =?UTF-8?q?.=20A=20new=20test=20case=20has=20been=20added=20to=20loading.p?= =?UTF-8?q?y=20to=20test=20loading=20a=20flow=20from=20a=20JSON=20file=20a?= =?UTF-8?q?nd=20applying=20tweaks.=20An=20unused=20import=20statement=20ha?= =?UTF-8?q?s=20been=20removed=20from=20loading.py.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/graph/graph/base.py | 3 +- src/backend/langflow/processing/process.py | 50 ++++++++++++++-------- tests/test_loading.py | 9 ++++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 5cefdadae..4fa2f4d17 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -11,6 +11,7 @@ from langflow.graph.vertex.types import ( from langflow.interface.tools.constants import FILE_TOOLS from langflow.utils import payload from langflow.utils.logger import logger +from langchain.chains.base import Chain class Graph: @@ -99,7 +100,7 @@ class Graph: ] return connected_nodes - def build(self) -> List[Vertex]: + def build(self) -> Chain: """Builds the graph.""" # Get root node root_node = payload.get_root_node(self) diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index c25f7b3d1..760f73723 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -1,5 +1,6 @@ import contextlib import io +from pathlib import Path from langchain.schema import AgentAction import json from langflow.interface.run import ( @@ -11,7 +12,7 @@ from langflow.utils.logger import logger from langflow.graph import Graph -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple, Union def fix_memory_inputs(langchain_object): @@ -131,34 +132,50 @@ def process_graph_cached(data_graph: Dict[str, Any], message: str): return {"result": str(result), "thought": thought.strip()} -def load_flow_from_json(path: str, build=True): - """Load flow from json file""" - # This is done to avoid circular imports +def load_flow_from_json( + input: Union[str, dict], tweaks: Optional[dict] = None, build=True +): + """ + Load flow from a JSON file or a JSON object. - with open(path, "r", encoding="utf-8") as f: - flow_graph = json.load(f) - data_graph = flow_graph["data"] - nodes = data_graph["nodes"] - # Substitute ZeroShotPrompt with PromptTemplate - # nodes = replace_zero_shot_prompt_with_prompt_template(nodes) - # Add input variables - # nodes = payload.extract_input_variables(nodes) + :param input: JSON file path or JSON object + :param tweaks: Optional tweaks to be processed + :param build: If True, build the graph, otherwise return the graph object + :return: Langchain object or Graph object depending on the build parameter + """ + # If input is a file path, load JSON from the file + if isinstance(input, (str, Path)): + with open(input, "r", encoding="utf-8") as f: + flow_graph = json.load(f) + # If input is a dictionary, assume it's a JSON object + elif isinstance(input, dict): + flow_graph = input + else: + raise TypeError( + "Input must be either a file path (str) or a JSON object (dict)" + ) - # Nodes, edges and root node - edges = data_graph["edges"] + graph_data = flow_graph["data"] + if tweaks is not None: + graph_data = process_tweaks(graph_data, tweaks) + nodes = graph_data["nodes"] + edges = graph_data["edges"] graph = Graph(nodes, edges) + if build: langchain_object = graph.build() + if hasattr(langchain_object, "verbose"): langchain_object.verbose = True if hasattr(langchain_object, "return_intermediate_steps"): - # https://github.com/hwchase17/langchain/issues/2068 # Deactivating until we have a frontend solution # to display intermediate steps langchain_object.return_intermediate_steps = False + fix_memory_inputs(langchain_object) return langchain_object + return graph @@ -181,7 +198,4 @@ def process_tweaks(graph_data: Dict, tweaks: Dict): for tweak_name, tweake_value in node_tweaks.items(): if tweak_name in template_data: template_data[tweak_name]["value"] = tweake_value - print( - f"Something changed in node {node_id} with tweak {tweak_name} and value {tweake_value}" - ) return graph_data diff --git a/tests/test_loading.py b/tests/test_loading.py index 885eb7a82..11fa8e471 100644 --- a/tests/test_loading.py +++ b/tests/test_loading.py @@ -14,6 +14,15 @@ def test_load_flow_from_json(): assert isinstance(loaded, Chain) +def test_load_flow_from_json_with_tweaks(): + """Test loading a flow from a json file and applying tweaks""" + tweaks = {"dndnode_82": {"model_name": "test model"}} + loaded = load_flow_from_json(pytest.BASIC_EXAMPLE_PATH, tweaks=tweaks) + assert loaded is not None + assert isinstance(loaded, Chain) + assert loaded.llm.model_name == "test model" + + def test_get_root_node(): with open(pytest.BASIC_EXAMPLE_PATH, "r") as f: flow_graph = json.load(f) From 83c28dcabe7be9b67de778bc96275877249e08ec Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 11:59:34 -0300 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=94=A8=20refactor(process.py):=20re?= =?UTF-8?q?factor=20process=5Ftweaks=20function=20to=20improve=20readabili?= =?UTF-8?q?ty=20and=20maintainability=20=E2=9C=A8=20feat(process.py):=20ad?= =?UTF-8?q?d=20input=20validation=20to=20process=5Ftweaks=20function=20The?= =?UTF-8?q?=20process=5Ftweaks=20function=20has=20been=20refactored=20to?= =?UTF-8?q?=20improve=20readability=20and=20maintainability.=20The=20apply?= =?UTF-8?q?=5Ftweaks=20function=20has=20been=20added=20to=20apply=20the=20?= =?UTF-8?q?tweaks=20to=20the=20node.=20The=20validate=5Finput=20function?= =?UTF-8?q?=20has=20been=20added=20to=20validate=20the=20input=20parameter?= =?UTF-8?q?s.=20The=20process=5Ftweaks=20function=20now=20raises=20a=20Val?= =?UTF-8?q?ueError=20if=20the=20input=20is=20not=20in=20the=20expected=20f?= =?UTF-8?q?ormat.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/processing/process.py | 73 ++++++++++++++++------ 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index 760f73723..e4ae33d27 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -11,7 +11,6 @@ from langflow.interface.run import ( from langflow.utils.logger import logger from langflow.graph import Graph - from typing import Any, Dict, List, Optional, Tuple, Union @@ -179,23 +178,61 @@ def load_flow_from_json( return graph -def process_tweaks(graph_data: Dict, tweaks: Dict): - """This function is used to tweak the graph data using the node id and the tweaks dict""" - # the tweaks dict is a dict of dicts - # the key is the node id and the value is a dict of the tweaks - # the dict of tweaks contains the name of a certain parameter and the value to be tweaked +def validate_input( + graph_data: Dict[str, Any], tweaks: Dict[str, Dict[str, Any]] +) -> List[Dict[str, Any]]: + if not isinstance(graph_data, dict) or not isinstance(tweaks, dict): + raise ValueError("graph_data and tweaks should be dictionaries") + + nodes = graph_data.get("data", {}).get("nodes") or graph_data.get("nodes") + + if not isinstance(nodes, list): + raise ValueError( + "graph_data should contain a list of nodes under 'data' key or directly under 'nodes' key" + ) + + return nodes + + +def apply_tweaks(node: Dict[str, Any], node_tweaks: Dict[str, Any]) -> None: + template_data = node.get("data", {}).get("node", {}).get("template") + + if not isinstance(template_data, dict): + logger.warning( + f"Template data for node {node.get('id')} should be a dictionary" + ) + return + + for tweak_name, tweak_value in node_tweaks.items(): + if tweak_name and tweak_value and tweak_name in template_data: + template_data[tweak_name]["value"] = tweak_value + + +def process_tweaks( + graph_data: Dict[str, Any], tweaks: Dict[str, Dict[str, Any]] +) -> Dict[str, Any]: + """ + This function is used to tweak the graph data using the node id and the tweaks dict. + + :param graph_data: The dictionary containing the graph data. It must contain a 'data' key with + 'nodes' as its child or directly contain 'nodes' key. Each node should have an 'id' and 'data'. + :param tweaks: A dictionary where the key is the node id and the value is a dictionary of the tweaks. + The inner dictionary contains the name of a certain parameter as the key and the value to be tweaked. + + :return: The modified graph_data dictionary. + + :raises ValueError: If the input is not in the expected format. + """ + nodes = validate_input(graph_data, tweaks) - # We need to process the graph data to add the tweaks - if "data" not in graph_data and "nodes" in graph_data: - nodes = graph_data["nodes"] - else: - nodes = graph_data["data"]["nodes"] for node in nodes: - node_id = node["id"] - if node_id in tweaks: - node_tweaks = tweaks[node_id] - template_data = node["data"]["node"]["template"] - for tweak_name, tweake_value in node_tweaks.items(): - if tweak_name in template_data: - template_data[tweak_name]["value"] = tweake_value + if isinstance(node, dict) and isinstance(node.get("id"), str): + node_id = node["id"] + if node_tweaks := tweaks.get(node_id): + apply_tweaks(node, node_tweaks) + else: + logger.warning( + "Each node should be a dictionary with an 'id' key of type str" + ) + return graph_data From 11185affdde27f0f9c71ddb8788e69aa55044d0d Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 12:02:15 -0300 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=90=9B=20fix(process.py):=20refacto?= =?UTF-8?q?r=20fix=5Fmemory=5Finputs=20function=20to=20improve=20readabili?= =?UTF-8?q?ty=20and=20reduce=20nesting=20The=20fix=5Fmemory=5Finputs=20fun?= =?UTF-8?q?ction=20was=20refactored=20to=20reduce=20nesting=20and=20improv?= =?UTF-8?q?e=20readability.=20The=20function=20now=20checks=20if=20the=20l?= =?UTF-8?q?angchain=5Fobject=20has=20a=20memory=20attribute=20and=20if=20i?= =?UTF-8?q?t=20is=20not=20None=20before=20proceeding.=20The=20try-except?= =?UTF-8?q?=20block=20was=20also=20refactored=20to=20reduce=20nesting.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/processing/process.py | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index e4ae33d27..8383f0cfe 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -20,22 +20,23 @@ def fix_memory_inputs(langchain_object): object's input variables. If so, it does nothing. Otherwise, it gets a possible new memory key using the get_memory_key function and updates the memory keys using the update_memory_keys function. """ - if hasattr(langchain_object, "memory") and langchain_object.memory is not None: - try: - if langchain_object.memory.memory_key in langchain_object.input_variables: - return - except AttributeError: - input_variables = ( - langchain_object.prompt.input_variables - if hasattr(langchain_object, "prompt") - else langchain_object.input_keys - ) - if langchain_object.memory.memory_key in input_variables: - return + if not hasattr(langchain_object, "memory") or langchain_object.memory is None: + return + try: + if langchain_object.memory.memory_key in langchain_object.input_variables: + return + except AttributeError: + input_variables = ( + langchain_object.prompt.input_variables + if hasattr(langchain_object, "prompt") + else langchain_object.input_keys + ) + if langchain_object.memory.memory_key in input_variables: + return - possible_new_mem_key = get_memory_key(langchain_object) - if possible_new_mem_key is not None: - update_memory_keys(langchain_object, possible_new_mem_key) + possible_new_mem_key = get_memory_key(langchain_object) + if possible_new_mem_key is not None: + update_memory_keys(langchain_object, possible_new_mem_key) def format_actions(actions: List[Tuple[AgentAction, str]]) -> str: From 76a1265eee946709211308a575893a693707e009 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 12:37:33 -0300 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=93=9D=20docs(README.md):=20update?= =?UTF-8?q?=20Langflow=20API=20usage=20example=20and=20add=20tweaks=20para?= =?UTF-8?q?meter=20The=20Langflow=20API=20usage=20example=20has=20been=20u?= =?UTF-8?q?pdated=20to=20reflect=20the=20new=20API=20endpoint=20URL.=20Add?= =?UTF-8?q?itionally,=20a=20new=20optional=20`tweaks`=20parameter=20has=20?= =?UTF-8?q?been=20added=20to=20the=20`run=5Fflow`=20function=20to=20allow?= =?UTF-8?q?=20customization=20of=20the=20flow.=20The=20example=20code=20ha?= =?UTF-8?q?s=20been=20updated=20to=20demonstrate=20how=20to=20use=20the=20?= =?UTF-8?q?`tweaks`=20parameter.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index bd377896c..8e3930997 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,11 @@ Alternatively, click the **"Open in Cloud Shell"** button below to launch Google Langflow integrates with langchain-serve to provide a one-command deployment to Jina AI Cloud. -Start by installing `langchain-serve` with +Start by installing `langchain-serve` with ```bash pip install -U langchain-serve -``` +``` Then, run: @@ -109,24 +109,38 @@ You can use Langflow directly on your browser, or use the API endpoints on Jina Show API usage (with python) ```python - import json - import requests +import requests - FLOW_PATH = "Time_traveller.json" +BASE_API_URL = "https://langflow-e3dd8820ec.wolf.jina.ai/api/v1/predict" +FLOW_ID = "864c4f98-2e59-468b-8e13-79cd8da07468" +# You can tweak the flow by adding a tweaks dictionary +# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}} +TWEAKS = { + "ChatOpenAI-g4jEr": {}, + "ConversationChain-UidfJ": {} +} - # HOST = 'http://localhost:7860' - HOST = 'https://langflow-f1ed20e309.wolf.jina.ai' - API_URL = f'{HOST}/predict' +def run_flow(message: str, flow_id: str, tweaks: dict = None) -> dict: + """ + Run a flow with a given message and optional tweaks. - def predict(message): - with open(FLOW_PATH, "r") as f: - json_data = json.load(f) - payload = {'exported_flow': json_data, 'message': message} - response = requests.post(API_URL, json=payload) - return response.json() + :param message: The message to send to the flow + :param flow_id: The ID of the flow to run + :param tweaks: Optional tweaks to customize the flow + :return: The JSON response from the flow + """ + api_url = f"{BASE_API_URL}/{flow_id}" + payload = {"message": message} - predict('Take me to 1920s Bangalore') + if tweaks: + payload["tweaks"] = tweaks + + response = requests.post(api_url, json=payload) + return response.json() + +# Setup any tweaks you want to apply to the flow +print(run_flow("Your message", flow_id=FLOW_ID, tweaks=TWEAKS)) ``` ```json From 8a5525f465059b3474706e897ad01b893cb07942 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 14:24:48 -0300 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=9A=80=20feat(constants.tsx):=20add?= =?UTF-8?q?=20tweaks=20parameter=20to=20getPythonCode=20function=20to=20al?= =?UTF-8?q?low=20for=20customization=20of=20flow=20behavior=20The=20`getPy?= =?UTF-8?q?thonCode`=20function=20now=20accepts=20a=20`tweaks`=20parameter?= =?UTF-8?q?=20which=20is=20used=20to=20customize=20the=20behavior=20of=20t?= =?UTF-8?q?he=20flow.=20The=20`buildTweaks`=20function=20is=20called=20to?= =?UTF-8?q?=20generate=20the=20`tweaks`=20object=20which=20is=20then=20pas?= =?UTF-8?q?sed=20to=20the=20`load=5Fflow=5Ffrom=5Fjson`=20function.=20This?= =?UTF-8?q?=20allows=20for=20more=20flexibility=20in=20the=20usage=20of=20?= =?UTF-8?q?the=20flow.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/frontend/src/constants.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/constants.tsx b/src/frontend/src/constants.tsx index 0e9a9ad3d..7017ac27e 100644 --- a/src/frontend/src/constants.tsx +++ b/src/frontend/src/constants.tsx @@ -121,9 +121,10 @@ export const getCurlCode = (flow: FlowType): string => { */ export const getPythonCode = (flow: FlowType): string => { const flowName = flow.name; + const tweaks = buildTweaks(flow); return `from langflow import load_flow_from_json - -flow = load_flow_from_json("${flowName}.json") +TWEAKS = ${JSON.stringify(tweaks, null, 2)} +flow = load_flow_from_json("${flowName}.json", tweaks=TWEAKS) # Now you can use it like any chain flow("Hey, have you heard of LangFlow?")`; }; From f180fa6f26293c20d55bcdd3acd15d0d93023d5d Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 14:25:10 -0300 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=90=9B=20fix(process.py):=20change?= =?UTF-8?q?=20input=20parameter=20type=20hint=20to=20include=20Path=20type?= =?UTF-8?q?=20The=20input=20parameter=20now=20accepts=20a=20Path=20object?= =?UTF-8?q?=20in=20addition=20to=20a=20string=20or=20dictionary.=20This=20?= =?UTF-8?q?improves=20the=20flexibility=20of=20the=20function=20and=20allo?= =?UTF-8?q?ws=20for=20easier=20file=20handling.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/processing/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index 8383f0cfe..4f5295c60 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -133,7 +133,7 @@ def process_graph_cached(data_graph: Dict[str, Any], message: str): def load_flow_from_json( - input: Union[str, dict], tweaks: Optional[dict] = None, build=True + input: Union[Path, str, dict], tweaks: Optional[dict] = None, build=True ): """ Load flow from a JSON file or a JSON object. From c5d6f487fac2a9f144913bd515c924416da6aade Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 19 Jun 2023 14:28:29 -0300 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9C=A8=20feat(Makefile):=20add=20build?= =?UTF-8?q?=5Fand=5Finstall=20target=20to=20build=20and=20install=20packag?= =?UTF-8?q?e=20without=20running=20it=20The=20path=20to=20the=20langflow.m?= =?UTF-8?q?ain=20module=20was=20incorrect,=20causing=20the=20backend=20tar?= =?UTF-8?q?get=20to=20fail.=20The=20path=20has=20been=20updated=20to=20the?= =?UTF-8?q?=20correct=20location.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build_and_install target has been added to build the package and install it without running it. This is useful when the package needs to be built and installed on a remote server. šŸ› fix(Makefile): fix path to langflow.main module in backend target --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6c1989ee1..bfed91f37 100644 --- a/Makefile +++ b/Makefile @@ -44,13 +44,18 @@ install_backend: backend: make install_backend - poetry run uvicorn langflow.main:app --port 7860 --reload --log-level debug + poetry run uvicorn src.backend.langflow.main:app --port 7860 --reload --log-level debug build_and_run: echo 'Removing dist folder' rm -rf dist make build && poetry run pip install dist/*.tar.gz && poetry run langflow +build_and_install: + echo 'Removing dist folder' + rm -rf dist + make build && poetry run pip install dist/*.tar.gz + build_frontend: cd src/frontend && CI='' npm run build cp -r src/frontend/build src/backend/langflow/frontend From 0dcd93ef92d4ae9a4e5a63e5bac74f0c9b23c16a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 19 Jun 2023 15:45:26 -0300 Subject: [PATCH 11/14] added discord and twitter icons, added github stars --- .../src/components/headerComponent/index.tsx | 52 +++++++++++++------ src/frontend/src/controllers/API/index.ts | 17 ++++++ 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 67ef327f2..48c73ac86 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -1,6 +1,6 @@ import { BellIcon, Home, Users2 } from "lucide-react"; -import { useContext } from "react"; -import { FaGithub } from "react-icons/fa"; +import { useContext, useEffect, useState } from "react"; +import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa"; import { Button } from "../ui/button"; import { TabsContext } from "../../contexts/tabsContext"; import AlertDropdown from "../../alerts/alertDropDown"; @@ -11,6 +11,7 @@ import { typesContext } from "../../contexts/typesContext"; import MenuBar from "./components/menuBar"; import { Link, useLocation, useParams } from "react-router-dom"; import { USER_PROJECTS_HEADER } from "../../constants"; +import { getRepoStars } from "../../controllers/API"; export default function Header() { const { flows, addFlow, tabId } = useContext(TabsContext); @@ -22,6 +23,16 @@ export default function Header() { const { notificationCenter, setNotificationCenter, setErrorData } = useContext(alertContext); const location = useLocation(); + + const [stars, setStars] = useState(null); + + useEffect(() => { + async function fetchStars() { + const starsCount = await getRepoStars("logspace-ai", "langflow"); + setStars(starsCount); + } + fetchStars(); + }, []); return (
@@ -57,22 +68,35 @@ export default function Header() {
-
- {/* - {/* */}
diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index f0c36a215..fb24a0f2b 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -18,6 +18,23 @@ export async function getAll(): Promise> { return await axios.get(`/api/v1/all`); } +const GITHUB_API_URL = "https://api.github.com"; +const GITHUB_PERSONAL_ACCESS_TOKEN = "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"; + +axios.defaults.headers.common[ + "Authorization" +] = `token ${GITHUB_PERSONAL_ACCESS_TOKEN}`; + +export async function getRepoStars(owner, repo) { + try { + const response = await axios.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`); + return response.data.stargazers_count; + } catch (error) { + console.error("Error fetching repository data:", error); + return null; + } +} + /** * Sends data to the API for prediction. * From 9be559397b422a941b23094c66e5e9416163df76 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 19 Jun 2023 16:14:25 -0300 Subject: [PATCH 12/14] removed api key --- src/frontend/src/controllers/API/index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index fb24a0f2b..28a41d578 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -19,11 +19,6 @@ export async function getAll(): Promise> { } const GITHUB_API_URL = "https://api.github.com"; -const GITHUB_PERSONAL_ACCESS_TOKEN = "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"; - -axios.defaults.headers.common[ - "Authorization" -] = `token ${GITHUB_PERSONAL_ACCESS_TOKEN}`; export async function getRepoStars(owner, repo) { try { From b616e0dd42d0852604ddfd16645d7a938207465b Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 19 Jun 2023 16:16:58 -0300 Subject: [PATCH 13/14] fixed twitter link --- src/frontend/src/components/headerComponent/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 48c73ac86..0d9459f45 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -82,7 +82,7 @@ export default function Header() { Date: Mon, 19 Jun 2023 16:27:08 -0300 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=94=96=20chore(pyproject.toml):=20b?= =?UTF-8?q?ump=20version=20to=200.1.4=20The=20version=20number=20has=20bee?= =?UTF-8?q?n=20updated=20from=200.1.3=20to=200.1.4.=20This=20is=20a=20chor?= =?UTF-8?q?e=20commit=20as=20it=20does=20not=20introduce=20any=20new=20fea?= =?UTF-8?q?tures=20or=20bug=20fixes,=20but=20rather=20updates=20the=20vers?= =?UTF-8?q?ion=20number=20to=20reflect=20changes=20made=20in=20the=20packa?= =?UTF-8?q?ge.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 14 +++++++------- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/poetry.lock b/poetry.lock index c8843ccba..b5503c034 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3812,14 +3812,14 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- [[package]] name = "pluggy" -version = "1.1.0" +version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "pluggy-1.1.0-py3-none-any.whl", hash = "sha256:d81d19a3a88d82ed06998353ce5d5c02587ef07ee2d808ae63904ab0ccef0087"}, - {file = "pluggy-1.1.0.tar.gz", hash = "sha256:c500b592c5512df35622e4faf2135aa0b7e989c7d31344194b4afb9d5e47b1bf"}, + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] [package.extras] @@ -5036,14 +5036,14 @@ files = [ [[package]] name = "setuptools" -version = "67.8.0" +version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, - {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index dd2cdda71..27db6b115 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow" -version = "0.1.3" +version = "0.1.4" description = "A Python package with a built-in web application" authors = ["Logspace "] maintainers = [