Merge branch 'dev' of https://github.com/logspace-ai/langflow into 45-implement-agents-as-tools
This commit is contained in:
commit
1fc05f6f46
28 changed files with 162 additions and 109 deletions
|
|
@ -43,9 +43,11 @@ the system we use to tag our issues and pull requests.
|
||||||
You can develop LangFlow using docker compose, or locally.
|
You can develop LangFlow using docker compose, or locally.
|
||||||
|
|
||||||
#### **Docker compose**
|
#### **Docker compose**
|
||||||
This will run the backend and frontend in separate containers. The frontend will be available at `localhost:3000` and the backend at `localhost:5003`.
|
This will run the backend and frontend in separate containers. The frontend will be available at `localhost:3000` and the backend at `localhost:7860`.
|
||||||
```bash
|
```bash
|
||||||
docker compose up --build
|
docker compose up --build
|
||||||
|
# or
|
||||||
|
make dev build=1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **Locally**
|
#### **Locally**
|
||||||
|
|
@ -58,7 +60,6 @@ Before you start, make sure you have the following installed:
|
||||||
For the backend, you will need to install the dependencies and start the development server.
|
For the backend, you will need to install the dependencies and start the development server.
|
||||||
```bash
|
```bash
|
||||||
poetry install
|
poetry install
|
||||||
# Port 5003 is required for the backend to work with the frontend
|
|
||||||
make run_backend
|
make run_backend
|
||||||
```
|
```
|
||||||
For the frontend, you will need to install the dependencies and start the development server.
|
For the frontend, you will need to install the dependencies and start the development server.
|
||||||
|
|
|
||||||
15
Makefile
15
Makefile
|
|
@ -39,6 +39,17 @@ build:
|
||||||
poetry build --format sdist
|
poetry build --format sdist
|
||||||
rm -rf src/backend/langflow/frontend
|
rm -rf src/backend/langflow/frontend
|
||||||
|
|
||||||
|
dev:
|
||||||
|
make install_frontend
|
||||||
|
ifeq ($(build),1)
|
||||||
|
@echo 'Running docker compose up with build'
|
||||||
|
docker compose up --build
|
||||||
|
else
|
||||||
|
@echo 'Running docker compose up without build'
|
||||||
|
docker compose up
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
make build
|
make build
|
||||||
poetry publish
|
poetry publish
|
||||||
|
|
@ -49,4 +60,8 @@ help:
|
||||||
@echo 'lint - run linters'
|
@echo 'lint - run linters'
|
||||||
@echo 'install_frontend - install the frontend dependencies'
|
@echo 'install_frontend - install the frontend dependencies'
|
||||||
@echo 'build_frontend - build the frontend static files'
|
@echo 'build_frontend - build the frontend static files'
|
||||||
|
@echo 'run_frontend - run the frontend in development mode'
|
||||||
|
@echo 'run_backend - run the backend in development mode'
|
||||||
@echo 'build - build the frontend static files and package the project'
|
@echo 'build - build the frontend static files and package the project'
|
||||||
|
@echo 'publish - build the frontend static files and package the project and publish it to PyPI'
|
||||||
|
@echo 'dev - run the project in development mode with docker compose'
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -34,6 +34,18 @@ Creating flows with LangFlow is easy. Simply drag sidebar components onto the ca
|
||||||
|
|
||||||
Explore by editing prompt parameters, link chains and agents, track an agent's thought process, and export your flow.
|
Explore by editing prompt parameters, link chains and agents, track an agent's thought process, and export your flow.
|
||||||
|
|
||||||
|
Once you're done, you can export your flow as a JSON file to use with LangChain.
|
||||||
|
To do so, click the "Export" button in the top right corner of the canvas, then
|
||||||
|
in Python, you can load the flow with:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from langflow import load_flow_from_json
|
||||||
|
|
||||||
|
flow = load_flow_from_json("path/to/flow.json")
|
||||||
|
# Now you can use it like any chain
|
||||||
|
flow("Hey, have you heard of LangFlow?")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 👋 Contributing
|
## 👋 Contributing
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ FROM python:3.10-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install Poetry
|
# Install Poetry
|
||||||
RUN apt-get update && apt-get install -y curl
|
RUN apt-get update && apt-get install gcc curl -y
|
||||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||||
# # Add Poetry to PATH
|
# # Add Poetry to PATH
|
||||||
ENV PATH="${PATH}:/root/.local/bin"
|
ENV PATH="${PATH}:/root/.local/bin"
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ services:
|
||||||
build:
|
build:
|
||||||
context: ./src/frontend
|
context: ./src/frontend
|
||||||
dockerfile: ./dev.Dockerfile
|
dockerfile: ./dev.Dockerfile
|
||||||
|
args:
|
||||||
|
- BACKEND_URL=http://backend:7860
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./src/frontend:/app
|
- ./src/frontend/public:/home/node/app/public
|
||||||
# Set process.env.BACKEND to the backend service
|
- ./src/frontend/src:/home/node/app/src
|
||||||
environment:
|
- ./src/frontend/package.json:/home/node/app/package.json
|
||||||
- BACKEND_HOST="http://backend"
|
|
||||||
- BACKEND_PORT="7860"
|
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
9
poetry.lock
generated
9
poetry.lock
generated
|
|
@ -1378,13 +1378,14 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openai"
|
name = "openai"
|
||||||
version = "0.26.5"
|
version = "0.27.2"
|
||||||
description = "Python client library for the OpenAI API"
|
description = "Python client library for the OpenAI API"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.1"
|
python-versions = ">=3.7.1"
|
||||||
files = [
|
files = [
|
||||||
{file = "openai-0.26.5.tar.gz", hash = "sha256:2882a59c67ae33c2716a04389a6e6680d061f073424953732f917fde219addfd"},
|
{file = "openai-0.27.2-py3-none-any.whl", hash = "sha256:6df674cf257e9e0504f1fd191c333d3f6a2442b13218d0eccf06230eb24d320e"},
|
||||||
|
{file = "openai-0.27.2.tar.gz", hash = "sha256:5869fdfa34b0ec66c39afa22f4a0fb83a135dff81f6505f52834c6ab3113f762"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
|
@ -1395,7 +1396,7 @@ tqdm = "*"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
datalib = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
|
datalib = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
|
||||||
dev = ["black (>=21.6b0,<22.0)", "pytest (>=6.0.0,<7.0.0)", "pytest-asyncio", "pytest-mock"]
|
dev = ["black (>=21.6b0,<22.0)", "pytest (>=6.0.0,<7.0.0)", "pytest-asyncio", "pytest-mock"]
|
||||||
embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "sklearn", "tenacity (>=8.0.1)"]
|
embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "scipy", "tenacity (>=8.0.1)"]
|
||||||
wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"]
|
wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2406,4 +2407,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "9287450d71ec7c3bd7b1ef2766e22b86fb92bf0e2f51260adf039b1175c74f7c"
|
content-hash = "ebc0a8ca9ea284d8e986306a10f13ff91e7e8aae18341c83329f5b1e1bcc66bd"
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,27 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "langflow"
|
name = "langflow"
|
||||||
version = "0.0.40"
|
version = "0.0.45"
|
||||||
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>"]
|
||||||
packages = [
|
maintainers = [
|
||||||
{ include = "langflow", from = "src/backend" },
|
"Gabriel Almeida <gabriel@logspace.ai>",
|
||||||
|
"Ibis Prevedello <ibiscp@gmail.com>",
|
||||||
|
"Lucas Eduoli <lucaseduoli@gmail.com>",
|
||||||
|
"Otávio Anovazzi <otavio2204@gmail.com>",
|
||||||
]
|
]
|
||||||
include = ["src/backend/langflow/*", "src/backend/langflow/**/*"]
|
repository = "https://github.com/logspace-ai/langflow"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
keywords = ["nlp", "langchain", "openai", "gpt", "gui"]
|
||||||
|
packages = [{ include = "langflow", from = "src/backend" }]
|
||||||
|
include = ["src/backend/langflow/*", "src/backend/langflow/**/*"]
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
langflow = "langflow.__main__:main"
|
langflow = "langflow.__main__:main"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.9"
|
python = "^3.9"
|
||||||
openai = "^0.26.5"
|
|
||||||
fastapi = "^0.92.0"
|
fastapi = "^0.92.0"
|
||||||
uvicorn = "^0.20.0"
|
uvicorn = "^0.20.0"
|
||||||
beautifulsoup4 = "^4.11.2"
|
beautifulsoup4 = "^4.11.2"
|
||||||
|
|
@ -24,6 +30,7 @@ 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.113"
|
langchain = "^0.0.113"
|
||||||
|
openai = "^0.27.2"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^23.1.0"
|
black = "^23.1.0"
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import platform
|
import platform
|
||||||
import re
|
|
||||||
|
|
||||||
from langflow.main import create_app
|
from langflow.main import create_app
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_number_of_workers(workers=None):
|
def get_number_of_workers(workers=None):
|
||||||
|
|
@ -15,35 +17,6 @@ def get_number_of_workers(workers=None):
|
||||||
return workers
|
return workers
|
||||||
|
|
||||||
|
|
||||||
def replace_port(static_files_dir, host, port):
|
|
||||||
# Load index.html from frontend directory
|
|
||||||
# In it there is a script tag that sets the base url
|
|
||||||
# like so setItem("port", "http://localhost:7860")
|
|
||||||
# localhost could be anything so we need to verify for string
|
|
||||||
# we need to set the base url to the port that the server is running on
|
|
||||||
# so that the frontend can make requests to the backend
|
|
||||||
# This is a hacky way to do it, but it works
|
|
||||||
new_string = f'setItem("port","http://{host}:{port}")'
|
|
||||||
with open(static_files_dir / "index.html", "r") as f:
|
|
||||||
index_html = f.read()
|
|
||||||
# using regex to replace the port
|
|
||||||
index_html = re.sub(
|
|
||||||
r"setItem\(\"port\",.*\)",
|
|
||||||
new_string,
|
|
||||||
index_html,
|
|
||||||
)
|
|
||||||
with open(static_files_dir / "index.html", "w") as f:
|
|
||||||
f.write(index_html)
|
|
||||||
# Verify that the port was replaced
|
|
||||||
with open(static_files_dir / "index.html", "r") as f:
|
|
||||||
index_html = f.read()
|
|
||||||
if new_string not in index_html:
|
|
||||||
raise ValueError(
|
|
||||||
"The port was not replaced in index.html. "
|
|
||||||
"Please check the regex in main.py"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def serve(
|
def serve(
|
||||||
host: str = "127.0.0.1", workers: int = 1, timeout: int = 60, port: int = 7860
|
host: str = "127.0.0.1", workers: int = 1, timeout: int = 60, port: int = 7860
|
||||||
):
|
):
|
||||||
|
|
@ -63,9 +36,6 @@ def serve(
|
||||||
"timeout": timeout,
|
"timeout": timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Replace the port in index.html
|
|
||||||
replace_port(static_files_dir, host, port)
|
|
||||||
|
|
||||||
if platform.system() in ["Darwin", "Windows"]:
|
if platform.system() in ["Darwin", "Windows"]:
|
||||||
# Run using uvicorn on MacOS and Windows
|
# Run using uvicorn on MacOS and Windows
|
||||||
# Windows doesn't support gunicorn
|
# Windows doesn't support gunicorn
|
||||||
|
|
|
||||||
6
src/backend/langflow/interface/custom_lists.py
Normal file
6
src/backend/langflow/interface/custom_lists.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
from langchain import llms
|
||||||
|
from langchain.llms.openai import OpenAIChat
|
||||||
|
|
||||||
|
|
||||||
|
llm_type_to_cls_dict = llms.type_to_cls_dict
|
||||||
|
llm_type_to_cls_dict["openai-chat"] = OpenAIChat
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from langchain import chains, agents, prompts, llms
|
from langchain import chains, agents, prompts
|
||||||
|
from langflow.interface.custom_lists import llm_type_to_cls_dict
|
||||||
from langflow.custom import customs
|
from langflow.custom import customs
|
||||||
from langflow.utils import util, allowed_components
|
from langflow.utils import util, allowed_components
|
||||||
from langchain.agents.load_tools import get_all_tool_names
|
from langchain.agents.load_tools import get_all_tool_names
|
||||||
|
|
@ -55,7 +56,7 @@ def list_llms():
|
||||||
"""List all llm types"""
|
"""List all llm types"""
|
||||||
return [
|
return [
|
||||||
llm.__name__
|
llm.__name__
|
||||||
for llm in llms.type_to_cls_dict.values()
|
for llm in llm_type_to_cls_dict.values()
|
||||||
if llm.__name__ in allowed_components.LLMS
|
if llm.__name__ in allowed_components.LLMS
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import Dict, Any # noqa: F401
|
from typing import Dict, Any # noqa: F401
|
||||||
from langchain import agents, chains, llms, prompts
|
from langchain import agents, chains, prompts
|
||||||
|
from langflow.interface.custom_lists import llm_type_to_cls_dict
|
||||||
from langchain.agents.load_tools import (
|
from langchain.agents.load_tools import (
|
||||||
_BASE_TOOLS,
|
_BASE_TOOLS,
|
||||||
_EXTRA_LLM_TOOLS,
|
_EXTRA_LLM_TOOLS,
|
||||||
|
|
@ -56,7 +57,7 @@ def get_prompt_signature(name: str):
|
||||||
def get_llm_signature(name: str):
|
def get_llm_signature(name: str):
|
||||||
"""Get the signature of an llm."""
|
"""Get the signature of an llm."""
|
||||||
try:
|
try:
|
||||||
return util.build_template_from_class(name, llms.type_to_cls_dict)
|
return util.build_template_from_class(name, llm_type_to_cls_dict)
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
raise ValueError("LLM not found") from exc
|
raise ValueError("LLM not found") from exc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ AGENTS = ["ZeroShotAgent"]
|
||||||
|
|
||||||
PROMPTS = ["PromptTemplate", "FewShotPromptTemplate"]
|
PROMPTS = ["PromptTemplate", "FewShotPromptTemplate"]
|
||||||
|
|
||||||
LLMS = ["OpenAI"]
|
LLMS = ["OpenAI", "OpenAIChat"]
|
||||||
|
|
||||||
TOOLS = ["Search", "PAL-MATH", "Calculator", "Serper Search"]
|
TOOLS = ["Search", "PAL-MATH", "Calculator", "Serper Search"]
|
||||||
|
|
|
||||||
8
src/backend/langflow/utils/constants.py
Normal file
8
src/backend/langflow/utils/constants.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
OPENAI_MODELS = [
|
||||||
|
"text-davinci-003",
|
||||||
|
"text-davinci-002",
|
||||||
|
"text-curie-001",
|
||||||
|
"text-babbage-001",
|
||||||
|
"text-ada-001",
|
||||||
|
]
|
||||||
|
CHAT_OPENAI_MODELS = ["gpt-3.5-turbo", "gpt-4", "gpt-4-32k"]
|
||||||
|
|
@ -11,6 +11,8 @@ from langchain.agents.load_tools import (
|
||||||
)
|
)
|
||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
|
|
||||||
|
from langflow.utils import constants
|
||||||
|
|
||||||
|
|
||||||
def build_template_from_function(name: str, type_to_loader_dict: Dict):
|
def build_template_from_function(name: str, type_to_loader_dict: Dict):
|
||||||
classes = [
|
classes = [
|
||||||
|
|
@ -296,7 +298,9 @@ def format_dict(d, name: Optional[str] = None):
|
||||||
|
|
||||||
# Add options to openai
|
# Add options to openai
|
||||||
if name == "OpenAI" and key == "model_name":
|
if name == "OpenAI" and key == "model_name":
|
||||||
value["options"] = ["text-davinci-003", "text-davinci-002"]
|
value["options"] = constants.OPENAI_MODELS
|
||||||
|
elif name == "OpenAIChat" and key == "model_name":
|
||||||
|
value["options"] = constants.CHAT_OPENAI_MODELS
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,23 @@
|
||||||
FROM node:19-alpine as frontend_build
|
#baseline
|
||||||
ARG BACKEND
|
FROM node:19-bullseye-slim AS base
|
||||||
WORKDIR /app
|
RUN mkdir -p /home/node/app
|
||||||
COPY . /app
|
RUN chown -R node:node /home/node && chmod -R 770 /home/node
|
||||||
RUN npm install
|
RUN apt-get update && apt-get install -y jq
|
||||||
|
WORKDIR /home/node/app
|
||||||
|
|
||||||
|
# client build
|
||||||
|
FROM base AS builder-client
|
||||||
|
ARG BACKEND_URL
|
||||||
|
ENV BACKEND_URL $BACKEND_URL
|
||||||
|
RUN echo "BACKEND_URL: $BACKEND_URL"
|
||||||
|
|
||||||
|
WORKDIR /home/node/app
|
||||||
|
COPY --chown=node:node . ./
|
||||||
|
|
||||||
|
COPY ./set_proxy.sh .
|
||||||
|
RUN chmod +x set_proxy.sh && ./set_proxy.sh
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
RUN npm install --loglevel warn
|
||||||
CMD ["npm", "start"]
|
CMD ["npm", "start"]
|
||||||
10
src/frontend/package-lock.json
generated
10
src/frontend/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "langflow",
|
"name": "langflow",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "langflow",
|
"name": "langflow",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
|
|
@ -17080,9 +17080,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webpack": {
|
"node_modules/webpack": {
|
||||||
"version": "5.75.0",
|
"version": "5.76.2",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz",
|
||||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
"integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.3",
|
"@types/eslint-scope": "^3.7.3",
|
||||||
"@types/estree": "^0.0.51",
|
"@types/estree": "^0.0.51",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "langflow",
|
"name": "langflow",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
|
|
@ -53,5 +53,6 @@
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"proxy": "http://backend:7860"
|
||||||
}
|
}
|
||||||
|
|
@ -5,9 +5,6 @@
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>LangFLow</title>
|
<title>LangFLow</title>
|
||||||
<script>
|
|
||||||
window.sessionStorage.setItem("port","http://localhost:7860")
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body id='body' style="width: 100%; height:100%">
|
<body id='body' style="width: 100%; height:100%">
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|
|
||||||
10
src/frontend/set_proxy.sh
Executable file
10
src/frontend/set_proxy.sh
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#! /bin/bash
|
||||||
|
# Edit package.json to set proxy
|
||||||
|
backend_url=$BACKEND_URL
|
||||||
|
echo "Setting proxy to $backend_url"
|
||||||
|
# Load package.json file and edit proxy
|
||||||
|
packagejson=$(cat package.json)
|
||||||
|
|
||||||
|
packagejson=$(echo "$packagejson" | jq ".proxy = \"$backend_url\"")
|
||||||
|
|
||||||
|
echo "$packagejson" > package.json
|
||||||
|
|
@ -39,7 +39,6 @@ export default function ParameterComponent({
|
||||||
const [enabled, setEnabled] = useState(
|
const [enabled, setEnabled] = useState(
|
||||||
data.node.template[name]?.value ?? false
|
data.node.template[name]?.value ?? false
|
||||||
);
|
);
|
||||||
console.log(data.node.template[name]);
|
|
||||||
const { reactFlowInstance } = useContext(typesContext);
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
let disabled =
|
let disabled =
|
||||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,8 @@ export default function GenericNode({ data, selected}:{data:NodeDataType,selecte
|
||||||
data={data}
|
data={data}
|
||||||
color={nodeColors[types[data.type]]}
|
color={nodeColors[types[data.type]]}
|
||||||
title={data.type}
|
title={data.type}
|
||||||
tooltipTitle={"Type: str"}
|
tooltipTitle={`Type: ${data.node.base_classes.join(' | ')}`}
|
||||||
id={data.type + "|" + data.id + data.node.base_classes.map((b) => ("|" + b))}
|
id={[data.type, data.id, ...data.node.base_classes].join('|')}
|
||||||
type={'str'}
|
type={'str'}
|
||||||
left={false}
|
left={false}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import { SingleAlertComponentType } from "../../../../types/alerts";
|
||||||
export default function SingleAlert({ dropItem, removeAlert}:SingleAlertComponentType) {
|
export default function SingleAlert({ dropItem, removeAlert}:SingleAlertComponentType) {
|
||||||
const [show, setShow] = useState(true);
|
const [show, setShow] = useState(true);
|
||||||
const type = dropItem.type;
|
const type = dropItem.type;
|
||||||
console.log(dropItem.id)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition
|
<Transition
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ export default function AlertDropdown({}: AlertDropdownType) {
|
||||||
componentRef.current &&
|
componentRef.current &&
|
||||||
!componentRef.current.contains(event.target as Node)
|
!componentRef.current.contains(event.target as Node)
|
||||||
) {
|
) {
|
||||||
console.log(event)
|
|
||||||
closePopUp();
|
closePopUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) {
|
||||||
setChatHistory((old) => {
|
setChatHistory((old) => {
|
||||||
let newChat = _.cloneDeep(old);
|
let newChat = _.cloneDeep(old);
|
||||||
if(JSON.stringify(flow.chat) !==JSON.stringify(old)){
|
if(JSON.stringify(flow.chat) !==JSON.stringify(old)){
|
||||||
console.log(old,flow.chat)
|
|
||||||
tabsChange = true
|
tabsChange = true
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +42,6 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) {
|
||||||
return newChat;
|
return newChat;
|
||||||
});
|
});
|
||||||
if(tabsChange){
|
if(tabsChange){
|
||||||
console.log(flow.chat)
|
|
||||||
if(thought){
|
if(thought){
|
||||||
updateFlow({..._.cloneDeep(flow),chat:[...flow.chat,{isSend,message,thought}]})
|
updateFlow({..._.cloneDeep(flow),chat:[...flow.chat,{isSend,message,thought}]})
|
||||||
}
|
}
|
||||||
|
|
@ -98,11 +96,9 @@ export default function Chat({ flow, reactFlowInstance }: ChatType) {
|
||||||
let message = chatValue;
|
let message = chatValue;
|
||||||
setChatValue("");
|
setChatValue("");
|
||||||
addChatHistory(message, true);
|
addChatHistory(message, true);
|
||||||
console.log({ ...reactFlowInstance.toObject(), message, chatHistory });
|
|
||||||
|
|
||||||
sendAll({ ...reactFlowInstance.toObject(), message, chatHistory})
|
sendAll({ ...reactFlowInstance.toObject(), message, chatHistory})
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
console.log(r.data);
|
|
||||||
addChatHistory(r.data.result, false, r.data.thought);
|
addChatHistory(r.data.result, false, r.data.thought);
|
||||||
setLockChat(false);
|
setLockChat(false);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
// Create a new flow with a default name if no flow is provided.
|
// Create a new flow with a default name if no flow is provided.
|
||||||
let newFlow: FlowType = {
|
let newFlow: FlowType = {
|
||||||
name: flow ? flow.name : "New Flow " + (flows.length===0?"":flows.length),
|
name: "New Flow",
|
||||||
id: id.toString(),
|
id: id.toString(),
|
||||||
data,
|
data,
|
||||||
chat: flow ? flow.chat : [],
|
chat: flow ? flow.chat : [],
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
import { APIObjectType, sendAllProps } from '../../types/api/index';
|
import { APIObjectType, sendAllProps } from '../../types/api/index';
|
||||||
import axios, { AxiosResponse } from "axios";
|
import axios, { AxiosResponse } from "axios";
|
||||||
|
|
||||||
const backendUrl = window.sessionStorage.getItem('port') || "http://localhost:7860";
|
|
||||||
|
|
||||||
export async function getAll():Promise<AxiosResponse<APIObjectType>> {
|
export async function getAll():Promise<AxiosResponse<APIObjectType>> {
|
||||||
return await axios.get(`${backendUrl}/all`);
|
return await axios.get(`/all`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendAll(data:sendAllProps) {
|
export async function sendAll(data:sendAllProps) {
|
||||||
console.log(data);
|
return await axios.post(`/predict`, data);
|
||||||
return await axios.post(`${backendUrl}/predict`, data);
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,17 +4,24 @@ import TabComponent from "../tabComponent";
|
||||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||||
import FlowPage from "../..";
|
import FlowPage from "../..";
|
||||||
import { darkContext } from "../../../../contexts/darkContext";
|
import { darkContext } from "../../../../contexts/darkContext";
|
||||||
import { BellIcon, MoonIcon, SunIcon } from "@heroicons/react/24/outline";
|
import {
|
||||||
|
ArrowDownTrayIcon,
|
||||||
|
ArrowUpTrayIcon,
|
||||||
|
BellIcon,
|
||||||
|
MoonIcon,
|
||||||
|
SunIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||||
import AlertDropdown from "../../../../alerts/alertDropDown";
|
import AlertDropdown from "../../../../alerts/alertDropDown";
|
||||||
import { alertContext } from "../../../../contexts/alertContext";
|
import { alertContext } from "../../../../contexts/alertContext";
|
||||||
|
|
||||||
export default function TabsManagerComponent() {
|
export default function TabsManagerComponent() {
|
||||||
const { flows, addFlow, tabIndex, setTabIndex } = useContext(TabsContext);
|
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = useContext(TabsContext);
|
||||||
const { openPopUp } = useContext(PopUpContext);
|
const { openPopUp } = useContext(PopUpContext);
|
||||||
const AlertWidth = 256
|
const AlertWidth = 256;
|
||||||
const { dark, setDark } = useContext(darkContext);
|
const { dark, setDark } = useContext(darkContext);
|
||||||
const {notificationCenter, setNotificationCenter} = useContext(alertContext)
|
const { notificationCenter, setNotificationCenter } =
|
||||||
|
useContext(alertContext);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//create the first flow
|
//create the first flow
|
||||||
if (flows.length === 0) {
|
if (flows.length === 0) {
|
||||||
|
|
@ -43,6 +50,12 @@ export default function TabsManagerComponent() {
|
||||||
flow={null}
|
flow={null}
|
||||||
/>
|
/>
|
||||||
<div className="ml-auto mr-2 flex gap-3">
|
<div className="ml-auto mr-2 flex gap-3">
|
||||||
|
<button onClick={() => uploadFlow()} className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-400 hover:text-gray-500">
|
||||||
|
Import <ArrowUpTrayIcon className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
<button onClick={() => downloadFlow()} className="flex items-center gap-1 mr-2 text-sm text-gray-400 hover:text-gray-500">
|
||||||
|
Export <ArrowDownTrayIcon className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className="text-gray-400 hover:text-gray-500 "
|
className="text-gray-400 hover:text-gray-500 "
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -58,13 +71,23 @@ export default function TabsManagerComponent() {
|
||||||
<button
|
<button
|
||||||
className="text-gray-400 hover:text-gray-500 relative"
|
className="text-gray-400 hover:text-gray-500 relative"
|
||||||
onClick={(event: React.MouseEvent<HTMLElement>) => {
|
onClick={(event: React.MouseEvent<HTMLElement>) => {
|
||||||
setNotificationCenter(false)
|
setNotificationCenter(false);
|
||||||
const top = (event.target as Element).getBoundingClientRect().top
|
const top = (event.target as Element).getBoundingClientRect().top;
|
||||||
const left = (event.target as Element).getBoundingClientRect().left
|
const left = (event.target as Element).getBoundingClientRect()
|
||||||
openPopUp(<div className="z-10 absolute" style={{top:top+20, left:left-AlertWidth}}><AlertDropdown/></div>)
|
.left;
|
||||||
|
openPopUp(
|
||||||
|
<div
|
||||||
|
className="z-10 absolute"
|
||||||
|
style={{ top: top + 20, left: left - AlertWidth }}
|
||||||
|
>
|
||||||
|
<AlertDropdown />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{notificationCenter&&<div className='absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]'></div>}
|
{notificationCenter && (
|
||||||
|
<div className="absolute w-1.5 h-1.5 rounded-full bg-red-600 right-[3px]"></div>
|
||||||
|
)}
|
||||||
<BellIcon className="h-5 w-5" aria-hidden="true" />
|
<BellIcon className="h-5 w-5" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -182,17 +182,6 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
|
||||||
>
|
>
|
||||||
<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 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">
|
||||||
<ControlButton
|
|
||||||
onClick={() => uploadFlow()}
|
|
||||||
>
|
|
||||||
<ArrowUpTrayIcon />
|
|
||||||
</ControlButton>
|
|
||||||
|
|
||||||
<ControlButton
|
|
||||||
onClick={() => downloadFlow()}
|
|
||||||
>
|
|
||||||
<ArrowDownTrayIcon />
|
|
||||||
</ControlButton>
|
|
||||||
</Controls>
|
</Controls>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
|
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue