Merge remote-tracking branch 'origin/zustand/io/migration' into globalVariables

This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-03-26 20:33:15 -03:00
commit 95f5c4421f
527 changed files with 15744 additions and 2411 deletions

View file

@ -11,7 +11,7 @@ on:
workflow_dispatch:
env:
POETRY_VERSION: "1.5.1"
POETRY_VERSION: "1.8.2"
jobs:
if_release:
@ -20,7 +20,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install poetry
run: pipx install poetry==$POETRY_VERSION
run: pipx install poetry==$POETRY_VERSION && poetry self add poetry-monorepo-dependency-plugin
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:

View file

@ -10,7 +10,7 @@ on:
- "pyproject.toml"
env:
POETRY_VERSION: "1.5.1"
POETRY_VERSION: "1.8.2"
jobs:
if_release:
@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install poetry
run: pipx install poetry==$POETRY_VERSION
run: pipx install poetry==$POETRY_VERSION && poetry self add poetry-monorepo-dependency-plugin
- name: Set up Python 3.10
uses: actions/setup-python@v5
with:

1
.gitignore vendored
View file

@ -258,6 +258,7 @@ langflow.db
/tmp/*
src/backend/langflow/frontend/
src/backend/base/langflow/frontend/
.docker
scratchpad*
chroma*/*

View file

@ -2,6 +2,10 @@
all: help
setup_poetry:
pipx install poetry
poetry self add poetry-monorepo-dependency-plugin
init:
@echo 'Installing backend dependencies'
make install_backend
@ -28,7 +32,7 @@ format:
lint:
make install_backend
poetry run mypy src/backend/langflow
poetry run mypy src/backend
poetry run ruff . --fix
install_frontend:
@ -49,16 +53,39 @@ else
endif
run_cli:
poetry run langflow run --path src/frontend/build
@echo 'Running the CLI'
@make install_frontend > /dev/null
@echo 'Building the frontend'
@make build_frontend > /dev/null
@echo 'Install backend dependencies'
@make install_backend > /dev/null
ifdef env
poetry run langflow run --path src/frontend/build --host $(host) --port $(port) --env-file $(env)
else
poetry run langflow run --path src/frontend/build --host $(host) --port $(port) --env-file .env
endif
run_cli_debug:
poetry run langflow run --path src/frontend/build --log-level debug
@echo 'Running the CLI in debug mode'
@make install_frontend > /dev/null
@echo 'Building the frontend'
@make build_frontend > /dev/null
@echo 'Install backend dependencies'
@make install_backend > /dev/null
ifdef env
poetry run langflow run --path src/frontend/build --log-level debug --host $(host) --port $(port) --env-file $(env)
else
poetry run langflow run --path src/frontend/build --log-level debug --host $(host) --port $(port) --env-file .env
endif
setup_devcontainer:
make init
make build_frontend
poetry run langflow --path src/frontend/build
setup_env:
@sh ./scripts/setup/update_poetry.sh 1.8.2
@sh ./scripts/setup/setup_env.sh
frontend:
make install_frontend
make run_frontend
@ -68,38 +95,53 @@ frontendc:
make run_frontend
install_backend:
poetry install --extras deploy
@echo 'Installing backend dependencies'
@make setup_env
@poetry install --extras deploy
backend:
make install_backend
@-kill -9 `lsof -t -i:7860`
ifeq ($(login),1)
@echo "Running backend without autologin";
poetry run langflow run --backend-only --port 7860 --host 0.0.0.0 --no-open-browser --env-file .env
poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env
else
@echo "Running backend with autologin";
LANGFLOW_AUTO_LOGIN=True poetry run langflow run --backend-only --port 7860 --host 0.0.0.0 --no-open-browser --env-file .env
LANGFLOW_AUTO_LOGIN=True poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env
endif
build_and_run:
echo 'Removing dist folder'
@echo 'Removing dist folder'
rm -rf dist
make build && poetry run pip install dist/*.tar.gz && poetry run langflow run
rm -rf src/backend/base/dist
make build
poetry run pip install dist/*.tar.gz && pip install src/backend/base/dist/*.tar.gz
poetry run langflow run
build_and_install:
echo 'Removing dist folder'
@echo 'Removing dist folder'
rm -rf dist
make build && poetry run pip install dist/*.tar.gz
rm -rf src/backend/base/dist
make build && poetry run pip install dist/*.whl && pip install src/backend/base/dist/*.whl --force-reinstall
build_frontend:
cd src/frontend && CI='' npm run build
cp -r src/frontend/build src/backend/langflow/frontend
cp -r src/frontend/build src/backend/base/langflow/frontend
build:
@echo 'Building the project'
@make setup_env
make build_langflow_base
make build_langflow
build_langflow:
poetry build-rewrite-path-deps --version-pinning-strategy=semver
build_langflow_base:
make install_frontend
make build_frontend
poetry build --format sdist
rm -rf src/backend/langflow/frontend
cd src/backend/base && poetry build-rewrite-path-deps --version-pinning-strategy=semver
rm -rf src/backend/base/langflow/frontend
dev:
make install_frontend
@ -111,10 +153,30 @@ else
docker compose $(if $(debug),-f docker-compose.debug.yml) up
endif
publish:
make build
lock_base:
cd src/backend/base && poetry lock
lock_langflow:
poetry lock
lock:
# Run both in parallel
# cd src/backend/base && poetry lock
# poetry lock
@echo 'Locking dependencies'
@make -j2 lock_base lock_langflow
publish_base:
make build_langflow_base
cd src/backend/base && poetry publish
publish_langflow:
make build_langflow
poetry publish
publish:
make publish_base
make publish_langflow
help:
@echo '----'
@echo 'format - run code formatters'

View file

@ -2,7 +2,7 @@ import Admonition from '@theme/Admonition';
# Inputs
### ChatInput
### Chat Input
This component is designed to get user input from the chat.
@ -22,7 +22,7 @@ This component is designed to get user input from the chat.
</p>
</Admonition>
### TextInput
### Text Input
This component is designed for simple text input, allowing users to pass textual data to subsequent components in the workflow. It's particularly useful for scenarios where a brief user input is required to initiate or influence the flow.

View file

@ -0,0 +1,464 @@
import Admonition from '@theme/Admonition';
# Models
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
<p>
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝
</p>
</Admonition>
### AmazonBedrock
This component facilitates the generation of text using the LLM (Large Language Model) model from Amazon Bedrock.
**Params**
- **Input Value:** Specifies the input text for text generation.
- **System Message (Optional):** A system message to pass to the model.
- **Model ID (Optional):** Specifies the model ID to be used for text generation. Defaults to _`"anthropic.claude-instant-v1"`_. Available options include:
- _`"ai21.j2-grande-instruct"`_
- _`"ai21.j2-jumbo-instruct"`_
- _`"ai21.j2-mid"`_
- _`"ai21.j2-mid-v1"`_
- _`"ai21.j2-ultra"`_
- _`"ai21.j2-ultra-v1"`_
- _`"anthropic.claude-instant-v1"`_
- _`"anthropic.claude-v1"`_
- _`"anthropic.claude-v2"`_
- _`"cohere.command-text-v14"`_
- **Credentials Profile Name (Optional):** Specifies the name of the credentials profile.
- **Region Name (Optional):** Specifies the region name.
- **Model Kwargs (Optional):** Additional keyword arguments for the model.
- **Endpoint URL (Optional):** Specifies the endpoint URL.
- **Streaming (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **Cache (Optional):** Specifies whether to cache the response.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
<Admonition type="note" title="Note">
<p>
Ensure that necessary credentials are provided to connect to the Amazon Bedrock API. If connection fails, a ValueError will be raised.
</p>
</Admonition>
---
### AnthropicLLM
This component allows the generation of text using Anthropic Chat&Completion large language models.
**Params**
- **Model Name:** Specifies the name of the Anthropic model to be used for text generation. Available options include:
- _`"claude-2.1"`_
- _`"claude-2.0"`_
- _`"claude-instant-1.2"`_
- _`"claude-instant-1"`_
- **Anthropic API Key:** Your Anthropic API key.
- **Max Tokens (Optional):** Specifies the maximum number of tokens to generate. Defaults to _`256`_.
- **Temperature (Optional):** Specifies the sampling temperature. Defaults to _`0.7`_.
- **API Endpoint (Optional):** Specifies the endpoint of the Anthropic API. Defaults to _`"https://api.anthropic.com"`_ if not specified.
- **Input Value:** Specifies the input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
For detailed documentation and integration guides, please refer to the [Anthropic Component Documentation](https://python.langchain.com/docs/integrations/chat/anthropic).
---
### AzureChatOpenAI
This component allows the generation of text using the LLM (Large Language Model) model from Azure OpenAI.
**Params**
- **Model Name:** Specifies the name of the Azure OpenAI model to be used for text generation. Available options include:
- _`"gpt-35-turbo"`_
- _`"gpt-35-turbo-16k"`_
- _`"gpt-35-turbo-instruct"`_
- _`"gpt-4"`_
- _`"gpt-4-32k"`_
- _`"gpt-4-vision"`_
- **Azure Endpoint:** Your Azure endpoint, including the resource. Example: `https://example-resource.azure.openai.com/`.
- **Deployment Name:** Specifies the name of the deployment.
- **API Version:** Specifies the version of the Azure OpenAI API to be used. Available options include:
- _`"2023-03-15-preview"`_
- _`"2023-05-15"`_
- _`"2023-06-01-preview"`_
- _`"2023-07-01-preview"`_
- _`"2023-08-01-preview"`_
- _`"2023-09-01-preview"`_
- _`"2023-12-01-preview"`_
- **API Key:** Your Azure OpenAI API key.
- **Temperature (Optional):** Specifies the sampling temperature. Defaults to _`0.7`_.
- **Max Tokens (Optional):** Specifies the maximum number of tokens to generate. Defaults to _`1000`_.
- **Input Value:** Specifies the input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
For detailed documentation and integration guides, please refer to the [Azure OpenAI Component Documentation](https://python.langchain.com/docs/integrations/llms/azure_openai).
---
### QianfanChatEndpoint
This component facilitates the generation of text using Baidu Qianfan chat models.
**Params**
- **Model Name:** Specifies the name of the Qianfan chat model to be used for text generation. Available options include:
- _`"ERNIE-Bot"`_
- _`"ERNIE-Bot-turbo"`_
- _`"BLOOMZ-7B"`_
- _`"Llama-2-7b-chat"`_
- _`"Llama-2-13b-chat"`_
- _`"Llama-2-70b-chat"`_
- _`"Qianfan-BLOOMZ-7B-compressed"`_
- _`"Qianfan-Chinese-Llama-2-7B"`_
- _`"ChatGLM2-6B-32K"`_
- _`"AquilaChat-7B"`_
- **Qianfan Ak:** Your Baidu Qianfan access key, obtainable from [here](https://cloud.baidu.com/product/wenxinworkshop).
- **Qianfan Sk:** Your Baidu Qianfan secret key, obtainable from [here](https://cloud.baidu.com/product/wenxinworkshop).
- **Top p (Optional):** Model parameter. Specifies the top-p value. Only supported in ERNIE-Bot and ERNIE-Bot-turbo models. Defaults to _`0.8`_.
- **Temperature (Optional):** Model parameter. Specifies the sampling temperature. Only supported in ERNIE-Bot and ERNIE-Bot-turbo models. Defaults to _`0.95`_.
- **Penalty Score (Optional):** Model parameter. Specifies the penalty score. Only supported in ERNIE-Bot and ERNIE-Bot-turbo models. Defaults to _`1.0`_.
- **Endpoint (Optional):** Endpoint of the Qianfan LLM, required if custom model is used.
- **Input Value:** Specifies the input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
---
### Cohere
This component enables text generation using Cohere large language models.
**Params**
- **Cohere API Key:** Your Cohere API key.
- **Max Tokens (Optional):** Specifies the maximum number of tokens to generate. Defaults to _`256`_.
- **Temperature (Optional):** Specifies the sampling temperature. Defaults to _`0.75`_.
- **Input Value:** Specifies the input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
---
### CTransformers
This component allows the generation of text using CTransformers large language models.
**Params**
- **Model:** Specifies the CTransformers model to be used for text generation.
- **Model File (Optional):** Path to the model file if using a custom model. Should be a _.bin_ file.
- **Model Type:** Specifies the type of the CTransformers model.
- **Config (Optional):** Additional configuration parameters for the model. It should be provided as a JSON object.
Defaults to:
`{"top_k":40,"top_p":0.95,"temperature":0.8,"repetition_penalty":1.1,"last_n_tokens":64,"seed":-1,"max_new_tokens":256,"stop":"","stream":"False","reset":"True","batch_size":8,"threads":-1,"context_length":-1,"gpu_layers":0}`.
- **Input Value:** Specifies the input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
---
### Google Generative AI
This component enables text generation using Google Generative AI.
**Params**
- **Google API Key:** Your Google API key to use for the Google Generative AI.
- **Model:** The name of the model to use. Supported examples are _`"gemini-pro"`_ and _`"gemini-pro-vision"`_.
- **Max Output Tokens (Optional):** The maximum number of tokens to generate.
- **Temperature:** Run inference with this temperature. Must be in the closed interval [0.0, 1.0].
- **Top K (Optional):** Decode using top-k sampling: consider the set of top_k most probable tokens. Must be positive.
- **Top P (Optional):** The maximum cumulative probability of tokens to consider when sampling.
- **N (Optional):** Number of chat completions to generate for each prompt. Note that the API may not return the full n completions if duplicates are generated.
- **Input Value:** The input to the model.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
---
### Hugging Face API
This component facilitates text generation using LLM models from the Hugging Face Inference API.
**Params**
- **Endpoint URL:** The URL of the Hugging Face Inference API endpoint. Should be provided along with necessary authentication credentials.
- **Task:** Specifies the task for text generation. Options include _`"text2text-generation"`_, _`"text-generation"`_, and _`"summarization"`_.
- **API Token:** The API token required for authentication with the Hugging Face Hub.
- **Model Keyword Arguments (Optional):** Additional keyword arguments for the model. Should be provided as a Python dictionary.
- **Input Value:** The input text for text generation.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** A system message to pass to the model.
---
### LlamaCpp
The `LlamaCpp` is a component for generating text using the llama.cpp model.
**Params**
- **Model Path:** The path to the llama.cpp model file. This should be provided as a file type input.
- **Input Value:** The input text for text generation.
- **Grammar (Optional):** The grammar for text generation.
- **Cache (Optional):** Specifies whether to cache the generated text.
- **Client (Optional):** The client to use for text generation.
- **Echo (Optional):** Specifies whether to echo the generated text. Defaults to _`False`_.
- **F16 KV:** Specifies whether to use F16 key-value pairs. Defaults to _`True`_.
- **Grammar Path (Optional):** The path to the grammar file.
- **Last N Tokens Size (Optional):** The size of the last N tokens. Defaults to _`64`_.
- **Logits All:** Specifies whether to include logits for all tokens. Defaults to _`False`_.
- **Logprobs (Optional):** The log probabilities for text generation.
- **Lora Base (Optional):** The base URL for Lora.
- **Lora Path (Optional):** The path for Lora.
- **Max Tokens (Optional):** The maximum number of tokens to generate. Defaults to _`256`_.
- **Metadata (Optional):** Additional metadata for the model.
- **Model Kwargs:** Additional keyword arguments for the model. Should be provided as a Python dictionary.
- **N Batch (Optional):** The batch size. Defaults to _`8`_.
- **N Ctx:** The context size. Defaults to _`512`_.
- **N GPU Layers (Optional):** The number of GPU layers.
- **N Parts:** The number of parts.
- **N Threads (Optional):** The number of threads. Defaults to _`1`_.
- **Repeat Penalty (Optional):** The repeat penalty for text generation. Defaults to _`1.1`_.
- **Rope Freq Base:** The base frequency for rope.
- **Rope Freq Scale:** The scale frequency for rope.
- **Seed:** The seed for random generation.
- **Stop (Optional):** The stop words for text generation.
- **Streaming:** Specifies whether to stream the response from the model. Defaults to _`True`_.
- **Suffix (Optional):** The suffix for text generation.
- **Tags (Optional):** The tags for text generation.
- **Temperature (Optional):** The temperature for text generation. Defaults to _`0.8`_.
- **Top K (Optional):** The top K tokens to consider for text generation. Defaults to _`40`_.
- **Top P (Optional):** The top P probability threshold for text generation. Defaults to _`0.95`_.
- **Use Mlock:** Specifies whether to use Mlock. Defaults to _`False`_.
- **Use Mmap (Optional):** Specifies whether to use Mmap. Defaults to _`True`_.
- **Verbose:** Specifies whether to enable verbose mode. Defaults to _`True`_.
- **Vocab Only:** Specifies whether to include vocabulary only.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
For more information, please refer to the [documentation](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/llamacpp).
---
### ChatOllama
This component facilitates text generation using the Local LLM model for chat with Ollama.
**Params**
- **Base URL:** The endpoint of the Ollama API. Defaults to 'http://localhost:11434' if not specified.
- **Model Name:** The name of the model to use. Refer to [https://ollama.ai/library](https://ollama.ai/library) for more models.
- **Input Value:** The input text for text generation.
- **Mirostat:** Enable/disable Mirostat sampling for controlling perplexity.
- **Mirostat Eta (Optional):** The learning rate for the Mirostat algorithm. (Default: 0.1)
- **Mirostat Tau (Optional):** Controls the balance between coherence and diversity of the output. (Default: 5.0)
- **Repeat Last N (Optional):** How far back the model looks to prevent repetition. (Default: 64, 0 = disabled, -1 = num_ctx)
- **Verbose (Optional):** Whether to print out response text.
- **Cache (Optional):** Enable or disable caching. Defaults to _`False`_.
- **Context Window Size (Optional):** Size of the context window for generating tokens. (Default: 2048)
- **Number of GPUs (Optional):** Number of GPUs to use for computation. (Default: 1 on macOS, 0 to disable)
- **Format (Optional):** Specify the format of the output (e.g., json).
- **Metadata (Optional):** Metadata to add to the run trace.
- **Number of Threads (Optional):** Number of threads to use during computation. (Default: detected for optimal performance)
- **Repeat Penalty (Optional):** Penalty for repetitions in generated text. (Default: 1.1)
- **Stop Tokens (Optional):** List of tokens to signal the model to stop generating text.
- **System (Optional):** System to use for generating text.
- **Tags (Optional):** Tags to add to the run trace.
- **Temperature (Optional):** Controls the creativity of model responses. Defaults to _`0.8`_.
- **Template (Optional):** Template to use for generating text.
- **TFS Z (Optional):** Tail free sampling value. (Default: 1)
- **Timeout (Optional):** Timeout for the request stream.
- **Top K (Optional):** Limits token selection to top K. (Default: 40)
- **Top P (Optional):** Works together with top-k. (Default: 0.9)
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** System message to pass to the model.
---
### OpenAIModel
This component facilitates text generation using OpenAI's models.
**Params**
- **Input Value:** The input text for text generation.
- **Max Tokens (Optional):** The maximum number of tokens to generate. Defaults to _`256`_.
- **Model Kwargs (Optional):** Additional keyword arguments for the model. Should be provided as a nested dictionary.
- **Model Name (Optional):** The name of the model to use. Defaults to _`gpt-4-1106-preview`_. Supported options include: _`gpt-4-turbo-preview`_, _`gpt-4-0125-preview`_, _`gpt-4-1106-preview`_, _`gpt-4-vision-preview`_, _`gpt-3.5-turbo-0125`_, _`gpt-3.5-turbo-1106`_.
- **OpenAI API Base (Optional):** The base URL of the OpenAI API. Defaults to _`https://api.openai.com/v1`_.
- **OpenAI API Key (Optional):** The API key for accessing the OpenAI API.
- **Temperature:** Controls the creativity of model responses. Defaults to _`0.7`_.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** System message to pass to the model.
---
### ChatVertexAI
The `ChatVertexAI` is a component for generating text using Vertex AI Chat large language models API.
**Params**
- **Input Value:** The input text for text generation.
- **Credentials:** The JSON file containing the credentials for accessing the Vertex AI Chat API.
- **Project:** The name of the project associated with the Vertex AI Chat API.
- **Examples (Optional):** List of examples to provide context for text generation.
- **Location:** The location of the Vertex AI Chat API service. Defaults to _`us-central1`_.
- **Max Output Tokens:** The maximum number of tokens to generate. Defaults to _`128`_.
- **Model Name:** The name of the model to use. Defaults to _`chat-bison`_.
- **Temperature:** Controls the creativity of model responses. Defaults to _`0.0`_.
- **Top K:** Limits token selection to top K. Defaults to _`40`_.
- **Top P:** Works together with top-k. Defaults to _`0.95`_.
- **Verbose:** Whether to print out response text. Defaults to _`False`_.
- **Stream (Optional):** Specifies whether to stream the response from the model. Defaults to _`False`_.
- **System Message (Optional):** System message to pass to the model.

View file

@ -21,7 +21,7 @@ The `PromptTemplate` component allows users to create prompts and define variabl
<Admonition type="info">
Once a variable is defined in the prompt template, it becomes a component
input of its own. Check out [Prompt
Customization](../docs/guidelines/prompt-customization.mdx) to learn more.
Customization](../guidelines/prompt-customization) to learn more.
</Admonition>
- **template:** Template used to format an individual request.

View file

@ -6,4 +6,640 @@ import Admonition from '@theme/Admonition';
<p>
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝
</p>
</Admonition>
</Admonition>
### AstraDB
The `AstraDB` is a component for initializing an AstraDB Vector Store from Records. It facilitates the creation of AstraDB-based vector indexes for efficient document storage and retrieval.
**Params**
- **Input:** The input documents or records.
- **Embedding:** The embedding model used by AstraDB.
- **Collection Name:** The name of the collection in AstraDB.
- **Token:** The token for AstraDB.
- **API Endpoint:** The API endpoint for AstraDB.
- **Namespace:** The namespace in AstraDB.
- **Metric:** The metric to use in AstraDB.
- **Batch Size:** The batch size for AstraDB.
- **Bulk Insert Batch Concurrency:** The bulk insert batch concurrency for AstraDB.
- **Bulk Insert Overwrite Concurrency:** The bulk insert overwrite concurrency for AstraDB.
- **Bulk Delete Concurrency:** The bulk delete concurrency for AstraDB.
- **Setup Mode:** The setup mode for the vector store.
- **Pre Delete Collection:** Pre delete collection.
- **Metadata Indexing Include:** Metadata indexing include.
- **Metadata Indexing Exclude:** Metadata indexing exclude.
- **Collection Indexing Policy:** Collection indexing policy.
<Admonition type="note" title="Note">
<p>
Ensure that the required AstraDB token and API endpoint are properly configured.
</p>
</Admonition>
---
### AstraDB Search
The `AstraDBSearch` is a component for searching an existing AstraDB Vector Store for similar documents. It extends the functionality of the `AstraDB` component to provide efficient document retrieval based on similarity metrics.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Embedding:** The embedding model used by AstraDB.
- **Collection Name:** The name of the collection in AstraDB.
- **Token:** The token for AstraDB.
- **API Endpoint:** The API endpoint for AstraDB.
- **Namespace:** The namespace in AstraDB.
- **Metric:** The metric to use in AstraDB.
- **Batch Size:** The batch size for AstraDB.
- **Bulk Insert Batch Concurrency:** The bulk insert batch concurrency for AstraDB.
- **Bulk Insert Overwrite Concurrency:** The bulk insert overwrite concurrency for AstraDB.
- **Bulk Delete Concurrency:** The bulk delete concurrency for AstraDB.
- **Setup Mode:** The setup mode for the vector store.
- **Pre Delete Collection:** Pre delete collection.
- **Metadata Indexing Include:** Metadata indexing include.
- **Metadata Indexing Exclude:** Metadata indexing exclude.
- **Collection Indexing Policy:** Collection indexing policy.
---
### Chroma
The `Chroma` is a component designed for implementing a Vector Store using Chroma. This component allows users to utilize Chroma for efficient vector storage and retrieval within their language processing workflows.
**Params**
- **Collection Name:** The name of the collection.
- **Persist Directory:** The directory to persist the Vector Store to.
- **Server CORS Allow Origins (Optional):** The CORS allow origins for the Chroma server.
- **Server Host (Optional):** The host for the Chroma server.
- **Server Port (Optional):** The port for the Chroma server.
- **Server gRPC Port (Optional):** The gRPC port for the Chroma server.
- **Server SSL Enabled (Optional):** Whether to enable SSL for the Chroma server.
- **Input:** Input data for creating the Vector Store.
- **Embedding:** The embeddings to use for the Vector Store.
For detailed documentation and integration guides, please refer to the [Chroma Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/chroma).
---
### Chroma Search
The `ChromaSearch` is a component designed for searching a Chroma collection for similar documents. This component integrates with Chroma to facilitate efficient document retrieval based on similarity metrics.
**Params**
- **Input:** The input text to search for similar documents.
- **Search Type:** The type of search to perform ("Similarity" or "MMR").
- **Collection Name:** The name of the Chroma collection.
- **Index Directory:** The directory where the Chroma index is stored.
- **Embedding:** The embedding model used to vectorize inputs (make sure to use the same as the index).
- **Server CORS Allow Origins (Optional):** The CORS allow origins for the Chroma server.
- **Server Host (Optional):** The host for the Chroma server.
- **Server Port (Optional):** The port for the Chroma server.
- **Server gRPC Port (Optional):** The gRPC port for the Chroma server.
- **Server SSL Enabled (Optional):** Whether SSL is enabled for the Chroma server.
---
### FAISS
The `FAISS` is a component designed for ingesting documents into a FAISS Vector Store. It facilitates efficient document indexing and retrieval using the FAISS library.
**Params**
- **Embedding:** The embedding model used to vectorize inputs.
- **Input:** The input documents to ingest into the FAISS Vector Store.
- **Folder Path:** The path to save the FAISS index. It will be relative to where Langflow is running.
- **Index Name:** The name of the FAISS index.
For detailed documentation and integration guides, please refer to the [FAISS Component Documentation](https://faiss.ai/index.html).
---
### FAISS Search
The `FAISSSearch` is a component for searching a FAISS Vector Store for similar documents. It enables efficient document retrieval based on similarity metrics using FAISS.
**Params**
- **Embedding:** The embedding model used by the FAISS Vector Store.
- **Folder Path:** The path from which to load the FAISS index. It will be relative to where Langflow is running.
- **Input:** The input value to search for similar documents.
- **Index Name:** The name of the FAISS index.
---
### MongoDB Atlas
The `MongoDBAtlas` is a component used to construct a MongoDB Atlas Vector Search vector store from Records. It facilitates the creation of MongoDB Atlas-based vector stores for efficient document storage and retrieval.
**Params**
- **Embedding:** The embedding model used by the MongoDB Atlas Vector Search.
- **Input:** The input documents or records.
- **Collection Name:** The name of the collection in the MongoDB Atlas database.
- **Database Name:** The name of the database in MongoDB Atlas.
- **Index Name:** The name of the index in MongoDB Atlas.
- **MongoDB Atlas Cluster URI:** The URI of the MongoDB Atlas cluster.
- **Search Kwargs:** Additional search arguments for MongoDB Atlas.
<Admonition type="note" title="Note">
<p>
Ensure that pymongo is installed to use MongoDB Atlas Vector Store.
</p>
</Admonition>
---
### MongoDB Atlas Search
The `MongoDBAtlasSearch` is a component for searching a MongoDB Atlas Vector Store for similar documents. It extends the functionality of the MongoDBAtlasComponent to provide efficient document retrieval based on similarity metrics.
**Params**
- **Search Type:** The type of search to perform. Options: "Similarity", "MMR".
- **Input:** The input value to search for.
- **Embedding:** The embedding model used by the MongoDB Atlas Vector Store.
- **Collection Name:** The name of the collection in the MongoDB Atlas database.
- **Database Name:** The name of the database in MongoDB Atlas.
- **Index Name:** The name of the index in MongoDB Atlas.
- **MongoDB Atlas Cluster URI:** The URI of the MongoDB Atlas cluster.
- **Search Kwargs:** Additional search arguments for MongoDB Atlas.
---
### PGVector
The `PGVector` is a component for implementing a Vector Store using PostgreSQL. It allows users to store and retrieve vectors efficiently within a PostgreSQL database.
**Params**
- **Input:** The input value to use for the Vector Store.
- **Embedding:** The embedding model used by the Vector Store.
- **PostgreSQL Server Connection String:** The URL for the PostgreSQL server.
- **Table:** The name of the table in the PostgreSQL database.
For detailed documentation and integration guides, please refer to the [PGVector Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/pgvector).
<Admonition type="note" title="Note">
<p>
Ensure that the required PostgreSQL server is accessible and properly configured.
</p>
</Admonition>
---
### PGVector Search
The `PGVectorSearch` is a component for searching a PGVector Store for similar documents. It extends the functionality of the PGVectorComponent to provide efficient document retrieval based on similarity metrics.
**Params**
- **Input:** The input value to search for.
- **Embedding:** The embedding model used by the Vector Store.
- **PostgreSQL Server Connection String:** The URL for the PostgreSQL server.
- **Table:** The name of the table in the PostgreSQL database.
- **Search Type:** The type of search to perform (e.g., "Similarity", "MMR").
---
### Pinecone
The `Pinecone` is a component used to construct a Pinecone wrapper from Records. It facilitates the creation of Pinecone-based vector indexes for efficient document storage and retrieval.
**Params**
- **Input:** The input documents or records.
- **Embedding:** The embedding model used by Pinecone.
- **Index Name:** The name of the index in Pinecone.
- **Namespace:** The namespace in Pinecone.
- **Pinecone API Key:** The API key for Pinecone.
- **Pinecone Environment:** The environment for Pinecone.
- **Search Kwargs:** Additional search keyword arguments for Pinecone.
- **Pool Threads:** The number of threads to use for Pinecone.
<Admonition type="note" title="Note">
<p>
Ensure that the required Pinecone API key and environment are properly configured.
</p>
</Admonition>
---
### Pinecone Search
The `PineconeSearch` is a component used to search a Pinecone Vector Store for similar documents. It extends the functionality of the `PineconeComponent` to provide efficient document retrieval based on similarity metrics.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Embedding:** The embedding model used by Pinecone.
- **Index Name:** The name of the index in Pinecone.
- **Namespace:** The namespace in Pinecone.
- **Pinecone API Key:** The API key for Pinecone.
- **Pinecone Environment:** The environment for Pinecone.
- **Search Kwargs:** Additional search keyword arguments for Pinecone.
- **Pool Threads:** The number of threads to use for Pinecone.
---
### Qdrant
The `Qdrant` is a component used to construct a Qdrant wrapper from a list of texts. It allows for efficient similarity search and retrieval operations based on the provided embeddings.
**Params**
- **Input:** The input documents or records.
- **Embedding:** The embedding model used by Qdrant.
- **API Key:** The API key for Qdrant (password field).
- **Collection Name:** The name of the collection in Qdrant.
- **Content Payload Key:** The key for the content payload in the documents (advanced).
- **Distance Function:** The distance function to use in Qdrant (advanced).
- **gRPC Port:** The gRPC port for Qdrant (advanced).
- **Host:** The host for Qdrant (advanced).
- **HTTPS:** Enable HTTPS for Qdrant (advanced).
- **Location:** The location for Qdrant (advanced).
- **Metadata Payload Key:** The key for the metadata payload in the documents (advanced).
- **Path:** The path for Qdrant (advanced).
- **Port:** The port for Qdrant (advanced).
- **Prefer gRPC:** Prefer gRPC for Qdrant (advanced).
- **Prefix:** The prefix for Qdrant (advanced).
- **Search Kwargs:** Additional search keyword arguments for Qdrant (advanced).
- **Timeout:** The timeout for Qdrant (advanced).
- **URL:** The URL for Qdrant (advanced).
---
### Qdrant Search
The `QdrantSearch` is a component used to search a Qdrant Vector Store for similar documents. It extends the functionality of the `QdrantComponent` to provide efficient document retrieval based on similarity metrics.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Embedding:** The embedding model used by Qdrant.
- **API Key:** The API key for Qdrant (password field).
- **Collection Name:** The name of the collection in Qdrant.
- **Content Payload Key:** The key for the content payload in the documents (advanced).
- **Distance Function:** The distance function to use in Qdrant (advanced).
- **gRPC Port:** The gRPC port for Qdrant (advanced).
- **Host:** The host for Qdrant (advanced).
- **HTTPS:** Enable HTTPS for Qdrant (advanced).
- **Location:** The location for Qdrant (advanced).
- **Metadata Payload Key:** The key for the metadata payload in the documents (advanced).
- **Path:** The path for Qdrant (advanced).
- **Port:** The port for Qdrant (advanced).
- **Prefer gRPC:** Prefer gRPC for Qdrant (advanced).
- **Prefix:** The prefix for Qdrant (advanced).
- **Search Kwargs:** Additional search keyword arguments for Qdrant (advanced).
- **Timeout:** The timeout for Qdrant (advanced).
- **URL:** The URL for Qdrant (advanced).
---
### Redis
The `Redis` is a component for implementing a Vector Store using Redis. It provides functionality to store and retrieve vectors efficiently from a Redis database.
**Params**
- **Index Name:** The name of the index in Redis (default: your_index).
- **Input:** The input data to build the Redis Vector Store (input types: Document, Record).
- **Embedding:** The embedding model used by Redis.
- **Schema:** The schema file (.yaml) to define the structure of the documents (optional).
- **Redis Server Connection String:** The connection string for the Redis server.
- **Redis Index:** The name of the Redis index (optional).
For detailed documentation, please refer to the [Redis Documentation](https://python.langchain.com/docs/integrations/vectorstores/redis).
<Admonition type="note" title="Note">
<p>
Ensure that the required Redis server connection URL and index name are properly configured. If no documents are provided, a schema must be provided.
</p>
</Admonition>
---
### Redis Search
The `RedisSearch` is a component for searching a Redis Vector Store for similar documents.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Index Name:** The name of the index in Redis (default: your_index).
- **Embedding:** The embedding model used by Redis.
- **Schema:** The schema file (.yaml) to define the structure of the documents (optional).
- **Redis Server Connection String:** The connection string for the Redis server.
- **Redis Index:** The name of the Redis index (optional).
---
### Supabase
The `Supabase` is a component for initializing a Supabase Vector Store from texts and embeddings.
**Params**
- **Input:** The input documents or records.
- **Embedding:** The embedding model used by Supabase.
- **Query Name:** The name of the query (optional).
- **Search Kwargs:** Additional search keyword arguments for Supabase (advanced).
- **Supabase Service Key:** The service key for Supabase.
- **Supabase URL:** The URL for the Supabase instance.
- **Table Name:** The name of the table in Supabase (advanced).
<Admonition type="note" title="Note">
<p>
Ensure that the required Supabase service key, Supabase URL, and table name are properly configured.
</p>
</Admonition>
---
### Supabase Search
The `SupabaseSearch` is a component for searching a Supabase Vector Store for similar documents.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Embedding:** The embedding model used by Supabase.
- **Query Name:** The name of the query (optional).
- **Search Kwargs:** Additional search keyword arguments for Supabase (advanced).
- **Supabase Service Key:** The service key for Supabase.
- **Supabase URL:** The URL for the Supabase instance.
- **Table Name:** The name of the table in Supabase (advanced).
---
### Vectara
The `Vectara` is a component for implementing a Vector Store using Vectara.
**Params**
- **Vectara Customer ID:** The customer ID for Vectara.
- **Vectara Corpus ID:** The corpus ID for Vectara.
- **Vectara API Key:** The API key for Vectara.
- **Files Url:** The URL(s) of the file(s) to be used for initializing the Vectara Vector Store (optional).
- **Input:** The input data to be upserted to the corpus (optional).
For detailed documentation and integration guides, please refer to the [Vectara Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/vectara).
<Admonition type="note" title="Note">
<p>
If `inputs` are provided, they will be upserted to the corpus. If `files_url` are provided, Vectara will process the files from the URLs.
</p>
</Admonition>
---
### Vectara Search
The `VectaraSearch` is a component for searching a Vectara Vector Store for similar documents.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Vectara Customer ID:** The customer ID for Vectara.
- **Vectara Corpus ID:** The corpus ID for Vectara.
- **Vectara API Key:** The API key for Vectara.
- **Files Url:** The URL(s) of the file(s) to be used for initializing the Vectara Vector Store (optional).
---
### Weaviate
The `Weaviate` is a component for implementing a Vector Store using Weaviate.
**Params**
- **Weaviate URL:** The URL of the Weaviate instance (default: http://localhost:8080).
- **Search By Text:** Boolean indicating whether to search by text (default: False).
- **API Key:** The API key for authentication (optional).
- **Index name:** The name of the index in Weaviate (optional).
- **Text Key:** The key used to extract text from documents (default: "text").
- **Input:** The input document or record.
- **Embedding:** The embedding model used by Weaviate.
- **Attributes:** Additional attributes to consider during indexing (optional).
For detailed documentation and integration guides, please refer to the [Weaviate Component Documentation](https://python.langchain.com/docs/integrations/vectorstores/weaviate).
<Admonition type="note" title="Note">
<p>
Before using the Weaviate Vector Store component, ensure that you have a Weaviate instance running and accessible at the specified URL. Additionally, make sure to provide the correct API key for authentication if required. Adjust the index name, text key, and attributes according to your dataset and indexing requirements. Finally, ensure that the provided embeddings are compatible with Weaviate's requirements.
</p>
</Admonition>
---
### Weaviate Search
The `WeaviateSearch` component facilitates searching a Weaviate Vector Store for similar documents.
**Params**
- **Search Type:** The type of search to perform (e.g., Similarity, MMR).
- **Input Value:** The input value to search for.
- **Weaviate URL:** The URL of the Weaviate instance (default: http://localhost:8080).
- **Search By Text:** Boolean indicating whether to search by text (default: False).
- **API Key:** The API key for authentication (optional).
- **Index name:** The name of the index in Weaviate (optional).
- **Text Key:** The key used to extract text from documents (default: "text").
- **Embedding:** The embedding model used by Weaviate.
- **Attributes:** Additional attributes to consider during indexing (optional).

View file

@ -3,8 +3,6 @@ description: Custom Components
hide_table_of_contents: true
---
import ZoomableImage from "/src/theme/ZoomableImage.js";
import Admonition from "@theme/Admonition";
# FlowRunner Component
@ -35,7 +33,7 @@ We will cover how to:
<summary>Example Code</summary>
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class FlowRunner(CustomComponent):
@ -75,7 +73,7 @@ class FlowRunner(CustomComponent):
<CH.Scrollycoding rows={20} className={""}>
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
class MyComponent(CustomComponent):
@ -95,7 +93,7 @@ The typical structure of a Custom Component is composed of _`display_name`_ and
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
# focus
@ -118,7 +116,7 @@ Let's start by defining our component's _`display_name`_ and _`description`_.
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
# focus
from langchain.schema import Document
@ -140,7 +138,7 @@ Second, we will import _`Document`_ from the [_langchain.schema_](https://docs.l
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
# focus
from langchain.schema import Document
@ -167,7 +165,7 @@ Now, let's add the [parameters](focus://11[20:55]) and the [return type](focus:/
---
```python focus=13:14
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
@ -189,7 +187,7 @@ We can now start writing the _`build`_ method. Let's list available flows in "My
---
```python focus=15:18
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
@ -222,7 +220,7 @@ And retrieve a flow that matches the selected name (we'll make a dropdown input
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
@ -250,7 +248,7 @@ You can load this flow using _`get_flow`_ and set a _`tweaks`_ dictionary to cus
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
@ -287,7 +285,7 @@ The content of a document can be extracted using the _`page_content`_ attribute,
---
```python focus=9:16
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
@ -366,3 +364,7 @@ Done! This is what our script and custom component looks like:
/>
</div>
import ZoomableImage from "/src/theme/ZoomableImage.js";
import Admonition from "@theme/Admonition";

View file

@ -30,7 +30,7 @@ Here is an example:
<CH.Code linuNumbers={false}>
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class DocumentProcessor(CustomComponent):
@ -92,7 +92,7 @@ The Python script for every Custom Component should follow a set of rules. Let's
The script must contain a **single class** that inherits from _`CustomComponent`_.
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class MyComponent(CustomComponent):
@ -113,7 +113,7 @@ class MyComponent(CustomComponent):
This class requires a _`build`_ method used to run the component and define its fields.
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class MyComponent(CustomComponent):
@ -134,7 +134,7 @@ class MyComponent(CustomComponent):
The [Return Type Annotation](https://docs.python.org/3/library/typing.html) of the _`build`_ method defines the component type (e.g., Chain, BaseLLM, or basic Python types). Check out all supported types in the [component reference](../components/custom).
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class MyComponent(CustomComponent):
@ -153,7 +153,7 @@ class MyComponent(CustomComponent):
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class MyComponent(CustomComponent):
@ -179,7 +179,7 @@ Check out the [component reference](../components/custom) for more details on th
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class MyComponent(CustomComponent):
@ -204,7 +204,7 @@ Let's create a custom component that processes a document (_`langchain.schema.Do
To start, let's choose a name for our component by adding a _`display_name`_ attribute. This name will appear on the canvas. The name of the class is not relevant, but let's call it _`DocumentProcessor`_.
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
# focus
@ -227,7 +227,7 @@ class DocumentProcessor(CustomComponent):
We can also write a description for it using a _`description`_ attribute.
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class DocumentProcessor(CustomComponent):
@ -244,7 +244,7 @@ class DocumentProcessor(CustomComponent):
---
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class DocumentProcessor(CustomComponent):
@ -287,7 +287,7 @@ The _`build_config`_ method is here defined to customize the component fields.
- _`display_name`_ is the name of the field to be displayed.
```python
from langflow import CustomComponent
from langflow.custom import CustomComponent
from langchain.schema import Document
class DocumentProcessor(CustomComponent):
@ -406,4 +406,6 @@ Langflow will attempt to load all of the components found in the specified direc
Once your custom components have been loaded successfully, they will appear in Langflow's sidebar. From there, you can add them to your Langflow canvas for use. However, please note that components with errors will not be available for addition to the canvas. Always ensure your code is error-free before attempting to load components.
Remember, creating custom components allows you to extend the functionality of Langflow to better suit your unique needs. Happy coding!
Remember, creating custom components allows you to extend the functionality of Langflow to better suit your unique needs. Happy coding!import ZoomableImage from "/src/theme/ZoomableImage.js";
import Admonition from "@theme/Admonition";

View file

@ -1,8 +1,3 @@
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";
# Features
@ -49,7 +44,7 @@ The Code button shows snippets to use your flow as a Python object or an API.
Through the Langflow package, you can load a flow from a JSON file and use it as a LangChain object.
```py
from langflow import load_flow_from_json
from langflow.load import load_flow_from_json
flow = load_flow_from_json("path/to/flow.json")
# Now you can use it like any chain
@ -67,3 +62,10 @@ The example below shows a Python script making a POST request to a local API end
>
<ReactPlayer playing controls url="/videos/langflow_api.mp4" />
</div>
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";

View file

@ -0,0 +1,32 @@
# Inputs and Outputs
TL;DR: Inputs and Outputs are a category of components that are used to define where data comes in and out of your flow. They also
dynamically change the Interaction Panel and can be renamed to make it easier to build and maintain your flows.
## Introduction
Langflow 1.0 introduces new categories of components called Inputs and Outputs. They are used to make it easier to understand and interact with your flows.
Let's take a look at the what they are and how they work.
## Inputs
Some Input components output Text, others Record, and others both (you pick). They can be used to input data into any field that accepts Text or Record data.
{/* Show pictures of Chat Input into Prompt and Chat Input into File Path in a file loader component */}
As with all components, they can be renamed to help you identify them more easily in the Interaction Panel and while using the API.
{/* Show picture of renaming a Chat Input component and the Interaction Panel */}
The difference between Chat Input and other Input components is the format of the output, the number of configurable fields, and the way they are displayed in the Interaction Panel.
Chat Input components can output Text or Record. When you want to pass the sender name, or sender to the next component, you can use the Record output, and when you want to pass the message only you can use the Text output. This is useful when saving the message to a database or a memory system like Zep.
You can find out more about it and the other Inputs [here](../components/inputs).
## Outputs
Some Output components output Text, others Record, and others both (you pick), just like the Inputs. They can be used to output data from any field that outputs Text or Record data.
{/* Show pictures of Prompt into Chat Output and File Path in a file loader component into Chat Output */}

View file

@ -0,0 +1 @@
# A New Customization and Control

View file

@ -0,0 +1 @@
# Debugging Reimagined

View file

@ -0,0 +1,124 @@
# Migrating to Langflow 1.0: A Guide
Langflow 1.0 is a significant update that brings many exciting changes and improvements to the platform. This guide will walk you through the key differences and help you migrate your existing projects to the new version.
If you have any questions or need assistance during the migration process, please don't hesitate to reach out to in our [Discord](https://discord.gg/wZSWQaukgJ) or [GitHub](https://github.com/logspace-ai/langflow/issues) community.
We have a special channel
## TLDR;
- Inputs and Outputs of Components have changed
- The composition model has been replaced with a flow of data
- Continued support for LangChain and new support for multiple frameworks
- Redesigned sidebar and customizable interaction panel
- New Native Categories and Components
- Improved user experience with Text and Record modes
- CustomComponent for all components
- Compatibility with previous versions using Runnable Executor
- Multiple flows in the canvas
- Improved component status
- Ability to connect Output components to any other Component
- Rename and edit component descriptions
- Pass tweaks and inputs in the API using Display Name
- Global Variables for Text Fields
- Experimental components like SubFlow and Flow as Tool
- Experimental State Management system with Notify and Listen components
## Inputs and Outputs of Components
Langflow 1.0 introduces adds the concept of Inputs and Outputs to flows, allowing clear definition of the data flow between components. Discover how to use Inputs and Outputs to pass data between components and create more dynamic flows.
[Learn more about Inputs and Outputs of Components](../guides/inputs-and-outputs)
## From Composition to Freedom
Even though composition is still possible in Langflow 1.0, the new standard is getting data moving through the flow. This allows for more flexibility and control over the data flow in your projects. Check out how to use this in new and existing projects.
[Learn more about the Flow of Data](../guides/flow-of-data)
## Continued Support for LangChain and Multiple Frameworks
Langflow 1.0 continues to support LangChain while also introducing support for multiple frameworks. This is another important boon that adding the paradigm of data flow brings to the table. Find out how to leverage the power of different frameworks in your projects.
[Learn more about Supported Frameworks](../guides/supported-frameworks)
## Sidebar Redesign and Customizable Interaction Panel
We've expanded on the chat experience by creating a customizable interaction panel that allows you to design a panel that fits your needs and interact with it. The sidebar has also been redesigned to provide a more intuitive and user-friendly experience. Explore the new sidebar and interaction panel features to enhance your workflow.
[Learn more about some of the UI updates](../guides/sidebar-and-interaction-panel)
## New Native Categories and Components
Langflow 1.0 introduces many new native categories, including Inputs, Outputs, Helpers, Experimental, Models, and more. Discover the new components available, such as Chat Input, Prompt, Files, API Request, and others.
[Learn more about New Categories and Components](../guides/new-categories-and-components)
## New Way of Using Langflow: Text and Record (and more to come)
With the introduction of Text and Record types connections between Components are more intuitive and easier to understand. This is the first step in a series of improvements to the way you interact with Langflow. Learn how to use Text, and Record and how they help you build better flows.
[Learn more about Text and Record](../guides/text-and-record)
## CustomComponent for All Components
Almost all components in Langflow 1.0 are now CustomComponents, allowing you to check and modify the code of each component. Discover how to leverage this feature to customize your components to your specific needs.
[Learn more about CustomComponent](../guides/custom-component)
## Compatibility with Previous Versions
To use flows built in previous versions of Langflow, you can utilize the experimental component Runnable Executor along with an Input and Output. **We'd love your feedback on this**. Learn how to adapt your existing flows to work seamlessly in the new version of Langflow.
[Learn more about Compatibility with Previous Versions](../guides/compatibility)
## Multiple Flows in the Canvas
Langflow 1.0 allows you to have more than one flow in the canvas and run them separately. Discover how to create and manage multiple flows within a single project.
[Learn more about Multiple Flows](../guides/multiple-flows)
## Improved Component Status
Each component now displays its status more clearly, allowing you to quickly identify any issues or errors. Explore how to use the new component status feature to troubleshoot and optimize your flows.
[Learn more about Component Status](../guides/component-status-and-data-passing)
## Connecting Output Components
You can now connect Output components to any other component (that has a Text output), providing a better understanding of the data flow. Explore the possibilities of connecting Output components and how it enhances your flow's functionality.
[Learn more about Connecting Output Components](../guides/connecting-output-components)
## Renaming and Editing Component Descriptions
Langflow 1.0 allows you to rename and edit the description of each component, making it easier to understand and interact with the flow. Learn how to customize your component names and descriptions for improved clarity.
[Learn more about Renaming and Editing Components](../guides/renaming-and-editing-components)
## Passing Tweaks and Inputs in the API
Things got a whole lot easier. You can now pass tweaks and inputs in the API by referencing the Display Name of the component. Discover how to leverage this feature to dynamically control your flow's behavior.
[Learn more about Passing Tweaks and Inputs](../guides/passing-tweaks-and-inputs)
## Global Variables for Text Fields
Global Variables can be used in any Text Field across your projects. Learn how to define and utilize Global Variables to streamline your workflow.
[Learn more about Global Variables](../guides/global-variables)
## Experimental Components
Explore the experimental components available in Langflow 1.0, such as SubFlow, which allows you to load a flow as a component dynamically, and Flow as Tool, which enables you to use a flow as a tool for an Agent.
[Learn more about Experimental Components](../guides/experimental-components)
## Experimental State Management System
We are experimenting with a State Management system for flows that allows components to trigger other components and pass messages between them using the Notify and Listen components. Discover how to leverage this system to create more dynamic and interactive flows.
[Learn more about State Management](../guides/state-management)
We hope this guide helps you navigate the changes and improvements in Langflow 1.0. If you have any questions or need further assistance, please don't hesitate to reach out to us in our [Discord](https://discord.gg/wZSWQaukgJ).

View file

@ -0,0 +1 @@
# Simplification Through Standardization

427
docs/package-lock.json generated
View file

@ -10,10 +10,10 @@
"dependencies": {
"@babel/preset-react": "^7.22.3",
"@code-hike/mdx": "^0.9.0",
"@docusaurus/core": "3.0.1",
"@docusaurus/plugin-ideal-image": "^3.0.1",
"@docusaurus/preset-classic": "3.0.1",
"@docusaurus/theme-classic": "^3.0.1",
"@docusaurus/core": "^3.1.1",
"@docusaurus/plugin-ideal-image": "^3.1.1",
"@docusaurus/preset-classic": "^3.1.1",
"@docusaurus/theme-classic": "^3.1.1",
"@docusaurus/theme-search-algolia": "^3.0.1",
"@mdx-js/react": "^2.3.0",
"@mendable/search": "^0.0.154",
@ -2069,9 +2069,9 @@
}
},
"node_modules/@docusaurus/core": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.0.1.tgz",
"integrity": "sha512-CXrLpOnW+dJdSv8M5FAJ3JBwXtL6mhUWxFA8aS0ozK6jBG/wgxERk5uvH28fCeFxOGbAT9v1e9dOMo1X2IEVhQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.1.1.tgz",
"integrity": "sha512-2nQfKFcf+MLEM7JXsXwQxPOmQAR6ytKMZVSx7tVi9HEm9WtfwBH1fp6bn8Gj4zLUhjWKCLoysQ9/Wm+EZCQ4yQ==",
"dependencies": {
"@babel/core": "^7.23.3",
"@babel/generator": "^7.23.3",
@ -2083,13 +2083,13 @@
"@babel/runtime": "^7.22.6",
"@babel/runtime-corejs3": "^7.22.6",
"@babel/traverse": "^7.22.8",
"@docusaurus/cssnano-preset": "3.0.1",
"@docusaurus/logger": "3.0.1",
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/cssnano-preset": "3.1.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-common": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-common": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@slorber/static-site-generator-webpack-plugin": "^4.0.7",
"@svgr/webpack": "^6.5.1",
"autoprefixer": "^10.4.14",
@ -2249,9 +2249,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/@docusaurus/cssnano-preset": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.0.1.tgz",
"integrity": "sha512-wjuXzkHMW+ig4BD6Ya1Yevx9UJadO4smNZCEljqBoQfIQrQskTswBs7lZ8InHP7mCt273a/y/rm36EZhqJhknQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.1.1.tgz",
"integrity": "sha512-LnoIDjJWbirdbVZDMq+4hwmrTl2yHDnBf9MLG9qyExeAE3ac35s4yUhJI8yyTCdixzNfKit4cbXblzzqMu4+8g==",
"dependencies": {
"cssnano-preset-advanced": "^5.3.10",
"postcss": "^8.4.26",
@ -2263,9 +2263,9 @@
}
},
"node_modules/@docusaurus/logger": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.0.1.tgz",
"integrity": "sha512-I5L6Nk8OJzkVA91O2uftmo71LBSxe1vmOn9AMR6JRCzYeEBrqneWMH02AqMvjJ2NpMiviO+t0CyPjyYV7nxCWQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.1.1.tgz",
"integrity": "sha512-BjkNDpQzewcTnST8trx4idSoAla6zZ3w22NqM/UMcFtvYJgmoE4layuTzlfql3VFPNuivvj7BOExa/+21y4X2Q==",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.6.0"
@ -2339,11 +2339,11 @@
}
},
"node_modules/@docusaurus/lqip-loader": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/lqip-loader/-/lqip-loader-3.0.1.tgz",
"integrity": "sha512-hFSu8ltYo0ZnWBWmjMhSprOr6nNKG01YdMDxH/hahBfyaNDCkZU4o7mQNgUW845lvYdp6bhjyW31WJwBjOnLqw==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/lqip-loader/-/lqip-loader-3.1.1.tgz",
"integrity": "sha512-s06lySAX5ghCiQe0+/GaMWcVvgkBQ6U8p182fW+JbdjxABS8ecx2in2AQJbvrwKNgiMjOhsXiaE6BmbQAmT6nw==",
"dependencies": {
"@docusaurus/logger": "3.0.1",
"@docusaurus/logger": "3.1.1",
"file-loader": "^6.2.0",
"lodash": "^4.17.21",
"sharp": "^0.32.3",
@ -2354,15 +2354,15 @@
}
},
"node_modules/@docusaurus/mdx-loader": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.0.1.tgz",
"integrity": "sha512-ldnTmvnvlrONUq45oKESrpy+lXtbnTcTsFkOTIDswe5xx5iWJjt6eSa0f99ZaWlnm24mlojcIGoUWNCS53qVlQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.1.1.tgz",
"integrity": "sha512-xN2IccH9+sv7TmxwsDJNS97BHdmlqWwho+kIVY4tcCXkp+k4QuzvWBeunIMzeayY4Fu13A6sAjHGv5qm72KyGA==",
"dependencies": {
"@babel/parser": "^7.22.7",
"@babel/traverse": "^7.22.8",
"@docusaurus/logger": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@mdx-js/mdx": "^3.0.0",
"@slorber/remark-comment": "^1.0.0",
"escape-html": "^1.0.3",
@ -2434,17 +2434,17 @@
}
},
"node_modules/@docusaurus/plugin-content-blog": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.0.1.tgz",
"integrity": "sha512-cLOvtvAyaMQFLI8vm4j26svg3ktxMPSXpuUJ7EERKoGbfpJSsgtowNHcRsaBVmfuCsRSk1HZ/yHBsUkTmHFEsg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.1.1.tgz",
"integrity": "sha512-ew/3VtVoG3emoAKmoZl7oKe1zdFOsI0NbcHS26kIxt2Z8vcXKCUgK9jJJrz0TbOipyETPhqwq4nbitrY3baibg==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/logger": "3.0.1",
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-common": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-common": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^11.1.1",
@ -2465,17 +2465,17 @@
}
},
"node_modules/@docusaurus/plugin-content-docs": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.0.1.tgz",
"integrity": "sha512-dRfAOA5Ivo+sdzzJGXEu33yAtvGg8dlZkvt/NEJ7nwi1F2j4LEdsxtfX2GKeETB2fP6XoGNSQnFXqa2NYGrHFg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.1.1.tgz",
"integrity": "sha512-lhFq4E874zw0UOH7ujzxnCayOyAt0f9YPVYSb9ohxrdCM8B4szxitUw9rIX4V9JLLHVoqIJb6k+lJJ1jrcGJ0A==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/logger": "3.0.1",
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/module-type-aliases": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/module-type-aliases": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@types/react-router-config": "^5.0.7",
"combine-promises": "^1.1.0",
"fs-extra": "^11.1.1",
@ -2494,12 +2494,12 @@
}
},
"node_modules/@docusaurus/plugin-content-docs/node_modules/@docusaurus/module-type-aliases": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.0.1.tgz",
"integrity": "sha512-DEHpeqUDsLynl3AhQQiO7AbC7/z/lBra34jTcdYuvp9eGm01pfH1wTVq8YqWZq6Jyx0BgcVl/VJqtE9StRd9Ag==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.1.1.tgz",
"integrity": "sha512-xBJyx0TMfAfVZ9ZeIOb1awdXgR4YJMocIEzTps91rq+hJDFJgJaylDtmoRhUxkwuYmNK1GJpW95b7DLztSBJ3A==",
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/types": "3.0.1",
"@docusaurus/types": "3.1.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2513,15 +2513,15 @@
}
},
"node_modules/@docusaurus/plugin-content-pages": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.0.1.tgz",
"integrity": "sha512-oP7PoYizKAXyEttcvVzfX3OoBIXEmXTMzCdfmC4oSwjG4SPcJsRge3mmI6O8jcZBgUPjIzXD21bVGWEE1iu8gg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.1.1.tgz",
"integrity": "sha512-NQHncNRAJbyLtgTim9GlEnNYsFhuCxaCNkMwikuxLTiGIPH7r/jpb7O3f3jUMYMebZZZrDq5S7om9a6rvB/YCA==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"fs-extra": "^11.1.1",
"tslib": "^2.6.0",
"webpack": "^5.88.1"
@ -2535,13 +2535,13 @@
}
},
"node_modules/@docusaurus/plugin-debug": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.0.1.tgz",
"integrity": "sha512-09dxZMdATky4qdsZGzhzlUvvC+ilQ2hKbYF+wez+cM2mGo4qHbv8+qKXqxq0CQZyimwlAOWQLoSozIXU0g0i7g==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.1.1.tgz",
"integrity": "sha512-xWeMkueM9wE/8LVvl4+Qf1WqwXmreMjI5Kgr7GYCDoJ8zu4kD+KaMhrh7py7MNM38IFvU1RfrGKacCEe2DRRfQ==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"fs-extra": "^11.1.1",
"react-json-view-lite": "^1.2.0",
"tslib": "^2.6.0"
@ -2555,13 +2555,13 @@
}
},
"node_modules/@docusaurus/plugin-google-analytics": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.0.1.tgz",
"integrity": "sha512-jwseSz1E+g9rXQwDdr0ZdYNjn8leZBnKPjjQhMBEiwDoenL3JYFcNW0+p0sWoVF/f2z5t7HkKA+cYObrUh18gg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.1.1.tgz",
"integrity": "sha512-+q2UpWTqVi8GdlLoSlD5bS/YpxW+QMoBwrPrUH/NpvpuOi0Of7MTotsQf9JWd3hymZxl2uu1o3PIrbpxfeDFDQ==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"tslib": "^2.6.0"
},
"engines": {
@ -2573,13 +2573,13 @@
}
},
"node_modules/@docusaurus/plugin-google-gtag": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.0.1.tgz",
"integrity": "sha512-UFTDvXniAWrajsulKUJ1DB6qplui1BlKLQZjX4F7qS/qfJ+qkKqSkhJ/F4VuGQ2JYeZstYb+KaUzUzvaPK1aRQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.1.1.tgz",
"integrity": "sha512-0mMPiBBlQ5LFHTtjxuvt/6yzh8v7OxLi3CbeEsxXZpUzcKO/GC7UA1VOWUoBeQzQL508J12HTAlR3IBU9OofSw==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@types/gtag.js": "^0.0.12",
"tslib": "^2.6.0"
},
@ -2592,13 +2592,13 @@
}
},
"node_modules/@docusaurus/plugin-google-tag-manager": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.0.1.tgz",
"integrity": "sha512-IPFvuz83aFuheZcWpTlAdiiX1RqWIHM+OH8wS66JgwAKOiQMR3+nLywGjkLV4bp52x7nCnwhNk1rE85Cpy/CIw==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.1.1.tgz",
"integrity": "sha512-d07bsrMLdDIryDtY17DgqYUbjkswZQr8cLWl4tzXrt5OR/T/zxC1SYKajzB3fd87zTu5W5klV5GmUwcNSMXQXA==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"tslib": "^2.6.0"
},
"engines": {
@ -2610,16 +2610,16 @@
}
},
"node_modules/@docusaurus/plugin-ideal-image": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-3.0.1.tgz",
"integrity": "sha512-IvAUpEIz6v1/fVz6UTdQY12pYIE5geNFtsuKpsULpMaotwYf3Gs7acXjQog4qquKkc65yV5zuvMj8BZMHEwLyQ==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-3.1.1.tgz",
"integrity": "sha512-FYce5eV5/fWO4qIG8sKYdK3MTwusdxQML/M62IiltUNM/cqFkDrty1d+H+/I2PYX1s7AOoL3YomdJNP4vra/Tg==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/lqip-loader": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/lqip-loader": "3.1.1",
"@docusaurus/responsive-loader": "^1.7.0",
"@docusaurus/theme-translations": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/theme-translations": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@slorber/react-ideal-image": "^0.0.12",
"react-waypoint": "^10.3.0",
"sharp": "^0.32.3",
@ -2641,16 +2641,16 @@
}
},
"node_modules/@docusaurus/plugin-sitemap": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.0.1.tgz",
"integrity": "sha512-xARiWnjtVvoEniZudlCq5T9ifnhCu/GAZ5nA7XgyLfPcNpHQa241HZdsTlLtVcecEVVdllevBKOp7qknBBaMGw==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.1.1.tgz",
"integrity": "sha512-iJ4hCaMmDaUqRv131XJdt/C/jJQx8UreDWTRqZKtNydvZVh/o4yXGRRFOplea1D9b/zpwL1Y+ZDwX7xMhIOTmg==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/logger": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-common": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-common": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"fs-extra": "^11.1.1",
"sitemap": "^7.1.1",
"tslib": "^2.6.0"
@ -2664,23 +2664,23 @@
}
},
"node_modules/@docusaurus/preset-classic": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.0.1.tgz",
"integrity": "sha512-il9m9xZKKjoXn6h0cRcdnt6wce0Pv1y5t4xk2Wx7zBGhKG1idu4IFHtikHlD0QPuZ9fizpXspXcTzjL5FXc1Gw==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.1.1.tgz",
"integrity": "sha512-jG4ys/hWYf69iaN/xOmF+3kjs4Nnz1Ay3CjFLDtYa8KdxbmUhArA9HmP26ru5N0wbVWhY+6kmpYhTJpez5wTyg==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/plugin-content-blog": "3.0.1",
"@docusaurus/plugin-content-docs": "3.0.1",
"@docusaurus/plugin-content-pages": "3.0.1",
"@docusaurus/plugin-debug": "3.0.1",
"@docusaurus/plugin-google-analytics": "3.0.1",
"@docusaurus/plugin-google-gtag": "3.0.1",
"@docusaurus/plugin-google-tag-manager": "3.0.1",
"@docusaurus/plugin-sitemap": "3.0.1",
"@docusaurus/theme-classic": "3.0.1",
"@docusaurus/theme-common": "3.0.1",
"@docusaurus/theme-search-algolia": "3.0.1",
"@docusaurus/types": "3.0.1"
"@docusaurus/core": "3.1.1",
"@docusaurus/plugin-content-blog": "3.1.1",
"@docusaurus/plugin-content-docs": "3.1.1",
"@docusaurus/plugin-content-pages": "3.1.1",
"@docusaurus/plugin-debug": "3.1.1",
"@docusaurus/plugin-google-analytics": "3.1.1",
"@docusaurus/plugin-google-gtag": "3.1.1",
"@docusaurus/plugin-google-tag-manager": "3.1.1",
"@docusaurus/plugin-sitemap": "3.1.1",
"@docusaurus/theme-classic": "3.1.1",
"@docusaurus/theme-common": "3.1.1",
"@docusaurus/theme-search-algolia": "3.1.1",
"@docusaurus/types": "3.1.1"
},
"engines": {
"node": ">=18.0"
@ -2726,22 +2726,22 @@
}
},
"node_modules/@docusaurus/theme-classic": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.0.1.tgz",
"integrity": "sha512-XD1FRXaJiDlmYaiHHdm27PNhhPboUah9rqIH0lMpBt5kYtsGjJzhqa27KuZvHLzOP2OEpqd2+GZ5b6YPq7Q05Q==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.1.1.tgz",
"integrity": "sha512-GiPE/jbWM8Qv1A14lk6s9fhc0LhPEQ00eIczRO4QL2nAQJZXkjPG6zaVx+1cZxPFWbAsqSjKe2lqkwF3fGkQ7Q==",
"dependencies": {
"@docusaurus/core": "3.0.1",
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/module-type-aliases": "3.0.1",
"@docusaurus/plugin-content-blog": "3.0.1",
"@docusaurus/plugin-content-docs": "3.0.1",
"@docusaurus/plugin-content-pages": "3.0.1",
"@docusaurus/theme-common": "3.0.1",
"@docusaurus/theme-translations": "3.0.1",
"@docusaurus/types": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-common": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/module-type-aliases": "3.1.1",
"@docusaurus/plugin-content-blog": "3.1.1",
"@docusaurus/plugin-content-docs": "3.1.1",
"@docusaurus/plugin-content-pages": "3.1.1",
"@docusaurus/theme-common": "3.1.1",
"@docusaurus/theme-translations": "3.1.1",
"@docusaurus/types": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-common": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
"copy-text-to-clipboard": "^3.2.0",
@ -2765,12 +2765,12 @@
}
},
"node_modules/@docusaurus/theme-classic/node_modules/@docusaurus/module-type-aliases": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.0.1.tgz",
"integrity": "sha512-DEHpeqUDsLynl3AhQQiO7AbC7/z/lBra34jTcdYuvp9eGm01pfH1wTVq8YqWZq6Jyx0BgcVl/VJqtE9StRd9Ag==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.1.1.tgz",
"integrity": "sha512-xBJyx0TMfAfVZ9ZeIOb1awdXgR4YJMocIEzTps91rq+hJDFJgJaylDtmoRhUxkwuYmNK1GJpW95b7DLztSBJ3A==",
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/types": "3.0.1",
"@docusaurus/types": "3.1.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2784,9 +2784,9 @@
}
},
"node_modules/@docusaurus/theme-classic/node_modules/@mdx-js/react": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz",
"integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz",
"integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==",
"dependencies": {
"@types/mdx": "^2.0.0"
},
@ -2800,9 +2800,9 @@
}
},
"node_modules/@docusaurus/theme-classic/node_modules/clsx": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
@ -2820,17 +2820,17 @@
}
},
"node_modules/@docusaurus/theme-common": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.0.1.tgz",
"integrity": "sha512-cr9TOWXuIOL0PUfuXv6L5lPlTgaphKP+22NdVBOYah5jSq5XAAulJTjfe+IfLsEG4L7lJttLbhW7LXDFSAI7Ag==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.1.1.tgz",
"integrity": "sha512-38urZfeMhN70YaXkwIGXmcUcv2CEYK/2l4b05GkJPrbEbgpsIZM3Xc+Js2ehBGGZmfZq8GjjQ5RNQYG+MYzCYg==",
"dependencies": {
"@docusaurus/mdx-loader": "3.0.1",
"@docusaurus/module-type-aliases": "3.0.1",
"@docusaurus/plugin-content-blog": "3.0.1",
"@docusaurus/plugin-content-docs": "3.0.1",
"@docusaurus/plugin-content-pages": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-common": "3.0.1",
"@docusaurus/mdx-loader": "3.1.1",
"@docusaurus/module-type-aliases": "3.1.1",
"@docusaurus/plugin-content-blog": "3.1.1",
"@docusaurus/plugin-content-docs": "3.1.1",
"@docusaurus/plugin-content-pages": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-common": "3.1.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2849,12 +2849,12 @@
}
},
"node_modules/@docusaurus/theme-common/node_modules/@docusaurus/module-type-aliases": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.0.1.tgz",
"integrity": "sha512-DEHpeqUDsLynl3AhQQiO7AbC7/z/lBra34jTcdYuvp9eGm01pfH1wTVq8YqWZq6Jyx0BgcVl/VJqtE9StRd9Ag==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.1.1.tgz",
"integrity": "sha512-xBJyx0TMfAfVZ9ZeIOb1awdXgR4YJMocIEzTps91rq+hJDFJgJaylDtmoRhUxkwuYmNK1GJpW95b7DLztSBJ3A==",
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/types": "3.0.1",
"@docusaurus/types": "3.1.1",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -2868,9 +2868,9 @@
}
},
"node_modules/@docusaurus/theme-common/node_modules/clsx": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
"integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
@ -2888,18 +2888,18 @@
}
},
"node_modules/@docusaurus/theme-search-algolia": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.0.1.tgz",
"integrity": "sha512-DDiPc0/xmKSEdwFkXNf1/vH1SzJPzuJBar8kMcBbDAZk/SAmo/4lf6GU2drou4Ae60lN2waix+jYWTWcJRahSA==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.1.1.tgz",
"integrity": "sha512-tBH9VY5EpRctVdaAhT+b1BY8y5dyHVZGFXyCHgTrvcXQy5CV4q7serEX7U3SveNT9zksmchPyct6i1sFDC4Z5g==",
"dependencies": {
"@docsearch/react": "^3.5.2",
"@docusaurus/core": "3.0.1",
"@docusaurus/logger": "3.0.1",
"@docusaurus/plugin-content-docs": "3.0.1",
"@docusaurus/theme-common": "3.0.1",
"@docusaurus/theme-translations": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/utils-validation": "3.0.1",
"@docusaurus/core": "3.1.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/plugin-content-docs": "3.1.1",
"@docusaurus/theme-common": "3.1.1",
"@docusaurus/theme-translations": "3.1.1",
"@docusaurus/utils": "3.1.1",
"@docusaurus/utils-validation": "3.1.1",
"algoliasearch": "^4.18.0",
"algoliasearch-helper": "^3.13.3",
"clsx": "^2.0.0",
@ -2926,9 +2926,9 @@
}
},
"node_modules/@docusaurus/theme-translations": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.0.1.tgz",
"integrity": "sha512-6UrbpzCTN6NIJnAtZ6Ne9492vmPVX+7Fsz4kmp+yor3KQwA1+MCzQP7ItDNkP38UmVLnvB/cYk/IvehCUqS3dg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.1.1.tgz",
"integrity": "sha512-xvWQFwjxHphpJq5fgk37FXCDdAa2o+r7FX8IpMg+bGZBNXyWBu3MjZ+G4+eUVNpDhVinTc+j6ucL0Ain5KCGrg==",
"dependencies": {
"fs-extra": "^11.1.1",
"tslib": "^2.6.0"
@ -2938,10 +2938,11 @@
}
},
"node_modules/@docusaurus/types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.0.1.tgz",
"integrity": "sha512-plyX2iU1tcUsF46uQ01pAd4JhexR7n0iiQ5MSnBFX6M6NSJgDYdru/i1/YNPKOnQHBoXGLHv0dNT6OAlDWNjrg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.1.1.tgz",
"integrity": "sha512-grBqOLnubUecgKFXN9q3uit2HFbCxTWX4Fam3ZFbMN0sWX9wOcDoA7lwdX/8AmeL20Oc4kQvWVgNrsT8bKRvzg==",
"dependencies": {
"@mdx-js/mdx": "^3.0.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"commander": "^5.1.0",
@ -2957,11 +2958,11 @@
}
},
"node_modules/@docusaurus/utils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.0.1.tgz",
"integrity": "sha512-TwZ33Am0q4IIbvjhUOs+zpjtD/mXNmLmEgeTGuRq01QzulLHuPhaBTTAC/DHu6kFx3wDgmgpAlaRuCHfTcXv8g==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.1.1.tgz",
"integrity": "sha512-ZJfJa5cJQtRYtqijsPEnAZoduW6sjAQ7ZCWSZavLcV10Fw0Z3gSaPKA/B4micvj2afRZ4gZxT7KfYqe5H8Cetg==",
"dependencies": {
"@docusaurus/logger": "3.0.1",
"@docusaurus/logger": "3.1.1",
"@svgr/webpack": "^6.5.1",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
@ -2992,9 +2993,9 @@
}
},
"node_modules/@docusaurus/utils-common": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.0.1.tgz",
"integrity": "sha512-W0AxD6w6T8g6bNro8nBRWf7PeZ/nn7geEWM335qHU2DDDjHuV4UZjgUGP1AQsdcSikPrlIqTJJbKzer1lRSlIg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.1.1.tgz",
"integrity": "sha512-eGne3olsIoNfPug5ixjepZAIxeYFzHHnor55Wb2P57jNbtVaFvij/T+MS8U0dtZRFi50QU+UPmRrXdVUM8uyMg==",
"dependencies": {
"tslib": "^2.6.0"
},
@ -3011,12 +3012,12 @@
}
},
"node_modules/@docusaurus/utils-validation": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.0.1.tgz",
"integrity": "sha512-ujTnqSfyGQ7/4iZdB4RRuHKY/Nwm58IIb+41s5tCXOv/MBU2wGAjOHq3U+AEyJ8aKQcHbxvTKJaRchNHYUVUQg==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.1.1.tgz",
"integrity": "sha512-KlY4P9YVDnwL+nExvlIpu79abfEv6ZCHuOX4ZQ+gtip+Wxj0daccdReIWWtqxM/Fb5Cz1nQvUCc7VEtT8IBUAA==",
"dependencies": {
"@docusaurus/logger": "3.0.1",
"@docusaurus/utils": "3.0.1",
"@docusaurus/logger": "3.1.1",
"@docusaurus/utils": "3.1.1",
"joi": "^17.9.2",
"js-yaml": "^4.1.0",
"tslib": "^2.6.0"
@ -4928,12 +4929,12 @@
"dev": true
},
"node_modules/body-parser": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.4",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
@ -4941,7 +4942,7 @@
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"raw-body": "2.5.1",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
@ -6124,9 +6125,9 @@
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
"node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"engines": {
"node": ">= 0.6"
}
@ -9620,16 +9621,16 @@
}
},
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.1",
"body-parser": "1.20.2",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.5.0",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
@ -10005,9 +10006,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
@ -11688,9 +11689,9 @@
}
},
"node_modules/ip": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz",
"integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
"dev": true
},
"node_modules/ipaddr.js": {
@ -17476,9 +17477,9 @@
}
},
"node_modules/raw-body": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
@ -22018,9 +22019,9 @@
}
},
"node_modules/webpack-dev-middleware": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
"integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
"integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
"dependencies": {
"colorette": "^2.0.10",
"memfs": "^3.4.3",

View file

@ -16,10 +16,10 @@
"dependencies": {
"@babel/preset-react": "^7.22.3",
"@code-hike/mdx": "^0.9.0",
"@docusaurus/core": "3.0.1",
"@docusaurus/plugin-ideal-image": "^3.0.1",
"@docusaurus/preset-classic": "3.0.1",
"@docusaurus/theme-classic": "^3.0.1",
"@docusaurus/core": "^3.1.1",
"@docusaurus/plugin-ideal-image": "^3.1.1",
"@docusaurus/preset-classic": "^3.1.1",
"@docusaurus/theme-classic": "^3.1.1",
"@docusaurus/theme-search-algolia": "^3.0.1",
"@mdx-js/react": "^2.3.0",
"@mendable/search": "^0.0.154",
@ -69,4 +69,4 @@
"engines": {
"node": ">=16.14"
}
}
}

View file

@ -11,6 +11,17 @@ module.exports = {
"getting-started/creating-flows",
],
},
{
type: "category",
label: "What's New",
collapsed: false,
items: [
"whats-new/migrating-to-one-point-zero",
"whats-new/customization-control",
"whats-new/debugging-reimagined",
"whats-new/simplification-standardization",
],
},
{
type: "category",
label: "Guidelines",
@ -66,18 +77,25 @@ module.exports = {
"guides/loading_document",
"guides/chatprompttemplate_guide",
"guides/langfuse_integration",
"guides/inputs-and-outputs",
"guides/flow-of-data",
"guides/supported-frameworks",
"guides/sidebar-and-interaction-panel",
"guides/new-categories-and-components",
"guides/text-and-record",
"guides/custom-component",
"guides/compatibility",
"guides/multiple-flows",
"guides/component-status-and-data-passing",
"guides/connecting-output-components",
"guides/renaming-and-editing-components",
"guides/passing-tweaks-and-inputs",
"guides/global-variables",
"guides/experimental-components",
"guides/state-management",
"guides/run-flow",
],
},
// {
// type: 'category',
// label: 'Components',
// collapsed: false,
// items: [
// 'components/agents', 'components/chains', 'components/loaders', 'components/embeddings', 'components/llms',
// 'components/memories', 'components/prompts','components/text-splitters', 'components/toolkits', 'components/tools',
// 'components/utilities', 'components/vector-stores', 'components/wrappers',
// ],
// },
{
type: "category",
label: "Examples",

File diff suppressed because one or more lines are too long

1035
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -24,30 +24,21 @@ documentation = "https://docs.langflow.org"
[tool.poetry.scripts]
langflow = "langflow.__main__:main"
[tool.poetry-monorepo-dependency-plugin]
enable = true
[tool.poetry.dependencies]
python = ">=3.10,<3.12"
duckdb = "^0.9.2"
fastapi = "^0.109.0"
uvicorn = "^0.27.0"
langflow-base = { path = "./src/backend/base", develop = true }
beautifulsoup4 = "^4.12.2"
google-search-results = "^2.4.1"
google-api-python-client = "^2.118.0"
typer = "^0.9.0"
gunicorn = "^21.2.0"
langchain = "~0.1.0"
openai = "^1.12.0"
pandas = "2.2.0"
chromadb = "^0.4.23"
huggingface-hub = { version = "^0.20.0", extras = ["inference"] }
rich = "^13.7.0"
llama-cpp-python = { version = "~0.2.0", optional = true }
networkx = "^3.1"
pypdf = "^4.0.0"
pysrt = "^1.1.2"
fake-useragent = "^1.4.0"
docstring-parser = "^0.15"
psycopg2-binary = "^2.9.6"
pyarrow = "^14.0.0"
wikipedia = "^1.4.0"
@ -56,15 +47,8 @@ weaviate-client = "*"
sentence-transformers = { version = "^2.3.1", optional = true }
ctransformers = { version = "^0.2.10", optional = true }
cohere = "^4.47.0"
python-multipart = "^0.0.7"
sqlmodel = "^0.0.14"
faiss-cpu = "^1.7.4"
anthropic = "^0.21.0"
orjson = "3.9.15"
multiprocess = "^0.70.14"
cachetools = "^5.3.1"
types-cachetools = "^5.3.0.5"
platformdirs = "^4.2.0"
pinecone-client = "^3.0.3"
pymongo = "^4.6.0"
supabase = "^2.3.0"
@ -72,27 +56,17 @@ certifi = "^2023.11.17"
psycopg = "^3.1.9"
psycopg-binary = "^3.1.9"
fastavro = "^1.8.0"
langchain-experimental = "*"
celery = { extras = ["redis"], version = "^5.3.6", optional = true }
redis = { version = "^5.0.1", optional = true }
flower = { version = "^2.0.0", optional = true }
alembic = "^1.13.0"
passlib = "^1.7.4"
bcrypt = "4.0.1"
python-jose = "^3.3.0"
metaphor-python = "^0.1.11"
pydantic = "^2.5.0"
pydantic-settings = "^2.1.0"
zep-python = "1.5.0"
zep-python = "*"
pywin32 = { version = "^306", markers = "sys_platform == 'win32'" }
loguru = "^0.7.1"
langfuse = "^2.9.0"
pillow = "^10.2.0"
metal-sdk = "^2.5.0"
markupsafe = "^2.1.3"
extract-msg = "^0.47.0"
# jq is not available for windows
jq = { version = "^1.6.0", markers = "sys_platform != 'win32'" }
boto3 = "^1.34.0"
numexpr = "^2.8.6"
qianfan = "0.3.5"
@ -101,17 +75,13 @@ pyautogen = "^0.2.0"
langchain-google-genai = "^0.0.6"
elasticsearch = "^8.12.0"
pytube = "^15.0.0"
python-socketio = "^5.11.0"
llama-index = "^0.10.13"
langchain-openai = "^0.0.5"
unstructured = { extras = ["md"], version = "^0.12.4" }
dspy-ai = "^2.4.0"
crewai = "^0.22.5"
langchain-anthropic = "^0.1.4"
python-docx = "^1.1.0"
[tool.poetry.group.dev.dependencies]
pytest-asyncio = "^0.23.1"
types-redis = "^4.6.0.5"
ipykernel = "^6.29.0"
mypy = "^1.8.0"

View file

@ -0,0 +1,9 @@
#!/bin/bash
# Create a .env if it doesn't exist, log all cases
if [ ! -f .env ]; then
echo "Creating .env file"
touch .env
else
echo ".env file already exists"
fi

View file

@ -0,0 +1,33 @@
#!/bin/bash
# Check if version argument is provided
if [ -z "$1" ]
then
echo "No argument supplied. Please provide the Poetry version to check."
exit 1
fi
echo "Checking Poetry version..."
# Check Poetry version
poetry_version=$(poetry --version | awk '{print $3}' | tr -d '()')
echo "Current Poetry version: $poetry_version"
# Compare version
if [[ "$(printf '%s\n' "$1" "$poetry_version" | sort -V | head -n1)" != "$1" ]]; then
echo "Poetry version is lower than $1. Updating..."
# Update Poetry
poetry self update
echo "Poetry updated successfully."
else
echo "Poetry version is $1 or higher. No need to update."
fi
# Check if poetry-monorepo-dependency-plugin is installed
if poetry self show | grep -q "poetry-monorepo-dependency-plugin"; then
echo "poetry-monorepo-dependency-plugin is already installed."
else
echo "Installing poetry-monorepo-dependency-plugin..."
poetry run pip install poetry-monorepo-dependency-plugin
echo "poetry-monorepo-dependency-plugin installed successfully."
fi

View file

@ -1,23 +1,29 @@
import platform
import socket
import sys
import time
import webbrowser
from pathlib import Path
from typing import Optional
import httpx
import typer
from dotenv import load_dotenv
from langflow.main import setup_app
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service, get_settings_service
from langflow.services.utils import initialize_services, initialize_settings_service
from langflow.utils.logger import configure, logger
from multiprocess import cpu_count # type: ignore
from multiprocess import (
Process, # type: ignore
cpu_count, # type: ignore
)
from rich import box
from rich import print as rprint
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from sqlmodel import select
from langflow.main import setup_app
from langflow.services.database.utils import session_getter
from langflow.services.deps import get_db_service, get_settings_service
from langflow.services.utils import initialize_services, initialize_settings_service
from langflow.utils.logger import configure, logger
console = Console()
@ -70,7 +76,7 @@ def update_settings(
dev: bool = False,
remove_api_keys: bool = False,
components_path: Optional[Path] = None,
store: bool = False,
store: bool = True,
):
"""Update the settings from a config file."""
@ -94,33 +100,6 @@ def update_settings(
settings_service.settings.update_settings(STORE=False)
def version_callback(value: bool):
"""
Show the version and exit.
"""
from langflow import __version__
if value:
typer.echo(f"Langflow Version: {__version__}")
raise typer.Exit()
@app.callback()
def main_entry_point(
version: bool = typer.Option(
None,
"--version",
callback=version_callback,
is_eager=True,
help="Show the version and exit.",
),
):
"""
Main entry point for the Langflow CLI.
"""
pass
@app.command()
def run(
host: str = typer.Option("127.0.0.1", help="Host to bind the server to.", envvar="LANGFLOW_HOST"),
@ -212,12 +191,23 @@ def run(
run_on_windows(host, port, log_level, options, app)
else:
# Run using gunicorn on Linux
run_on_mac_or_linux(host, port, log_level, options, app)
run_on_mac_or_linux(host, port, log_level, options, app, open_browser)
def run_on_mac_or_linux(host, port, log_level, options, app):
def run_on_mac_or_linux(host, port, log_level, options, app, open_browser=True):
webapp_process = Process(target=run_langflow, args=(host, port, log_level, options, app))
webapp_process.start()
status_code = 0
while status_code != 200:
try:
status_code = httpx.get(f"http://{host}:{port}/health").status_code
except Exception:
time.sleep(1)
print_banner(host, port)
run_langflow(host, port, log_level, options, app)
if open_browser:
webbrowser.open(f"http://{host}:{port}")
def run_on_windows(host, port, log_level, options, app):
@ -292,11 +282,10 @@ def run_langflow(host, port, log_level, options, app):
Run Langflow server on localhost
"""
try:
if platform.system() in ["Windows", "Darwin"]:
if platform.system() in ["Windows"]:
# Run using uvicorn on MacOS and Windows
# Windows doesn't support gunicorn
# MacOS requires an env variable to be set to use gunicorn
import uvicorn
uvicorn.run(
@ -310,8 +299,7 @@ def run_langflow(host, port, log_level, options, app):
LangflowApplication(app, options).run()
except KeyboardInterrupt:
logger.info("Shutting down server")
sys.exit(0)
pass
except Exception as e:
logger.exception(e)
sys.exit(1)
@ -336,7 +324,7 @@ def superuser(
# Verify that the superuser was created
from langflow.services.database.models.user.model import User
user: User = session.exec(select(User).where(User.username == username)).first()
user: User = session.query(User).filter(User.username == username).first()
if user is None or not user.is_superuser:
typer.echo("Superuser creation failed.")
return
@ -348,23 +336,11 @@ def superuser(
@app.command()
def migration(
test: bool = typer.Option(True, help="Run migrations in test mode."),
fix: bool = typer.Option(
False,
help="Fix migrations. This is a destructive operation, and should only be used if you know what you are doing.",
),
):
def migration(test: bool = typer.Option(True, help="Run migrations in test mode.")):
"""
Run or test migrations.
"""
if fix:
if not typer.confirm(
"This will delete all data necessary to fix migrations. Are you sure you want to continue?"
):
raise typer.Abort()
initialize_services(fix_migration=fix)
initialize_services()
db_service = get_db_service()
if not test:
db_service.run_migrations()

View file

@ -66,16 +66,10 @@ def run_migrations_online() -> None:
try:
from langflow.services.database.factory import DatabaseServiceFactory
from langflow.services.deps import get_db_service
from langflow.services.manager import (
initialize_settings_service,
service_manager,
)
from langflow.services.schema import ServiceType
from langflow.services.manager import initialize_settings_service, service_manager
initialize_settings_service()
service_manager.register_factory(
DatabaseServiceFactory(), [ServiceType.SETTINGS_SERVICE]
)
service_manager.register_factory(DatabaseServiceFactory())
connectable = get_db_service().engine
except Exception as e:
logger.error(f"Error getting database engine: {e}")
@ -89,9 +83,7 @@ def run_migrations_online() -> None:
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata, render_as_batch=True
)
context.configure(connection=connection, target_metadata=target_metadata, render_as_batch=True)
with context.begin_transaction():
context.run_migrations()

View file

@ -0,0 +1,199 @@
from typing import TYPE_CHECKING, Any, Callable, Coroutine, List, Optional, Tuple, Union
from pydantic.v1 import BaseModel, Field, create_model
from sqlmodel import select
from langflow.schema.schema import INPUT_FIELD_NAME, Record
from langflow.services.database.models.flow.model import Flow
from langflow.services.deps import session_scope
if TYPE_CHECKING:
from langflow.graph.graph.base import Graph
from langflow.graph.vertex.base import Vertex
INPUT_TYPE_MAP = {
"ChatInput": {"type_hint": "Optional[str]", "default": '""'},
"TextInput": {"type_hint": "Optional[str]", "default": '""'},
"JSONInput": {"type_hint": "Optional[dict]", "default": "{}"},
}
def list_flows(*, user_id: Optional[str] = None) -> List[Record]:
if not user_id:
raise ValueError("Session is invalid")
try:
with session_scope() as session:
flows = session.exec(
select(Flow).where(Flow.user_id == user_id).where(Flow.is_component == False) # noqa
).all()
flows_records = [flow.to_record() for flow in flows]
return flows_records
except Exception as e:
raise ValueError(f"Error listing flows: {e}")
async def load_flow(
user_id: str, flow_id: Optional[str] = None, flow_name: Optional[str] = None, tweaks: Optional[dict] = None
) -> "Graph":
from langflow.graph.graph.base import Graph
from langflow.processing.process import process_tweaks
if not flow_id and not flow_name:
raise ValueError("Flow ID or Flow Name is required")
if not flow_id and flow_name:
flow_id = find_flow(flow_name, user_id)
if not flow_id:
raise ValueError(f"Flow {flow_name} not found")
with session_scope() as session:
graph_data = flow.data if (flow := session.get(Flow, flow_id)) else None
if not graph_data:
raise ValueError(f"Flow {flow_id} not found")
if tweaks:
graph_data = process_tweaks(graph_data=graph_data, tweaks=tweaks)
graph = Graph.from_payload(graph_data, flow_id=flow_id)
return graph
def find_flow(flow_name: str, user_id: str) -> Optional[str]:
with session_scope() as session:
flow = session.exec(select(Flow).where(Flow.name == flow_name).where(Flow.user_id == user_id)).first()
return flow.id if flow else None
async def run_flow(
inputs: Union[dict, List[dict]] = None,
tweaks: Optional[dict] = None,
flow_id: Optional[str] = None,
flow_name: Optional[str] = None,
user_id: Optional[str] = None,
) -> Any:
graph = await load_flow(user_id, flow_id, flow_name, tweaks)
if inputs is None:
inputs = []
inputs_list = []
inputs_components = []
types = []
for input_dict in inputs:
inputs_list.append({INPUT_FIELD_NAME: input_dict.get("input_value")})
inputs_components.append(input_dict.get("components", []))
types.append(input_dict.get("type", []))
return await graph.arun(inputs_list, inputs_components=inputs_components, types=types)
def generate_function_for_flow(inputs: List["Vertex"], flow_id: str) -> Coroutine:
"""
Generate a dynamic flow function based on the given inputs and flow ID.
Args:
inputs (List[Vertex]): The list of input vertices for the flow.
flow_id (str): The ID of the flow.
Returns:
Coroutine: The dynamic flow function.
Raises:
None
Example:
inputs = [vertex1, vertex2]
flow_id = "my_flow"
function = generate_function_for_flow(inputs, flow_id)
result = function(input1, input2)
"""
# Prepare function arguments with type hints and default values
args = [
f"{input_.display_name.lower().replace(' ', '_')}: {INPUT_TYPE_MAP[input_.base_name]['type_hint']} = {INPUT_TYPE_MAP[input_.base_name]['default']}"
for input_ in inputs
]
# Maintain original argument names for constructing the tweaks dictionary
original_arg_names = [input_.display_name for input_ in inputs]
# Prepare a Pythonic, valid function argument string
func_args = ", ".join(args)
# Map original argument names to their corresponding Pythonic variable names in the function
arg_mappings = ", ".join(
f'"{original_name}": {name}'
for original_name, name in zip(original_arg_names, [arg.split(":")[0] for arg in args])
)
func_body = f"""
from typing import Optional
async def flow_function({func_args}):
tweaks = {{ {arg_mappings} }}
from langflow.helpers.flow import run_flow
from langchain_core.tools import ToolException
try:
return await run_flow(
tweaks={{key: {{'input_value': value}} for key, value in tweaks.items()}},
flow_id="{flow_id}",
)
except Exception as e:
raise ToolException(f'Error running flow: ' + e)
"""
compiled_func = compile(func_body, "<string>", "exec")
local_scope = {}
exec(compiled_func, globals(), local_scope)
return local_scope["flow_function"]
def build_function_and_schema(flow_record: Record, graph: "Graph") -> Tuple[Callable, BaseModel]:
"""
Builds a dynamic function and schema for a given flow.
Args:
flow_record (Record): The flow record containing information about the flow.
graph (Graph): The graph representing the flow.
Returns:
Tuple[Callable, BaseModel]: A tuple containing the dynamic function and the schema.
"""
flow_id = flow_record.id
inputs = get_flow_inputs(graph)
dynamic_flow_function = generate_function_for_flow(inputs, flow_id)
schema = build_schema_from_inputs(flow_record.name, inputs)
return dynamic_flow_function, schema
def get_flow_inputs(graph: "Graph") -> List["Vertex"]:
"""
Retrieves the flow inputs from the given graph.
Args:
graph (Graph): The graph object representing the flow.
Returns:
List[Record]: A list of input records, where each record contains the ID, name, and description of the input vertex.
"""
inputs = []
for vertex in graph.vertices:
if vertex.is_input:
inputs.append(vertex)
return inputs
def build_schema_from_inputs(name: str, inputs: List[tuple[str, str, str]]) -> BaseModel:
"""
Builds a schema from the given inputs.
Args:
name (str): The name of the schema.
inputs (List[tuple[str, str, str]]): A list of tuples representing the inputs.
Each tuple contains three elements: the input name, the input type, and the input description.
Returns:
BaseModel: The schema model.
"""
fields = {}
for input_ in inputs:
field_name = input_.display_name.lower().replace(" ", "_")
description = input_.description
fields[field_name] = (str, Field(default="", description=description))
return create_model(name, **fields)

View file

@ -26,20 +26,13 @@ def upgrade() -> None:
flow_constraints = inspector.get_unique_constraints("flow")
user_constraints = inspector.get_unique_constraints("user")
try:
if not any(
constraint["name"] == "uq_apikey_id" for constraint in api_key_constraints
):
if not any(constraint["name"] == "uq_apikey_id" for constraint in api_key_constraints):
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.create_unique_constraint("uq_apikey_id", ["id"])
if not any(
constraint["name"] == "uq_flow_id" for constraint in flow_constraints
):
if not any(constraint["name"] == "uq_flow_id" for constraint in flow_constraints):
with op.batch_alter_table("flow", schema=None) as batch_op:
batch_op.create_unique_constraint("uq_flow_id", ["id"])
if not any(
constraint["name"] == "uq_user_id" for constraint in user_constraints
):
if not any(constraint["name"] == "uq_user_id" for constraint in user_constraints):
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.create_unique_constraint("uq_user_id", ["id"])
except Exception as e:
@ -57,16 +50,13 @@ def downgrade() -> None:
flow_constraints = inspector.get_unique_constraints("flow")
user_constraints = inspector.get_unique_constraints("user")
try:
if any(
constraint["name"] == "uq_apikey_id" for constraint in api_key_constraints
):
if any(constraint["name"] == "uq_apikey_id" for constraint in api_key_constraints):
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.drop_constraint("uq_user_id", type_="unique")
if any(constraint["name"] == "uq_flow_id" for constraint in flow_constraints):
with op.batch_alter_table("flow", schema=None) as batch_op:
batch_op.drop_constraint("uq_flow_id", type_="unique")
if any(constraint["name"] == "uq_user_id" for constraint in user_constraints):
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.drop_constraint("uq_apikey_id", type_="unique")
except Exception as e:

View file

@ -0,0 +1,65 @@
"""Replace Credential table with Variable
Revision ID: 1a110b568907
Revises: 63b9c451fd30
Create Date: 2024-03-25 09:40:02.743453
"""
from typing import Sequence, Union
import sqlalchemy as sa
import sqlmodel
from alembic import op
from sqlalchemy.engine.reflection import Inspector
# revision identifiers, used by Alembic.
revision: str = "1a110b568907"
down_revision: Union[str, None] = "63b9c451fd30"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore
table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ###
if "variable" not in table_names:
op.create_table(
"variable",
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("type", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_variable_user_id"),
sa.PrimaryKeyConstraint("id"),
)
if "credential" in table_names:
op.drop_table("credential")
# ### end Alembic commands ###
def downgrade() -> None:
conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore
table_names = inspector.get_table_names()
# ### commands auto generated by Alembic - please adjust! ###
if "credential" not in table_names:
op.create_table(
"credential",
sa.Column("name", sa.VARCHAR(), nullable=True),
sa.Column("value", sa.VARCHAR(), nullable=True),
sa.Column("provider", sa.VARCHAR(), nullable=True),
sa.Column("user_id", sa.CHAR(length=32), nullable=False),
sa.Column("id", sa.CHAR(length=32), nullable=False),
sa.Column("created_at", sa.DATETIME(), nullable=False),
sa.Column("updated_at", sa.DATETIME(), nullable=True),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_credential_user_id"),
sa.PrimaryKeyConstraint("id"),
)
if "variable" in table_names:
op.drop_table("variable")
# ### end Alembic commands ###

View file

@ -24,10 +24,8 @@ def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.alter_column(
"name", existing_type=sqlmodel.sql.sqltypes.AutoString(), nullable=True
)
except Exception as e:
batch_op.alter_column("name", existing_type=sqlmodel.sql.sqltypes.AutoString(), nullable=True)
except Exception:
pass
# ### end Alembic commands ###
@ -37,6 +35,6 @@ def downgrade() -> None:
try:
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=False)
except Exception as e:
except Exception:
pass
# ### end Alembic commands ###

View file

@ -31,23 +31,16 @@ def upgrade() -> None:
# and other related indices
if "flowstyle" in existing_tables:
op.drop_table("flowstyle")
if "ix_flowstyle_flow_id" in [
index["name"] for index in inspector.get_indexes("flowstyle")
]:
op.drop_index(
"ix_flowstyle_flow_id", table_name="flowstyle", if_exists=True
)
if "ix_flowstyle_flow_id" in [index["name"] for index in inspector.get_indexes("flowstyle")]:
op.drop_index("ix_flowstyle_flow_id", table_name="flowstyle", if_exists=True)
existing_indices_flow = []
existing_fks_flow = []
if "flow" in existing_tables:
existing_indices_flow = [
index["name"] for index in inspector.get_indexes("flow")
]
existing_indices_flow = [index["name"] for index in inspector.get_indexes("flow")]
# Existing foreign keys for the 'flow' table, if it exists
existing_fks_flow = [
fk["referred_table"] + "." + fk["referred_columns"][0]
for fk in inspector.get_foreign_keys("flow")
fk["referred_table"] + "." + fk["referred_columns"][0] for fk in inspector.get_foreign_keys("flow")
]
# Now check if the columns user_id exists in the 'flow' table
# If it does not exist, we need to create the foreign key
@ -67,9 +60,7 @@ def upgrade() -> None:
sa.UniqueConstraint("id", name="uq_user_id"),
)
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.create_index(
batch_op.f("ix_user_username"), ["username"], unique=True
)
batch_op.create_index(batch_op.f("ix_user_username"), ["username"], unique=True)
if "apikey" not in existing_tables:
op.create_table(
@ -82,20 +73,14 @@ def upgrade() -> None:
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("api_key", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.ForeignKeyConstraint(
["user_id"], ["user.id"], name="fk_apikey_user_id_user"
),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_apikey_user_id_user"),
sa.PrimaryKeyConstraint("id", name="pk_apikey"),
sa.UniqueConstraint("id", name="uq_apikey_id"),
)
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.create_index(
batch_op.f("ix_apikey_api_key"), ["api_key"], unique=True
)
batch_op.create_index(batch_op.f("ix_apikey_api_key"), ["api_key"], unique=True)
batch_op.create_index(batch_op.f("ix_apikey_name"), ["name"], unique=False)
batch_op.create_index(
batch_op.f("ix_apikey_user_id"), ["user_id"], unique=False
)
batch_op.create_index(batch_op.f("ix_apikey_user_id"), ["user_id"], unique=False)
if "flow" not in existing_tables:
op.create_table(
"flow",
@ -104,9 +89,7 @@ def upgrade() -> None:
sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.ForeignKeyConstraint(
["user_id"], ["user.id"], name="fk_flow_user_id_user"
),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="fk_flow_user_id_user"),
sa.PrimaryKeyConstraint("id", name="pk_flow"),
sa.UniqueConstraint("id", name="uq_flow_id"),
)
@ -129,16 +112,12 @@ def upgrade() -> None:
if "user.id" not in existing_fks_flow:
batch_op.create_foreign_key("fk_flow_user_id", "user", ["user_id"], ["id"])
if "ix_flow_description" not in existing_indices_flow:
batch_op.create_index(
batch_op.f("ix_flow_description"), ["description"], unique=False
)
batch_op.create_index(batch_op.f("ix_flow_description"), ["description"], unique=False)
if "ix_flow_name" not in existing_indices_flow:
batch_op.create_index(batch_op.f("ix_flow_name"), ["name"], unique=False)
with op.batch_alter_table("flow", schema=None) as batch_op:
if "ix_flow_user_id" not in existing_indices_flow:
batch_op.create_index(
batch_op.f("ix_flow_user_id"), ["user_id"], unique=False
)
batch_op.create_index(batch_op.f("ix_flow_user_id"), ["user_id"], unique=False)
# ### end Alembic commands ###
@ -169,10 +148,4 @@ def downgrade() -> None:
batch_op.drop_index(batch_op.f("ix_user_username"), if_exists=True)
op.drop_table("user")
if "flowstyle" in existing_tables:
op.drop_table("flowstyle")
if "component" in existing_tables:
op.drop_table("component")
# ### end Alembic commands ###

View file

@ -31,9 +31,7 @@ def upgrade() -> None:
"credential",
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("value", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column(
"provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True
),
sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),

View file

@ -23,20 +23,14 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore
table_names = inspector.get_table_names()
table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("flow")]
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("flow", schema=None) as batch_op:
if "icon" not in column_names:
batch_op.add_column(
sa.Column("icon", sqlmodel.sql.sqltypes.AutoString(), nullable=True)
)
batch_op.add_column(sa.Column("icon", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
if "icon_bg_color" not in column_names:
batch_op.add_column(
sa.Column(
"icon_bg_color", sqlmodel.sql.sqltypes.AutoString(), nullable=True
)
)
batch_op.add_column(sa.Column("icon_bg_color", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
# ### end Alembic commands ###
@ -44,7 +38,7 @@ def upgrade() -> None:
def downgrade() -> None:
conn = op.get_bind()
inspector = Inspector.from_engine(conn) # type: ignore
table_names = inspector.get_table_names()
table_names = inspector.get_table_names() # noqa
column_names = [column["name"] for column in inspector.get_columns("flow")]
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table("flow", schema=None) as batch_op:

View file

@ -29,18 +29,14 @@ def upgrade() -> None:
try:
if "is_component" not in flow_columns:
with op.batch_alter_table("flow", schema=None) as batch_op:
batch_op.add_column(
sa.Column("is_component", sa.Boolean(), nullable=True)
)
except Exception as e:
batch_op.add_column(sa.Column("is_component", sa.Boolean(), nullable=True))
except Exception:
pass
try:
if "store_api_key" not in user_columns:
with op.batch_alter_table("user", schema=None) as batch_op:
batch_op.add_column(
sa.Column("store_api_key", sqlmodel.AutoString(), nullable=True)
)
except Exception as e:
batch_op.add_column(sa.Column("store_api_key", sqlmodel.AutoString(), nullable=True))
except Exception:
pass
# ### end Alembic commands ###

View file

@ -30,9 +30,7 @@ def upgrade() -> None:
try:
if "name" in api_key_columns:
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.alter_column(
"name", existing_type=sa.VARCHAR(), nullable=False
)
batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=False)
except Exception as e:
print(e)
@ -40,15 +38,9 @@ def upgrade() -> None:
try:
with op.batch_alter_table("flow", schema=None) as batch_op:
if "updated_at" not in flow_columns:
batch_op.add_column(
sa.Column("updated_at", sa.DateTime(), nullable=True)
)
batch_op.add_column(sa.Column("updated_at", sa.DateTime(), nullable=True))
if "folder" not in flow_columns:
batch_op.add_column(
sa.Column(
"folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True
)
)
batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
except Exception as e:
print(e)
@ -68,7 +60,6 @@ def downgrade() -> None:
pass
try:
with op.batch_alter_table("apikey", schema=None) as batch_op:
batch_op.alter_column("name", existing_type=sa.VARCHAR(), nullable=True)
except Exception as e:

View file

@ -32,33 +32,19 @@ def upgrade() -> None:
with op.batch_alter_table("flow", schema=None) as batch_op:
flow_columns = [column["name"] for column in inspector.get_columns("flow")]
if "is_component" not in flow_columns:
batch_op.add_column(
sa.Column("is_component", sa.Boolean(), nullable=True)
)
batch_op.add_column(sa.Column("is_component", sa.Boolean(), nullable=True))
if "updated_at" not in flow_columns:
batch_op.add_column(
sa.Column("updated_at", sa.DateTime(), nullable=True)
)
batch_op.add_column(sa.Column("updated_at", sa.DateTime(), nullable=True))
if "folder" not in flow_columns:
batch_op.add_column(
sa.Column(
"folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True
)
)
batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
if "user_id" not in flow_columns:
batch_op.add_column(
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)
)
batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True))
indices = inspector.get_indexes("flow")
indices_names = [index["name"] for index in indices]
if "ix_flow_user_id" not in indices_names:
batch_op.create_index(
batch_op.f("ix_flow_user_id"), ["user_id"], unique=False
)
batch_op.create_index(batch_op.f("ix_flow_user_id"), ["user_id"], unique=False)
if "fk_flow_user_id_user" not in indices_names:
batch_op.create_foreign_key(
"fk_flow_user_id_user", "user", ["user_id"], ["id"]
)
batch_op.create_foreign_key("fk_flow_user_id_user", "user", ["user_id"], ["id"])
except Exception:
pass

View file

@ -33,21 +33,13 @@ def upgrade() -> None:
if "updated_at" not in flow_columns:
batch_op.add_column(sa.Column("updated_at", sa.DateTime(), nullable=True))
if "folder" not in flow_columns:
batch_op.add_column(
sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True)
)
batch_op.add_column(sa.Column("folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True))
if "user_id" not in flow_columns:
batch_op.add_column(
sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)
)
batch_op.add_column(sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True))
if "ix_flow_user_id" not in flow_indexes:
batch_op.create_index(
batch_op.f("ix_flow_user_id"), ["user_id"], unique=False
)
batch_op.create_index(batch_op.f("ix_flow_user_id"), ["user_id"], unique=False)
if "flow_user_id_fkey" not in flow_fks:
batch_op.create_foreign_key(
"flow_user_id_fkey", "user", ["user_id"], ["id"]
)
batch_op.create_foreign_key("flow_user_id_fkey", "user", ["user_id"], ["id"])
def downgrade() -> None:

View file

@ -19,7 +19,7 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
connection = op.get_bind()
connection = op.get_bind() # noqa
pass
# ### end Alembic commands ###

View file

@ -22,9 +22,7 @@ def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("flow", schema=None) as batch_op:
batch_op.alter_column(
"user_id", existing_type=sa.CHAR(length=32), nullable=True
)
batch_op.alter_column("user_id", existing_type=sa.CHAR(length=32), nullable=True)
except Exception as e:
print(e)
pass
@ -36,9 +34,7 @@ def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("flow", schema=None) as batch_op:
batch_op.alter_column(
"user_id", existing_type=sa.CHAR(length=32), nullable=False
)
batch_op.alter_column("user_id", existing_type=sa.CHAR(length=32), nullable=False)
except Exception as e:
print(e)
pass

View file

@ -31,9 +31,7 @@ def upgrade() -> None:
try:
if "credential" in tables and "fk_credential_user_id" not in foreign_keys_names:
with op.batch_alter_table("credential", schema=None) as batch_op:
batch_op.create_foreign_key(
"fk_credential_user_id", "user", ["user_id"], ["id"]
)
batch_op.create_foreign_key("fk_credential_user_id", "user", ["user_id"], ["id"])
except Exception as e:
print(e)
pass

View file

@ -8,20 +8,10 @@ from langflow.api.v1.schemas import ApiKeyCreateRequest, ApiKeysResponse
from langflow.services.auth import utils as auth_utils
# Assuming you have these methods in your service layer
from langflow.services.database.models.api_key.crud import (
create_api_key,
delete_api_key,
get_api_keys,
)
from langflow.services.database.models.api_key.model import (
ApiKeyCreate,
UnmaskedApiKeyRead,
)
from langflow.services.database.models.api_key.crud import create_api_key, delete_api_key, get_api_keys
from langflow.services.database.models.api_key.model import ApiKeyCreate, UnmaskedApiKeyRead
from langflow.services.database.models.user.model import User
from langflow.services.deps import (
get_session,
get_settings_service,
)
from langflow.services.deps import get_session, get_settings_service
if TYPE_CHECKING:
pass

View file

@ -1,18 +1,13 @@
import time
import uuid
from functools import partial
from typing import TYPE_CHECKING, Annotated, Optional
from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException
from fastapi.responses import StreamingResponse
from loguru import logger
from langflow.api.utils import (
build_and_cache_graph,
format_elapsed_time,
format_exception_message,
get_next_runnable_vertices,
get_top_level_vertices,
)
from langflow.api.utils import build_and_cache_graph, format_elapsed_time, format_exception_message
from langflow.api.v1.schemas import (
InputValueRequest,
ResultDataResponse,
@ -56,7 +51,22 @@ async def get_vertices(
chat_service: "ChatService" = Depends(get_chat_service),
session=Depends(get_session),
):
"""Check the flow_id is in the flow_data_store."""
"""
Retrieve the vertices order for a given flow.
Args:
flow_id (str): The ID of the flow.
stop_component_id (str, optional): The ID of the stop component. Defaults to None.
start_component_id (str, optional): The ID of the start component. Defaults to None.
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
session (Session, optional): The session dependency. Defaults to Depends(get_session).
Returns:
VerticesOrderResponse: The response containing the ordered vertex IDs and the run ID.
Raises:
HTTPException: If there is an error checking the build status.
"""
try:
# First, we need to check if the flow_id is in the cache
graph = None
@ -65,19 +75,25 @@ async def get_vertices(
graph = await build_and_cache_graph(flow_id, session, chat_service, graph)
if stop_component_id or start_component_id:
try:
vertices = graph.sort_vertices(stop_component_id, start_component_id)
first_layer = graph.sort_vertices(stop_component_id, start_component_id)
except Exception as exc:
logger.error(exc)
vertices = graph.sort_vertices()
first_layer = graph.sort_vertices()
else:
vertices = graph.sort_vertices()
first_layer = graph.sort_vertices()
# When we send vertices to the frontend
# we need to remove them from the predecessors
# so they are not considered for building again
# which duplicates the results
for vertex_id in first_layer:
graph.remove_from_predecessors(vertex_id)
# Now vertices is a list of lists
# We need to get the id of each vertex
# and return the same structure but only with the ids
run_id = uuid.uuid4()
graph.set_run_id(run_id)
return VerticesOrderResponse(ids=vertices, run_id=run_id)
return VerticesOrderResponse(ids=first_layer, run_id=run_id, vertices_to_run=list(graph.vertices_to_run))
except Exception as exc:
logger.error(f"Error checking build status: {exc}")
@ -94,7 +110,23 @@ async def build_vertex(
chat_service: "ChatService" = Depends(get_chat_service),
current_user=Depends(get_current_active_user),
):
"""Build a vertex instead of the entire graph."""
"""Build a vertex instead of the entire graph.
Args:
flow_id (str): The ID of the flow.
vertex_id (str): The ID of the vertex to build.
background_tasks (BackgroundTasks): The background tasks object for logging.
inputs (Optional[InputValueRequest], optional): The input values for the vertex. Defaults to None.
chat_service (ChatService, optional): The chat service dependency. Defaults to Depends(get_chat_service).
current_user (Any, optional): The current user dependency. Defaults to Depends(get_current_active_user).
Returns:
VertexBuildResponse: The response containing the built vertex information.
Raises:
HTTPException: If there is an error building the vertex.
"""
start_time = time.perf_counter()
next_runnable_vertices = []
@ -110,23 +142,25 @@ async def build_vertex(
graph = cache.get("result")
result_data_response = ResultDataResponse(results={})
duration = ""
vertex = graph.get_vertex(vertex_id)
try:
if not vertex.frozen or not vertex._built:
inputs_dict = inputs.model_dump() if inputs else {}
await vertex.build(user_id=current_user.id, inputs=inputs_dict)
if vertex.result is not None:
params = vertex._built_object_repr()
valid = True
result_dict = vertex.result
artifacts = vertex.artifacts
else:
raise ValueError(f"No result found for vertex {vertex_id}")
next_runnable_vertices = await get_next_runnable_vertices(graph, vertex, vertex_id, chat_service, flow_id)
top_level_vertices = get_top_level_vertices(graph, next_runnable_vertices)
lock = chat_service._cache_locks[flow_id]
set_cache_coro = partial(chat_service.set_cache, flow_id=flow_id)
(
next_runnable_vertices,
top_level_vertices,
result_dict,
params,
valid,
artifacts,
vertex,
) = await graph.build_vertex(
lock=lock,
set_cache_coro=set_cache_coro,
vertex_id=vertex_id,
user_id=current_user.id,
inputs_dict=inputs.model_dump() if inputs else {},
)
result_data_response = ResultDataResponse(**result_dict.model_dump())
except Exception as exc:
@ -185,9 +219,6 @@ async def build_vertex(
raise HTTPException(status_code=500, detail=str(exc)) from exc
# Now onto an endpoint that is an SSE endpoint
# it will receive a component_id and a flow_id
#
@router.get("/build/{flow_id}/{vertex_id}/stream", response_class=StreamingResponse)
async def build_vertex_stream(
flow_id: str,
@ -196,7 +227,31 @@ async def build_vertex_stream(
chat_service: "ChatService" = Depends(get_chat_service),
session_service: "SessionService" = Depends(get_session_service),
):
"""Build a vertex instead of the entire graph."""
"""Build a vertex instead of the entire graph.
This function is responsible for building a single vertex instead of the entire graph.
It takes the `flow_id` and `vertex_id` as required parameters, and an optional `session_id`.
It also depends on the `ChatService` and `SessionService` services.
If `session_id` is not provided, it retrieves the graph from the cache using the `chat_service`.
If `session_id` is provided, it loads the session data using the `session_service`.
Once the graph is obtained, it retrieves the specified vertex using the `vertex_id`.
If the vertex does not support streaming, an error is raised.
If the vertex has a built result, it sends the result as a chunk.
If the vertex is not frozen or not built, it streams the vertex data.
If the vertex has a result, it sends the result as a chunk.
If none of the above conditions are met, an error is raised.
If any exception occurs during the process, an error message is sent.
Finally, the stream is closed.
Returns:
A `StreamingResponse` object with the streamed vertex data in text/event-stream format.
Raises:
HTTPException: If an error occurs while building the vertex.
"""
try:
async def stream_vertex():

View file

@ -17,6 +17,7 @@ from langflow.api.v1.schemas import (
UpdateCustomComponentRequest,
UploadFileResponse,
)
from langflow.graph.graph.base import Graph
from langflow.graph.schema import RunOutputs
from langflow.interface.custom.custom_component import CustomComponent
from langflow.interface.custom.directory_reader import DirectoryReader
@ -53,7 +54,7 @@ def get_all(
async def run_flow_with_caching(
session: Annotated[Session, Depends(get_session)],
flow_id: str,
inputs: Optional[List[InputValueRequest]] = [],
inputs: Optional[List[InputValueRequest]] = [InputValueRequest(components=[], input_value="")],
outputs: Optional[List[str]] = [],
tweaks: Annotated[Optional[Tweaks], Body(embed=True)] = None, # noqa: F821
stream: Annotated[bool, Body(embed=True)] = False, # noqa: F821
@ -102,23 +103,13 @@ async def run_flow_with_caching(
if outputs is None:
outputs = []
task_result: List[RunOutputs] = []
artifacts = {}
if session_id:
session_data = await session_service.load_session(session_id, flow_id=flow_id)
graph, artifacts = session_data if session_data else (None, None)
task_result: List[RunOutputs] = []
if not graph:
raise ValueError("Graph not found in the session")
task_result, session_id = await run_graph(
graph=graph,
flow_id=flow_id,
session_id=session_id,
inputs=inputs,
outputs=outputs,
artifacts=artifacts,
session_service=session_service,
stream=stream,
)
if graph is None:
raise ValueError(f"Session {session_id} not found")
else:
# Get the flow that matches the flow_id and belongs to the user
# flow = session.query(Flow).filter(Flow.id == flow_id).filter(Flow.user_id == api_key_user.id).first()
@ -130,28 +121,38 @@ async def run_flow_with_caching(
raise ValueError(f"Flow {flow_id} has no data")
graph_data = flow.data
graph_data = process_tweaks(graph_data, tweaks or {})
task_result, session_id = await run_graph(
graph=graph_data,
flow_id=flow_id,
session_id=session_id,
inputs=inputs,
outputs=outputs,
artifacts={},
session_service=session_service,
stream=stream,
)
graph = Graph.from_payload(graph_data, flow_id=flow_id)
task_result, session_id = await run_graph(
graph=graph,
flow_id=flow_id,
session_id=session_id,
inputs=inputs,
outputs=outputs,
artifacts=artifacts,
session_service=session_service,
stream=stream,
)
return RunResponse(outputs=task_result, session_id=session_id)
except sa.exc.StatementError as exc:
# StatementError('(builtins.ValueError) badly formed hexadecimal UUID string')
if "badly formed hexadecimal UUID string" in str(exc):
logger.error(f"Flow ID {flow_id} is not a valid UUID")
# This means the Flow ID is not a valid UUID which means it can't find the flow
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
except ValueError as exc:
if f"Flow {flow_id} not found" in str(exc):
logger.error(f"Flow {flow_id} not found")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
elif f"Session {session_id} not found" in str(exc):
logger.error(f"Session {session_id} not found")
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
else:
logger.exception(exc)
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
except Exception as exc:
logger.exception(exc)
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
@router.post(
@ -238,7 +239,7 @@ async def create_upload_file(
# get endpoint to return version of langflow
@router.get("/version")
def get_version():
from langflow import __version__
from langflow.version import __version__
return {"version": __version__}
@ -309,4 +310,5 @@ async def custom_component_update(
return component_node
except Exception as exc:
logger.exception(exc)
raise HTTPException(status_code=400, detail=str(exc)) from exc

View file

@ -4,6 +4,8 @@ from io import BytesIO
from fastapi import APIRouter, Depends, HTTPException, UploadFile
from fastapi.responses import StreamingResponse
from langflow.api.v1.schemas import UploadFileResponse
from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models.flow import Flow

View file

@ -12,12 +12,7 @@ from langflow.api.utils import remove_api_keys, validate_is_component
from langflow.api.v1.schemas import FlowListCreate, FlowListRead
from langflow.initial_setup.setup import STARTER_FOLDER_NAME
from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models.flow import (
Flow,
FlowCreate,
FlowRead,
FlowUpdate,
)
from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate
from langflow.services.database.models.user.model import User
from langflow.services.deps import get_session, get_settings_service
from langflow.services.settings.service import SettingsService

View file

@ -10,6 +10,7 @@ from langflow.services.auth.utils import (
create_user_tokens,
)
from langflow.services.deps import get_session, get_settings_service
from langflow.services.settings.manager import SettingsService
router = APIRouter(tags=["Login"])
@ -41,7 +42,7 @@ async def login_to_get_access_token(
httponly=auth_settings.REFRESH_HTTPONLY,
samesite=auth_settings.REFRESH_SAME_SITE,
secure=auth_settings.REFRESH_SECURE,
expires=auth_settings.REFRESH_TOKEN_EXPIRE_MINUTES * 60,
expires=auth_settings.REFRESH_TOKEN_EXPIRE_SECONDS,
)
response.set_cookie(
"access_token_lf",
@ -49,7 +50,7 @@ async def login_to_get_access_token(
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=auth_settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
expires=auth_settings.ACCESS_TOKEN_EXPIRE_SECONDS,
)
return tokens
else:
@ -75,7 +76,7 @@ async def auto_login(
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=auth_settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
expires=None, # Set to None to make it a session cookie
)
return tokens
@ -89,7 +90,9 @@ async def auto_login(
@router.post("/refresh")
async def refresh_token(request: Request, response: Response, settings_service=Depends(get_settings_service)):
async def refresh_token(
request: Request, response: Response, settings_service: "SettingsService" = Depends(get_settings_service)
):
auth_settings = settings_service.auth_settings
token = request.cookies.get("refresh_token_lf")
@ -102,7 +105,7 @@ async def refresh_token(request: Request, response: Response, settings_service=D
httponly=auth_settings.REFRESH_HTTPONLY,
samesite=auth_settings.REFRESH_SAME_SITE,
secure=auth_settings.REFRESH_SECURE,
expires=auth_settings.REFRESH_TOKEN_EXPIRE_MINUTES * 60,
expires=auth_settings.REFRESH_TOKEN_EXPIRE_SECONDS,
)
response.set_cookie(
"access_token_lf",
@ -110,7 +113,7 @@ async def refresh_token(request: Request, response: Response, settings_service=D
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=auth_settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
expires=auth_settings.ACCESS_TOKEN_EXPIRE_SECONDS,
)
return tokens
else:

View file

@ -1,6 +1,8 @@
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from langflow.services.deps import get_monitor_service
from langflow.services.monitor.schema import VertexBuildMapModel
from langflow.services.monitor.service import MonitorService

View file

@ -1,17 +1,10 @@
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Literal, Optional, Union
from uuid import UUID
from pydantic import (
BaseModel,
ConfigDict,
Field,
RootModel,
field_validator,
model_serializer,
)
from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator, model_serializer
from langflow.graph.schema import RunOutputs
from langflow.schema import dotdict
@ -61,18 +54,19 @@ class RunResponse(BaseModel):
outputs: Optional[List[RunOutputs]] = []
session_id: Optional[str] = None
@model_serializer(mode="wrap")
def serialize(self, handler):
@model_serializer(mode="plain")
def serialize(self):
# Serialize all the outputs if they are base models
serialized = {"session_id": self.session_id, "outputs": []}
if self.outputs:
serialized_outputs = []
for output in self.outputs:
if isinstance(output, BaseModel):
if isinstance(output, BaseModel) and not isinstance(output, RunOutputs):
serialized_outputs.append(output.model_dump(exclude_none=True))
else:
serialized_outputs.append(output)
self.outputs = serialized_outputs
return handler(self)
serialized["outputs"] = serialized_outputs
return serialized
class PreloadResponse(BaseModel):
@ -234,6 +228,7 @@ class ApiKeyCreateRequest(BaseModel):
class VerticesOrderResponse(BaseModel):
ids: List[str]
run_id: UUID
vertices_to_run: List[str]
class ResultDataResponse(BaseModel):
@ -264,10 +259,14 @@ class VerticesBuiltResponse(BaseModel):
class InputValueRequest(BaseModel):
components: Optional[List[str]] = []
input_value: Optional[str] = None
type: Optional[Literal["chat", "text", "json", "any"]] = Field(
"any",
description="Defines on which components the input value should be applied. 'any' applies to all input components.",
)
# add an example
model_config = {
"json_schema_extra": {
model_config = ConfigDict(
json_schema_extra={
"examples": [
{
"components": ["components_id", "Component Name"],
@ -275,9 +274,12 @@ class InputValueRequest(BaseModel):
},
{"components": ["Component Name"], "input_value": "input_value"},
{"input_value": "input_value"},
{"type": "chat", "input_value": "input_value"},
{"type": "json", "input_value": '{"key": "value"}'},
]
}
}
},
extra="forbid",
)
class Tweaks(RootModel):

View file

@ -3,12 +3,7 @@ from collections import defaultdict
from fastapi import APIRouter, HTTPException
from loguru import logger
from langflow.api.v1.base import (
Code,
CodeValidationResponse,
PromptValidationResponse,
ValidatePromptRequest,
)
from langflow.api.v1.base import Code, CodeValidationResponse, PromptValidationResponse, ValidatePromptRequest
from langflow.base.prompts.utils import (
add_new_variables_to_template,
get_old_custom_fields,

View file

@ -0,0 +1,69 @@
from typing import List, Union
from langchain.agents import AgentExecutor, BaseMultiActionAgent, BaseSingleActionAgent
from langflow.field_typing import BaseMemory, Text, Tool
from langflow.interface.custom.custom_component import CustomComponent
class LCAgentComponent(CustomComponent):
def build_config(self):
return {
"lc": {
"display_name": "LangChain",
"info": "The LangChain to interact with.",
},
"handle_parsing_errors": {
"display_name": "Handle Parsing Errors",
"info": "If True, the agent will handle parsing errors. If False, the agent will raise an error.",
"advanced": True,
},
"output_key": {
"display_name": "Output Key",
"info": "The key to use to get the output from the agent.",
"advanced": True,
},
"memory": {
"display_name": "Memory",
"info": "Memory to use for the agent.",
},
"tools": {
"display_name": "Tools",
"info": "Tools the agent can use.",
},
"input_value": {
"display_name": "Input",
"info": "Input text to pass to the agent.",
},
}
async def run_agent(
self,
agent: Union[BaseSingleActionAgent, BaseMultiActionAgent, AgentExecutor],
inputs: str,
input_variables: list[str],
tools: List[Tool],
memory: BaseMemory = None,
handle_parsing_errors: bool = True,
output_key: str = "output",
) -> Text:
if isinstance(agent, AgentExecutor):
runnable = agent
else:
runnable = AgentExecutor.from_agent_and_tools(
agent=agent, tools=tools, verbose=True, memory=memory, handle_parsing_errors=handle_parsing_errors
)
input_dict = {"input": inputs}
for var in input_variables:
if var not in ["agent_scratchpad", "input"]:
input_dict[var] = ""
result = await runnable.ainvoke(input_dict)
self.status = result
if output_key in result:
return result.get(output_key)
elif "output" not in result:
if output_key != "output":
raise ValueError(f"Output key not found in result. Tried '{output_key}' and 'output'.")
else:
raise ValueError("Output key not found in result. Tried 'output'.")
return result.get("output")

View file

@ -1,8 +1,8 @@
import warnings
from typing import Optional, Union
from langflow import CustomComponent
from langflow.field_typing import Text
from langflow.interface.custom.custom_component import CustomComponent
from langflow.memory import add_messages
from langflow.schema import Record

View file

@ -1,7 +1,7 @@
from typing import Optional
from langflow import CustomComponent
from langflow.field_typing import Text
from langflow.interface.custom.custom_component import CustomComponent
class TextComponent(CustomComponent):

View file

@ -0,0 +1,48 @@
from typing import Optional
from langchain_core.language_models.chat_models import BaseChatModel
from langchain_core.language_models.llms import LLM
from langchain_core.messages import HumanMessage, SystemMessage
from langflow.interface.custom.custom_component import CustomComponent
class LCModelComponent(CustomComponent):
display_name: str = "Model Name"
description: str = "Model Description"
def get_result(self, runnable: LLM, stream: bool, input_value: str):
"""
Retrieves the result from the output of a Runnable object.
Args:
output (Runnable): The output object to retrieve the result from.
stream (bool): Indicates whether to use streaming or invocation mode.
input_value (str): The input value to pass to the output object.
Returns:
The result obtained from the output object.
"""
if stream:
result = runnable.stream(input_value)
else:
message = runnable.invoke(input_value)
result = message.content if hasattr(message, "content") else message
self.status = result
return result
def get_chat_result(
self, runnable: BaseChatModel, stream: bool, input_value: str, system_message: Optional[str] = None
):
messages = []
if system_message:
messages.append(SystemMessage(system_message))
if input_value:
messages.append(HumanMessage(input_value))
if stream:
result = runnable.stream(messages)
else:
message = runnable.invoke(messages)
result = message.content
self.status = result
return result

View file

@ -1,8 +1,9 @@
from typing import Callable, List, Optional, Union
from langchain.agents import AgentExecutor, AgentType, initialize_agent, types
from langflow import CustomComponent
from langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool
from langflow.interface.custom.custom_component import CustomComponent
class AgentInitializerComponent(CustomComponent):

View file

@ -0,0 +1,34 @@
from langchain_experimental.agents.agent_toolkits.csv.base import create_csv_agent
from langflow.custom import CustomComponent
from langflow.field_typing import AgentExecutor, BaseLanguageModel
class CSVAgentComponent(CustomComponent):
display_name = "CSVAgent"
description = "Construct a CSV agent from a CSV and tools."
documentation = "https://python.langchain.com/docs/modules/agents/toolkits/csv"
def build_config(self):
return {
"llm": {"display_name": "LLM", "type": BaseLanguageModel},
"path": {"display_name": "Path", "field_type": "file", "suffixes": [".csv"], "file_types": [".csv"]},
"handle_parsing_errors": {"display_name": "Handle Parse Errors", "advanced": True},
"agent_type": {
"display_name": "Agent Type",
"options": ["zero-shot-react-description", "openai-functions", "openai-tools"],
"advanced": True,
},
}
def build(
self, llm: BaseLanguageModel, path: str, handle_parsing_errors: bool = True, agent_type: str = "openai-tools"
) -> AgentExecutor:
# Instantiate and return the CSV agent class with the provided llm and path
return create_csv_agent(
llm=llm,
path=path,
agent_type=agent_type,
verbose=True,
agent_executor_kwargs=dict(handle_parsing_errors=handle_parsing_errors),
)

View file

@ -1,9 +1,10 @@
from langflow import CustomComponent
from langchain.agents import AgentExecutor, create_json_agent
from langchain_community.agent_toolkits.json.toolkit import JsonToolkit
from langflow.field_typing import (
BaseLanguageModel,
)
from langchain_community.agent_toolkits.json.toolkit import JsonToolkit
from langflow.interface.custom.custom_component import CustomComponent
class JsonAgentComponent(CustomComponent):

View file

@ -9,8 +9,9 @@ from langchain.prompts.chat import MessagesPlaceholder
from langchain.schema.memory import BaseMemory
from langchain.tools import Tool
from langchain_community.chat_models import ChatOpenAI
from langflow import CustomComponent
from langflow.field_typing.range_spec import RangeSpec
from langflow.interface.custom.custom_component import CustomComponent
class ConversationalAgent(CustomComponent):

View file

@ -1,10 +1,12 @@
from langflow import CustomComponent
from typing import Union, Callable
from typing import Callable, Union
from langchain.agents import AgentExecutor
from langflow.field_typing import BaseLanguageModel
from langchain_community.agent_toolkits.sql.base import create_sql_agent
from langchain.sql_database import SQLDatabase
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain_community.agent_toolkits.sql.base import create_sql_agent
from langflow.field_typing import BaseLanguageModel
from langflow.interface.custom.custom_component import CustomComponent
class SQLAgentComponent(CustomComponent):

Some files were not shown because too many files have changed in this diff Show more