Merge node-shortcuts-refactor into shortcuts_settings
This commit is contained in:
commit
bc3d32b9ed
71 changed files with 3484 additions and 1529 deletions
2
.github/workflows/pre-release-base.yml
vendored
2
.github/workflows/pre-release-base.yml
vendored
|
|
@ -74,4 +74,4 @@ jobs:
|
|||
push: true
|
||||
file: ./build_and_push_base.Dockerfile
|
||||
tags: |
|
||||
logspace/langflow:base-${{ needs.release.outputs.version }}
|
||||
langflowai/langflow:base-${{ needs.release.outputs.version }}
|
||||
|
|
|
|||
5
.github/workflows/pre-release-langflow.yml
vendored
5
.github/workflows/pre-release-langflow.yml
vendored
|
|
@ -63,6 +63,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
needs: release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
|
|
@ -79,8 +80,8 @@ jobs:
|
|||
push: true
|
||||
file: ./build_and_push.Dockerfile
|
||||
tags: |
|
||||
logspace/langflow:${{ needs.release.outputs.version }}
|
||||
logspace/langflow:1.0-alpha
|
||||
langflowai/langflow:${{ needs.release.outputs.version }}
|
||||
langflowai/langflow:1.0-alpha
|
||||
|
||||
create_release:
|
||||
name: Create Release
|
||||
|
|
|
|||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -52,8 +52,8 @@ jobs:
|
|||
push: true
|
||||
file: ./build_and_push.Dockerfile
|
||||
tags: |
|
||||
logspace/langflow:${{ steps.check-version.outputs.version }}
|
||||
logspace/langflow:latest
|
||||
langflowai/langflow:${{ steps.check-version.outputs.version }}
|
||||
langflowai/langflow:latest
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ services:
|
|||
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-http.middlewares=${STACK_NAME?Variable not set}-www-redirect,${STACK_NAME?Variable not set}-https-redirect
|
||||
|
||||
backend: &backend
|
||||
image: "logspace/langflow:latest"
|
||||
image: "langflowai/langflow:latest"
|
||||
depends_on:
|
||||
- db
|
||||
- broker
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
FROM logspace/langflow:latest
|
||||
FROM langflowai/langflow:latest
|
||||
|
||||
CMD ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ The Docker Compose configuration spins up two services: `langflow` and `postgres
|
|||
|
||||
### LangFlow Service
|
||||
|
||||
The `langflow` service uses the `logspace/langflow:latest` Docker image and exposes port 7860. It depends on the `postgres` service.
|
||||
The `langflow` service uses the `langflowai/langflow:latest` Docker image and exposes port 7860. It depends on the `postgres` service.
|
||||
|
||||
Environment variables:
|
||||
|
||||
|
|
@ -62,4 +62,4 @@ Volumes:
|
|||
|
||||
## Switching to a Specific LangFlow Version
|
||||
|
||||
If you want to use a specific version of LangFlow, you can modify the `image` field under the `langflow` service in the Docker Compose file. For example, to use version 1.0-alpha, change `logspace/langflow:latest` to `logspace/langflow:1.0-alpha`.
|
||||
If you want to use a specific version of LangFlow, you can modify the `image` field under the `langflow` service in the Docker Compose file. For example, to use version 1.0-alpha, change `langflowai/langflow:latest` to `langflowai/langflow:1.0-alpha`.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ version: "3.8"
|
|||
|
||||
services:
|
||||
langflow:
|
||||
image: logspace/langflow:latest
|
||||
image: langflowai/langflow:latest
|
||||
ports:
|
||||
- "7860:7860"
|
||||
depends_on:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
FROM logspace/langflow:1.0-alpha
|
||||
FROM langflowai/langflow:1.0-alpha
|
||||
|
||||
CMD ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--port", "7860"]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ version: "3.8"
|
|||
|
||||
services:
|
||||
langflow:
|
||||
image: logspace/langflow:1.0-alpha
|
||||
image: langflowai/langflow:1.0-alpha
|
||||
ports:
|
||||
- "7860:7860"
|
||||
depends_on:
|
||||
|
|
|
|||
27
docs/docs/getting-started/huggingface-spaces.mdx
Normal file
27
docs/docs/getting-started/huggingface-spaces.mdx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# 🤗 HuggingFace Spaces
|
||||
|
||||
Hugging Face provides a great alternative for running Langflow in their Spaces environment. This means you can run Langflow without any local installation required.
|
||||
|
||||
The first step is to go to the [Langflow Space](https://huggingface.co/spaces/Langflow/Langflow?duplicate=true) or [Langflow 1.0 Preview Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true)
|
||||
|
||||
Remember to use a Chromium-based browser for the best experience. You'll be presented with the following screen:
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/duplicate-space.png",
|
||||
dark: "img/duplicate-space.png",
|
||||
}}
|
||||
style={{ width: "100%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
From here, just name your Space, define the visibility (Public or Private), and click on `Duplicate Space` to start the installation process. When that is done, you'll be redirected to the Space's main page to start using Langflow right away!
|
||||
|
||||
Once you get Langflow running, click on New Project in the top right corner of the screen. Langflow provides a range of example flows to help you get started.
|
||||
|
||||
To quickly try one of them, open a starter example, set up your API keys and click ⚡ Run, on the bottom right corner of the canvas. This will open up Langflow's Interaction Panel with the chat console, text inputs, and outputs.
|
||||
77
docs/docs/getting-started/install-langflow.mdx
Normal file
77
docs/docs/getting-started/install-langflow.mdx
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# 📦 Install Langflow
|
||||
|
||||
<Admonition type="info">
|
||||
Langflow v1.0 is also available in a [HuggingFace Preview Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) if you'd rather try it out before installing locally.
|
||||
</Admonition>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Langflow requires the following programs installed on your system.
|
||||
|
||||
* [Python 3.10](https://www.python.org/downloads/release/python-3100/)
|
||||
|
||||
* [pip](https://pypi.org/project/pip/) or [pipx](https://pipx.pypa.io/stable/installation/)
|
||||
|
||||
## Install Langflow
|
||||
|
||||
To install Langflow:
|
||||
|
||||
pip:
|
||||
```bash
|
||||
python -m pip install langflow -U
|
||||
```
|
||||
|
||||
pipx:
|
||||
```bash
|
||||
pipx install langflow --python python3.10 --fetch-missing-python
|
||||
```
|
||||
Pipx can fetch the missing Python version for you with `--fetch-missing-python`, but you can also install the Python version manually.
|
||||
|
||||
|
||||
## Install Langflow pre-release
|
||||
|
||||
Use `--force-reinstall` to ensure you have the latest version of Langflow and its dependencies.
|
||||
|
||||
To install a pre-release version of Langflow:
|
||||
|
||||
pip:
|
||||
```bash
|
||||
python -m pip install langflow --pre --force-reinstall
|
||||
```
|
||||
|
||||
pipx:
|
||||
```bash
|
||||
pipx install langflow --python python3.10 --fetch-missing-python --pip-args="--pre --force-reinstall"
|
||||
```
|
||||
|
||||
## Having a problem?
|
||||
|
||||
If you encounter a problem, see [Possible Installation Issues](/migration/possible-installation-issues).
|
||||
|
||||
To get help in the Langflow CLI:
|
||||
|
||||
```bash
|
||||
python -m langflow --help
|
||||
```
|
||||
|
||||
## ⛓️ Run Langflow
|
||||
|
||||
1. To run Langflow, enter the following command.
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
2. Confirm that a local Langflow instance starts by visiting `http://127.0.0.1:7860` in your browser.
|
||||
```bash
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
3. Continue on to the [Quickstart](./quickstart.mdx).
|
||||
10
docs/docs/getting-started/new-to-llms.mdx
Normal file
10
docs/docs/getting-started/new-to-llms.mdx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# 📚 New to LLMs?
|
||||
|
||||
Large Language Models, or LLMs, are part of an exciting new world in computing.
|
||||
|
||||
We made Langflow for anyone to create with LLMs, and hope you'll feel comfortable installing Langflow and [getting started](./quickstart.mdx).
|
||||
|
||||
If you want to learn more about LLMs, prompt engineering, and AI models, Langflow recommends [promptingguide.ai](https://promptingguide.ai), an open-source repository of prompt engineering content maintained by AI experts.
|
||||
PromptingGuide offers content for [beginners](https://www.promptingguide.ai/introduction/basics) and [experts](https://www.promptingguide.ai/techniques/cot), as well as the latest [research papers](https://www.promptingguide.ai/papers) and [test results](https://www.promptingguide.ai/research) fueling AI's progress.
|
||||
|
||||
Wherever you are on your AI journey, it's helpful to keep Prompting Guide open in a tab.
|
||||
119
docs/docs/getting-started/quickstart.mdx
Normal file
119
docs/docs/getting-started/quickstart.mdx
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import ReactPlayer from "react-player";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# ⚡️ Quickstart
|
||||
|
||||
This quickstart demonstrates how to install Langflow, run it locally, build a basic prompt flow, and modify that prompt for different outcomes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Python 3.10](https://www.python.org/downloads/release/python-3100/)
|
||||
|
||||
* [pip](https://pypi.org/project/pip/) or [pipx](https://pipx.pypa.io/stable/installation/)
|
||||
|
||||
* [OpenAI API key](https://platform.openai.com)
|
||||
|
||||
## Install Langflow
|
||||
|
||||
<Admonition type="info">
|
||||
Langflow v1.0 is also available in a [HuggingFace Preview Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) if you'd rather try it out before installing locally. This quickstart will run there, too.
|
||||
</Admonition>
|
||||
|
||||
1. To install Langflow, enter the following command in pip or pipx:
|
||||
|
||||
pip:
|
||||
```bash
|
||||
python -m pip install langflow -U
|
||||
```
|
||||
|
||||
pipx:
|
||||
```bash
|
||||
pipx install langflow --python python3.10 --fetch-missing-python
|
||||
```
|
||||
Pipx can fetch the missing Python version for you with `--fetch-missing-python`, but you can also install the Python version manually.
|
||||
|
||||
2. Start a local Langflow instance with the Langflow CLI:
|
||||
```bash
|
||||
langflow run
|
||||
```
|
||||
|
||||
Or start Langflow with Python:
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
Result:
|
||||
```
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
3. Go to `http://127.0.0.1:7860` and confirm the Langflow UI is available.
|
||||
|
||||
<Admonition type="info">
|
||||
If you encounter a problem, see [Possible Installation Issues](/migration/possible-installation-issues).
|
||||
</Admonition>
|
||||
|
||||
## Create the basic prompting project
|
||||
|
||||
Now that you have Langflow installed and running, let us formally welcome you to Langflow!👋
|
||||
|
||||
You will use Langflow's prompt tools to issue prompts to the OpenAI LLM.
|
||||
|
||||
Prompts serve as the inputs to a large language model (LLM), acting as the interface between human instructions and computational tasks.
|
||||
|
||||
By submitting natural language requests in a prompt to an LLM, you can obtain answers, generate text, and solve problems.
|
||||
|
||||
1. From the Langflow dashboard, click **New Project**.
|
||||
2. Select **Basic Prompting**.
|
||||
3. The **Basic Prompting** flow is created.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/quickstart.png",
|
||||
dark: "img/quickstart.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This flow allows you to chat with the **OpenAI** component via a **Prompt** component.
|
||||
Examine the **Prompt** component. The **Template** field instructs the LLM to `Answer the user as if you were a pirate.`
|
||||
This should be interesting...
|
||||
|
||||
4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
1. In the **Variable Name** field, enter `openai_api_key`.
|
||||
2. In the **Value** field, paste your OpenAI API Key (`sk-...`).
|
||||
3. Click **Save Variable**.
|
||||
|
||||
## Run the basic prompting flow
|
||||
|
||||
1. Click the **Run** button.
|
||||
The **Interaction Panel** opens, where you can converse with your bot.
|
||||
2. Type a message and press Enter.
|
||||
The bot responds in a markedly piratical manner!
|
||||
|
||||
## Modify the prompt for a different result
|
||||
|
||||
1. To modify your prompt results, in the **Prompt** template, click the **Template** field.
|
||||
The **Edit Prompt** window opens.
|
||||
2. Change `Answer the user as if you were a pirate` to a different character, perhaps `Answer the user as if you were Harold Abelson.`
|
||||
3. Run the basic prompting flow again.
|
||||
The response will be markedly different.
|
||||
|
||||
## Next steps
|
||||
|
||||
Well done! You've built your first prompt in Langflow. 🎉
|
||||
|
||||
By adding Langflow components to this prompt, you can build all sorts of interesting flows.
|
||||
|
||||
* [Memory chatbot](/guides/memory-chatbot.mdx)
|
||||
* [Blog writer](/guides/blog-writer.mdx)
|
||||
* [Document QA](/guides/document-qa.mdx)
|
||||
|
||||
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# 🌟 RAG with Astra DB
|
||||
|
||||
This guide will walk you through how to build a RAG (Retrieval Augmented Generation) application using **Astra DB** and **Langflow**.
|
||||
|
||||
[Astra DB](https://www.datastax.com/products/datastax-astra?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=astradb) is a cloud-native database built on Apache Cassandra that is optimized for the cloud. It is a fully managed database-as-a-service that simplifies operations and reduces costs. Astra DB is built on the same technology that powers the largest Cassandra deployments in the world.
|
||||
|
||||
In this guide, we will use Astra DB as a vector store to store and retrieve the documents that will be used by the RAG application to generate responses.
|
||||
|
||||
<Admonition type="tip">
|
||||
This guide assumes that you have Langflow up and running. If you are new to
|
||||
Langflow, you can check out the [Getting Started](/) guide.
|
||||
</Admonition>
|
||||
|
||||
TLDR;
|
||||
|
||||
- [Create a free Astra DB account](https://astra.datastax.com/signup?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=create-a-free-astra-db-account)
|
||||
- Duplicate our [Langflow 1.0 Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true)
|
||||
- Create a new database, get a **Token** and the **API Endpoint**
|
||||
- Click on the **New Project** button and look for Vector Store RAG. This will create a new project with the necessary components
|
||||
- Import the project into Langflow by dropping it on the Canvas or My Collection page
|
||||
- Update the **Token** and **API Endpoint** in the **Astra DB** components
|
||||
- Update the OpenAI API key in the **OpenAI** components
|
||||
- Run the ingestion flow which is the one that uses the **Astra DB** component
|
||||
- Click on the ⚡ _Run_ button and start interacting with your RAG application
|
||||
|
||||
# First things first
|
||||
|
||||
## Create an Astra DB Database
|
||||
|
||||
To get started, you will need to [create an Astra DB database](https://astra.datastax.com/signup?utm_source=langflow-pre-release&utm_medium=referral&utm_campaign=langflow-announcement&utm_content=create-an-astradb-database).
|
||||
|
||||
Once you have created an account, you will be taken to the Astra DB dashboard. Click on the **Create Database** button.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-create-database.png",
|
||||
dark: "img/astra-create-database.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Now you will need to configure your database. Choose the **Serverless (Vector)** deployment type, and pick a Database name, provider and region.
|
||||
|
||||
After you have configured your database, click on the **Create Database** button.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-configure-deployment.png",
|
||||
dark: "img/astra-configure-deployment.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Once your database is initialized, to the right of the page, you will see the _Database Details_ section which contains a button for you to copy the **API Endpoint** and another to generate a **Token**.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-generate-token.png",
|
||||
dark: "img/astra-generate-token.png",
|
||||
}}
|
||||
style={{ width: "50%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Now we are all set to start building our RAG application using Astra DB and Langflow.
|
||||
|
||||
## (Optional) Duplicate the Langflow 1.0 HuggingFace Space
|
||||
|
||||
If you haven't already, now is the time to launch Langflow. To make things easier, you can duplicate our [Langflow 1.0 Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true) which sets up a Langflow instance just for you.
|
||||
|
||||
## Open the Vector Store RAG Project
|
||||
|
||||
To get started, click on the **New Project** button and look for the **Vector Store RAG** project. This will open a starter project with the necessary components to run a RAG application using Astra DB.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/drag-and-drop-flow.png",
|
||||
dark: "img/drag-and-drop-flow.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This project consists of two flows. The simpler one is the **Ingestion Flow** which is responsible for ingesting the documents into the Astra DB database.
|
||||
|
||||
Your first step should be to understand what each flow does and how they interact with each other.
|
||||
|
||||
The ingestion flow consists of:
|
||||
|
||||
- **Files** component that uploads a text file to Langflow
|
||||
- **Recursive Character Text Splitter** component that splits the text into smaller chunks
|
||||
- **OpenAIEmbeddings** component that generates embeddings for the text chunks
|
||||
- **Astra DB** component that stores the text chunks in the Astra DB database
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-ingestion-flow.png",
|
||||
dark: "img/astra-ingestion-flow.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Now, let's update the **Astra DB** and **Astra DB Search** components with the **Token** and **API Endpoint** that we generated earlier, and the OpenAI Embeddings components with your OpenAI API key.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-ingestion-fields.png",
|
||||
dark: "img/astra-ingestion-fields.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
And run it! This will ingest the Text data from your file into the Astra DB database.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-ingestion-run.png",
|
||||
dark: "img/astra-ingestion-run.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Now, on to the **RAG Flow**. This flow is responsible for generating responses to your queries. It will define all of the steps from getting the User's input to generating a response and displaying it in the Interaction Panel.
|
||||
|
||||
The RAG flow is a bit more complex. It consists of:
|
||||
|
||||
- **Chat Input** component that defines where to put the user input coming from the Interaction Panel
|
||||
- **OpenAI Embeddings** component that generates embeddings from the user input
|
||||
- **Astra DB Search** component that retrieves the most relevant Records from the Astra DB database
|
||||
- **Text Output** component that turns the Records into Text by concatenating them and also displays it in the Interaction Panel
|
||||
- One interesting point you'll see here is that this component is named `Extracted Chunks`, and that is how it will appear in the Interaction Panel
|
||||
- **Prompt** component that takes in the user input and the retrieved Records as text and builds a prompt for the OpenAI model
|
||||
- **OpenAI** component that generates a response to the prompt
|
||||
- **Chat Output** component that displays the response in the Interaction Panel
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-rag-flow.png",
|
||||
dark: "img/astra-rag-flow.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
To run it all we have to do is click on the ⚡ _Run_ button and start interacting with your RAG application.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-rag-flow-run.png",
|
||||
dark: "img/astra-rag-flow-run.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This opens the Interaction Panel where you can chat your data.
|
||||
|
||||
Because this flow has a **Chat Input** and a **Text Output** component, the Panel displays a chat input at the bottom and the Extracted Chunks section on the left.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-rag-flow-interaction-panel.png",
|
||||
dark: "img/astra-rag-flow-interaction-panel.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
Once we interact with it we get a response and the Extracted Chunks section is updated with the retrieved records.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/astra-rag-flow-interaction-panel-interaction.png",
|
||||
dark: "img/astra-rag-flow-interaction-panel-interaction.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
And that's it! You have successfully ran a RAG application using Astra DB and Langflow.
|
||||
|
||||
# Conclusion
|
||||
|
||||
In this guide, we have learned how to run a RAG application using Astra DB and Langflow.
|
||||
We have seen how to create an Astra DB database, import the Astra DB RAG Flows project into Langflow, and run the ingestion and RAG flows.
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import ReactPlayer from "react-player";
|
||||
|
||||
# Basic prompting
|
||||
|
||||
Prompts serve as the inputs to a large language model (LLM), acting as the interface between human instructions and computational tasks.
|
||||
|
||||
By submitting natural language requests in a prompt to an LLM, you can obtain answers, generate text, and solve problems.
|
||||
|
||||
This article demonstrates how to use Langflow's prompt tools to issue basic prompts to an LLM, and how various prompting strategies can affect your outcomes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install Langflow.
|
||||
```bash
|
||||
python -m pip install langflow --pre
|
||||
```
|
||||
|
||||
2. Start a local Langflow instance with the Langflow CLI:
|
||||
```bash
|
||||
langflow run
|
||||
```
|
||||
Or start Langflow with Python:
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
Result:
|
||||
```
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
Alternatively, go to [HuggingFace Spaces](https://docs.langflow.org/getting-started/hugging-face-spaces) or [Lightning.ai Studio](https://lightning.ai/ogabrielluiz-8j6t8/studios/langflow) for a pre-built Langflow test environment.
|
||||
|
||||
3. Create an [OpenAI API key](https://platform.openai.com).
|
||||
|
||||
## Create the basic prompting project
|
||||
|
||||
1. From the Langflow dashboard, click **New Project**.
|
||||
2. Select **Basic Prompting**.
|
||||
3. The **Basic Prompting** flow is created.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/basic-prompting.png",
|
||||
dark: "img/basic-prompting.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This flow allows you to chat with the **OpenAI** component via a **Prompt** component.
|
||||
Examine the **Prompt** component. The **Template** field instructs the LLM to `Answer the user as if you were a pirate.`
|
||||
This should be interesting...
|
||||
|
||||
4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
1. In the **Variable Name** field, enter `openai_api_key`.
|
||||
2. In the **Value** field, paste your OpenAI API Key (`sk-...`).
|
||||
3. Click **Save Variable**.
|
||||
|
||||
## Run the basic prompting flow
|
||||
|
||||
1. Click the **Run** button.
|
||||
The **Interaction Panel** opens, where you can converse with your bot.
|
||||
2. Type a message and press Enter.
|
||||
The bot responds in a markedly piratical manner!
|
||||
|
||||
## Modify the prompt for a different result
|
||||
|
||||
1. To modify your prompt results, in the **Prompt** template, click the **Template** field.
|
||||
The **Edit Prompt** window opens.
|
||||
2. Change `Answer the user as if you were a pirate` to a different character, perhaps `Answer the user as if you were Harold Abelson.`
|
||||
3. Run the basic prompting flow again.
|
||||
The response will be markedly different.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import ReactPlayer from "react-player";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# Blog writer
|
||||
|
||||
Build a blog writer with OpenAI that uses URLs for reference content.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install Langflow.
|
||||
```bash
|
||||
python -m pip install langflow --pre
|
||||
```
|
||||
|
||||
2. Start a local Langflow instance with the Langflow CLI:
|
||||
```bash
|
||||
langflow run
|
||||
```
|
||||
Or start Langflow with Python:
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
Result:
|
||||
```bash
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
Alternatively, go to [HuggingFace Spaces](https://docs.langflow.org/getting-started/hugging-face-spaces) or [Lightning.ai Studio](https://lightning.ai/ogabrielluiz-8j6t8/studios/langflow) for a pre-built Langflow test environment.
|
||||
|
||||
3. Create an [OpenAI API key](https://platform.openai.com).
|
||||
|
||||
## Create the Blog Writer project
|
||||
|
||||
1. From the Langflow dashboard, click **New Project**.
|
||||
2. Select **Blog Writer**.
|
||||
3. The **Blog Writer** flow is created.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/blog-writer.png",
|
||||
dark: "img/blog-writer.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This flow creates a one-shot prompt flow with **Prompt**, **OpenAI**, and **Chat Output** components, and augments the flow with reference content and instructions from the **URL** and **Instructions** components.
|
||||
|
||||
The **Prompt** component's default **Template** field looks like this:
|
||||
```bash
|
||||
Reference 1:
|
||||
|
||||
{reference_1}
|
||||
|
||||
---
|
||||
|
||||
Reference 2:
|
||||
|
||||
{reference_2}
|
||||
|
||||
---
|
||||
|
||||
{instructions}
|
||||
|
||||
Blog:
|
||||
|
||||
```
|
||||
|
||||
The `{instructions}` value is received from the **Value** field of the **Instructions** component.
|
||||
The `reference_1` and `reference_2` values are received from the **URL** fields of the **URL** components.
|
||||
|
||||
4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
1. In the **Variable Name** field, enter `openai_api_key`.
|
||||
2. In the **Value** field, paste your OpenAI API Key (`sk-...`).
|
||||
3. Click **Save Variable**.
|
||||
|
||||
## Run the Blog Writer flow
|
||||
|
||||
1. Click the **Run** button.
|
||||
The **Interaction Panel** opens, where you can run your one-shot flow.
|
||||
2. Click the **Lighting Bolt** icon to run your flow.
|
||||
3. The **OpenAI** component constructs a blog post with the **URL** items as context.
|
||||
The default **URL** values are for web pages at `promptingguide.ai`, so your blog post will be about prompting LLMs.
|
||||
|
||||
To write about something different, change the values in the **URL** components, and see what the LLM constructs.
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import ReactPlayer from "react-player";
|
||||
import Admonition from "@theme/Admonition";
|
||||
|
||||
# Document QA
|
||||
|
||||
Build a question-and-answer chatbot with a document loaded from local memory.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install Langflow.
|
||||
```bash
|
||||
python -m pip install langflow --pre
|
||||
```
|
||||
|
||||
2. Start a local Langflow instance with the Langflow CLI:
|
||||
```bash
|
||||
langflow run
|
||||
```
|
||||
Or start Langflow with Python:
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
Result:
|
||||
```
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
Alternatively, go to [HuggingFace Spaces](https://docs.langflow.org/getting-started/hugging-face-spaces) or [Lightning.ai Studio](https://lightning.ai/ogabrielluiz-8j6t8/studios/langflow) for a pre-built Langflow test environment.
|
||||
|
||||
3. Create an [OpenAI API key](https://platform.openai.com).
|
||||
|
||||
## Create the Document QA project
|
||||
|
||||
1. From the Langflow dashboard, click **New Project**.
|
||||
2. Select **Document QA**.
|
||||
3. The **Document QA** flow is created.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/document-qa.png",
|
||||
dark: "img/document-qa.png",
|
||||
}}
|
||||
style={{ width: "80%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
This flow creates a basic chatbot with the **Chat Input**, **Prompt**, **OpenAI**, and **Chat Output** components.
|
||||
This chatbot is augmented with the **Files** component, which loads a file from your local machine into the **Prompt** component as `{Document}`.
|
||||
The **Prompt** component is instructed to answer questions based on the contents of `{Document}`.
|
||||
Including a file with the prompt gives the **OpenAI** component context it may not otherwise have access to.
|
||||
|
||||
4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
1. In the **Variable Name** field, enter `openai_api_key`.
|
||||
2. In the **Value** field, paste your OpenAI API Key (`sk-...`).
|
||||
3. Click **Save Variable**.
|
||||
|
||||
5. To select a document to load, in the **Files** component, click within the **Path** field.
|
||||
1. Select a local file, and then click **Open**.
|
||||
2. The file name appears in the field.
|
||||
<Admonition type="tip">
|
||||
The file must be of an extension type listed [here](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/base/data/utils.py#L13).
|
||||
</Admonition>
|
||||
|
||||
## Run the Document QA flow
|
||||
|
||||
1. Click the **Run** button.
|
||||
The **Interaction Panel** opens, where you can converse with your bot.
|
||||
2. Type a message and press Enter.
|
||||
For this example, we loaded an error log `.txt` file and asked, "What went wrong?"
|
||||
The bot responded:
|
||||
```
|
||||
The issue occurred during the execution of migrations in the application. Specifically, an error was raised by the Alembic library, indicating that new upgrade operations were detected that had not been accounted for in the existing migration scripts. The operation in question involved modifying the nullable property of a column (apikey, created_at) in the database, with details about the existing type (DATETIME()), existing server default, and other properties.
|
||||
```
|
||||
|
||||
This result indicates that the bot received the loaded document and understood the context surrounding the vague question. It also correctly identified the issue in the error log, and followed up with appropriate troubleshooting suggestions. Nice!
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
import ThemedImage from "@theme/ThemedImage";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import ZoomableImage from "/src/theme/ZoomableImage.js";
|
||||
import ReactPlayer from "react-player";
|
||||
|
||||
# Memory chatbot
|
||||
|
||||
This flow extends the [basic prompting flow](./basic-prompting.mdx) to include chat memory for unique SessionIDs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install Langflow.
|
||||
```bash
|
||||
python -m pip install langflow --pre
|
||||
```
|
||||
|
||||
2. Start a local Langflow instance with the Langflow CLI:
|
||||
```bash
|
||||
langflow run
|
||||
```
|
||||
Or start Langflow with Python:
|
||||
```bash
|
||||
python -m langflow run
|
||||
```
|
||||
|
||||
Result:
|
||||
```
|
||||
│ Welcome to ⛓ Langflow │
|
||||
│ │
|
||||
│ Access http://127.0.0.1:7860 │
|
||||
│ Collaborate, and contribute at our GitHub Repo 🚀 │
|
||||
```
|
||||
|
||||
Alternatively, go to [HuggingFace Spaces](https://docs.langflow.org/getting-started/hugging-face-spaces) or [Lightning.ai Studio](https://lightning.ai/ogabrielluiz-8j6t8/studios/langflow) for a pre-built Langflow test environment.
|
||||
|
||||
3. Create an [OpenAI API key](https://platform.openai.com).
|
||||
|
||||
## Create the memory chatbot project
|
||||
|
||||
1. From the Langflow dashboard, click **New Project**.
|
||||
2. Select **Memory Chatbot**.
|
||||
3. The **Memory Chatbot** flow is created.
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/memory-chatbot.png",
|
||||
dark: "img/memory-chatbot.png",
|
||||
}}
|
||||
style={{
|
||||
width: "80%",
|
||||
margin: "20px auto",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
/>
|
||||
|
||||
This flow creates a basic chatbot with the **Chat Input**, **Prompt**, and **OpenAI** components.
|
||||
This chatbot is augmented with the **Chat Memory** component, which stores messages submitted via **Chat Input** and prepends them to subsequent prompts to OpenAI via `{context}`.
|
||||
The **Chat History** component gives the **OpenAI** component a memory of previous questions.
|
||||
|
||||
4. To create an environment variable for the **OpenAI** component, in the **OpenAI API Key** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
1. In the **Variable Name** field, enter `openai_api_key`.
|
||||
2. In the **Value** field, paste your OpenAI API Key (`sk-...`).
|
||||
3. Click **Save Variable**.
|
||||
|
||||
## Run the memory chatbot flow
|
||||
|
||||
1. Click the **Run** button.
|
||||
The **Interaction Panel** opens, where you can converse with your bot.
|
||||
2. Type a message and press Enter.
|
||||
The bot will respond according to the template in the **Prompt** component.
|
||||
3. Type more questions. In the **Outputs** log, your queries are logged in order. Up to 5 queries are stored by default. Try asking `What is the first subject I asked you about?` to see where the LLM's memory disappears.
|
||||
|
||||
## Modify the Session ID field to have multiple conversations
|
||||
|
||||
`SessionID` is a unique identifier in Langchain for a conversation session between a chatbot and a client.
|
||||
A `SessionID` is created when a conversation is initiated, and then associated with all subsequent messages during that session.
|
||||
|
||||
In the **Memory Chatbot** flow you created, the **Chat Memory** component references past interactions with **Chat Input** by **Session ID**.
|
||||
You can demonstrate this by modifying the **Session ID** value to switch between conversation histories.
|
||||
|
||||
1. In the **Session ID** field of the **Chat Memory** and **Chat Input** components, change the **Session ID** value from `MySessionID` to `AnotherSessionID`.
|
||||
2. Click the **Run** button to run your flow.
|
||||
In the **Interaction Panel**, you will have a new conversation. (You may need to clear the cache with the **Eraser** button).
|
||||
3. Type a few questions to your bot.
|
||||
4. In the **Session ID** field of the **Chat Memory** and **Chat Input** components, change the **Session ID** value back to `MySessionID`.
|
||||
5. Run your flow.
|
||||
The **Outputs** log of the **Interaction Panel** displays the history from your initial chat with `MySessionID`.
|
||||
|
||||
## Store Session ID as a Langflow variable
|
||||
|
||||
To store **Session ID** as a Langflow variable, in the **Session ID** field, click the **Globe** button, and then click **Add New Variable**.
|
||||
|
||||
1. In the **Variable Name** field, enter a name like `customer_chat_emea`.
|
||||
2. In the **Value** field, enter a value like `1B5EBD79-6E9C-4533-B2C8-7E4FF29E983B`.
|
||||
3. Click **Save Variable**.
|
||||
4. Apply this variable to **Chat Input**.
|
||||
|
||||
|
|
@ -5,7 +5,9 @@ import Admonition from "@theme/Admonition";
|
|||
|
||||
# 👋 Welcome to Langflow
|
||||
|
||||
Langflow is an easy way to build from simple to complex AI applications. It is a low-code platform that allows you to integrate AI into everything you do.
|
||||
Langflow is a low-code platform that allows you to integrate AI into everything you do.
|
||||
|
||||
Use Langflow's simple but powerful UI to build any AI application you can dream up, from simple to complex.
|
||||
|
||||
{" "}
|
||||
|
||||
|
|
@ -20,96 +22,17 @@ Langflow is an easy way to build from simple to complex AI applications. It is a
|
|||
|
||||
## 🚀 First steps
|
||||
|
||||
## Installation
|
||||
* [Install Langflow](/getting-started/install-langflow) - Install and start a local Langflow server.
|
||||
|
||||
Make sure you have **Python 3.10** installed on your system.
|
||||
* [Quickstart](/getting-started/quickstart) - Install Langflow, create a flow, and run it.
|
||||
|
||||
You can install **Langflow** with [pipx](https://pipx.pypa.io/stable/installation/) or with pip.
|
||||
* [HuggingFace Spaces](/getting-started/huggingface-spaces) - Duplicate the Langflow preview space and try it out before you install.
|
||||
|
||||
Pipx can fetch the missing Python version for you, but you can also install it manually.
|
||||
* [New to LLMs?](/getting-started/new-to-llms) - Learn more about LLMs, prompting, and more at [promptingguide.ai](https://promptingguide.ai).
|
||||
|
||||
```bash
|
||||
# Remember to check if you have Python 3.10 installed
|
||||
python -m pip install langflow -U
|
||||
# or
|
||||
pipx install langflow --python python3.10 --fetch-missing-python
|
||||
```
|
||||
## Learn more about Langflow 1.0
|
||||
|
||||
Or you can install a pre-release version using:
|
||||
Learn more about the exciting changes in Langflow 1.0, and how to migrate your existing Langflow projects.
|
||||
|
||||
```bash
|
||||
python -m pip install langflow --pre --force-reinstall
|
||||
# or
|
||||
pipx install langflow --python python3.10 --fetch-missing-python --pip-args="--pre --force-reinstall"
|
||||
```
|
||||
|
||||
<Admonition type="tip">
|
||||
<p>
|
||||
Please, check out our [Possible Installation Issues
|
||||
section](/migration/possible-installation-issues) if you encounter any
|
||||
problems.
|
||||
</p>
|
||||
</Admonition>
|
||||
|
||||
We recommend using --force-reinstall to ensure you have the latest version of Langflow and its dependencies.
|
||||
|
||||
### ⛓️ Running Langflow
|
||||
|
||||
Langflow can be run in a variety of ways, including using the command-line interface (CLI) or HuggingFace Spaces.
|
||||
|
||||
```bash
|
||||
python -m langflow run # or langflow --help
|
||||
```
|
||||
|
||||
#### 🤗 HuggingFace Spaces
|
||||
|
||||
Hugging Face provides a great alternative for running Langflow in their Spaces environment. This means you can run Langflow without any local installation required.
|
||||
|
||||
The first step is to go to the [Langflow Space](https://huggingface.co/spaces/Langflow/Langflow?duplicate=true) or [Langflow 1.0 Preview Space](https://huggingface.co/spaces/Langflow/Langflow-Preview?duplicate=true)
|
||||
|
||||
Remember to use a Chromium-based browser for the best experience. You'll be presented with the following screen:
|
||||
|
||||
<ZoomableImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: "img/duplicate-space.png",
|
||||
dark: "img/duplicate-space.png",
|
||||
}}
|
||||
style={{ width: "100%", margin: "20px auto" }}
|
||||
/>
|
||||
|
||||
From here, just name your Space, define the visibility (Public or Private), and click on `Duplicate Space` to start the installation process. When that is done, you'll be redirected to the Space's main page to start using Langflow right away!
|
||||
|
||||
Once you get Langflow running, click on New Project in the top right corner of the screen. Langflow provides a range of example flows to help you get started.
|
||||
|
||||
To quickly try one of them, open a starter example, set up your API keys and click ⚡ Run, on the bottom right corner of the canvas. This will open up Langflow's Interaction Panel with the chat console, text inputs, and outputs.
|
||||
|
||||
### 🖥️ Command Line Interface (CLI)
|
||||
|
||||
Langflow provides a command-line interface (CLI) for easy management and configuration.
|
||||
|
||||
#### Usage
|
||||
|
||||
You can run the Langflow using the following command:
|
||||
|
||||
```bash
|
||||
langflow run [OPTIONS]
|
||||
```
|
||||
|
||||
Find more information about the available options by running:
|
||||
|
||||
```bash
|
||||
python -m langflow --help
|
||||
```
|
||||
|
||||
## Find out more about 1.0
|
||||
|
||||
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
|
||||
<p>
|
||||
We are currently working on updating the documentation for Langflow 1.0.
|
||||
</p>
|
||||
</Admonition>
|
||||
|
||||
To get you learning more about what's new and why you should be excited about Langflow 1.0,
|
||||
go to [A new chapter for Langflow](/whats-new/a-new-chapter-langflow) and also come back often
|
||||
to check out our [migration guides](/whats-new/migrating-to-one-point-zero) as we release them.
|
||||
* [A new chapter for Langflow](/whats-new/a-new-chapter-langflow)
|
||||
* [Migration guides](/whats-new/migrating-to-one-point-zero)
|
||||
|
|
@ -6,14 +6,26 @@ module.exports = {
|
|||
collapsed: false,
|
||||
items: [
|
||||
"index",
|
||||
"getting-started/cli",
|
||||
// "guides/basic-prompting",
|
||||
// "guides/document-qa",
|
||||
// "guides/blog-writer",
|
||||
// "guides/memory-chatbot",
|
||||
"getting-started/install-langflow",
|
||||
"getting-started/quickstart",
|
||||
"getting-started/huggingface-spaces",
|
||||
"getting-started/new-to-llms",
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
type: "category",
|
||||
label: " Starter Projects",
|
||||
collapsed: false,
|
||||
items: [
|
||||
"guides/basic-prompting",
|
||||
"guides/blog-writer",
|
||||
"guides/document-qa",
|
||||
"guides/memory-chatbot",
|
||||
"guides/rag-with-astradb",
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
type: "category",
|
||||
label: " What's New",
|
||||
|
|
@ -46,6 +58,7 @@ module.exports = {
|
|||
"migration/global-variables",
|
||||
// "migration/experimental-components",
|
||||
// "migration/state-management",
|
||||
//"guides/rag-with-astradb",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -53,6 +66,7 @@ module.exports = {
|
|||
label: "Guidelines",
|
||||
collapsed: false,
|
||||
items: [
|
||||
"getting-started/cli",
|
||||
"guidelines/login",
|
||||
"guidelines/api",
|
||||
"guidelines/components",
|
||||
|
|
|
|||
BIN
docs/static/img/basic-prompting.png
vendored
Normal file
BIN
docs/static/img/basic-prompting.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
BIN
docs/static/img/blog-writer.png
vendored
Normal file
BIN
docs/static/img/blog-writer.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 524 KiB |
BIN
docs/static/img/document-qa.png
vendored
Normal file
BIN
docs/static/img/document-qa.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
BIN
docs/static/img/memory-chatbot.png
vendored
Normal file
BIN
docs/static/img/memory-chatbot.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
BIN
docs/static/img/quickstart.png
vendored
Normal file
BIN
docs/static/img/quickstart.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 486 KiB |
1780
poetry.lock
generated
1780
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "langflow"
|
||||
version = "1.0.0a24"
|
||||
version = "1.0.0a28"
|
||||
description = "A Python package with a built-in web application"
|
||||
authors = ["Langflow <contact@langflow.org>"]
|
||||
maintainers = [
|
||||
|
|
@ -81,6 +81,7 @@ chromadb = "^0.4.24"
|
|||
langchain-anthropic = "^0.1.6"
|
||||
langchain-astradb = "^0.1.0"
|
||||
langchain-openai = "^0.1.1"
|
||||
zep-python = { version = "^2.0.0rc5", allow-prereleases = true }
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
types-redis = "^4.6.0.5"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM logspace/backend_build as backend_build
|
||||
FROM langflowai/backend_build as backend_build
|
||||
|
||||
FROM python:3.10-slim
|
||||
WORKDIR /app
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ async def simplified_run_flow(
|
|||
graph_data = flow.data
|
||||
|
||||
graph_data = process_tweaks(graph_data, input_request.tweaks or {}, stream=stream)
|
||||
graph = Graph.from_payload(graph_data, flow_id=flow_id, user_id=api_key_user.id)
|
||||
graph = Graph.from_payload(graph_data, flow_id=flow_id, user_id=str(api_key_user.id))
|
||||
inputs = [
|
||||
InputValueRequest(components=[], input_value=input_request.input_value, type=input_request.input_type)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class BuildStatus(Enum):
|
|||
|
||||
|
||||
class TweaksRequest(BaseModel):
|
||||
tweaks: Optional[Dict[str, Dict[str, str]]] = Field(default_factory=dict)
|
||||
tweaks: Optional[Dict[str, Dict[str, Any]]] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class UpdateTemplateRequest(BaseModel):
|
||||
|
|
|
|||
51
src/backend/base/langflow/base/memory/memory.py
Normal file
51
src/backend/base/langflow/base/memory/memory.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
from typing import Optional
|
||||
|
||||
from langflow.field_typing import Text
|
||||
from langflow.helpers.record import records_to_text
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class BaseMemoryComponent(CustomComponent):
|
||||
display_name = "Chat Memory"
|
||||
description = "Retrieves stored chat messages given a specific Session ID."
|
||||
beta: bool = True
|
||||
icon = "history"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"sender": {
|
||||
"options": ["Machine", "User", "Machine and User"],
|
||||
"display_name": "Sender Type",
|
||||
},
|
||||
"sender_name": {"display_name": "Sender Name", "advanced": True},
|
||||
"n_messages": {
|
||||
"display_name": "Number of Messages",
|
||||
"info": "Number of messages to retrieve.",
|
||||
},
|
||||
"session_id": {
|
||||
"display_name": "Session ID",
|
||||
"info": "Session ID of the chat history.",
|
||||
"input_types": ["Text"],
|
||||
},
|
||||
"order": {
|
||||
"options": ["Ascending", "Descending"],
|
||||
"display_name": "Order",
|
||||
"info": "Order of the messages.",
|
||||
"advanced": True,
|
||||
},
|
||||
"record_template": {
|
||||
"display_name": "Record Template",
|
||||
"multiline": True,
|
||||
"info": "Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
||||
def get_messages(self, **kwargs) -> list[Record]:
|
||||
raise NotImplementedError
|
||||
|
||||
def add_message(
|
||||
self, sender: str, sender_name: str, text: str, session_id: str, metadata: Optional[dict] = None, **kwargs
|
||||
):
|
||||
raise NotImplementedError
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.field_typing import Text
|
||||
|
||||
|
||||
class CombineTextsUnsortedComponent(CustomComponent):
|
||||
display_name = "Combine Texts (Unsorted)"
|
||||
description = "Concatenate text sources into a single text chunk using a specified delimiter."
|
||||
icon = "merge"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"texts": {
|
||||
"display_name": "Texts",
|
||||
"info": "The first text input to concatenate.",
|
||||
},
|
||||
"delimiter": {
|
||||
"display_name": "Delimiter",
|
||||
"info": "A string used to separate the two text inputs. Defaults to a whitespace.",
|
||||
},
|
||||
}
|
||||
|
||||
def build(self, texts: list[str], delimiter: str = " ") -> Text:
|
||||
combined = delimiter.join(texts)
|
||||
self.status = combined
|
||||
return combined
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
from typing import Optional
|
||||
|
||||
from langflow.base.memory.memory import BaseMemoryComponent
|
||||
from langflow.field_typing import Text
|
||||
from langflow.helpers.record import records_to_text
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.memory import get_messages
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class MemoryComponent(CustomComponent):
|
||||
class MemoryComponent(BaseMemoryComponent):
|
||||
display_name = "Chat Memory"
|
||||
description = "Retrieves stored chat messages given a specific Session ID."
|
||||
beta: bool = True
|
||||
|
|
@ -42,6 +43,24 @@ class MemoryComponent(CustomComponent):
|
|||
},
|
||||
}
|
||||
|
||||
def get_messages(self, **kwargs) -> list[Record]:
|
||||
# Validate kwargs by checking if it contains the correct keys
|
||||
if "sender" not in kwargs:
|
||||
kwargs["sender"] = None
|
||||
if "sender_name" not in kwargs:
|
||||
kwargs["sender_name"] = None
|
||||
if "session_id" not in kwargs:
|
||||
kwargs["session_id"] = None
|
||||
if "limit" not in kwargs:
|
||||
kwargs["limit"] = 5
|
||||
if "order" not in kwargs:
|
||||
kwargs["order"] = "Descending"
|
||||
|
||||
kwargs["order"] = "DESC" if kwargs["order"] == "Descending" else "ASC"
|
||||
if kwargs["sender"] == "Machine and User":
|
||||
kwargs["sender"] = None
|
||||
return get_messages(**kwargs)
|
||||
|
||||
def build(
|
||||
self,
|
||||
sender: Optional[str] = "Machine and User",
|
||||
|
|
@ -51,10 +70,7 @@ class MemoryComponent(CustomComponent):
|
|||
order: Optional[str] = "Descending",
|
||||
record_template: Optional[str] = "{sender_name}: {text}",
|
||||
) -> Text:
|
||||
order = "DESC" if order == "Descending" else "ASC"
|
||||
if sender == "Machine and User":
|
||||
sender = None
|
||||
messages = get_messages(
|
||||
messages = self.get_messages(
|
||||
sender=sender,
|
||||
sender_name=sender_name,
|
||||
session_id=session_id,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
from typing import Optional, cast
|
||||
|
||||
from langchain_community.chat_message_histories.zep import SearchScope, SearchType, ZepChatMessageHistory
|
||||
|
||||
from langflow.base.memory.memory import BaseMemoryComponent
|
||||
from langflow.field_typing import Text
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class ZepMessageReaderComponent(BaseMemoryComponent):
|
||||
display_name = "Zep Message Reader"
|
||||
description = "Retrieves stored chat messages from Zep."
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"session_id": {
|
||||
"display_name": "Session ID",
|
||||
"info": "Session ID of the chat history.",
|
||||
"input_types": ["Text"],
|
||||
},
|
||||
"url": {
|
||||
"display_name": "Zep URL",
|
||||
"info": "URL of the Zep instance.",
|
||||
"input_types": ["Text"],
|
||||
},
|
||||
"api_key": {
|
||||
"display_name": "Zep API Key",
|
||||
"info": "API Key for the Zep instance.",
|
||||
"password": True,
|
||||
},
|
||||
"query": {
|
||||
"display_name": "Query",
|
||||
"info": "Query to search for in the chat history.",
|
||||
},
|
||||
"metadata": {
|
||||
"display_name": "Metadata",
|
||||
"info": "Optional metadata to attach to the message.",
|
||||
"advanced": True,
|
||||
},
|
||||
"search_scope": {
|
||||
"options": ["Messages", "Summary"],
|
||||
"display_name": "Search Scope",
|
||||
"info": "Scope of the search.",
|
||||
"advanced": True,
|
||||
},
|
||||
"search_type": {
|
||||
"options": ["Similarity", "MMR"],
|
||||
"display_name": "Search Type",
|
||||
"info": "Type of search.",
|
||||
"advanced": True,
|
||||
},
|
||||
"limit": {
|
||||
"display_name": "Limit",
|
||||
"info": "Limit of search results.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
||||
def get_messages(self, **kwargs) -> list[Record]:
|
||||
"""
|
||||
Retrieves messages from the ZepChatMessageHistory memory.
|
||||
|
||||
If a query is provided, the search method is used to search for messages in the memory, otherwise all messages are returned.
|
||||
|
||||
Args:
|
||||
memory (ZepChatMessageHistory): The ZepChatMessageHistory instance to retrieve messages from.
|
||||
query (str, optional): The query string to search for messages. Defaults to None.
|
||||
metadata (dict, optional): Additional metadata to filter the search results. Defaults to None.
|
||||
search_scope (str, optional): The scope of the search. Can be 'messages' or 'summary'. Defaults to 'messages'.
|
||||
search_type (str, optional): The type of search. Can be 'similarity' or 'exact'. Defaults to 'similarity'.
|
||||
limit (int, optional): The maximum number of search results to return. Defaults to None.
|
||||
|
||||
Returns:
|
||||
list[Record]: A list of Record objects representing the search results.
|
||||
"""
|
||||
memory: ZepChatMessageHistory = cast(ZepChatMessageHistory, kwargs.get("memory"))
|
||||
if not memory:
|
||||
raise ValueError("ZepChatMessageHistory instance is required.")
|
||||
query = kwargs.get("query")
|
||||
search_scope = kwargs.get("search_scope", SearchScope.messages).lower()
|
||||
search_type = kwargs.get("search_type", SearchType.similarity).lower()
|
||||
limit = kwargs.get("limit")
|
||||
|
||||
if query:
|
||||
memory_search_results = memory.search(
|
||||
query,
|
||||
search_scope=search_scope,
|
||||
search_type=search_type,
|
||||
limit=limit,
|
||||
)
|
||||
# Get the messages from the search results if the search scope is messages
|
||||
result_dicts = []
|
||||
for result in memory_search_results:
|
||||
result_dict = {}
|
||||
if search_scope == SearchScope.messages:
|
||||
result_dict["text"] = result.message
|
||||
else:
|
||||
result_dict["text"] = result.summary
|
||||
result_dict["metadata"] = result.metadata
|
||||
result_dict["score"] = result.score
|
||||
result_dicts.append(result_dict)
|
||||
results = [Record(data=result_dict) for result_dict in result_dicts]
|
||||
else:
|
||||
messages = memory.messages
|
||||
results = [Record.from_lc_message(message) for message in messages]
|
||||
return results
|
||||
|
||||
def build(
|
||||
self,
|
||||
session_id: Text,
|
||||
url: Optional[Text] = None,
|
||||
api_key: Optional[Text] = None,
|
||||
query: Optional[Text] = None,
|
||||
search_scope: SearchScope = SearchScope.messages,
|
||||
search_type: SearchType = SearchType.similarity,
|
||||
limit: Optional[int] = None,
|
||||
) -> list[Record]:
|
||||
try:
|
||||
from zep_python import ZepClient
|
||||
from zep_python.langchain import ZepChatMessageHistory
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Could not import zep-python package. " "Please install it with `pip install zep-python`."
|
||||
)
|
||||
if url == "":
|
||||
url = None
|
||||
zep_client = ZepClient(api_url=url, api_key=api_key)
|
||||
memory = ZepChatMessageHistory(session_id=session_id, zep_client=zep_client)
|
||||
records = self.get_messages(
|
||||
memory=memory,
|
||||
query=query,
|
||||
search_scope=search_scope,
|
||||
search_type=search_type,
|
||||
limit=limit,
|
||||
)
|
||||
self.status = records
|
||||
return records
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
|
||||
from langflow.base.memory.memory import BaseMemoryComponent
|
||||
from langflow.field_typing import Text
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from zep_python.langchain import ZepChatMessageHistory
|
||||
|
||||
|
||||
class ZepMessageWriterComponent(BaseMemoryComponent):
|
||||
display_name = "Zep Message Writer"
|
||||
description = "Writes a message to Zep."
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"session_id": {
|
||||
"display_name": "Session ID",
|
||||
"info": "Session ID of the chat history.",
|
||||
"input_types": ["Text"],
|
||||
},
|
||||
"url": {
|
||||
"display_name": "Zep URL",
|
||||
"info": "URL of the Zep instance.",
|
||||
"input_types": ["Text"],
|
||||
},
|
||||
"api_key": {
|
||||
"display_name": "Zep API Key",
|
||||
"info": "API Key for the Zep instance.",
|
||||
"password": True,
|
||||
},
|
||||
"limit": {
|
||||
"display_name": "Limit",
|
||||
"info": "Limit of search results.",
|
||||
"advanced": True,
|
||||
},
|
||||
"input_value": {
|
||||
"display_name": "Input Record",
|
||||
"info": "Record to write to Zep.",
|
||||
},
|
||||
}
|
||||
|
||||
def add_message(
|
||||
self, sender: Text, sender_name: Text, text: Text, session_id: Text, metadata: dict | None = None, **kwargs
|
||||
):
|
||||
"""
|
||||
Adds a message to the ZepChatMessageHistory memory.
|
||||
|
||||
Args:
|
||||
sender (Text): The type of the message sender. Valid values are "Machine" or "User".
|
||||
sender_name (Text): The name of the message sender.
|
||||
text (Text): The content of the message.
|
||||
session_id (Text): The session ID associated with the message.
|
||||
metadata (dict | None, optional): Additional metadata for the message. Defaults to None.
|
||||
**kwargs: Additional keyword arguments.
|
||||
|
||||
Raises:
|
||||
ValueError: If the ZepChatMessageHistory instance is not provided.
|
||||
|
||||
"""
|
||||
memory: ZepChatMessageHistory | None = kwargs.pop("memory", None)
|
||||
if memory is None:
|
||||
raise ValueError("ZepChatMessageHistory instance is required.")
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
metadata["sender_name"] = sender_name
|
||||
metadata.update(kwargs)
|
||||
if sender == "Machine":
|
||||
memory.add_ai_message(text, metadata=metadata)
|
||||
elif sender == "User":
|
||||
memory.add_user_message(text, metadata=metadata)
|
||||
else:
|
||||
raise ValueError(f"Invalid sender type: {sender}")
|
||||
|
||||
def build(
|
||||
self,
|
||||
input_value: Record,
|
||||
session_id: Text,
|
||||
url: Optional[Text] = None,
|
||||
api_key: Optional[Text] = None,
|
||||
) -> Record:
|
||||
try:
|
||||
from zep_python import ZepClient
|
||||
from zep_python.langchain import ZepChatMessageHistory
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Could not import zep-python package. " "Please install it with `pip install zep-python`."
|
||||
)
|
||||
if url == "":
|
||||
url = None
|
||||
zep_client = ZepClient(api_url=url, api_key=api_key)
|
||||
memory = ZepChatMessageHistory(session_id=session_id, zep_client=zep_client)
|
||||
self.add_message(**input_value.data, memory=memory)
|
||||
self.status = f"Added message to Zep memory for session {session_id}"
|
||||
return input_value
|
||||
|
|
@ -61,10 +61,10 @@ class WeaviateSearchVectorStore(WeaviateVectorStoreComponent, LCVectorStoreCompo
|
|||
input_value: Text,
|
||||
search_type: str,
|
||||
url: str,
|
||||
index_name: str,
|
||||
number_of_results: int = 4,
|
||||
search_by_text: bool = False,
|
||||
api_key: Optional[str] = None,
|
||||
index_name: Optional[str] = None,
|
||||
text_key: str = "text",
|
||||
embedding: Optional[Embeddings] = None,
|
||||
attributes: Optional[list] = None,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import weaviate # type: ignore
|
|||
from langchain.embeddings.base import Embeddings
|
||||
from langchain.schema import BaseRetriever
|
||||
from langchain_community.vectorstores import VectorStore, Weaviate
|
||||
from langchain_core.documents import Document
|
||||
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.schema.schema import Record
|
||||
|
|
@ -50,9 +51,9 @@ class WeaviateVectorStoreComponent(CustomComponent):
|
|||
def build(
|
||||
self,
|
||||
url: str,
|
||||
index_name: str,
|
||||
search_by_text: bool = False,
|
||||
api_key: Optional[str] = None,
|
||||
index_name: Optional[str] = None,
|
||||
text_key: str = "text",
|
||||
embedding: Optional[Embeddings] = None,
|
||||
inputs: Optional[Record] = None,
|
||||
|
|
@ -78,11 +79,13 @@ class WeaviateVectorStoreComponent(CustomComponent):
|
|||
return pascal_case_word
|
||||
|
||||
index_name = _to_pascal_case(index_name) if index_name else None
|
||||
documents = []
|
||||
if not index_name:
|
||||
raise ValueError("Index name is required")
|
||||
documents: list[Document] = []
|
||||
for _input in inputs or []:
|
||||
if isinstance(_input, Record):
|
||||
documents.append(_input.to_lc_document())
|
||||
else:
|
||||
elif isinstance(_input, Document):
|
||||
documents.append(_input)
|
||||
|
||||
if documents and embedding is not None:
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@
|
|||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional\n\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.interface.custom.custom_component import CustomComponent\nfrom langflow.memory import get_messages\n\n\nclass MemoryComponent(CustomComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n order = \"DESC\" if order == \"Descending\" else \"ASC\"\n if sender == \"Machine and User\":\n sender = None\n messages = get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n",
|
||||
"value": "from typing import Optional\n\nfrom langflow.base.memory.memory import BaseMemoryComponent\nfrom langflow.field_typing import Text\nfrom langflow.helpers.record import records_to_text\nfrom langflow.memory import get_messages\nfrom langflow.schema.schema import Record\n\n\nclass MemoryComponent(BaseMemoryComponent):\n display_name = \"Chat Memory\"\n description = \"Retrieves stored chat messages given a specific Session ID.\"\n beta: bool = True\n icon = \"history\"\n\n def build_config(self):\n return {\n \"sender\": {\n \"options\": [\"Machine\", \"User\", \"Machine and User\"],\n \"display_name\": \"Sender Type\",\n },\n \"sender_name\": {\"display_name\": \"Sender Name\", \"advanced\": True},\n \"n_messages\": {\n \"display_name\": \"Number of Messages\",\n \"info\": \"Number of messages to retrieve.\",\n },\n \"session_id\": {\n \"display_name\": \"Session ID\",\n \"info\": \"Session ID of the chat history.\",\n \"input_types\": [\"Text\"],\n },\n \"order\": {\n \"options\": [\"Ascending\", \"Descending\"],\n \"display_name\": \"Order\",\n \"info\": \"Order of the messages.\",\n \"advanced\": True,\n },\n \"record_template\": {\n \"display_name\": \"Record Template\",\n \"multiline\": True,\n \"info\": \"Template to convert Record to Text. If left empty, it will be dynamically set to the Record's text key.\",\n \"advanced\": True,\n },\n }\n\n def get_messages(self, **kwargs) -> list[Record]:\n # Validate kwargs by checking if it contains the correct keys\n if \"sender\" not in kwargs:\n kwargs[\"sender\"] = None\n if \"sender_name\" not in kwargs:\n kwargs[\"sender_name\"] = None\n if \"session_id\" not in kwargs:\n kwargs[\"session_id\"] = None\n if \"limit\" not in kwargs:\n kwargs[\"limit\"] = 5\n if \"order\" not in kwargs:\n kwargs[\"order\"] = \"Descending\"\n\n kwargs[\"order\"] = \"DESC\" if kwargs[\"order\"] == \"Descending\" else \"ASC\"\n if kwargs[\"sender\"] == \"Machine and User\":\n kwargs[\"sender\"] = None\n return get_messages(**kwargs)\n\n def build(\n self,\n sender: Optional[str] = \"Machine and User\",\n sender_name: Optional[str] = None,\n session_id: Optional[str] = None,\n n_messages: int = 5,\n order: Optional[str] = \"Descending\",\n record_template: Optional[str] = \"{sender_name}: {text}\",\n ) -> Text:\n messages = self.get_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n messages_str = records_to_text(template=record_template or \"\", records=messages)\n self.status = messages_str\n return messages_str\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
|
|
|
|||
|
|
@ -227,34 +227,11 @@ def initialize_qdrant(class_object: Type[Qdrant], params: dict):
|
|||
return class_object.from_documents(**params)
|
||||
|
||||
|
||||
def initialize_elasticsearch(class_object: Type[ElasticsearchStore], params: dict):
|
||||
"""Initialize elastic and return the class object"""
|
||||
if "index_name" not in params:
|
||||
raise ValueError("Elasticsearch Index must be provided in the params")
|
||||
if "es_url" not in params:
|
||||
raise ValueError("Elasticsearch URL must be provided in the params")
|
||||
if not docs_in_params(params):
|
||||
existing_index_params = {
|
||||
"embedding": params.pop("embedding"),
|
||||
}
|
||||
if "index_name" in params:
|
||||
existing_index_params["index_name"] = params.pop("index_name")
|
||||
if "es_url" in params:
|
||||
existing_index_params["es_url"] = params.pop("es_url")
|
||||
|
||||
return class_object.from_existing_index(**existing_index_params)
|
||||
# If there are docs in the params, create a new index
|
||||
if "texts" in params:
|
||||
params["documents"] = params.pop("texts")
|
||||
return class_object.from_documents(**params)
|
||||
|
||||
|
||||
vecstore_initializer: Dict[str, Callable[[Type[Any], dict], Any]] = {
|
||||
"Pinecone": initialize_pinecone,
|
||||
"Chroma": initialize_chroma,
|
||||
"Qdrant": initialize_qdrant,
|
||||
"Weaviate": initialize_weaviate,
|
||||
"ElasticsearchStore": initialize_elasticsearch,
|
||||
"FAISS": initialize_faiss,
|
||||
"SupabaseVectorStore": initialize_supabase,
|
||||
"MongoDBAtlasVectorSearch": initialize_mongodb,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ from pathlib import Path
|
|||
from typing import List, Optional, Union
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from loguru import logger
|
||||
|
||||
from langflow.graph import Graph
|
||||
from langflow.graph.schema import RunOutputs
|
||||
from langflow.processing.process import process_tweaks, run_graph
|
||||
|
|
@ -101,6 +103,12 @@ def run_flow_from_json(
|
|||
List[RunOutputs]: A list of RunOutputs objects representing the results of running the flow.
|
||||
"""
|
||||
# Set all streaming to false
|
||||
try:
|
||||
import nest_asyncio # type: ignore
|
||||
|
||||
nest_asyncio.apply()
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not apply nest_asyncio: {e}")
|
||||
if tweaks is None:
|
||||
tweaks = {}
|
||||
tweaks["stream"] = False
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
|
||||
from langchain.agents import AgentExecutor
|
||||
from langchain.schema import AgentAction
|
||||
from loguru import logger
|
||||
|
|
@ -13,6 +14,7 @@ from langflow.schema.graph import InputValue, Tweaks
|
|||
from langflow.schema.schema import INPUT_FIELD_NAME
|
||||
from langflow.services.session.service import SessionService
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.api.v1.schemas import InputValueRequest
|
||||
|
||||
|
|
@ -269,16 +271,19 @@ def process_tweaks(
|
|||
:return: The modified graph_data dictionary.
|
||||
:raises ValueError: If the input is not in the expected format.
|
||||
"""
|
||||
tweaks_dict = {}
|
||||
if not isinstance(tweaks, dict):
|
||||
tweaks = tweaks.model_dump()
|
||||
if "stream" not in tweaks:
|
||||
tweaks["stream"] = stream
|
||||
nodes = validate_input(graph_data, tweaks)
|
||||
tweaks_dict = tweaks.model_dump()
|
||||
else:
|
||||
tweaks_dict = tweaks
|
||||
if "stream" not in tweaks_dict:
|
||||
tweaks_dict["stream"] = stream
|
||||
nodes = validate_input(graph_data, tweaks_dict)
|
||||
nodes_map = {node.get("id"): node for node in nodes}
|
||||
nodes_display_name_map = {node.get("data", {}).get("node", {}).get("display_name"): node for node in nodes}
|
||||
|
||||
all_nodes_tweaks = {}
|
||||
for key, value in tweaks.items():
|
||||
for key, value in tweaks_dict.items():
|
||||
if isinstance(value, dict):
|
||||
if node := nodes_map.get(key):
|
||||
apply_tweaks(node, value)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from typing import List, Optional, Union
|
||||
from typing import Any, List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field, RootModel
|
||||
|
||||
from langflow.schema.schema import InputType
|
||||
from pydantic import BaseModel, Field, RootModel
|
||||
|
||||
|
||||
class InputValue(BaseModel):
|
||||
|
|
@ -14,7 +15,7 @@ class InputValue(BaseModel):
|
|||
|
||||
|
||||
class Tweaks(RootModel):
|
||||
root: dict[str, Union[str, dict[str, str]]] = Field(
|
||||
root: dict[str, Union[str, dict[str, Any]]] = Field(
|
||||
description="A dictionary of tweaks to adjust the flow's execution. Allows customizing flow behavior dynamically. All tweaks are overridden by the input values.",
|
||||
)
|
||||
model_config = {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import copy
|
||||
from typing import Literal, Optional
|
||||
from typing import Literal, Optional, cast
|
||||
|
||||
from langchain_core.documents import Document
|
||||
from langchain_core.messages import BaseMessage
|
||||
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
||||
from pydantic import BaseModel, model_validator
|
||||
from langchain_core.messages import HumanMessage, AIMessage
|
||||
|
||||
|
|
@ -67,8 +67,8 @@ class Record(BaseModel):
|
|||
Returns:
|
||||
Record: The converted Record.
|
||||
"""
|
||||
data = {"text": message.content}
|
||||
data["metadata"] = message.to_json()
|
||||
data: dict = {"text": message.content}
|
||||
data["metadata"] = cast(dict, message.to_json())
|
||||
return cls(data=data, text_key="text")
|
||||
|
||||
def __add__(self, other: "Record") -> "Record":
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class ApiKeyBase(SQLModel):
|
|||
|
||||
class ApiKey(ApiKeyBase, table=True):
|
||||
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True)
|
||||
created_at: datetime = Field(
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None, sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
)
|
||||
api_key: str = Field(index=True, unique=True)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class Variable(VariableBase, table=True):
|
|||
description="Unique ID for the variable",
|
||||
)
|
||||
# name is unique per user
|
||||
created_at: datetime = Field(
|
||||
created_at: Optional[datetime] = Field(
|
||||
default=None,
|
||||
sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=True),
|
||||
description="Creation time of the variable",
|
||||
|
|
|
|||
|
|
@ -101,10 +101,16 @@ def add_row_to_table(
|
|||
conn.execute(insert_sql, values)
|
||||
except Exception as e:
|
||||
# Log values types
|
||||
column_error_message = ""
|
||||
for key, value in validated_dict.items():
|
||||
logger.error(f"{key}: {type(value)}")
|
||||
if value in str(e):
|
||||
column_error_message = f"Column: {key} Value: {value} Error: {e}"
|
||||
|
||||
logger.error(f"Error adding row to table: {e}")
|
||||
if column_error_message:
|
||||
logger.error(f"Error adding row to {table_name}: {column_error_message}")
|
||||
else:
|
||||
logger.error(f"Error adding row to {table_name}: {e}")
|
||||
|
||||
|
||||
async def log_message(
|
||||
|
|
|
|||
223
src/backend/base/poetry.lock
generated
223
src/backend/base/poetry.lock
generated
|
|
@ -517,13 +517,13 @@ test-randomorder = ["pytest-randomly"]
|
|||
|
||||
[[package]]
|
||||
name = "dataclasses-json"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
description = "Easily serialize dataclasses to and from JSON."
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
python-versions = "<4.0,>=3.7"
|
||||
files = [
|
||||
{file = "dataclasses_json-0.6.4-py3-none-any.whl", hash = "sha256:f90578b8a3177f7552f4e1a6e535e84293cd5da421fcce0642d49c0d7bdf8df2"},
|
||||
{file = "dataclasses_json-0.6.4.tar.gz", hash = "sha256:73696ebf24936560cca79a2430cbc4f3dd23ac7bf46ed17f38e5e5e7657a6377"},
|
||||
{file = "dataclasses_json-0.6.5-py3-none-any.whl", hash = "sha256:f49c77aa3a85cac5bf5b7f65f4790ca0d2be8ef4d92c75e91ba0103072788a39"},
|
||||
{file = "dataclasses_json-0.6.5.tar.gz", hash = "sha256:1c287594d9fcea72dc42d6d3836cf14848c2dc5ce88f65ed61b36b57f515fe26"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -624,13 +624,13 @@ gmpy2 = ["gmpy2"]
|
|||
|
||||
[[package]]
|
||||
name = "emoji"
|
||||
version = "2.11.0"
|
||||
version = "2.11.1"
|
||||
description = "Emoji for Python"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||
files = [
|
||||
{file = "emoji-2.11.0-py2.py3-none-any.whl", hash = "sha256:63fc9107f06c6c2e48e5078ce9575cef98518f5ac09474f6148a43e989989582"},
|
||||
{file = "emoji-2.11.0.tar.gz", hash = "sha256:772eaa30f4e0b1ce95148a092df4c7dc97644532c03225326b0fd05e8a9f72a3"},
|
||||
{file = "emoji-2.11.1-py2.py3-none-any.whl", hash = "sha256:b7ba25299bbf520cc8727848ae66b986da32aee27dc2887eaea2bff07226ce49"},
|
||||
{file = "emoji-2.11.1.tar.gz", hash = "sha256:062ff0b3154b6219143f8b9f4b3e5c64c35bc2b146e6e2349ab5f29e218ce1ee"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -638,13 +638,13 @@ dev = ["coverage", "coveralls", "pytest"]
|
|||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
|
||||
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
|
||||
{file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
|
||||
{file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -652,13 +652,13 @@ test = ["pytest (>=6)"]
|
|||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.110.1"
|
||||
version = "0.110.2"
|
||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fastapi-0.110.1-py3-none-any.whl", hash = "sha256:5df913203c482f820d31f48e635e022f8cbfe7350e4830ef05a3163925b1addc"},
|
||||
{file = "fastapi-0.110.1.tar.gz", hash = "sha256:6feac43ec359dfe4f45b2c18ec8c94edb8dc2dfc461d417d9e626590c071baad"},
|
||||
{file = "fastapi-0.110.2-py3-none-any.whl", hash = "sha256:239403f2c0a3dda07a9420f95157a7f014ddb2b770acdbc984f9bdf3ead7afdb"},
|
||||
{file = "fastapi-0.110.2.tar.gz", hash = "sha256:b53d673652da3b65e8cd787ad214ec0fe303cad00d2b529b86ce7db13f17518d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -1064,19 +1064,19 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "langchain-community"
|
||||
version = "0.0.33"
|
||||
version = "0.0.34"
|
||||
description = "Community contributed LangChain integrations."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain_community-0.0.33-py3-none-any.whl", hash = "sha256:830f0d5f4ff9638b99ca01820c26abfa4b65fa705ef89b5ce55ac9aa3a7d83af"},
|
||||
{file = "langchain_community-0.0.33.tar.gz", hash = "sha256:bb56dbc1ef11ca09f258468e11368781adda9219e144073e30cda69496d342b2"},
|
||||
{file = "langchain_community-0.0.34-py3-none-any.whl", hash = "sha256:bc13b21a44bbfca01bff8b35c10a26d71485b57c1d284f499b577ba6e1a5d84a"},
|
||||
{file = "langchain_community-0.0.34.tar.gz", hash = "sha256:96e9a807d9b4777820df5a970996f6bf3ad5632137bf0f4d863bd832bdeb2b0f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = ">=3.8.3,<4.0.0"
|
||||
dataclasses-json = ">=0.5.7,<0.7"
|
||||
langchain-core = ">=0.1.43,<0.2.0"
|
||||
langchain-core = ">=0.1.45,<0.2.0"
|
||||
langsmith = ">=0.1.0,<0.2.0"
|
||||
numpy = ">=1,<2"
|
||||
PyYAML = ">=5.3"
|
||||
|
|
@ -1090,13 +1090,13 @@ extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.
|
|||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.1.44"
|
||||
version = "0.1.46"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langchain_core-0.1.44-py3-none-any.whl", hash = "sha256:d8772dccef95fc97bfa2dcd19412e620ebe14def1f0e218374971f6e30a46a49"},
|
||||
{file = "langchain_core-0.1.44.tar.gz", hash = "sha256:e313975d9ae2926342e6f2ad760338d31f18b1223e9b8b4dc408daeeade46a83"},
|
||||
{file = "langchain_core-0.1.46-py3-none-any.whl", hash = "sha256:1c0befcd2665dd4aa153318aa9bf729071644b4c179e491769b8e583b4bf7441"},
|
||||
{file = "langchain_core-0.1.46.tar.gz", hash = "sha256:17c416349f5c7a9808e70e3725749a3a2df5088f1ecca045c883871aa95f9c9e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -1162,13 +1162,13 @@ types-requests = ">=2.31.0.2,<3.0.0.0"
|
|||
|
||||
[[package]]
|
||||
name = "langsmith"
|
||||
version = "0.1.48"
|
||||
version = "0.1.51"
|
||||
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.8.1"
|
||||
files = [
|
||||
{file = "langsmith-0.1.48-py3-none-any.whl", hash = "sha256:2f8967e2aaaed8881efe6f346590681243b315af8ba8a037d969c299d42071d3"},
|
||||
{file = "langsmith-0.1.48.tar.gz", hash = "sha256:9cd21cd0928123b2bd2363f03515cb1f6a833d9a9f00420240d5132861d15fcc"},
|
||||
{file = "langsmith-0.1.51-py3-none-any.whl", hash = "sha256:1e7363a3f472ecf02a1d91f6dbacde25519554b98c490be71716fcffaab0ca6b"},
|
||||
{file = "langsmith-0.1.51.tar.gz", hash = "sha256:b99b40a8c00e66174540865caa61412622fa1dc4f02602965364919c90528f97"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -1943,18 +1943,19 @@ xmp = ["defusedxml"]
|
|||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.2.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
version = "4.2.1"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"},
|
||||
{file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"},
|
||||
{file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"},
|
||||
{file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
||||
type = ["mypy (>=1.8)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
|
|
@ -1980,18 +1981,18 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.0"
|
||||
version = "2.7.1"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"},
|
||||
{file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"},
|
||||
{file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"},
|
||||
{file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.18.1"
|
||||
pydantic-core = "2.18.2"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -1999,90 +2000,90 @@ email = ["email-validator (>=2.0.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.1"
|
||||
version = "2.18.2"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"},
|
||||
{file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"},
|
||||
{file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"},
|
||||
{file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"},
|
||||
{file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"},
|
||||
{file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"},
|
||||
{file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"},
|
||||
{file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"},
|
||||
{file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"},
|
||||
{file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"},
|
||||
{file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"},
|
||||
{file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"},
|
||||
{file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"},
|
||||
{file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"},
|
||||
{file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"},
|
||||
{file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"},
|
||||
{file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"},
|
||||
{file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"},
|
||||
{file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"},
|
||||
{file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"},
|
||||
{file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"},
|
||||
{file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "langflow-base"
|
||||
version = "0.0.36"
|
||||
version = "0.0.39"
|
||||
description = "A Python package with a built-in web application"
|
||||
authors = ["Langflow <contact@langflow.org>"]
|
||||
maintainers = [
|
||||
|
|
|
|||
570
src/frontend/package-lock.json
generated
570
src/frontend/package-lock.json
generated
|
|
@ -42,20 +42,24 @@
|
|||
"dompurify": "^3.0.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.331.0",
|
||||
"million": "^3.0.6",
|
||||
"moment": "^2.29.4",
|
||||
"openseadragon": "^4.1.1",
|
||||
"playwright": "^1.42.0",
|
||||
"react": "^18.2.21",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.21",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-hotkeys-hook": "^4.5.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-pdf": "^7.7.1",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react18-json-view": "^0.2.3",
|
||||
|
|
@ -1061,6 +1065,59 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"make-dir": "^3.1.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"nopt": "^5.0.0",
|
||||
"npmlog": "^5.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"semver": "^7.3.5",
|
||||
"tar": "^6.1.11"
|
||||
},
|
||||
"bin": {
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@million/lint": {
|
||||
"version": "0.0.73",
|
||||
"resolved": "https://registry.npmjs.org/@million/lint/-/lint-0.0.73.tgz",
|
||||
|
|
@ -4294,6 +4351,12 @@
|
|||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||
"deprecated": "Use your platform's native atob() and btoa() methods instead"
|
||||
},
|
||||
"node_modules/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ace-builds": {
|
||||
"version": "1.33.1",
|
||||
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.33.1.tgz",
|
||||
|
|
@ -4431,6 +4494,12 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/arch": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
|
||||
|
|
@ -4451,6 +4520,19 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/are-we-there-yet": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
|
||||
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"delegates": "^1.0.0",
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
|
|
@ -4936,6 +5018,21 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/canvas": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
|
||||
"integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.0",
|
||||
"nan": "^2.17.0",
|
||||
"simple-get": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/ccount": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
|
||||
|
|
@ -5019,6 +5116,15 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.6.1.tgz",
|
||||
|
|
@ -5124,6 +5230,15 @@
|
|||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/color-support": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
|
||||
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"color-support": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
|
|
@ -5157,7 +5272,13 @@
|
|||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
|
|
@ -5612,6 +5733,12 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
|
|
@ -5620,6 +5747,15 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
|
|
@ -6467,6 +6603,11 @@
|
|||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"node_modules/file-type": {
|
||||
"version": "17.1.6",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz",
|
||||
|
|
@ -6711,11 +6852,41 @@
|
|||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-minipass/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
|
|
@ -6747,6 +6918,46 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"aproba": "^1.0.3 || ^2.0.0",
|
||||
"color-support": "^1.1.2",
|
||||
"console-control-strings": "^1.0.0",
|
||||
"has-unicode": "^2.0.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"signal-exit": "^3.0.0",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wide-align": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/gauge/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
|
|
@ -6795,7 +7006,7 @@
|
|||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
|
@ -6826,7 +7037,7 @@
|
|||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
|
@ -6836,7 +7047,7 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
|
|
@ -6968,6 +7179,12 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
|
|
@ -7273,7 +7490,7 @@
|
|||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
|
@ -8282,6 +8499,37 @@
|
|||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/make-cancellable-promise": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz",
|
||||
"integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==",
|
||||
"funding": {
|
||||
"url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"semver": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/make-event-props": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz",
|
||||
"integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/wojtekmaj/make-event-props?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-table": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
||||
|
|
@ -8530,6 +8778,22 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-refs": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.2.2.tgz",
|
||||
"integrity": "sha512-RwcT7GsQR3KbuLw1rRuodq4Nt547BKEBkliZ0qqsrpyNne9bGTFtsFIsIpx82huWhcl3kOlOlH4H0xkPk/DqVw==",
|
||||
"funding": {
|
||||
"url": "https://github.com/wojtekmaj/merge-refs?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
|
@ -9215,6 +9479,37 @@
|
|||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib/node_modules/minipass": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/minizlib/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/mj-context-menu": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
|
||||
|
|
@ -9265,6 +9560,12 @@
|
|||
"thenify-all": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
|
||||
"integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
|
|
@ -9339,6 +9640,21 @@
|
|||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
|
||||
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="
|
||||
},
|
||||
"node_modules/nopt": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
|
||||
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "bin/nopt.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
|
|
@ -9389,6 +9705,18 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/npmlog": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
|
||||
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"are-we-there-yet": "^2.0.0",
|
||||
"console-control-strings": "^1.1.0",
|
||||
"gauge": "^3.0.0",
|
||||
"set-blocking": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nwsapi": {
|
||||
"version": "2.2.9",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
|
||||
|
|
@ -9466,7 +9794,7 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
|
@ -9485,6 +9813,14 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openseadragon": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.1.1.tgz",
|
||||
"integrity": "sha512-owU9gsasAcobLN+LM8lN58Xc2VDSDotY9mkrwS/NB6g9KX/PcusV4RZvhHng2RF/Q0pMziwldf62glwXoGnuzg==",
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/openseadragon"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
||||
|
|
@ -9714,7 +10050,7 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -9763,6 +10099,27 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/path2d-polyfill": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz",
|
||||
"integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pdfjs-dist": {
|
||||
"version": "3.11.174",
|
||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz",
|
||||
"integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvas": "^2.11.2",
|
||||
"path2d-polyfill": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/peek-readable": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
|
||||
|
|
@ -10512,6 +10869,15 @@
|
|||
"react": ">=16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hotkeys-hook": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz",
|
||||
"integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.1",
|
||||
"react-dom": ">=16.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.1.0.tgz",
|
||||
|
|
@ -10573,6 +10939,43 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.0.tgz",
|
||||
"integrity": "sha512-wRiUsea88TjKDc4FBEn+sLvIDesp6brMbGWnJGjew2waAc9evdhja/2LvePc898HJbHw0L+MTWy7NhpnELAvLQ=="
|
||||
},
|
||||
"node_modules/react-pdf": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.1.tgz",
|
||||
"integrity": "sha512-cbbf/PuRtGcPPw+HLhMI1f6NSka8OJgg+j/yPWTe95Owf0fK6gmVY7OXpTxMeh92O3T3K3EzfE0ML0eXPGwR5g==",
|
||||
"dependencies": {
|
||||
"clsx": "^2.0.0",
|
||||
"dequal": "^2.0.3",
|
||||
"make-cancellable-promise": "^1.3.1",
|
||||
"make-event-props": "^1.6.0",
|
||||
"merge-refs": "^1.2.1",
|
||||
"pdfjs-dist": "3.11.174",
|
||||
"prop-types": "^15.6.2",
|
||||
"tiny-invariant": "^1.0.0",
|
||||
"warning": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/wojtekmaj/react-pdf?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-pdf/node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/react-reconciler": {
|
||||
"version": "0.29.1",
|
||||
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.1.tgz",
|
||||
|
|
@ -10996,7 +11399,7 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
|
|
@ -11171,6 +11574,12 @@
|
|||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
|
|
@ -11450,6 +11859,61 @@
|
|||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"decompress-response": "^4.2.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-get/node_modules/decompress-response": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
|
||||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"mimic-response": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-get/node_modules/mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
|
|
@ -11904,6 +12368,50 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
|
|
@ -11929,6 +12437,11 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
|
|
@ -12886,6 +13399,14 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wcwidth": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||
|
|
@ -13047,6 +13568,35 @@
|
|||
"resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
|
||||
"integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw=="
|
||||
},
|
||||
"node_modules/wide-align": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/wide-align/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/wide-align/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
|
|
@ -13168,7 +13718,7 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.16.0",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@
|
|||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/axios": "^0.14.0",
|
||||
"ace-builds": "^1.24.1",
|
||||
<<<<<<< HEAD
|
||||
"ag-grid-community": "^31.2.1",
|
||||
=======
|
||||
>>>>>>> node-shortcuts-refactor
|
||||
"ag-grid-react": "^31.2.1",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"axios": "^1.5.0",
|
||||
|
|
@ -37,20 +40,24 @@
|
|||
"dompurify": "^3.0.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.331.0",
|
||||
"million": "^3.0.6",
|
||||
"moment": "^2.29.4",
|
||||
"openseadragon": "^4.1.1",
|
||||
"playwright": "^1.42.0",
|
||||
"react": "^18.2.21",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.21",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-hotkeys-hook": "^4.5.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-pdf": "^7.7.1",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react18-json-view": "^0.2.3",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,13 @@ import { validationStatusType } from "../../types/components";
|
|||
import { NodeDataType } from "../../types/flow";
|
||||
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||
import { classNames, cn, getFieldTitle, sortFields } from "../../utils/utils";
|
||||
import {
|
||||
classNames,
|
||||
cn,
|
||||
getFieldTitle,
|
||||
isWrappedWithClass,
|
||||
sortFields,
|
||||
} from "../../utils/utils";
|
||||
import ParameterComponent from "./components/parameterComponent";
|
||||
|
||||
export default function GenericNode({
|
||||
|
|
@ -339,6 +345,8 @@ export default function GenericNode({
|
|||
);
|
||||
};
|
||||
|
||||
const [openWDoubleCLick, setOpenWDoubleCLick] = useState(false);
|
||||
|
||||
const getBaseBorderClass = (selected) =>
|
||||
selected ? "border border-ring" : "border";
|
||||
|
||||
|
|
@ -349,6 +357,8 @@ export default function GenericNode({
|
|||
return (
|
||||
<NodeToolbar>
|
||||
<NodeToolbarComponent
|
||||
openWDoubleClick={openWDoubleCLick}
|
||||
setOpenWDoubleClick={setOpenWDoubleCLick}
|
||||
data={data}
|
||||
deleteNode={(id) => {
|
||||
takeSnapshot();
|
||||
|
|
@ -382,12 +392,18 @@ export default function GenericNode({
|
|||
updateNodeCode,
|
||||
isOutdated,
|
||||
selected,
|
||||
openWDoubleCLick,
|
||||
setOpenWDoubleCLick,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{memoizedNodeToolbarComponent}
|
||||
<div
|
||||
onDoubleClick={(event) => {
|
||||
if (!isWrappedWithClass(event, "nodoubleclick"))
|
||||
setOpenWDoubleCLick(true);
|
||||
}}
|
||||
className={getNodeBorderClassName(
|
||||
selected,
|
||||
showNode,
|
||||
|
|
@ -460,7 +476,7 @@ export default function GenericNode({
|
|||
event.preventDefault();
|
||||
}}
|
||||
data-testid={"title-" + data.node?.display_name}
|
||||
className="generic-node-tooltip-div cursor-text text-primary"
|
||||
className="nodoubleclick generic-node-tooltip-div cursor-text text-primary"
|
||||
>
|
||||
{data.node?.display_name}
|
||||
</div>
|
||||
|
|
@ -713,7 +729,7 @@ export default function GenericNode({
|
|||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
"generic-node-desc-text truncate-multiline word-break-break-word",
|
||||
"nodoubleclick generic-node-desc-text truncate-multiline word-break-break-word",
|
||||
(data.node?.description === "" ||
|
||||
!data.node?.description) &&
|
||||
nameEditable
|
||||
|
|
|
|||
141
src/frontend/src/components/ImageViewer/index.tsx
Normal file
141
src/frontend/src/components/ImageViewer/index.tsx
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import ForwardedIconComponent from "../genericIconComponent";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import OpenSeadragon from 'openseadragon';
|
||||
import { Separator } from "../ui/separator";
|
||||
import { saveAs } from 'file-saver'
|
||||
import useAlertStore from "../../stores/alertStore";
|
||||
import { IMGViewErrorMSG, IMGViewErrorTitle } from "../../constants/constants";
|
||||
|
||||
export default function ImageViewer({image }) {
|
||||
const viewerRef = useRef(null);
|
||||
const [errorDownloading, setErrordownloading] = useState(false)
|
||||
const setErrorList = useAlertStore(state => state.setErrorData);
|
||||
const [initialMsg, setInicialMsg] = useState("Please build your flow");
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (viewerRef.current) {
|
||||
// Initialize OpenSeadragon viewer
|
||||
const viewer = OpenSeadragon({
|
||||
element: viewerRef.current,
|
||||
prefixUrl: 'https://cdnjs.cloudflare.com/ajax/libs/openseadragon/2.4.2/images/', // Optional: Set the path to OpenSeadragon images
|
||||
tileSources: {type: 'image', url: image},
|
||||
defaultZoomLevel: 1,
|
||||
maxZoomPixelRatio: 4,
|
||||
showNavigationControl: false,
|
||||
});
|
||||
const zoomInButton = document.getElementById('zoom-in-button');
|
||||
const zoomOutButton = document.getElementById('zoom-out-button');
|
||||
const homeButton = document.getElementById('home-button');
|
||||
const fullPageButton = document.getElementById('full-page-button');
|
||||
|
||||
zoomInButton!.addEventListener('click', () => viewer.viewport.zoomBy(1.2));
|
||||
zoomOutButton!.addEventListener('click', () => viewer.viewport.zoomBy(0.8));
|
||||
homeButton!.addEventListener('click', () => viewer.viewport.goHome());
|
||||
fullPageButton!.addEventListener('click', () => viewer.setFullScreen(true));
|
||||
|
||||
// Optionally, you can set additional viewer options here
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
viewer.destroy();
|
||||
zoomInButton!.removeEventListener('click', () => viewer.viewport.zoomBy(1.2));
|
||||
zoomOutButton!.removeEventListener('click', () => viewer.viewport.zoomBy(0.8));
|
||||
homeButton!.removeEventListener('click', () => viewer.viewport.goHome());
|
||||
fullPageButton!.removeEventListener('click', () => viewer.setFullScreen(true));
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing OpenSeadragon:', error);
|
||||
}
|
||||
}, [image]);
|
||||
|
||||
function download() {
|
||||
const imageUrl = image;
|
||||
// Fetch the image data
|
||||
fetch(imageUrl)
|
||||
.then(response => response.blob())
|
||||
.then(blob => {
|
||||
// Save the image using FileSaver.js
|
||||
saveAs(blob, 'image.jpg');
|
||||
})
|
||||
.catch(error => {
|
||||
setErrorList({title: "There was an error downloading your image"})
|
||||
console.error('Error downloading image:', error)
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
image === "" ? (
|
||||
<div className="w-full h-full bg-muted rounded-md flex align-center justify-center flex-col gap-5 border border-border">
|
||||
<div className="flex gap-2 align-center justify-center ">
|
||||
<ForwardedIconComponent
|
||||
name="Image"
|
||||
/>
|
||||
{IMGViewErrorTitle}
|
||||
</div>
|
||||
<div className="flex align-center justify-center">
|
||||
<div className="langflow-chat-desc flex align-center justify-center">
|
||||
<div className="langflow-chat-desc-span">
|
||||
{IMGViewErrorMSG}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="w-full flex align-center justify-center my-2 mb-4">
|
||||
<div className="shadow-round-btn-shadow hover:shadow-round-btn-shadow flex items-center justify-center rounded-sm border bg-muted shadow-md transition-all w-[50%]">
|
||||
<button id="zoom-in-button" className="relative inline-flex w-full items-center justify-center px-3 py-3 text-sm font-semibold transition-all w-full transition-all duration-500 ease-in-out ease-in-out hover:bg-hover">
|
||||
<ForwardedIconComponent
|
||||
name="ZoomIn"
|
||||
className={"text-secondary-foreground w-5 h-5"}
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
<button id="zoom-out-button" className="relative inline-flex w-full items-center justify-center px-3 py-3 text-sm font-semibold transition-all transition-all duration-500 ease-in-out ease-in-out hover:bg-hover">
|
||||
<ForwardedIconComponent
|
||||
name="ZoomOut"
|
||||
className={"text-secondary-foreground w-5 h-5"}
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
<button id="home-button" className="relative inline-flex w-full items-center justify-center px-3 py-3 text-sm font-semibold transition-all transition-all duration-500 ease-in-out ease-in-out hover:bg-hover">
|
||||
<ForwardedIconComponent
|
||||
name="RotateCcw"
|
||||
className={"text-secondary-foreground w-5 h-5"}
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
<button id="full-page-button" className="relative inline-flex w-full items-center justify-center px-3 py-3 text-sm font-semibold transition-all transition-all duration-500 ease-in-out ease-in-out hover:bg-hover">
|
||||
<ForwardedIconComponent
|
||||
name="Maximize2"
|
||||
className={"text-secondary-foreground w-5 h-5"}
|
||||
/>
|
||||
</button>
|
||||
<div>
|
||||
<Separator orientation="vertical" />
|
||||
</div>
|
||||
|
||||
<button onClick={download} className="relative inline-flex w-full items-center justify-center px-3 py-3 text-sm font-semibold transition-all transition-all duration-500 ease-in-out ease-in-out hover:bg-hover">
|
||||
<ForwardedIconComponent
|
||||
name="ArrowDownToLine"
|
||||
className={"text-secondary-foreground w-5 h-5"}
|
||||
/>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="canvas" ref={viewerRef} className={`w-full h-[90%] `} />
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -9,32 +9,32 @@ import { useStoreStore } from "../../stores/storeStore";
|
|||
import { classNames } from "../../utils/utils";
|
||||
import ForwardedIconComponent from "../genericIconComponent";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
|
||||
export default function FlowToolbar(): JSX.Element {
|
||||
function handleAPIWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
setOpenCodeModal((oldOpen) => !oldOpen)
|
||||
}
|
||||
|
||||
function handleChatWShortcut(e: KeyboardEvent) {
|
||||
if (useFlowStore.getState().hasIO) {
|
||||
e.preventDefault();
|
||||
setOpen((oldState) => !oldState);
|
||||
}
|
||||
}
|
||||
|
||||
useHotkeys("mod+k", handleChatWShortcut);
|
||||
useHotkeys("mod+r", handleAPIWShortcut);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openCodeModal, setOpenCodeModal] = useState<boolean>(false);
|
||||
|
||||
const hasIO = useFlowStore((state) => state.hasIO);
|
||||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
const validApiKey = useStoreStore((state) => state.validApiKey);
|
||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
const hasApiKey = useStoreStore((state) => state.hasApiKey);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
(event.key === "K" || event.key === "k") &&
|
||||
(event.metaKey || event.ctrlKey) &&
|
||||
useFlowStore.getState().hasIO
|
||||
) {
|
||||
event.preventDefault();
|
||||
setOpen((oldState) => !oldState);
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const prevNodesRef = useRef<any[] | undefined>();
|
||||
|
||||
const ModalMemo = useMemo(
|
||||
|
|
@ -117,7 +117,7 @@ export default function FlowToolbar(): JSX.Element {
|
|||
</div>
|
||||
<div className="flex cursor-pointer items-center gap-2">
|
||||
{currentFlow && currentFlow.data && (
|
||||
<ApiModal flow={currentFlow}>
|
||||
<ApiModal flow={currentFlow} open={openCodeModal} setOpen={setOpenCodeModal}>
|
||||
<div
|
||||
className={classNames(
|
||||
"relative inline-flex w-full items-center justify-center gap-1 px-5 py-3 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-hover"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
export const convertCSVToData = (csvFile, csvSeparator: string) => {
|
||||
const lines = csvFile.data.trim().split("\n");
|
||||
const headers = lines[0].trim().split(csvSeparator);
|
||||
|
||||
|
||||
const initialRowData: any = [];
|
||||
const initialColDefs = headers.map((header) => ({
|
||||
field: header.trim(),
|
||||
wrapText: true,
|
||||
autoHeight: true,
|
||||
height: "100%",
|
||||
}));
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const data = lines[i].trim().split(csvSeparator);
|
||||
const rowDataEntry: any = {};
|
||||
|
||||
for (let j = 0; j < headers.length; j++) {
|
||||
const value = isNaN(data[j]) ? data[j] : parseFloat(data[j]);
|
||||
rowDataEntry[headers[j].trim()] = value;
|
||||
}
|
||||
|
||||
initialRowData.push(rowDataEntry);
|
||||
}
|
||||
|
||||
return { rowData: initialRowData, colDefs: initialColDefs };
|
||||
};
|
||||
182
src/frontend/src/components/csvOutputComponent/index.tsx
Normal file
182
src/frontend/src/components/csvOutputComponent/index.tsx
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
import "ag-grid-community/styles/ag-grid.css"; // Mandatory CSS required by the grid
|
||||
import "ag-grid-community/styles/ag-theme-balham.css"; // Optional Theme applied to the grid
|
||||
import { AgGridReact } from "ag-grid-react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
CSVError,
|
||||
CSVNoDataError,
|
||||
CSVViewErrorTitle,
|
||||
} from "../../constants/constants";
|
||||
import { useDarkStore } from "../../stores/darkStore";
|
||||
import { FlowPoolObjectType } from "../../types/chat";
|
||||
import { NodeType } from "../../types/flow";
|
||||
import ForwardedIconComponent from "../genericIconComponent";
|
||||
import Loading from "../ui/loading";
|
||||
import { convertCSVToData } from "./helpers/convert-data-function";
|
||||
|
||||
function CsvOutputComponent({
|
||||
csvNode,
|
||||
flowPool,
|
||||
}: {
|
||||
csvNode: NodeType;
|
||||
flowPool: FlowPoolObjectType;
|
||||
}) {
|
||||
const csvNodeArtifacts = flowPool?.data?.artifacts?.repr;
|
||||
const jsonString = csvNodeArtifacts?.replace(/'/g, '"');
|
||||
let file = null;
|
||||
try {
|
||||
file = JSON?.parse(jsonString) || "";
|
||||
} catch (e) {
|
||||
console.log("Error parsing JSON");
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
return (
|
||||
<div className=" align-center flex h-full w-full flex-col items-center justify-center gap-5">
|
||||
<div className="align-center flex w-full justify-center gap-2">
|
||||
<ForwardedIconComponent name="Table" />
|
||||
{CSVViewErrorTitle}
|
||||
</div>
|
||||
<div className="align-center flex w-full justify-center">
|
||||
<div className="langflow-chat-desc align-center flex justify-center px-6 py-8">
|
||||
<div className="langflow-chat-desc-span">{CSVError}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const separator = csvNode?.data?.node?.template?.separator?.value || ",";
|
||||
|
||||
const dark = useDarkStore.getState().dark;
|
||||
|
||||
const [rowData, setRowData] = useState([]);
|
||||
const [colDefs, setColDefs] = useState([]);
|
||||
|
||||
const [status, setStatus] = useState("loading");
|
||||
var currentRowHeight: number;
|
||||
var minRowHeight = 25;
|
||||
const defaultColDef = useMemo(() => {
|
||||
return {
|
||||
width: 200,
|
||||
editable: true,
|
||||
filter: true,
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setStatus("loading");
|
||||
if (file) {
|
||||
const { rowData: data, colDefs: columns } = convertCSVToData(
|
||||
file,
|
||||
separator
|
||||
);
|
||||
setRowData(data);
|
||||
setColDefs(columns);
|
||||
|
||||
setTimeout(() => {
|
||||
setStatus("loaded");
|
||||
}, 1000);
|
||||
} else {
|
||||
setStatus("nodata");
|
||||
}
|
||||
}, [separator]);
|
||||
|
||||
const getRowHeight = useCallback(() => {
|
||||
return currentRowHeight;
|
||||
}, []);
|
||||
|
||||
const onGridReady = useCallback((params: any) => {
|
||||
minRowHeight = params.api.getSizesForCurrentTheme().rowHeight;
|
||||
currentRowHeight = minRowHeight;
|
||||
}, []);
|
||||
|
||||
const updateRowHeight = (params: { api: any }) => {
|
||||
const bodyViewport = document.querySelector(".ag-body-viewport");
|
||||
if (!bodyViewport) {
|
||||
return;
|
||||
}
|
||||
var gridHeight = bodyViewport.clientHeight;
|
||||
var renderedRowCount = params.api.getDisplayedRowCount();
|
||||
|
||||
if (renderedRowCount * minRowHeight >= gridHeight) {
|
||||
if (currentRowHeight !== minRowHeight) {
|
||||
currentRowHeight = minRowHeight;
|
||||
params.api.resetRowHeights();
|
||||
}
|
||||
} else {
|
||||
currentRowHeight = Math.floor(gridHeight / renderedRowCount);
|
||||
params.api.resetRowHeights();
|
||||
}
|
||||
};
|
||||
|
||||
const onFirstDataRendered = useCallback(
|
||||
(params: any) => {
|
||||
updateRowHeight(params);
|
||||
},
|
||||
[updateRowHeight]
|
||||
);
|
||||
|
||||
const onGridSizeChanged = useCallback(
|
||||
(params: any) => {
|
||||
updateRowHeight(params);
|
||||
},
|
||||
[updateRowHeight]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className=" h-full rounded-md border bg-muted">
|
||||
{status === "nodata" && (
|
||||
<div className=" align-center flex h-full w-full flex-col items-center justify-center gap-5">
|
||||
<div className="align-center flex w-full justify-center gap-2">
|
||||
<ForwardedIconComponent name="Table" />
|
||||
{CSVViewErrorTitle}
|
||||
</div>
|
||||
<div className="align-center flex w-full justify-center">
|
||||
<div className="langflow-chat-desc align-center flex justify-center px-6 py-8">
|
||||
<div className="langflow-chat-desc-span">{CSVNoDataError}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{status === "error" && (
|
||||
<div className=" align-center flex h-full w-full flex-col items-center justify-center gap-5">
|
||||
<div className="align-center flex w-full justify-center gap-2">
|
||||
<ForwardedIconComponent name="Table" />
|
||||
{CSVViewErrorTitle}
|
||||
</div>
|
||||
<div className="align-center flex w-full justify-center">
|
||||
<div className="langflow-chat-desc align-center flex justify-center px-6 py-8">
|
||||
<div className="langflow-chat-desc-span">{CSVError}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === "loaded" && (
|
||||
<div
|
||||
className={`${dark ? "ag-theme-balham-dark" : "ag-theme-balham"}`}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
>
|
||||
<AgGridReact
|
||||
rowData={rowData}
|
||||
columnDefs={colDefs}
|
||||
defaultColDef={defaultColDef}
|
||||
getRowHeight={getRowHeight}
|
||||
onGridReady={onGridReady}
|
||||
onFirstDataRendered={onFirstDataRendered}
|
||||
onGridSizeChanged={onGridSizeChanged}
|
||||
scrollbarWidth={8}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{status === "loading" && (
|
||||
<div className=" flex h-full w-full items-center justify-center align-middle">
|
||||
<Loading />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CsvOutputComponent;
|
||||
23
src/frontend/src/components/pdfViewer/Error/index.tsx
Normal file
23
src/frontend/src/components/pdfViewer/Error/index.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { CHAT_FIRST_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT, PDFCheckFlow, PDFLoadErrorTitle } from "../../../constants/constants";
|
||||
import IconComponent from "../../genericIconComponent";
|
||||
|
||||
|
||||
export default function Error(): JSX.Element {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full w-full bg-muted">
|
||||
<div className="chat-alert-box">
|
||||
<span className="flex gap-2">
|
||||
<IconComponent name="FileX2" />
|
||||
<span className="langflow-chat-span">{PDFLoadErrorTitle}</span>
|
||||
</span>
|
||||
<br />
|
||||
<div className="langflow-chat-desc">
|
||||
<span className="langflow-chat-desc-span">
|
||||
{PDFCheckFlow}{" "}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
155
src/frontend/src/components/pdfViewer/index.tsx
Normal file
155
src/frontend/src/components/pdfViewer/index.tsx
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { Document, Page, pdfjs } from "react-pdf";
|
||||
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
|
||||
import "react-pdf/dist/esm/Page/TextLayer.css";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
import Loading from "../ui/loading";
|
||||
import Error from "./Error";
|
||||
import NoDataPdf from "./noData";
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
|
||||
|
||||
export default function PdfViewer({ pdf }: { pdf: string }): JSX.Element {
|
||||
const [numPages, setNumPages] = useState(-1);
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [scale, setScale] = useState(1);
|
||||
const [width, setWidth] = useState<number | undefined>(undefined);
|
||||
const [showControl, setShowControl] = useState(false);
|
||||
const container = useRef<null | HTMLDivElement>(null);
|
||||
|
||||
//shortcuts to change page
|
||||
useEffect(() => {
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === "ArrowLeft") {
|
||||
if (pageNumber > 1) previousPage();
|
||||
} else if (event.key === "ArrowRight") {
|
||||
if (pageNumber < numPages) nextPage();
|
||||
}
|
||||
}
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [pageNumber]);
|
||||
|
||||
function onDocumentLoadSuccess({ numPages }) {
|
||||
setNumPages(numPages);
|
||||
setPageNumber(1);
|
||||
}
|
||||
|
||||
function changePage(offset) {
|
||||
setPageNumber((prevPageNumber) => prevPageNumber + offset);
|
||||
}
|
||||
|
||||
function previousPage() {
|
||||
changePage(-1);
|
||||
}
|
||||
|
||||
function nextPage() {
|
||||
changePage(1);
|
||||
}
|
||||
|
||||
//set handle scale in % to real number
|
||||
function handleScaleChange(e) {
|
||||
//check if e is a number
|
||||
if (isNaN(e) || e < 0.1) return;
|
||||
// round to 2 decimal places
|
||||
e = Math.round(e * 10) / 10;
|
||||
|
||||
setScale(e);
|
||||
}
|
||||
|
||||
function zoomIn() {
|
||||
handleScaleChange(scale + 0.1);
|
||||
}
|
||||
function zoomOut() {
|
||||
if (scale > 0.1) handleScaleChange(scale - 0.1);
|
||||
}
|
||||
|
||||
function handlePageLoad(page) {
|
||||
if (!container.current) return;
|
||||
const containerWidth = container.current.clientWidth;
|
||||
const pageWidth = page.width;
|
||||
if (containerWidth > pageWidth) {
|
||||
setWidth(containerWidth - 10);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={container}
|
||||
onMouseEnter={(_) => setShowControl(true)}
|
||||
onMouseLeave={(_) => setShowControl(false)}
|
||||
className="flex h-full w-full flex-col items-center justify-end overflow-clip rounded-lg border border-border"
|
||||
>
|
||||
<div className={"h-full min-h-0 w-full overflow-auto custom-scroll"}>
|
||||
<Document
|
||||
loading={
|
||||
<div className="flex h-full w-full items-center justify-center align-middle">
|
||||
<Loading />
|
||||
</div>
|
||||
}
|
||||
onLoadSuccess={onDocumentLoadSuccess}
|
||||
file={pdf}
|
||||
noData={<NoDataPdf />}
|
||||
error={<Error />}
|
||||
className="h-full w-full"
|
||||
>
|
||||
<Page
|
||||
width={width}
|
||||
onLoadSuccess={handlePageLoad}
|
||||
scale={scale}
|
||||
renderTextLayer
|
||||
pageNumber={pageNumber}
|
||||
className={"h-full max-h-0 w-full"}
|
||||
/>
|
||||
</Document>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
"absolute z-50 pb-5 " + (showControl && numPages > 0 ? "" : " hidden")
|
||||
}
|
||||
>
|
||||
<div className=" flex w-min items-center justify-center gap-0.5 rounded-xl bg-secondary px-2 align-middle">
|
||||
<button
|
||||
type="button"
|
||||
disabled={pageNumber <= 1}
|
||||
onClick={previousPage}
|
||||
>
|
||||
<IconComponent
|
||||
name={"ChevronLeft"}
|
||||
className="h-6 w-6"
|
||||
></IconComponent>
|
||||
</button>
|
||||
<p>
|
||||
{pageNumber || (numPages ? 1 : "--")}/{numPages || "--"}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
disabled={pageNumber >= numPages}
|
||||
onClick={nextPage}
|
||||
>
|
||||
<IconComponent
|
||||
name={"ChevronRight"}
|
||||
className="h-6 w-6"
|
||||
></IconComponent>
|
||||
</button>
|
||||
<p className="px-2">|</p>
|
||||
<button type="button" onClick={zoomOut}>
|
||||
<IconComponent name={"ZoomOut"} className="h-6 w-6"></IconComponent>
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
step={0.1}
|
||||
className="w-6 border-b bg-transparent text-center arrow-hide"
|
||||
onChange={(e) => handleScaleChange(e.target.value)}
|
||||
value={scale}
|
||||
/>
|
||||
<button type="button" onClick={zoomIn}>
|
||||
<IconComponent name={"ZoomIn"} className="h-6 w-6"></IconComponent>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
src/frontend/src/components/pdfViewer/noData/index.tsx
Normal file
17
src/frontend/src/components/pdfViewer/noData/index.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { PDFErrorTitle, PDFLoadError } from "../../../constants/constants";
|
||||
|
||||
export default function NoDataPdf(): JSX.Element {
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center bg-muted">
|
||||
<div className="chat-alert-box">
|
||||
<span>
|
||||
📄 <span className="langflow-chat-span">{PDFErrorTitle}</span>
|
||||
</span>
|
||||
<br />
|
||||
<div className="langflow-chat-desc">
|
||||
<span className="langflow-chat-desc-span">{PDFLoadError} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -161,6 +161,29 @@ export const IMPORT_DIALOG_SUBTITLE =
|
|||
*/
|
||||
export const TOOLTIP_EMPTY = "No compatible components found.";
|
||||
|
||||
export const CSVViewErrorTitle = "CSV output";
|
||||
|
||||
export const CSVNoDataError = "No data available";
|
||||
|
||||
export const PDFViewConstant = "Expand the ouptut to see the PDF";
|
||||
|
||||
export const CSVError = "Error loading CSV";
|
||||
|
||||
export const PDFLoadErrorTitle = "Error loading PDF";
|
||||
|
||||
export const PDFCheckFlow = "Please check your flow and try again";
|
||||
|
||||
export const PDFErrorTitle = "PDF Output";
|
||||
|
||||
export const PDFLoadError = "Run the flow to see the pdf";
|
||||
|
||||
export const IMGViewConstant = "Expand the view to see the image";
|
||||
|
||||
export const IMGViewErrorMSG =
|
||||
"Run the flow or inform a valid url to see your image";
|
||||
|
||||
export const IMGViewErrorTitle = "Image output";
|
||||
|
||||
/**
|
||||
* The base text for subtitle of code dialog
|
||||
* @constant
|
||||
|
|
@ -688,8 +711,14 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([
|
|||
|
||||
export const priorityFields = new Set(["code", "template"]);
|
||||
|
||||
export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]);
|
||||
export const OUTPUT_TYPES = new Set(["ChatOutput", "TextOutput"]);
|
||||
export const INPUT_TYPES = new Set(["ChatInput", "TextInput", "KeyPairInput"]);
|
||||
export const OUTPUT_TYPES = new Set([
|
||||
"ChatOutput",
|
||||
"TextOutput",
|
||||
"PDFOutput",
|
||||
"ImageOutput",
|
||||
"CSVOutput",
|
||||
]);
|
||||
|
||||
export const CHAT_FIRST_INITIAL_TEXT =
|
||||
"Start a conversation and click the agent's thoughts";
|
||||
|
|
|
|||
|
|
@ -37,14 +37,21 @@ const ApiModal = forwardRef(
|
|||
{
|
||||
flow,
|
||||
children,
|
||||
open: myOpen,
|
||||
setOpen: mySetOpen,
|
||||
}: {
|
||||
flow: FlowType;
|
||||
children: ReactNode;
|
||||
open: any;
|
||||
setOpen: any;
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const { autoLogin } = useContext(AuthContext);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [open, setOpen] =
|
||||
mySetOpen !== undefined && myOpen !== undefined
|
||||
? [myOpen, mySetOpen]
|
||||
: useState(false);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const tweak = useRef<tweakType>([]);
|
||||
const tweaksList = useRef<string[]>([]);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,13 @@ const EditNodeModal = forwardRef(
|
|||
nodeLength,
|
||||
open,
|
||||
setOpen,
|
||||
setOpenWDoubleClick,
|
||||
}: {
|
||||
data: NodeDataType;
|
||||
nodeLength: number;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
setOpenWDoubleClick: (open: boolean) => void;
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
|
|
@ -82,6 +84,12 @@ const EditNodeModal = forwardRef(
|
|||
}
|
||||
}, [open]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setOpenWDoubleClick(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
import { cloneDeep } from "lodash";
|
||||
import ImageViewer from "../../../../components/ImageViewer";
|
||||
import CsvOutputComponent from "../../../../components/csvOutputComponent";
|
||||
import PdfViewer from "../../../../components/pdfViewer";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../../../../components/ui/select";
|
||||
import { Textarea } from "../../../../components/ui/textarea";
|
||||
import { PDFViewConstant } from "../../../../constants/constants";
|
||||
import { InputOutput } from "../../../../constants/enums";
|
||||
import useFlowStore from "../../../../stores/flowStore";
|
||||
import { IOFieldViewProps } from "../../../../types/components";
|
||||
|
|
@ -15,6 +27,19 @@ export default function IOFieldView({
|
|||
const setNode = useFlowStore((state) => state.setNode);
|
||||
const flowPool = useFlowStore((state) => state.flowPool);
|
||||
const node = nodes.find((node) => node.id === fieldId);
|
||||
const flowPoolNode = (flowPool[node!.id] ?? [])[
|
||||
(flowPool[node!.id]?.length ?? 1) - 1
|
||||
];
|
||||
const handleChangeSelect = (e) => {
|
||||
if (node) {
|
||||
let newNode = cloneDeep(node);
|
||||
if (newNode.data.node.template.separator) {
|
||||
newNode.data.node.template.separator.value = e;
|
||||
setNode(newNode.id, newNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function handleOutputType() {
|
||||
if (!node) return <>"No node found!"</>;
|
||||
switch (type) {
|
||||
|
|
@ -91,6 +116,58 @@ export default function IOFieldView({
|
|||
readOnly
|
||||
/>
|
||||
);
|
||||
case "PDFOutput":
|
||||
return left ? (
|
||||
<div>{PDFViewConstant}</div>
|
||||
) : (
|
||||
<PdfViewer pdf={flowPoolNode?.params ?? ""} />
|
||||
);
|
||||
case "CSVOutput":
|
||||
return left ? (
|
||||
<>
|
||||
<div className="flex justify-between">
|
||||
Expand the ouptut to see the CSV
|
||||
</div>
|
||||
<div className="flex items-center justify-between pt-5">
|
||||
<span>CSV separator </span>
|
||||
<Select
|
||||
value={node.data.node.template.separator.value}
|
||||
onValueChange={(e) => handleChangeSelect(e)}
|
||||
>
|
||||
<SelectTrigger className="w-[70px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{node?.data?.node?.template?.separator?.options.map(
|
||||
(separator) => (
|
||||
<SelectItem key={separator} value={separator}>
|
||||
{separator}
|
||||
</SelectItem>
|
||||
)
|
||||
)}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<CsvOutputComponent csvNode={node} flowPool={flowPoolNode} />
|
||||
</>
|
||||
);
|
||||
case "ImageOutput":
|
||||
return left ? (
|
||||
<div>Expand the view to see the image</div>
|
||||
) : (
|
||||
<ImageViewer
|
||||
image={
|
||||
(flowPool[node.id] ?? [])[
|
||||
(flowPool[node.id]?.length ?? 1) - 1
|
||||
]?.params ?? ""
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
default:
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import {
|
|||
import { getTagsIds } from "../../utils/storeUtils";
|
||||
import ConfirmationModal from "../ConfirmationModal";
|
||||
import BaseModal from "../baseModal";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import ExportModal from "../exportModal";
|
||||
|
||||
export default function ShareModal({
|
||||
component,
|
||||
|
|
@ -41,6 +43,12 @@ export default function ShareModal({
|
|||
setOpen?: (open: boolean) => void;
|
||||
disabled?: boolean;
|
||||
}): JSX.Element {
|
||||
function handleOpenWShortcut(e: KeyboardEvent) {
|
||||
if (hasApiKey || hasStore) {
|
||||
e.preventDefault()
|
||||
internalSetOpen(state => !state);
|
||||
}
|
||||
}
|
||||
const version = useDarkStore((state) => state.version);
|
||||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
const hasApiKey = useStoreStore((state) => state.hasApiKey);
|
||||
|
|
@ -51,6 +59,8 @@ export default function ShareModal({
|
|||
const [openConfirmationModal, setOpenConfirmationModal] = useState(false);
|
||||
const nameComponent = is_component ? "component" : "workflow";
|
||||
|
||||
useHotkeys("mod+alt+s", handleOpenWShortcut)
|
||||
|
||||
const [tags, setTags] = useState<{ id: string; name: string }[]>([]);
|
||||
const [loadingTags, setLoadingTags] = useState<boolean>(false);
|
||||
const [sharePublic, setSharePublic] = useState(true);
|
||||
|
|
@ -206,9 +216,8 @@ export default function ShareModal({
|
|||
{children ? children : <></>}
|
||||
</BaseModal.Trigger>
|
||||
<BaseModal.Header
|
||||
description={`Publish ${
|
||||
is_component ? "your component" : "workflow"
|
||||
} to the Langflow Store.`}
|
||||
description={`Publish ${is_component ? "your component" : "workflow"
|
||||
} to the Langflow Store.`}
|
||||
>
|
||||
<span className="pr-2">Share</span>
|
||||
<IconComponent
|
||||
|
|
@ -251,18 +260,34 @@ export default function ShareModal({
|
|||
|
||||
<BaseModal.Footer>
|
||||
<div className="flex w-full justify-between gap-2">
|
||||
<Button
|
||||
{!is_component && <ExportModal>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
onClick={() => {
|
||||
// (setOpen || internalSetOpen)(false);
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Download" className="h-4 w-4" />
|
||||
Export
|
||||
</Button>
|
||||
</ExportModal>
|
||||
}
|
||||
{is_component && <Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
onClick={() => {
|
||||
handleExportComponent();
|
||||
(setOpen || internalSetOpen)(false);
|
||||
handleExportComponent();
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Download" className="h-4 w-4" />
|
||||
Export
|
||||
</Button>
|
||||
|
||||
}
|
||||
<Button
|
||||
disabled={loadingNames}
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ export default function Page({
|
|||
if (
|
||||
selectionMenuVisible &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "g"
|
||||
) {
|
||||
event.preventDefault();
|
||||
|
|
@ -153,6 +154,7 @@ export default function Page({
|
|||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "p" &&
|
||||
!event.shiftKey &&
|
||||
selectedNode.length > 0
|
||||
) {
|
||||
event.preventDefault();
|
||||
|
|
@ -169,6 +171,7 @@ export default function Page({
|
|||
}
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "d" &&
|
||||
selectedNode.length > 0
|
||||
) {
|
||||
|
|
@ -183,12 +186,12 @@ export default function Page({
|
|||
}
|
||||
if (!isWrappedWithClass(event, "noundo")) {
|
||||
if (
|
||||
(event.key === "y" || (event.key === "z" && event.shiftKey)) &&
|
||||
((event.key === "y" && !event.shiftKey) || (event.key === "z" && event.shiftKey)) &&
|
||||
(event.ctrlKey || event.metaKey)
|
||||
) {
|
||||
event.preventDefault(); // prevent the default action
|
||||
redo();
|
||||
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
|
||||
} else if (event.key === "z" && (event.ctrlKey || event.metaKey) && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
undo();
|
||||
}
|
||||
|
|
@ -199,6 +202,7 @@ export default function Page({
|
|||
) {
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "c" &&
|
||||
lastSelection
|
||||
) {
|
||||
|
|
@ -206,6 +210,7 @@ export default function Page({
|
|||
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
||||
} else if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "x" &&
|
||||
lastSelection
|
||||
) {
|
||||
|
|
@ -213,6 +218,7 @@ export default function Page({
|
|||
setLastCopiedSelection(_.cloneDeep(lastSelection), true);
|
||||
} else if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "v" &&
|
||||
lastCopiedSelection
|
||||
) {
|
||||
|
|
@ -224,6 +230,7 @@ export default function Page({
|
|||
});
|
||||
} else if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
!event.shiftKey &&
|
||||
event.key === "g" &&
|
||||
lastSelection
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import _, { cloneDeep } from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { useUpdateNodeInternals } from "reactflow";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import CodeAreaComponent from "../../../../components/codeAreaComponent";
|
||||
|
|
@ -44,6 +45,8 @@ export default function NodeToolbarComponent({
|
|||
setShowState,
|
||||
onCloseAdvancedModal,
|
||||
isOutdated,
|
||||
openWDoubleClick,
|
||||
setOpenWDoubleClick,
|
||||
}: nodeToolbarPropsType): JSX.Element {
|
||||
const nodeLength = Object.keys(data.node!.template).filter(
|
||||
(templateField) =>
|
||||
|
|
@ -65,6 +68,93 @@ export default function NodeToolbarComponent({
|
|||
const hasApiKey = useStoreStore((state) => state.hasApiKey);
|
||||
const validApiKey = useStoreStore((state) => state.validApiKey);
|
||||
|
||||
function handleMinimizeWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (isMinimal) {
|
||||
setShowState((show) => !show);
|
||||
setShowNode(data.showNode ?? true ? false : true);
|
||||
return;
|
||||
}
|
||||
setNoticeData({
|
||||
title:
|
||||
"Minimization are only available for nodes with one handle or fewer.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
function handleUpdateWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (hasApiKey || hasStore) {
|
||||
handleSelectChange("update");
|
||||
}
|
||||
}
|
||||
|
||||
function handleGroupWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (isGroup) {
|
||||
handleSelectChange("ungroup");
|
||||
}
|
||||
}
|
||||
|
||||
function handleShareWShortcut(e: KeyboardEvent) {
|
||||
if (hasApiKey || hasStore) {
|
||||
e.preventDefault();
|
||||
setShowconfirmShare((state) => !state);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCodeWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (hasCode) return setOpenModal((state) => !state);
|
||||
setNoticeData({ title: `You can not access ${data.id} code` });
|
||||
}
|
||||
|
||||
function handleAdvancedWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (!isGroup) {
|
||||
setShowModalAdvanced((state) => !state);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSaveWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (isSaved) {
|
||||
setShowOverrideModal((state) => !state);
|
||||
return;
|
||||
}
|
||||
if (hasCode) {
|
||||
saveComponent(cloneDeep(data), false);
|
||||
setSuccessData({ title: `${data.id} saved successfully` });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function handleDocsWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
if (data.node?.documentation) {
|
||||
return openInNewTab(data.node?.documentation);
|
||||
}
|
||||
setNoticeData({
|
||||
title: `${data.id} docs is not available at the moment.`,
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadWShortcut(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
downloadNode(flowComponent!);
|
||||
}
|
||||
|
||||
useHotkeys("mod+q", handleMinimizeWShortcut);
|
||||
useHotkeys("mod+u", handleUpdateWShortcut);
|
||||
useHotkeys("mod+g", handleGroupWShortcut);
|
||||
useHotkeys("mod+shift+s", handleShareWShortcut);
|
||||
useHotkeys("mod+shift+u", handleCodeWShortcut);
|
||||
useHotkeys("mod+shift+a", handleAdvancedWShortcut);
|
||||
useHotkeys("mod+s", handleSaveWShortcut);
|
||||
useHotkeys("mod+shift+d", handleDocsWShortcut);
|
||||
useHotkeys("mod+j", handleDownloadWShortcut);
|
||||
useHotkeys("space", handleCodeWShortcut);
|
||||
|
||||
const isMinimal = numberOfHandles <= 1;
|
||||
const isGroup = data.node?.flow ? true : false;
|
||||
|
||||
|
|
@ -75,7 +165,6 @@ export default function NodeToolbarComponent({
|
|||
const setNodes = useFlowStore((state) => state.setNodes);
|
||||
|
||||
const setEdges = useFlowStore((state) => state.setEdges);
|
||||
const unselectAll = useFlowStore((state) => state.unselectAll);
|
||||
const saveComponent = useFlowsManagerStore((state) => state.saveComponent);
|
||||
const getNodePosition = useFlowStore((state) => state.getNodePosition);
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
|
|
@ -88,6 +177,10 @@ export default function NodeToolbarComponent({
|
|||
createFlowComponent(cloneDeep(data), version)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (openWDoubleClick) setShowModalAdvanced(true);
|
||||
}, [openWDoubleClick, setOpenWDoubleClick]);
|
||||
|
||||
const openInNewTab = (url) => {
|
||||
window.open(url, "_blank", "noreferrer");
|
||||
};
|
||||
|
|
@ -120,6 +213,15 @@ export default function NodeToolbarComponent({
|
|||
|
||||
const handleSelectChange = (event) => {
|
||||
switch (event) {
|
||||
case "save":
|
||||
if (isSaved) {
|
||||
return setShowOverrideModal(true);
|
||||
}
|
||||
saveComponent(cloneDeep(data), false);
|
||||
break;
|
||||
case "code":
|
||||
setOpenModal(!openModal);
|
||||
break;
|
||||
case "advanced":
|
||||
setShowModalAdvanced(true);
|
||||
break;
|
||||
|
|
@ -265,112 +367,6 @@ export default function NodeToolbarComponent({
|
|||
const [openModal, setOpenModal] = useState(false);
|
||||
const hasCode = Object.keys(data.node!.template).includes("code");
|
||||
|
||||
useEffect(() => {
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
if (
|
||||
selected &&
|
||||
(hasApiKey || hasStore) &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "u"
|
||||
) {
|
||||
event.preventDefault();
|
||||
handleSelectChange("update");
|
||||
}
|
||||
if (
|
||||
selected &&
|
||||
isGroup &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "g"
|
||||
) {
|
||||
event.preventDefault();
|
||||
handleSelectChange("ungroup");
|
||||
}
|
||||
if (
|
||||
selected &&
|
||||
(hasApiKey || hasStore) &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "S"
|
||||
) {
|
||||
event.preventDefault();
|
||||
setShowconfirmShare((state) => !state);
|
||||
}
|
||||
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "Q"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (isMinimal) {
|
||||
setShowState((show) => !show);
|
||||
setShowNode(data.showNode ?? true ? false : true);
|
||||
return;
|
||||
}
|
||||
setNoticeData({
|
||||
title:
|
||||
"Minimization are only available for nodes with one handle or fewer.",
|
||||
});
|
||||
}
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "U"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (hasCode) return setOpenModal((state) => !state);
|
||||
setNoticeData({ title: `You can not access ${data.id} code` });
|
||||
}
|
||||
if (
|
||||
selected &&
|
||||
!isGroup &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "A"
|
||||
) {
|
||||
event.preventDefault();
|
||||
setShowModalAdvanced((state) => !state);
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "s") {
|
||||
if (isSaved) {
|
||||
event.preventDefault();
|
||||
return setShowOverrideModal((state) => !state);
|
||||
}
|
||||
if (hasCode) {
|
||||
event.preventDefault();
|
||||
saveComponent(cloneDeep(data), false);
|
||||
setSuccessData({ title: `${data.id} saved successfully` });
|
||||
}
|
||||
}
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "D"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (data.node?.documentation) {
|
||||
return openInNewTab(data.node?.documentation);
|
||||
}
|
||||
setNoticeData({
|
||||
title: `${data.id} docs is not available at the moment.`,
|
||||
});
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "j") {
|
||||
event.preventDefault();
|
||||
downloadNode(flowComponent!);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
}, [isSaved, showNode, data.showNode, isMinimal]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-26 h-10">
|
||||
|
|
@ -472,6 +468,19 @@ export default function NodeToolbarComponent({
|
|||
</SelectTrigger>
|
||||
</ShadTooltip>
|
||||
<SelectContent>
|
||||
{hasCode && (
|
||||
<SelectItem value={"code"}>
|
||||
<ToolbarSelectItem
|
||||
keyboardKey="Space"
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
shift={false}
|
||||
mod={false}
|
||||
value={"Code"}
|
||||
icon={"Code"}
|
||||
dataTestId="code-button-modal"
|
||||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{nodeLength > 0 && (
|
||||
<SelectItem value={nodeLength === 0 ? "disabled" : "advanced"}>
|
||||
<ToolbarSelectItem
|
||||
|
|
@ -484,7 +493,17 @@ export default function NodeToolbarComponent({
|
|||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{/* <SelectItem value={"duplicate"}>
|
||||
<SelectItem value={"save"}>
|
||||
<ToolbarSelectItem
|
||||
keyboardKey="S"
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
shift={false}
|
||||
value={"Save"}
|
||||
icon={"SaveAll"}
|
||||
dataTestId="save-button-modal"
|
||||
/>
|
||||
</SelectItem>
|
||||
<SelectItem value={"duplicate"}>
|
||||
<ToolbarSelectItem
|
||||
keyboardKey="D"
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
|
|
@ -493,7 +512,7 @@ export default function NodeToolbarComponent({
|
|||
icon={"Copy"}
|
||||
dataTestId="duplicate-button-modal"
|
||||
/>
|
||||
</SelectItem> */}
|
||||
</SelectItem>
|
||||
<SelectItem value={"copy"}>
|
||||
<ToolbarSelectItem
|
||||
keyboardKey="C"
|
||||
|
|
@ -567,7 +586,7 @@ export default function NodeToolbarComponent({
|
|||
icon={showNode ? "Minimize2" : "Maximize2"}
|
||||
value={showNode ? "Minimize" : "Expand"}
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
shift={true}
|
||||
shift={false}
|
||||
keyboardKey={"Q"}
|
||||
dataTestId={"minimize-button-nodeToolbar"}
|
||||
/>
|
||||
|
|
@ -639,12 +658,15 @@ export default function NodeToolbarComponent({
|
|||
</span>
|
||||
</ConfirmationModal.Content>
|
||||
</ConfirmationModal>
|
||||
<EditNodeModal
|
||||
data={data}
|
||||
nodeLength={nodeLength}
|
||||
open={showModalAdvanced}
|
||||
setOpen={setShowModalAdvanced}
|
||||
/>
|
||||
{showModalAdvanced && (
|
||||
<EditNodeModal
|
||||
setOpenWDoubleClick={setOpenWDoubleClick}
|
||||
data={data}
|
||||
nodeLength={nodeLength}
|
||||
open={showModalAdvanced}
|
||||
setOpen={setShowModalAdvanced}
|
||||
/>
|
||||
)}
|
||||
{showconfirmShare && (
|
||||
<ShareModal
|
||||
open={showconfirmShare}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { toolbarSelectItemProps } from "../../../../../types/components";
|
|||
export default function ToolbarSelectItem({
|
||||
shift,
|
||||
isMac,
|
||||
mod = true,
|
||||
keyboardKey,
|
||||
value,
|
||||
icon,
|
||||
|
|
@ -21,22 +22,23 @@ export default function ToolbarSelectItem({
|
|||
/>
|
||||
<span className={styleObj?.valueClasses}>{value}</span>
|
||||
|
||||
{isMac ? (
|
||||
<ForwardedIconComponent
|
||||
name="Command"
|
||||
className={`absolute
|
||||
${shift ? " right-[2rem] " : "right-[1.15rem]"}
|
||||
top-[0.65em] h-3.5 w-3.5 stroke-2 ${styleObj?.commandClasses}`}
|
||||
></ForwardedIconComponent>
|
||||
) : (
|
||||
<span
|
||||
className={`absolute ${
|
||||
shift ? " right-[2.15rem] " : "right-[1.15rem]"
|
||||
} top-[0.43em] stroke-2 `}
|
||||
>
|
||||
{shift ? "Ctrl" : "Ctrl +"}
|
||||
</span>
|
||||
)}
|
||||
{mod &&
|
||||
(isMac ? (
|
||||
<ForwardedIconComponent
|
||||
name="Command"
|
||||
className={`absolute
|
||||
${shift ? " right-[2rem] " : "right-[1.15rem]"}
|
||||
top-[0.65em] h-3.5 w-3.5 stroke-2 ${styleObj?.commandClasses}`}
|
||||
></ForwardedIconComponent>
|
||||
) : (
|
||||
<span
|
||||
className={`absolute ${
|
||||
shift ? " right-[2.15rem] " : "right-[1.15rem]"
|
||||
} top-[0.43em] stroke-2 `}
|
||||
>
|
||||
{shift ? "Ctrl" : "Ctrl +"}
|
||||
</span>
|
||||
))}
|
||||
{shift && (
|
||||
<ForwardedIconComponent
|
||||
name="ArrowBigUp"
|
||||
|
|
|
|||
|
|
@ -505,6 +505,8 @@ export type fileCardPropsType = {
|
|||
};
|
||||
|
||||
export type nodeToolbarPropsType = {
|
||||
openWDoubleClick: boolean;
|
||||
setOpenWDoubleClick: (open: boolean) => void;
|
||||
data: NodeDataType;
|
||||
deleteNode: (idx: string) => void;
|
||||
setShowNode: (boolean: any) => void;
|
||||
|
|
@ -733,6 +735,7 @@ export type toolbarSelectItemProps = {
|
|||
isMac: boolean;
|
||||
shift: boolean;
|
||||
keyboardKey: string;
|
||||
mod?:boolean;
|
||||
value: string;
|
||||
icon: string;
|
||||
styleObj?: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue