Merge pull request #49 from logspace-ai/dev

Release
This commit is contained in:
Ibis Prevedello 2023-03-20 12:55:31 -03:00 • committed by GitHub
commit 15a5e9979b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 201 additions and 122 deletions

View file

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

View file

@ -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 'build - build the frontend static files and package the project' @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 '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'

View file

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

View file

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

View file

@ -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" restart: on-failure
- BACKEND_PORT="7860"
restart: on-failure

113
poetry.lock generated
View file

@ -594,19 +594,19 @@ tests = ["asttokens", "littleutils", "pytest", "rich"]
[[package]] [[package]]
name = "fastapi" name = "fastapi"
version = "0.91.0" version = "0.92.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "fastapi-0.91.0-py3-none-any.whl", hash = "sha256:8dc18f860755159b3c4b30577c61c821b98f382acfeb6d5a849f9fa6a5369789"}, {file = "fastapi-0.92.0-py3-none-any.whl", hash = "sha256:ae7b97c778e2f2ec3fb3cb4fb14162129411d99907fb71920f6d69a524340ebf"},
{file = "fastapi-0.91.0.tar.gz", hash = "sha256:ff2fa93af3f2f982b07b5f96e8512565b3ef0e5f8f02469dbfd6bc27f6fd9a9e"}, {file = "fastapi-0.92.0.tar.gz", hash = "sha256:023a0f5bd2c8b2609014d3bba1e14a1d7df96c6abea0a73070621c9862b9a4de"},
] ]
[package.dependencies] [package.dependencies]
pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
starlette = ">=0.24.0,<0.25.0" starlette = ">=0.25.0,<0.26.0"
[package.extras] [package.extras]
all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
@ -950,14 +950,14 @@ files = [
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "6.0.0" version = "6.1.0"
description = "Read metadata from Python packages" description = "Read metadata from Python packages"
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"},
{file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"},
] ]
[package.dependencies] [package.dependencies]
@ -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]]
@ -1993,53 +1994,53 @@ files = [
[[package]] [[package]]
name = "sqlalchemy" name = "sqlalchemy"
version = "1.4.46" version = "1.4.47"
description = "Database Abstraction Library" description = "Database Abstraction Library"
category = "main" category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
files = [ files = [
{file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, {file = "SQLAlchemy-1.4.47-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcfb480bfc9e1fab726003ae00a6bfc67a29bad275b63a4e36d17fe7f13a624e"},
{file = "SQLAlchemy-1.4.46-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf"}, {file = "SQLAlchemy-1.4.47-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28fda5a69d6182589892422c5a9b02a8fd1125787aab1d83f1392aa955bf8d0a"},
{file = "SQLAlchemy-1.4.46-cp27-cp27m-win32.whl", hash = "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854"}, {file = "SQLAlchemy-1.4.47-cp27-cp27m-win32.whl", hash = "sha256:45e799c1a41822eba6bee4e59b0e38764e1a1ee69873ab2889079865e9ea0e23"},
{file = "SQLAlchemy-1.4.46-cp27-cp27m-win_amd64.whl", hash = "sha256:7b81b1030c42b003fc10ddd17825571603117f848814a344d305262d370e7c34"}, {file = "SQLAlchemy-1.4.47-cp27-cp27m-win_amd64.whl", hash = "sha256:10edbb92a9ef611f01b086e271a9f6c1c3e5157c3b0c5ff62310fb2187acbd4a"},
{file = "SQLAlchemy-1.4.46-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:939f9a018d2ad04036746e15d119c0428b1e557470361aa798e6e7d7f5875be0"}, {file = "SQLAlchemy-1.4.47-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a4df53472c9030a8ddb1cce517757ba38a7a25699bbcabd57dcc8a5d53f324e"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b7f4b6aa6e87991ec7ce0e769689a977776db6704947e562102431474799a857"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:511d4abc823152dec49461209607bbfb2df60033c8c88a3f7c93293b8ecbb13d"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf17ac9a61e7a3f1c7ca47237aac93cabd7f08ad92ac5b96d6f8dea4287fc1"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbe57f39f531c5d68d5594ea4613daa60aba33bb51a8cc42f96f17bbd6305e8d"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7f8267682eb41a0584cf66d8a697fef64b53281d01c93a503e1344197f2e01fe"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca8ab6748e3ec66afccd8b23ec2f92787a58d5353ce9624dccd770427ee67c82"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cb0ad8a190bc22d2112001cfecdec45baffdf41871de777239da6a28ed74b6"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299b5c5c060b9fbe51808d0d40d8475f7b3873317640b9b7617c7f988cf59fda"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-win32.whl", hash = "sha256:5f752676fc126edc1c4af0ec2e4d2adca48ddfae5de46bb40adbd3f903eb2120"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-win32.whl", hash = "sha256:684e5c773222781775c7f77231f412633d8af22493bf35b7fa1029fdf8066d10"},
{file = "SQLAlchemy-1.4.46-cp310-cp310-win_amd64.whl", hash = "sha256:31de1e2c45e67a5ec1ecca6ec26aefc299dd5151e355eb5199cd9516b57340be"}, {file = "SQLAlchemy-1.4.47-cp310-cp310-win_amd64.whl", hash = "sha256:2bba39b12b879c7b35cde18b6e14119c5f1a16bd064a48dd2ac62d21366a5e17"},
{file = "SQLAlchemy-1.4.46-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d68e1762997bfebf9e5cf2a9fd0bcf9ca2fdd8136ce7b24bbd3bbfa4328f3e4a"}, {file = "SQLAlchemy-1.4.47-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:795b5b9db573d3ed61fae74285d57d396829e3157642794d3a8f72ec2a5c719b"},
{file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d112b0f3c1bc5ff70554a97344625ef621c1bfe02a73c5d97cac91f8cd7a41e"}, {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:989c62b96596b7938cbc032e39431e6c2d81b635034571d6a43a13920852fb65"},
{file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69fac0a7054d86b997af12dc23f581cf0b25fb1c7d1fed43257dee3af32d3d6d"}, {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b67bda733da1dcdccaf354e71ef01b46db483a4f6236450d3f9a61efdba35a"},
{file = "SQLAlchemy-1.4.46-cp311-cp311-win32.whl", hash = "sha256:887865924c3d6e9a473dc82b70977395301533b3030d0f020c38fd9eba5419f2"}, {file = "SQLAlchemy-1.4.47-cp311-cp311-win32.whl", hash = "sha256:9a198f690ac12a3a807e03a5a45df6a30cd215935f237a46f4248faed62e69c8"},
{file = "SQLAlchemy-1.4.46-cp311-cp311-win_amd64.whl", hash = "sha256:984ee13543a346324319a1fb72b698e521506f6f22dc37d7752a329e9cd00a32"}, {file = "SQLAlchemy-1.4.47-cp311-cp311-win_amd64.whl", hash = "sha256:03be6f3cb66e69fb3a09b5ea89d77e4bc942f3bf84b207dba84666a26799c166"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:9167d4227b56591a4cc5524f1b79ccd7ea994f36e4c648ab42ca995d28ebbb96"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:16ee6fea316790980779268da47a9260d5dd665c96f225d28e7750b0bb2e2a04"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d61e9ecc849d8d44d7f80894ecff4abe347136e9d926560b818f6243409f3c86"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557675e0befafa08d36d7a9284e8761c97490a248474d778373fb96b0d7fd8de"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3ec187acf85984263299a3f15c34a6c0671f83565d86d10f43ace49881a82718"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb2797fee8a7914fb2c3dc7de404d3f96eb77f20fc60e9ee38dc6b0ca720f2c2"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9883f5fae4fd8e3f875adc2add69f8b945625811689a6c65866a35ee9c0aea23"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28297aa29e035f29cba6b16aacd3680fbc6a9db682258d5f2e7b49ec215dbe40"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-win32.whl", hash = "sha256:535377e9b10aff5a045e3d9ada8a62d02058b422c0504ebdcf07930599890eb0"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-win32.whl", hash = "sha256:998e782c8d9fd57fa8704d149ccd52acf03db30d7dd76f467fd21c1c21b414fa"},
{file = "SQLAlchemy-1.4.46-cp36-cp36m-win_amd64.whl", hash = "sha256:18cafdb27834fa03569d29f571df7115812a0e59fd6a3a03ccb0d33678ec8420"}, {file = "SQLAlchemy-1.4.47-cp36-cp36m-win_amd64.whl", hash = "sha256:dde4d02213f1deb49eaaf8be8a6425948963a7af84983b3f22772c63826944de"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:a1ad90c97029cc3ab4ffd57443a20fac21d2ec3c89532b084b073b3feb5abff3"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e98ef1babe34f37f443b7211cd3ee004d9577a19766e2dbacf62fce73c76245a"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4847f4b1d822754e35707db913396a29d874ee77b9c3c3ef3f04d5a9a6209618"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a3879853208a242b5913f3a17c6ac0eae9dc210ff99c8f10b19d4a1ed8ed9b"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a99282848b6cae0056b85da17392a26b2d39178394fc25700bcf967e06e97a"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7120a2f72599d4fed7c001fa1cbbc5b4d14929436135768050e284f53e9fbe5e"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b1cc7835b39835c75cf7c20c926b42e97d074147c902a9ebb7cf2c840dc4e2"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:048509d7f3ac27b83ad82fd96a1ab90a34c8e906e4e09c8d677fc531d12c23c5"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-win32.whl", hash = "sha256:c522e496f9b9b70296a7675272ec21937ccfc15da664b74b9f58d98a641ce1b6"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-win32.whl", hash = "sha256:6572d7c96c2e3e126d0bb27bfb1d7e2a195b68d951fcc64c146b94f088e5421a"},
{file = "SQLAlchemy-1.4.46-cp37-cp37m-win_amd64.whl", hash = "sha256:ae067ab639fa499f67ded52f5bc8e084f045d10b5ac7bb928ae4ca2b6c0429a5"}, {file = "SQLAlchemy-1.4.47-cp37-cp37m-win_amd64.whl", hash = "sha256:a6c3929df5eeaf3867724003d5c19fed3f0c290f3edc7911616616684f200ecf"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:e3c1808008124850115a3f7e793a975cfa5c8a26ceeeb9ff9cbb4485cac556df"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71d4bf7768169c4502f6c2b0709a02a33703544f611810fb0c75406a9c576ee1"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d164df3d83d204c69f840da30b292ac7dc54285096c6171245b8d7807185aa"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd45c60cc4f6d68c30d5179e2c2c8098f7112983532897566bb69c47d87127d3"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b33ffbdbbf5446cf36cd4cc530c9d9905d3c2fe56ed09e25c22c850cdb9fac92"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fdbb8e9d4e9003f332a93d6a37bca48ba8095086c97a89826a136d8eddfc455"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d94682732d1a0def5672471ba42a29ff5e21bb0aae0afa00bb10796fc1e28dd"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f216a51451a0a0466e082e163591f6dcb2f9ec182adb3f1f4b1fd3688c7582c"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-win32.whl", hash = "sha256:f8cb80fe8d14307e4124f6fad64dfd87ab749c9d275f82b8b4ec84c84ecebdbe"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-win32.whl", hash = "sha256:bd988b3362d7e586ef581eb14771bbb48793a4edb6fcf62da75d3f0f3447060b"},
{file = "SQLAlchemy-1.4.46-cp38-cp38-win_amd64.whl", hash = "sha256:07e48cbcdda6b8bc7a59d6728bd3f5f574ffe03f2c9fb384239f3789c2d95c2e"}, {file = "SQLAlchemy-1.4.47-cp38-cp38-win_amd64.whl", hash = "sha256:32ab09f2863e3de51529aa84ff0e4fe89a2cb1bfbc11e225b6dbc60814e44c94"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1b1e5e96e2789d89f023d080bee432e2fef64d95857969e70d3cadec80bd26f0"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:07764b240645627bc3e82596435bd1a1884646bfc0721642d24c26b12f1df194"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3714e5b33226131ac0da60d18995a102a17dddd42368b7bdd206737297823ad"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e2a42017984099ef6f56438a6b898ce0538f6fadddaa902870c5aa3e1d82583"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:955162ad1a931fe416eded6bb144ba891ccbf9b2e49dc7ded39274dd9c5affc5"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b6d807c76c20b4bc143a49ad47782228a2ac98bdcdcb069da54280e138847fc"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6e4cb5c63f705c9d546a054c60d326cbde7421421e2d2565ce3e2eee4e1a01f"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a94632ba26a666e7be0a7d7cc3f7acab622a04259a3aa0ee50ff6d44ba9df0d"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-win32.whl", hash = "sha256:51e1ba2884c6a2b8e19109dc08c71c49530006c1084156ecadfaadf5f9b8b053"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-win32.whl", hash = "sha256:f80915681ea9001f19b65aee715115f2ad310730c8043127cf3e19b3009892dd"},
{file = "SQLAlchemy-1.4.46-cp39-cp39-win_amd64.whl", hash = "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466"}, {file = "SQLAlchemy-1.4.47-cp39-cp39-win_amd64.whl", hash = "sha256:fc700b862e0a859a37faf85367e205e7acaecae5a098794aff52fdd8aea77b12"},
{file = "SQLAlchemy-1.4.46.tar.gz", hash = "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30"}, {file = "SQLAlchemy-1.4.47.tar.gz", hash = "sha256:95fc02f7fc1f3199aaa47a8a757437134cf618e9d994c84effd53f530c38586f"},
] ]
[package.dependencies] [package.dependencies]
@ -2088,14 +2089,14 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]] [[package]]
name = "starlette" name = "starlette"
version = "0.24.0" version = "0.25.0"
description = "The little ASGI library that shines." description = "The little ASGI library that shines."
category = "main" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "starlette-0.24.0-py3-none-any.whl", hash = "sha256:75e2b24d71ff4f7cb9a3338f83d234c2d4135bf80f52aeb105c02a01d72a5df1"}, {file = "starlette-0.25.0-py3-none-any.whl", hash = "sha256:774f1df1983fd594b9b6fb3ded39c2aa1979d10ac45caac0f4255cbe2acb8628"},
{file = "starlette-0.24.0.tar.gz", hash = "sha256:7925947f177a19e906c6ace10f07c64c4f9fdf7d509caaac6589f7cc0cfd95f3"}, {file = "starlette-0.25.0.tar.gz", hash = "sha256:854c71e73736c429c2bdb07801f2c76c9cba497e7c3cf4988fde5e95fe4cdb3c"},
] ]
[package.dependencies] [package.dependencies]
@ -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 = "de85751ffee58e67b57ed3fedd5ec3115a65c8fdb0fcd1e904d96ecb3ce2b803" content-hash = "ebc0a8ca9ea284d8e986306a10f13ff91e7e8aae18341c83329f5b1e1bcc66bd"

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "langflow" name = "langflow"
version = "0.0.40" version = "0.0.44"
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 = [ packages = [
@ -15,8 +15,7 @@ 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.91.0"
uvicorn = "^0.20.0" uvicorn = "^0.20.0"
beautifulsoup4 = "^4.11.2" beautifulsoup4 = "^4.11.2"
google-search-results = "^2.4.1" google-search-results = "^2.4.1"
@ -24,6 +23,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"

View file

@ -7,6 +7,9 @@ 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):
@ -23,7 +26,14 @@ def replace_port(static_files_dir, host, port):
# we need to set the base url to the port that the server is running on # 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 # so that the frontend can make requests to the backend
# This is a hacky way to do it, but it works # This is a hacky way to do it, but it works
new_string = f'setItem("port","http://{host}:{port}")'
# Check if the host is http or https
logger.info(f"host: {host}")
logger.info(f"port: {port}")
url = f"{host}:{port}" if "http" in host else f"http://{host}:{port}"
logger.info(f"url: {url}")
new_string = f'setItem("port","{url}")'
with open(static_files_dir / "index.html", "r") as f: with open(static_files_dir / "index.html", "r") as f:
index_html = f.read() index_html = f.read()
# using regex to replace the port # using regex to replace the port

View 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

View file

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

View file

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

View file

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

View file

@ -297,6 +297,8 @@ 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"] = ["text-davinci-003", "text-davinci-002"]
elif name == "OpenAIChat" and key == "model_name":
value["options"] = ["gpt-3.5-turbo", "gpt-4"]
return d return d

View file

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

View file

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

View file

@ -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://localhost:7860"
} }

View file

@ -14,4 +14,4 @@
<div style="width: 100vw; height:100vh" id='root'> <div style="width: 100vw; height:100vh" id='root'>
</div> </div>
</body> </body>
</html> </html>

10
src/frontend/set_proxy.sh Executable file
View 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

View file

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

View file

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

View file

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

View file

@ -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();
} }
} }

View file

@ -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);
}) })

View file

@ -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);
} }

View file

@ -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 text-gray-400 hover:text-gray-500">
Import <ArrowUpTrayIcon className="w-5 h-5" />
</button>
<button onClick={() => downloadFlow()} className="flex items-center gap-1 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>

View file

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