diff --git a/docs/docs/components/embeddings.mdx b/docs/docs/components/embeddings.mdx index 015ba1ce1..d4ad17542 100644 --- a/docs/docs/components/embeddings.mdx +++ b/docs/docs/components/embeddings.mdx @@ -98,9 +98,9 @@ Used to load [OpenAI’s](https://openai.com/) embedding models. Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) [Embeddings API](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings). -:::info + Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. -::: + - **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. - **location:** The default location to use when making API calls – defaults to `us-central1`. diff --git a/docs/docs/components/io.mdx b/docs/docs/components/io.mdx index e0b8fb87d..0ef93d684 100644 --- a/docs/docs/components/io.mdx +++ b/docs/docs/components/io.mdx @@ -1,9 +1,8 @@ - -import Admonition from '@theme/Admonition'; +import Admonition from "@theme/Admonition"; # I/O -## ChatInput +### ChatInput This component is designed to get user input from the chat. @@ -15,9 +14,7 @@ This component is designed to get user input from the chat. - **Message:** specifies the message text. It is a multiline text input. -- **Session ID:** specifies the session ID of the chat history. - -- **As Record:** if true, the message will be returned as a _`Record`_. Defaults to _`false`_. +- **Session ID:** specifies the session ID of the chat history. If provided, the message will be saved in the Message History.

@@ -25,7 +22,7 @@ This component is designed to get user input from the chat.

-## ChatOutput +### ChatOutput This component is designed to send a message to the chat. @@ -35,65 +32,21 @@ This component is designed to send a message to the chat. - **Sender Name:** specifies the name of the sender. Defaults to _`"AI"`_. -- **Session ID:** specifies the session ID of the chat history. +- **Session ID:** specifies the session ID of the chat history. If provided, the message will be saved in the Message History. - **Message:** specifies the message text. -- **As Record:** if true, the message will be returned as a _`Record`_. Defaults to _`false`_. -

If _`As Record`_ is _`true`_ and the _`Message`_ is a _`Record`_, the data of the _`Record`_ will be updated with the _`Sender`_, _`Sender Name`_, and _`Session ID`_.

-## StoreMessages -This component is designed to store messages in a structured format. It can store messages provided directly as records or construct records from provided texts and metadata. +### TextInput -**Params** +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. -- **Records:** (Optional) Specifies the list of records to store. Each `Record` should contain the keys `'sender'`, `'sender_name'`, and `'session_id'`. If not provided, `texts` must be used along with `session_id`, `sender`, and `sender_name` to construct the records. - -- **Texts:** (Optional) Specifies the list of text messages to store. If `records` is not provided, `texts` must be provided along with `session_id`, `sender`, and `sender_name`. - -- **Session ID:** (Optional) Specifies the session ID associated with the messages. Required if `records` is not provided and `texts` are used. - -- **Sender:** (Optional) Specifies the identifier of the sender. Required if `records` is not provided and `texts` are used. - -- **Sender Name:** (Optional) Specifies the name of the sender. Required if `records` is not provided and `texts` are used. - - -

- The component prioritizes the use of `Records` for storing messages. If `Records` are not provided, it requires `Texts`, `Session ID`, `Sender`, and `Sender Name` to construct and store records. Ensure that either `Records` or the combination of `Texts`, `Session ID`, `Sender`, and `Sender Name` is provided. -

-
- -## MessageHistory - -This component is designed to retrieve stored messages based on various filters such as sender type, sender name, and session ID. It allows for a flexible retrieval of chat history, providing insights into past interactions. - -**Params** - -- **Sender Type:** (Optional) Specifies the type of the sender. Options are _`"Machine"`_ or _`"User"`_. Filters the messages by the type of sender. - -- **Sender Name:** (Optional) Specifies the name of the sender. Filters the messages by the name of the sender. - -- **Session ID:** (Optional) Specifies the session ID of the chat history. Filters the messages belonging to a specific session. - -- **Number of Messages:** Specifies the number of messages to retrieve. Defaults to _`5`_. Determines how many recent messages from the chat history to fetch. - - -

- The component retrieves messages based on the provided criteria. If no specific criteria are provided, it will return the most recent messages up to the specified limit. This component can be used to review past interactions and analyze the flow of conversations. - - -

-
- -## TextInput - -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 process flow. **Params** @@ -101,6 +54,20 @@ This component is designed for simple text input, allowing users to pass textual

- The `TextInput` component serves as a straightforward means for capturing user input. It ensures that textual data can be seamlessly integrated into the Langflow's component-based processing pipeline, fostering interactivity within automated workflows. + The `TextInput` component serves as a straightforward means for setting Text input values in the chat window. It ensures that textual data can be seamlessly passed to subsequent components in the flow.

+ +### TextOutput + +This component is designed to display text data to the user. It's particularly useful for scenarios where you don't want to send the text data to the chat, but still want to display it. + +**Params** + +- **Value:** Specifies the text data to be displayed. This is where the text data to be displayed is provided. If no value is provided, it defaults to an empty string. + + +

+ The `TextOutput` component serves as a straightforward means for displaying text data. It ensures that textual data can be seamlessly observed in the chat window throughout your flow. +

+
\ No newline at end of file diff --git a/docs/docs/components/llms.mdx b/docs/docs/components/llms.mdx index 088556d2f..d72364376 100644 --- a/docs/docs/components/llms.mdx +++ b/docs/docs/components/llms.mdx @@ -40,9 +40,10 @@ Wrapper around Anthropic's large language model used for chat-based interactions The `CTransformers` component provides access to the Transformer models implemented in C/C++ using the [GGML](https://github.com/ggerganov/ggml) library. -:::info + + Make sure to have the `ctransformers` python package installed. Learn more about installation, supported models, and usage [here](https://github.com/marella/ctransformers). -::: + **config:** Configuration for the Transformer models. Check out [config](https://github.com/marella/ctransformers#config). Defaults to: @@ -115,9 +116,9 @@ Wrapper around [Cohere's](https://cohere.com) large language models. Wrapper around [HuggingFace](https://www.huggingface.co/models) models. -:::info + The HuggingFace Hub is an online platform that hosts over 120k models, 20k datasets, and 50k demo apps, all of which are open-source and publicly available. Discover more at [HuggingFace](http://www.huggingface.co). -::: + - **huggingfacehub_api_token:** Token needed to authenticate the API. - **model_kwargs:** Keyword arguments to pass to the model. @@ -130,9 +131,9 @@ The HuggingFace Hub is an online platform that hosts over 120k models, 20k datas The `LlamaCpp` component provides access to the `llama.cpp` models. -:::info + Make sure to have the `llama.cpp` python package installed. Learn more about installation, supported models, and usage [here](https://github.com/ggerganov/llama.cpp). -::: + - **echo:** Whether to echo the prompt – defaults to `False`. - **f16_kv:** Use half-precision for key/value cache – defaults to `True`. @@ -181,9 +182,9 @@ Wrapper around [OpenAI's](https://openai.com) large language models. Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large language models. -:::info + Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. -::: + - **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. - **location:** The default location to use when making API calls – defaults to `us-central1`. @@ -203,9 +204,9 @@ Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large language models. -:::info + Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. -::: + - **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. - **location:** The default location to use when making API calls – defaults to `us-central1`. diff --git a/docs/docs/components/memories.mdx b/docs/docs/components/memories.mdx index 3bf9a957c..b92538134 100644 --- a/docs/docs/components/memories.mdx +++ b/docs/docs/components/memories.mdx @@ -12,6 +12,26 @@ Memory is a concept in chat-based applications that allows the system to remembe --- +### MessageHistory + +This component is designed to retrieve stored messages based on various filters such as sender type, sender name, session ID, and a specific file path where messages are stored. It allows for a flexible retrieval of chat history, providing insights into past interactions. + +**Params** + +- **Sender Type:** (Optional) Specifies the type of the sender. Options are _`"Machine"`_, _`"User"`_, or _`"Machine and User"`_. Filters the messages by the type of the sender. + +- **Sender Name:** (Optional) Specifies the name of the sender. Filters the messages by the name of the sender. + +- **Session ID:** (Optional) Specifies the session ID of the chat history. Filters the messages belonging to a specific session. + +- **Number of Messages:** Specifies the number of messages to retrieve. Defaults to _`5`_. Determines how many recent messages from the chat history to fetch. + + +

+ The component retrieves messages based on the provided criteria, including the specific file path for stored messages. If no specific criteria are provided, it will return the most recent messages up to the specified limit. This component can be used to review past interactions and analyze the flow of conversations. +

+
+ ### ConversationBufferMemory The `ConversationBufferMemory` component is a type of memory system that plainly stores the last few inputs and outputs of a conversation. @@ -27,7 +47,7 @@ The `ConversationBufferMemory` component is a type of memory system that plainly ### ConversationBufferWindowMemory -`ConversationBufferWindowMemory` is a variation of the `ConversationBufferMemory` that maintains a list of the recent interactions in a conversation. It only keeps the last K interactions in memory, which can be useful for maintaining a sliding window of the most recent interactions without letting the buffer get too large. +`ConversationBufferWindowMemory` is a variation of the `ConversationBufferMemory` that maintains a list of the recent interactions in a conversation. It only keeps the last K interactions in memory, which can be useful for maintaining a sliding window of the most recent interactions without letting the buffer get too large. **Params** @@ -72,7 +92,7 @@ The `ConversationEntityMemory` component incorporates intricate memory structure ### ConversationSummaryMemory -The `ConversationSummaryMemory` is a memory component that creates a summary of the conversation over time. It condenses information from the conversation and stores the current summary in memory. It is particularly useful for longer conversations where keeping the entire message history in the prompt would take up too many tokens. +The `ConversationSummaryMemory` is a memory component that creates a summary of the conversation over time. It condenses information from the conversation and stores the current summary in memory. It is particularly useful for longer conversations where keeping the entire message history in the prompt would take up too many tokens. **Params** diff --git a/docs/docs/components/tools.mdx b/docs/docs/components/tools.mdx index c92d6eee0..40fb2c5c2 100644 --- a/docs/docs/components/tools.mdx +++ b/docs/docs/components/tools.mdx @@ -9,6 +9,21 @@ import Admonition from '@theme/Admonition'; +### SearchApi + +Real-time search engine results API. Returns structured JSON data that includes answer box, knowledge graph, organic results, and more. + +**Parameters** + +- **Api Key:** A unique identifier for the SearchApi, necessary for authenticating requests to real-time search engines. This key can be retrieved from the [SearchApi dashboard](https://www.searchapi.io/). +- **Engine:** Specifies the search engine. For instance: google, google_scholar, bing, youtube, and youtube_transcripts. A full list of supported engines is available in the [documentation](https://www.searchapi.io/docs/google). +- **Parameters:** Allows the selection of any parameters recognized by SearchApi, with some being required and others optional. + +**Output** + +- **Document:** The JSON response from the request as a Document. + + ### BingSearchRun Bing Search is a web search engine owned and operated by Microsoft. It provides search results for various types of content, including web pages, images, videos, and news articles. It uses a combination of algorithms and human editors to deliver search results to users. @@ -60,4 +75,4 @@ Tool for getting metadata about a SQL database. The input to this tool is a comm **Params** -- **Db:** SQLDatabase to query. \ No newline at end of file +- **Db:** SQLDatabase to query. diff --git a/docs/docs/deployment/gcp-deployment.md b/docs/docs/deployment/gcp-deployment.md index 771550f24..032426d94 100644 --- a/docs/docs/deployment/gcp-deployment.md +++ b/docs/docs/deployment/gcp-deployment.md @@ -4,9 +4,8 @@ This guide will help you set up a Langflow development VM in a Google Cloud Platform project using Google Cloud Shell. -:::note -When Cloud Shell opens, be sure to select **Trust repo**. Some `gcloud` commands might not run in an ephemeral Cloud Shell environment. -::: +> Note: When Cloud Shell opens, be sure to select **Trust repo**. Some `gcloud` commands might not run in an ephemeral Cloud Shell environment. + ## Standard VM diff --git a/docs/docs/examples/buffer-memory.mdx b/docs/docs/examples/buffer-memory.mdx index 2b5b76586..3167081a5 100644 --- a/docs/docs/examples/buffer-memory.mdx +++ b/docs/docs/examples/buffer-memory.mdx @@ -14,6 +14,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/buffer-memory.png", + dark: "img/buffer-memory.png", }} /> diff --git a/docs/docs/examples/conversation-chain.mdx b/docs/docs/examples/conversation-chain.mdx index db3181881..1cd59ca55 100644 --- a/docs/docs/examples/conversation-chain.mdx +++ b/docs/docs/examples/conversation-chain.mdx @@ -20,6 +20,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/basic-chat.png", + dark: "img/basic-chat.png", }} /> diff --git a/docs/docs/examples/csv-loader.mdx b/docs/docs/examples/csv-loader.mdx index c59dfc1e7..351e99440 100644 --- a/docs/docs/examples/csv-loader.mdx +++ b/docs/docs/examples/csv-loader.mdx @@ -32,6 +32,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/csv-loader.png", + dark: "img/csv-loader.png", }} /> @@ -39,12 +40,12 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; -- [`CSVLoader`](https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/csv) +- [`CSVLoader`](https://python.langchain.com/docs/integrations/document_loaders/csv) - [`CharacterTextSplitter`](https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter) -- [`OpenAIEmbedding`](https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/openai) -- [`Chroma`](https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/chroma) +- [`OpenAIEmbedding`](https://python.langchain.com/docs/integrations/text_embedding/openai) +- [`Chroma`](https://python.langchain.com/docs/integrations/vectorstores/chroma) - [`VectorStoreInfo`](https://python.langchain.com/docs/modules/data_connection/vectorstores/) - [`OpenAI`](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai) -- [`VectorStoreAgent`](https://python.langchain.com/docs/modules/agents/toolkits/vectorstore) +- [`VectorStoreAgent`](https://js.langchain.com/docs/modules/agents/tools/how_to/agents_with_vectorstores) diff --git a/docs/docs/examples/flow-runner.mdx b/docs/docs/examples/flow-runner.mdx index c496cd745..e20dc39f7 100644 --- a/docs/docs/examples/flow-runner.mdx +++ b/docs/docs/examples/flow-runner.mdx @@ -14,6 +14,7 @@ The CustomComponent class allows us to create components that interact with Lang alt="Document Processor Component" sources={{ light: "img/flow_runner.png", + dark: "img/flow_runner.png", }} style={{ width: "30%", @@ -339,6 +340,7 @@ Done! This is what our script and custom component looks like: alt="Document Processor Code" sources={{ light: "img/flow_runner_code.png", + dark: "img/flow_runner_code.png", }} style={{ maxWidth: "100%", @@ -353,6 +355,7 @@ Done! This is what our script and custom component looks like: alt="Document Processor Component" sources={{ light: "img/flow_runner.png", + dark: "img/flow_runner.png", }} style={{ width: "40%", diff --git a/docs/docs/examples/how-upload-examples.mdx b/docs/docs/examples/how-upload-examples.mdx index 2b1a2b06c..4f54558eb 100644 --- a/docs/docs/examples/how-upload-examples.mdx +++ b/docs/docs/examples/how-upload-examples.mdx @@ -12,6 +12,7 @@ Langflow Examples is a repository on [GitHub](https://github.com/logspace-ai/lan alt="Docusaurus themed image" sources={{ light: "img/community-examples.png", + dark: "img/community-examples.png", }} style={{ width: "100%" }} /> diff --git a/docs/docs/examples/midjourney-prompt-chain.mdx b/docs/docs/examples/midjourney-prompt-chain.mdx index c79bb0b27..9df732026 100644 --- a/docs/docs/examples/midjourney-prompt-chain.mdx +++ b/docs/docs/examples/midjourney-prompt-chain.mdx @@ -32,6 +32,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/midjourney-prompt-chain.png", + dark: "img/midjourney-prompt-chain.png", }} /> @@ -40,6 +41,6 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; - [`OpenAI`](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai) -- [`ConversationSummaryMemory`](https://python.langchain.com/docs/modules/memory/how_to/summary) +- [`ConversationSummaryMemory`](https://python.langchain.com/docs/modules/memory/types/summary) diff --git a/docs/docs/examples/multiple-vectorstores.mdx b/docs/docs/examples/multiple-vectorstores.mdx index 0c9f11c4c..2e554bbf1 100644 --- a/docs/docs/examples/multiple-vectorstores.mdx +++ b/docs/docs/examples/multiple-vectorstores.mdx @@ -24,7 +24,7 @@ https://pt.wikipedia.org/wiki/Harry_Potter Learn more about Multiple Vector Stores - [here](https://python.langchain.com/docs/modules/agents/toolkits/vectorstore?highlight=Multiple%20Vector%20Stores#multiple-vectorstores). + [here](https://python.langchain.com/docs/modules/data_connection/vectorstores/). ## ⛓️ Langflow Example @@ -37,6 +37,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/multiple-vectorstores.png", + dark: "img/multiple-vectorstores.png", }} /> @@ -44,14 +45,14 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; -- [`WebBaseLoader`](https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/web_base) -- [`TextLoader`](https://python.langchain.com/docs/modules/data_connection/document_loaders/integrations/unstructured_file) +- [`WebBaseLoader`](https://python.langchain.com/docs/integrations/document_loaders/web_base) +- [`TextLoader`](https://python.langchain.com/docs/modules/data_connection/document_loaders/) - [`CharacterTextSplitter`](https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter) -- [`OpenAIEmbedding`](https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/openai) -- [`Chroma`](https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/chroma) +- [`OpenAIEmbedding`](https://python.langchain.com/docs/integrations/text_embedding/openai) +- [`Chroma`](https://python.langchain.com/docs/integrations/vectorstores/chroma) - [`VectorStoreInfo`](https://python.langchain.com/docs/modules/data_connection/vectorstores/) - [`OpenAI`](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai) -- [`VectorStoreRouterToolkit`](https://python.langchain.com/docs/modules/agents/toolkits/vectorstore) -- [`VectorStoreRouterAgent`](https://python.langchain.com/docs/modules/agents/toolkits/vectorstore) +- [`VectorStoreRouterToolkit`](https://js.langchain.com/docs/modules/agents/tools/how_to/agents_with_vectorstores) +- [`VectorStoreRouterAgent`](https://js.langchain.com/docs/modules/agents/tools/how_to/agents_with_vectorstores) diff --git a/docs/docs/examples/python-function.mdx b/docs/docs/examples/python-function.mdx index f537075c6..9eadd7273 100644 --- a/docs/docs/examples/python-function.mdx +++ b/docs/docs/examples/python-function.mdx @@ -28,7 +28,7 @@ The `AgentInitializer` component is a quick way to construct an agent from the m The `PythonFunction` is a custom component that uses the LangChain 🦜🔗 tool decorator. Learn more about it - [here](https://python.langchain.com/docs/modules/agents/tools/how_to/custom_tools). + [here](https://python.langchain.com/docs/modules/agents/tools/custom_tools). ## ⛓️ Langflow Example @@ -41,6 +41,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/python-function.png", + dark: "img/python-function.png", }} /> @@ -48,7 +49,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; -- [`PythonFunctionTool`](https://python.langchain.com/docs/modules/agents/tools/how_to/custom_tools) +- [`PythonFunctionTool`](https://python.langchain.com/docs/modules/agents/tools/custom_tools) - [`ChatOpenAI`](https://python.langchain.com/docs/modules/model_io/models/chat/integrations/openai) - [`AgentInitializer`](https://python.langchain.com/docs/modules/agents/) diff --git a/docs/docs/examples/searchapi-tool.mdx b/docs/docs/examples/searchapi-tool.mdx new file mode 100644 index 000000000..d3cb4734a --- /dev/null +++ b/docs/docs/examples/searchapi-tool.mdx @@ -0,0 +1,52 @@ +import Admonition from "@theme/Admonition"; + +# SearchApi Tool + +The [SearchApi](https://www.searchapi.io/) allows developers to retrieve results from search engines such as Google, Google Scholar, YouTube, YouTube transcripts, and more, and can be used as in Langflow through the `SearchApi` tool. + + + To use the SearchApi, you must first obtain an API key by registering at [SearchApi's website](https://www.searchapi.io/). + + +In the given example, we specify `engine` as `youtube_transcripts` and provide a `video_id`. + + + All engines and parameters can be found in [SearchApi documentation](https://www.searchapi.io/docs/google). + + +The `RetrievalQA` chain processes a `Document` along with a user's question to return an answer. + + + In this example, we used [`ChatOpenAI`](https://platform.openai.com/) as the + LLM, but feel free to experiment with other Language Models! + + +The `RetrievalQA` takes `CombineDocsChain` and `SearchApi` tool as inputs, using the tool as a `Document` to answer questions. + + + Learn more about the SearchApi + [here](https://python.langchain.com/docs/integrations/tools/searchapi). + + +## ⛓️ Langflow Example + +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import ZoomableImage from "/src/theme/ZoomableImage.js"; + + + +#### Download Flow + + + +- [`OpenAI`](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai) +- [`SearchApiAPIWrapper`](https://python.langchain.com/docs/integrations/providers/searchapi#wrappers) +- [`ZeroShotAgent`](https://python.langchain.com/docs/modules/agents/how_to/custom_mrkl_agent) + + \ No newline at end of file diff --git a/docs/docs/examples/serp-api-tool.mdx b/docs/docs/examples/serp-api-tool.mdx index 60e55791a..7e8d95936 100644 --- a/docs/docs/examples/serp-api-tool.mdx +++ b/docs/docs/examples/serp-api-tool.mdx @@ -22,7 +22,7 @@ The `ZeroShotAgent` takes the `LLMChain` and the `Search` tool as inputs, using Learn more about the Serp API - [here](https://python.langchain.com/docs/modules/agents/tools/integrations/serpapi). + [here](https://python.langchain.com/docs/integrations/providers/serpapi ). ## ⛓️ Langflow Example @@ -35,6 +35,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/serp-api-tool.png", + dark: "img/serp-api-tool.png", }} /> @@ -45,7 +46,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; - [`ZeroShotPrompt`](https://python.langchain.com/docs/modules/model_io/prompts/prompt_templates/) - [`OpenAI`](https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai) - [`LLMChain`](https://python.langchain.com/docs/modules/chains/foundational/llm_chain) -- [`Search`](https://python.langchain.com/docs/modules/agents/tools/integrations/serpapi) +- [`Search`](https://python.langchain.com/docs/integrations/providers/serpapi) - [`ZeroShotAgent`](https://python.langchain.com/docs/modules/agents/how_to/custom_mrkl_agent) diff --git a/docs/docs/getting-started/creating-flows.mdx b/docs/docs/getting-started/creating-flows.mdx index b09951f42..aecc3ea16 100644 --- a/docs/docs/getting-started/creating-flows.mdx +++ b/docs/docs/getting-started/creating-flows.mdx @@ -13,6 +13,7 @@ Creating flows with Langflow is easy. Drag sidebar components onto the canvas an alt="Docusaurus themed image" sources={{ light: "img/langflow_canvas.png", + dark: "img/langflow_canvas.png" }} /> diff --git a/docs/docs/getting-started/hugging-face-spaces.mdx b/docs/docs/getting-started/hugging-face-spaces.mdx index acc4bb8d5..4759ea398 100644 --- a/docs/docs/getting-started/hugging-face-spaces.mdx +++ b/docs/docs/getting-started/hugging-face-spaces.mdx @@ -12,6 +12,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/hugging-face.png", + dark: "img/hugging-face.png", }} style={{ width: "100%" }} /> diff --git a/docs/docs/guidelines/api.mdx b/docs/docs/guidelines/api.mdx index 97d2db76e..8bba633fb 100644 --- a/docs/docs/guidelines/api.mdx +++ b/docs/docs/guidelines/api.mdx @@ -17,6 +17,7 @@ Langflow offers an API Key functionality that allows users to access their indiv alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/api-key.png"), + dark: useBaseUrl("img/api-key.png"), }} style={{ width: "50%", maxWidth: "600px", margin: "0 auto" }} /> diff --git a/docs/docs/guidelines/chat-interface.mdx b/docs/docs/guidelines/chat-interface.mdx index 0ac23dc8a..5da5d4647 100644 --- a/docs/docs/guidelines/chat-interface.mdx +++ b/docs/docs/guidelines/chat-interface.mdx @@ -13,6 +13,7 @@ Langflow’s chat interface provides a user-friendly experience and functionalit alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/chat_interface.png"), + dark: useBaseUrl("img/chat_interface.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -25,6 +26,7 @@ Notice that editing variables in the chat interface take place temporarily and w alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/chat_interface2.png"), + dark: useBaseUrl("img/chat_interface2.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -36,6 +38,7 @@ To view the complete prompt in its original, structured format, click the "Displ alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/chat_interface3.png"), + dark: useBaseUrl("img/chat_interface3.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -47,6 +50,7 @@ In the chat interface, you can redefine which variable should be interpreted as alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/chat_interface4.png"), + dark: useBaseUrl("img/chat_interface4.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> diff --git a/docs/docs/guidelines/chat-widget.mdx b/docs/docs/guidelines/chat-widget.mdx index 7f6737fea..46ed974a8 100644 --- a/docs/docs/guidelines/chat-widget.mdx +++ b/docs/docs/guidelines/chat-widget.mdx @@ -38,6 +38,7 @@ import Admonition from "@theme/Admonition"; alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/widget-sidebar.png"), + dark: useBaseUrl("img/widget-sidebar.png"), }} style={{ width: "50%", maxWidth: "600px", margin: "0 auto" }} /> @@ -53,6 +54,7 @@ import Admonition from "@theme/Admonition"; alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/widget-code.png"), + dark: useBaseUrl("img/widget-code.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> diff --git a/docs/docs/guidelines/components.mdx b/docs/docs/guidelines/components.mdx index 7188bf1e0..32ec00615 100644 --- a/docs/docs/guidelines/components.mdx +++ b/docs/docs/guidelines/components.mdx @@ -30,6 +30,7 @@ Components are the building blocks of the flows. They are made of inputs, output alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/single-compenent.png"), + dark: useBaseUrl("img/single-compenent.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> diff --git a/docs/docs/guidelines/custom-component.mdx b/docs/docs/guidelines/custom-component.mdx index 4f18d0375..99106d400 100644 --- a/docs/docs/guidelines/custom-component.mdx +++ b/docs/docs/guidelines/custom-component.mdx @@ -63,6 +63,7 @@ class DocumentProcessor(CustomComponent): alt="Document Processor Component" sources={{ light: "img/document_processor.png", + dark: "img/document_processor.png", }} style={{ margin: "0 auto", @@ -330,6 +331,7 @@ All done! This is what our script and brand-new custom component look like: alt="Document Processor Code" sources={{ light: "img/document_processor_code.png", + dark: "img/document_processor_code.png", }} style={{ maxWidth: "100%", @@ -344,6 +346,7 @@ All done! This is what our script and brand-new custom component look like: alt="Document Processor Component" sources={{ light: "img/document_processor.png", + dark: "img/document_processor.png", }} style={{ width: "40%", diff --git a/docs/docs/guidelines/features.mdx b/docs/docs/guidelines/features.mdx index 6235b68db..19837430d 100644 --- a/docs/docs/guidelines/features.mdx +++ b/docs/docs/guidelines/features.mdx @@ -18,6 +18,7 @@ import Admonition from "@theme/Admonition"; alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/features.png"), + dark: useBaseUrl("img/features.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> diff --git a/docs/docs/guidelines/login.mdx b/docs/docs/guidelines/login.mdx index 85ca1371f..fde7cd09a 100644 --- a/docs/docs/guidelines/login.mdx +++ b/docs/docs/guidelines/login.mdx @@ -86,6 +86,7 @@ With _`LANGFLOW_AUTO_LOGIN`_ set to _`False`_, Langflow requires users to sign u alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/sign-up.png"), + dark: useBaseUrl("img/sign-up.png"), }} style={{ width: "50%", maxWidth: "600px", margin: "0 auto" }} /> @@ -102,6 +103,7 @@ Users can change their profile settings by clicking on the profile icon in the t alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/my-account.png"), + dark: useBaseUrl("img/my-account.png"), }} style={{ width: "50%", maxWidth: "600px", margin: "0 auto" }} /> @@ -112,6 +114,7 @@ By clicking on **Profile Settings**, the user is taken to the profile settings p alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/profile-settings.png"), + dark: useBaseUrl("img/profile-settings.png"), }} style={{ maxWidth: "600px", margin: "0 auto" }} /> @@ -122,6 +125,7 @@ By clicking on **Admin Page**, the superuser is taken to the admin page, where t alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/admin-page.png"), + dark: useBaseUrl("img/admin-page.png"), }} style={{ maxWidth: "600px", margin: "0 auto" }} diff --git a/docs/docs/guidelines/prompt-customization.mdx b/docs/docs/guidelines/prompt-customization.mdx index efb5b3928..2a1b1f210 100644 --- a/docs/docs/guidelines/prompt-customization.mdx +++ b/docs/docs/guidelines/prompt-customization.mdx @@ -13,6 +13,7 @@ The prompt template allows users to create prompts and define variables that pro alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/prompt_customization.png"), + dark: useBaseUrl("img/prompt_customization.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -25,6 +26,7 @@ Variables can be used to define instructions, questions, context, inputs, or exa alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/prompt_customization2.png"), + dark: useBaseUrl("img/prompt_customization2.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -37,6 +39,7 @@ Once inserted, these variables are immediately recognized as new fields in the p alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/prompt_customization3.png"), + dark: useBaseUrl("img/prompt_customization3.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -49,6 +52,7 @@ You can also use documents or output parsers as prompt variables. By plugging th alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/prompt_customization4.png"), + dark: useBaseUrl("img/prompt_customization4.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> @@ -63,6 +67,7 @@ If working with an interactive (chat-like) flow, remember to keep one of the inp alt="Docusaurus themed image" sources={{ light: useBaseUrl("img/prompt_customization5.png"), + dark: useBaseUrl("img/prompt_customization5.png"), }} style={{ width: "100%", maxWidth: "800px", margin: "0 auto" }} /> diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx index 512d2578b..840f10f10 100644 --- a/docs/docs/index.mdx +++ b/docs/docs/index.mdx @@ -12,6 +12,7 @@ import ZoomableImage from "/src/theme/ZoomableImage.js"; alt="Docusaurus themed image" sources={{ light: "img/new_langflow_demo.gif", + dark: "img/new_langflow_demo.gif", }} style={{ width: "100%" }} /> diff --git a/docs/sidebars.js b/docs/sidebars.js index 0309f2d9a..18cf18040 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -82,6 +82,7 @@ module.exports = { "examples/buffer-memory", "examples/midjourney-prompt-chain", "examples/csv-loader", + "examples/searchapi-tool", "examples/serp-api-tool", "examples/multiple-vectorstores", "examples/python-function", diff --git a/docs/static/img/searchapi-tool.png b/docs/static/img/searchapi-tool.png new file mode 100644 index 000000000..0e11a3b16 Binary files /dev/null and b/docs/static/img/searchapi-tool.png differ diff --git a/docs/static/json_files/SearchApi_Tool.json b/docs/static/json_files/SearchApi_Tool.json new file mode 100644 index 000000000..304f191f1 --- /dev/null +++ b/docs/static/json_files/SearchApi_Tool.json @@ -0,0 +1 @@ +{"id":"7fc56f82-3493-4742-9c85-82b144127aff","data":{"nodes":[{"id":"ChatOpenAI-4Mfuz","type":"genericNode","position":{"x":-2243.8068684913856,"y":-2026.350019258601},"data":{"type":"ChatOpenAI","node":{"template":{"callbacks":{"type":"langchain_core.callbacks.base.BaseCallbackHandler","required":false,"placeholder":"","list":true,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"callbacks","advanced":false,"dynamic":false,"info":""},"async_client":{"type":"Any","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"async_client","advanced":false,"dynamic":false,"info":""},"cache":{"type":"bool","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"cache","advanced":false,"dynamic":false,"info":""},"client":{"type":"Any","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"client","advanced":false,"dynamic":false,"info":""},"default_headers":{"type":"dict","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"default_headers","advanced":false,"dynamic":false,"info":""},"default_query":{"type":"dict","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"default_query","advanced":false,"dynamic":false,"info":""},"http_client":{"type":"Any","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"http_client","advanced":false,"dynamic":false,"info":""},"max_retries":{"type":"int","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"value":2,"fileTypes":[],"password":false,"name":"max_retries","advanced":false,"dynamic":false,"info":""},"max_tokens":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":true,"name":"max_tokens","advanced":false,"dynamic":false,"info":"","value":""},"metadata":{"type":"dict","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"metadata","advanced":false,"dynamic":false,"info":""},"model_kwargs":{"type":"dict","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"model_kwargs","advanced":true,"dynamic":false,"info":""},"model_name":{"type":"str","required":false,"placeholder":"","list":true,"show":true,"multiline":false,"value":"gpt-3.5-turbo-16k","fileTypes":[],"password":false,"options":["gpt-4-1106-preview","gpt-4-vision-preview","gpt-4","gpt-4-32k","gpt-3.5-turbo","gpt-3.5-turbo-16k"],"name":"model_name","advanced":false,"dynamic":false,"info":""},"n":{"type":"int","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"value":1,"fileTypes":[],"password":false,"name":"n","advanced":false,"dynamic":false,"info":""},"name":{"type":"str","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"name","advanced":false,"dynamic":false,"info":""},"openai_api_base":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"openai_api_base","display_name":"OpenAI API Base","advanced":false,"dynamic":false,"info":"\nThe base URL of the OpenAI API. Defaults to https://api.openai.com/v1.\n\nYou can change this to use other APIs like JinaChat, LocalAI and Prem.\n"},"openai_api_key":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"","fileTypes":[],"password":true,"name":"openai_api_key","display_name":"OpenAI API Key","advanced":false,"dynamic":false,"info":""},"openai_organization":{"type":"str","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"openai_organization","display_name":"OpenAI Organization","advanced":false,"dynamic":false,"info":""},"openai_proxy":{"type":"str","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"openai_proxy","display_name":"OpenAI Proxy","advanced":false,"dynamic":false,"info":""},"request_timeout":{"type":"float","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"request_timeout","advanced":false,"dynamic":false,"info":"","rangeSpec":{"min":-1,"max":1,"step":0.1}},"streaming":{"type":"bool","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"value":false,"fileTypes":[],"password":false,"name":"streaming","advanced":false,"dynamic":false,"info":""},"tags":{"type":"str","required":false,"placeholder":"","list":true,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"tags","advanced":false,"dynamic":false,"info":""},"temperature":{"type":"float","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"0.5","fileTypes":[],"password":false,"name":"temperature","advanced":false,"dynamic":false,"info":"","rangeSpec":{"min":-1,"max":1,"step":0.1}},"tiktoken_model_name":{"type":"str","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"tiktoken_model_name","advanced":false,"dynamic":false,"info":""},"verbose":{"type":"bool","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"value":false,"fileTypes":[],"password":false,"name":"verbose","advanced":false,"dynamic":false,"info":""},"_type":"ChatOpenAI"},"description":"[*Deprecated*] `OpenAI` Chat large language models API.","base_classes":["BaseLanguageModel","BaseChatModel","ChatOpenAI","BaseLLM"],"display_name":"ChatOpenAI","documentation":"https://python.langchain.com/docs/modules/model_io/models/chat/integrations/openai","custom_fields":{},"output_types":[],"field_formatters":{},"beta":false},"id":"ChatOpenAI-4Mfuz"},"selected":false,"width":384,"height":649,"positionAbsolute":{"x":-2243.8068684913856,"y":-2026.350019258601},"dragging":false},{"id":"CharacterTextSplitter-WVMFU","type":"genericNode","position":{"x":-2661.4749778477553,"y":-1608.9437055023366},"data":{"type":"CharacterTextSplitter","node":{"template":{"documents":{"type":"Document","required":true,"placeholder":"","list":true,"show":true,"multiline":false,"value":"","fileTypes":[],"file_path":"","password":false,"name":"documents","advanced":false,"dynamic":false,"info":""},"chunk_overlap":{"type":"int","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":200,"fileTypes":[],"file_path":"","password":false,"name":"chunk_overlap","display_name":"Chunk Overlap","advanced":false,"dynamic":false,"info":""},"chunk_size":{"type":"int","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"2000","fileTypes":[],"file_path":"","password":false,"name":"chunk_size","display_name":"Chunk Size","advanced":false,"dynamic":false,"info":""},"separator":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"\"","fileTypes":[],"file_path":"","password":false,"name":"separator","display_name":"Separator","advanced":false,"dynamic":false,"info":""},"_type":"CharacterTextSplitter"},"description":"Splitting text that looks at characters.","base_classes":["Document"],"display_name":"CharacterTextSplitter","documentation":"https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter","custom_fields":{},"output_types":["Document"],"field_formatters":{},"beta":false},"id":"CharacterTextSplitter-WVMFU"},"selected":false,"width":384,"height":501,"positionAbsolute":{"x":-2661.4749778477553,"y":-1608.9437055023366},"dragging":false},{"id":"Chroma-OtYDg","type":"genericNode","position":{"x":-2194.2051907050227,"y":-1370.1637632208287},"data":{"type":"Chroma","node":{"template":{"documents":{"type":"Document","required":false,"placeholder":"","list":true,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"documents","display_name":"Documents","advanced":false,"dynamic":false,"info":""},"embedding":{"type":"Embeddings","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"embedding","display_name":"Embedding","advanced":false,"dynamic":false,"info":""},"chroma_server_cors_allow_origins":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"chroma_server_cors_allow_origins","display_name":"Server CORS Allow Origins","advanced":true,"dynamic":false,"info":""},"chroma_server_grpc_port":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"chroma_server_grpc_port","display_name":"Server gRPC Port","advanced":true,"dynamic":false,"info":""},"chroma_server_host":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"chroma_server_host","display_name":"Server Host","advanced":true,"dynamic":false,"info":""},"chroma_server_port":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"chroma_server_port","display_name":"Server Port","advanced":true,"dynamic":false,"info":""},"chroma_server_ssl_enabled":{"type":"bool","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":false,"fileTypes":[],"file_path":"","password":false,"name":"chroma_server_ssl_enabled","display_name":"Server SSL Enabled","advanced":true,"dynamic":false,"info":""},"code":{"type":"code","required":true,"placeholder":"","list":false,"show":true,"multiline":true,"value":"from typing import List, Optional, Union\n\nimport chromadb # type: ignore\nfrom langchain.embeddings.base import Embeddings\nfrom langchain.schema import BaseRetriever, Document\nfrom langchain.vectorstores import Chroma\nfrom langchain.vectorstores.base import VectorStore\n\nfrom langflow import CustomComponent\n\n\nclass ChromaComponent(CustomComponent):\n \"\"\"\n A custom component for implementing a Vector Store using Chroma.\n \"\"\"\n\n display_name: str = \"Chroma\"\n description: str = \"Implementation of Vector Store using Chroma\"\n documentation = \"https://python.langchain.com/docs/integrations/vectorstores/chroma\"\n beta: bool = True\n\n def build_config(self):\n \"\"\"\n Builds the configuration for the component.\n\n Returns:\n - dict: A dictionary containing the configuration options for the component.\n \"\"\"\n return {\n \"collection_name\": {\"display_name\": \"Collection Name\", \"value\": \"langflow\"},\n \"persist\": {\"display_name\": \"Persist\"},\n \"persist_directory\": {\"display_name\": \"Persist Directory\"},\n \"code\": {\"show\": False, \"display_name\": \"Code\"},\n \"documents\": {\"display_name\": \"Documents\", \"is_list\": True},\n \"embedding\": {\"display_name\": \"Embedding\"},\n \"chroma_server_cors_allow_origins\": {\n \"display_name\": \"Server CORS Allow Origins\",\n \"advanced\": True,\n },\n \"chroma_server_host\": {\"display_name\": \"Server Host\", \"advanced\": True},\n \"chroma_server_port\": {\"display_name\": \"Server Port\", \"advanced\": True},\n \"chroma_server_grpc_port\": {\n \"display_name\": \"Server gRPC Port\",\n \"advanced\": True,\n },\n \"chroma_server_ssl_enabled\": {\n \"display_name\": \"Server SSL Enabled\",\n \"advanced\": True,\n },\n }\n\n def build(\n self,\n collection_name: str,\n persist: bool,\n embedding: Embeddings,\n chroma_server_ssl_enabled: bool,\n persist_directory: Optional[str] = None,\n documents: Optional[List[Document]] = None,\n chroma_server_cors_allow_origins: Optional[str] = None,\n chroma_server_host: Optional[str] = None,\n chroma_server_port: Optional[int] = None,\n chroma_server_grpc_port: Optional[int] = None,\n ) -> Union[VectorStore, BaseRetriever]:\n \"\"\"\n Builds the Vector Store or BaseRetriever object.\n\n Args:\n - collection_name (str): The name of the collection.\n - persist_directory (Optional[str]): The directory to persist the Vector Store to.\n - chroma_server_ssl_enabled (bool): Whether to enable SSL for the Chroma server.\n - persist (bool): Whether to persist the Vector Store or not.\n - embedding (Optional[Embeddings]): The embeddings to use for the Vector Store.\n - documents (Optional[Document]): The documents to use for the Vector Store.\n - chroma_server_cors_allow_origins (Optional[str]): The CORS allow origins for the Chroma server.\n - chroma_server_host (Optional[str]): The host for the Chroma server.\n - chroma_server_port (Optional[int]): The port for the Chroma server.\n - chroma_server_grpc_port (Optional[int]): The gRPC port for the Chroma server.\n\n Returns:\n - Union[VectorStore, BaseRetriever]: The Vector Store or BaseRetriever object.\n \"\"\"\n\n # Chroma settings\n chroma_settings = None\n\n if chroma_server_host is not None:\n chroma_settings = chromadb.config.Settings(\n chroma_server_cors_allow_origins=chroma_server_cors_allow_origins or None,\n chroma_server_host=chroma_server_host,\n chroma_server_port=chroma_server_port or None,\n chroma_server_grpc_port=chroma_server_grpc_port or None,\n chroma_server_ssl_enabled=chroma_server_ssl_enabled,\n )\n\n # If documents, then we need to create a Chroma instance using .from_documents\n if documents is not None and embedding is not None:\n if len(documents) == 0:\n raise ValueError(\"If documents are provided, there must be at least one document.\")\n return Chroma.from_documents(\n documents=documents, # type: ignore\n persist_directory=persist_directory if persist else None,\n collection_name=collection_name,\n embedding=embedding,\n client_settings=chroma_settings,\n )\n\n return Chroma(persist_directory=persist_directory, client_settings=chroma_settings)\n","fileTypes":[],"file_path":"","password":false,"name":"code","advanced":false,"dynamic":true,"info":""},"collection_name":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"video","fileTypes":[],"file_path":"","password":false,"name":"collection_name","display_name":"Collection Name","advanced":false,"dynamic":false,"info":""},"persist":{"type":"bool","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":false,"fileTypes":[],"file_path":"","password":false,"name":"persist","display_name":"Persist","advanced":false,"dynamic":false,"info":""},"persist_directory":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"persist_directory","display_name":"Persist Directory","advanced":false,"dynamic":false,"info":""},"_type":"CustomComponent"},"description":"Implementation of Vector Store using Chroma","base_classes":["VectorStore","BaseRetriever"],"display_name":"Chroma","documentation":"https://python.langchain.com/docs/integrations/vectorstores/chroma","custom_fields":{"chroma_server_cors_allow_origins":null,"chroma_server_grpc_port":null,"chroma_server_host":null,"chroma_server_port":null,"chroma_server_ssl_enabled":null,"collection_name":null,"documents":null,"embedding":null,"persist":null,"persist_directory":null},"output_types":["Chroma"],"field_formatters":{},"beta":true},"id":"Chroma-OtYDg"},"selected":false,"width":384,"height":625,"positionAbsolute":{"x":-2194.2051907050227,"y":-1370.1637632208287},"dragging":false},{"id":"OpenAIEmbeddings-9yqtI","type":"genericNode","position":{"x":-2653.011009324626,"y":-1103.8414515074774},"data":{"type":"OpenAIEmbeddings","node":{"template":{"allowed_special":{"type":"str","required":false,"placeholder":"","list":true,"show":true,"multiline":false,"value":[],"fileTypes":[],"password":false,"name":"allowed_special","advanced":true,"dynamic":false,"info":""},"async_client":{"type":"Any","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"async_client","advanced":true,"dynamic":false,"info":""},"chunk_size":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":1000,"fileTypes":[],"password":false,"name":"chunk_size","advanced":true,"dynamic":false,"info":""},"client":{"type":"Any","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"client","advanced":true,"dynamic":false,"info":""},"default_headers":{"type":"dict","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"default_headers","advanced":true,"dynamic":false,"info":""},"default_query":{"type":"dict","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"default_query","advanced":true,"dynamic":false,"info":""},"deployment":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"text-embedding-ada-002","fileTypes":[],"password":false,"name":"deployment","advanced":true,"dynamic":false,"info":""},"disallowed_special":{"type":"str","required":false,"placeholder":"","list":true,"show":true,"multiline":false,"value":"all","fileTypes":[],"password":false,"name":"disallowed_special","advanced":true,"dynamic":false,"info":""},"embedding_ctx_length":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":8191,"fileTypes":[],"password":false,"name":"embedding_ctx_length","advanced":true,"dynamic":false,"info":""},"headers":{"type":"Any","required":false,"placeholder":"","list":false,"show":false,"multiline":true,"value":"{\"Authorization\": \"Bearer \"}","fileTypes":[],"password":false,"name":"headers","advanced":true,"dynamic":false,"info":""},"http_client":{"type":"Any","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"http_client","advanced":true,"dynamic":false,"info":""},"max_retries":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":2,"fileTypes":[],"password":false,"name":"max_retries","advanced":true,"dynamic":false,"info":""},"model":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"text-embedding-ada-002","fileTypes":[],"password":false,"name":"model","advanced":true,"dynamic":false,"info":""},"model_kwargs":{"type":"dict","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"model_kwargs","advanced":true,"dynamic":false,"info":""},"openai_api_base":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":true,"name":"openai_api_base","display_name":"OpenAI API Base","advanced":true,"dynamic":false,"info":"","value":""},"openai_api_key":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"","fileTypes":[],"password":true,"name":"openai_api_key","display_name":"OpenAI API Key","advanced":false,"dynamic":false,"info":""},"openai_api_type":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":true,"name":"openai_api_type","display_name":"OpenAI API Type","advanced":true,"dynamic":false,"info":"","value":""},"openai_api_version":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":true,"name":"openai_api_version","display_name":"OpenAI API Version","advanced":true,"dynamic":false,"info":"","value":""},"openai_organization":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"openai_organization","display_name":"OpenAI Organization","advanced":true,"dynamic":false,"info":""},"openai_proxy":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"openai_proxy","display_name":"OpenAI Proxy","advanced":true,"dynamic":false,"info":""},"request_timeout":{"type":"float","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"request_timeout","advanced":true,"dynamic":false,"info":"","rangeSpec":{"min":-1,"max":1,"step":0.1}},"retry_max_seconds":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":20,"fileTypes":[],"password":false,"name":"retry_max_seconds","advanced":true,"dynamic":false,"info":""},"retry_min_seconds":{"type":"int","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":4,"fileTypes":[],"password":false,"name":"retry_min_seconds","advanced":true,"dynamic":false,"info":""},"show_progress_bar":{"type":"bool","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":false,"fileTypes":[],"password":false,"name":"show_progress_bar","advanced":true,"dynamic":false,"info":""},"skip_empty":{"type":"bool","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":false,"fileTypes":[],"password":false,"name":"skip_empty","advanced":true,"dynamic":false,"info":""},"tiktoken_enabled":{"type":"bool","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":"","fileTypes":[],"password":true,"name":"tiktoken_enabled","advanced":false,"dynamic":false,"info":""},"tiktoken_model_name":{"type":"str","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":true,"name":"tiktoken_model_name","advanced":false,"dynamic":false,"info":"","value":""},"_type":"OpenAIEmbeddings"},"description":"[*Deprecated*] OpenAI embedding models.","base_classes":["Embeddings","OpenAIEmbeddings"],"display_name":"OpenAIEmbeddings","documentation":"https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/openai","custom_fields":{},"output_types":[],"field_formatters":{},"beta":false},"id":"OpenAIEmbeddings-9yqtI"},"selected":false,"width":384,"height":443,"positionAbsolute":{"x":-2653.011009324626,"y":-1103.8414515074774},"dragging":false},{"id":"RetrievalQA-DpylI","type":"genericNode","position":{"x":-1757.239471200792,"y":-1258.2132589352987},"data":{"type":"RetrievalQA","node":{"template":{"callbacks":{"type":"langchain_core.callbacks.base.BaseCallbackHandler","required":false,"placeholder":"","list":true,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"callbacks","advanced":false,"dynamic":false,"info":""},"combine_documents_chain":{"type":"BaseCombineDocumentsChain","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"combine_documents_chain","advanced":false,"dynamic":false,"info":""},"memory":{"type":"BaseMemory","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"memory","advanced":false,"dynamic":false,"info":""},"retriever":{"type":"BaseRetriever","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"password":false,"name":"retriever","advanced":false,"dynamic":false,"info":""},"input_key":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"query","fileTypes":[],"password":false,"name":"input_key","advanced":true,"dynamic":false,"info":""},"metadata":{"type":"dict","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"metadata","advanced":false,"dynamic":false,"info":""},"name":{"type":"str","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"name","advanced":false,"dynamic":false,"info":""},"output_key":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"result","fileTypes":[],"password":false,"name":"output_key","advanced":true,"dynamic":false,"info":""},"return_source_documents":{"type":"bool","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"value":true,"fileTypes":[],"password":false,"name":"return_source_documents","advanced":true,"dynamic":false,"info":""},"tags":{"type":"str","required":false,"placeholder":"","list":true,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"tags","advanced":false,"dynamic":false,"info":""},"verbose":{"type":"bool","required":false,"placeholder":"","list":false,"show":false,"multiline":false,"fileTypes":[],"password":false,"name":"verbose","advanced":true,"dynamic":false,"info":""},"_type":"RetrievalQA"},"description":"Chain for question-answering against an index.","base_classes":["Chain","RetrievalQA","BaseRetrievalQA","Callable"],"display_name":"RetrievalQA","documentation":"https://python.langchain.com/docs/modules/chains/popular/vector_db_qa","custom_fields":{},"output_types":[],"field_formatters":{},"beta":false},"id":"RetrievalQA-DpylI"},"selected":false,"width":384,"height":339,"positionAbsolute":{"x":-1757.239471200792,"y":-1258.2132589352987},"dragging":true},{"id":"CombineDocsChain-afKOq","type":"genericNode","position":{"x":-1775.9040057312934,"y":-1644.0423777157919},"data":{"type":"CombineDocsChain","node":{"template":{"llm":{"type":"BaseLanguageModel","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"value":"","fileTypes":[],"file_path":"","password":false,"name":"llm","display_name":"LLM","advanced":false,"dynamic":false,"info":""},"chain_type":{"type":"str","required":true,"placeholder":"","list":true,"show":true,"multiline":false,"value":"refine","fileTypes":[],"file_path":"","password":false,"options":["stuff","map_reduce","map_rerank","refine"],"name":"chain_type","advanced":false,"dynamic":false,"info":""},"_type":"load_qa_chain"},"description":"Load question answering chain.","base_classes":["BaseCombineDocumentsChain","Callable"],"display_name":"CombineDocsChain","documentation":"","custom_fields":{},"output_types":[],"field_formatters":{},"beta":false},"id":"CombineDocsChain-afKOq"},"selected":false,"width":384,"height":333,"dragging":false,"positionAbsolute":{"x":-1775.9040057312934,"y":-1644.0423777157919}},{"id":"SearchApi-kZmEj","type":"genericNode","position":{"x":-3074.364183247263,"y":-1782.5742787937606},"data":{"type":"SearchApi","node":{"template":{"api_key":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":true,"name":"api_key","display_name":"API Key","advanced":false,"dynamic":false,"info":"The API key to use SearchApi.","value":""},"code":{"type":"code","required":true,"placeholder":"","list":false,"show":true,"multiline":true,"value":"from langflow import CustomComponent\nfrom langchain.schema import Document\nfrom langflow.services.database.models.base import orjson_dumps\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\nfrom typing import Optional\n\n\nclass SearchApi(CustomComponent):\n display_name: str = \"SearchApi\"\n description: str = \"Real-time search engines API.\"\n output_types: list[str] = [\"Document\"]\n documentation: str = \"https://www.searchapi.io/docs/google\"\n field_config = {\n \"engine\": {\n \"display_name\": \"Engine\",\n \"field_type\": \"str\",\n \"info\": \"The search engine to use.\",\n },\n \"params\": {\n \"display_name\": \"Parameters\",\n \"info\": \"The parameters to send with the request.\",\n },\n \"code\": {\"show\": False},\n \"api_key\": {\n \"display_name\": \"API Key\",\n \"field_type\": \"str\",\n \"required\": True, \n \"password\": True,\n \"info\": \"The API key to use SearchApi.\",\n },\n }\n\n def build(\n self,\n engine: str,\n api_key: str,\n params: Optional[dict] = None,\n ) -> Document:\n if params is None:\n params = {}\n\n search_api_wrapper = SearchApiAPIWrapper(engine=engine, searchapi_api_key=api_key)\n\n query = params.pop(\"query\", \"default query\") \n results = search_api_wrapper.results(query, **params)\n\n result = orjson_dumps(results, indent_2=False)\n \n document = Document(page_content=result) \n\n return document","fileTypes":[],"file_path":"","password":false,"name":"code","advanced":false,"dynamic":true,"info":""},"engine":{"type":"str","required":true,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"engine","display_name":"Engine","advanced":false,"dynamic":false,"info":"The search engine to use.","value":"youtube_transcripts"},"params":{"type":"dict","required":false,"placeholder":"","list":false,"show":true,"multiline":false,"fileTypes":[],"file_path":"","password":false,"name":"params","display_name":"Parameters","advanced":false,"dynamic":false,"info":"The parameters to send with the request.","value":[{"video_id":"krsBRQbOPQ4"}]},"_type":"CustomComponent"},"description":"Real-time search engines API.","base_classes":["Document"],"display_name":"SearchApi","documentation":"https://www.searchapi.io/docs/google","custom_fields":{"api_key":null,"engine":null,"params":null},"output_types":["SearchApi"],"field_formatters":{},"beta":true},"id":"SearchApi-kZmEj"},"selected":false,"width":384,"height":539,"dragging":false,"positionAbsolute":{"x":-3074.364183247263,"y":-1782.5742787937606}}],"edges":[{"source":"CharacterTextSplitter-WVMFU","sourceHandle":"{œbaseClassesœ:[œDocumentœ],œdataTypeœ:œCharacterTextSplitterœ,œidœ:œCharacterTextSplitter-WVMFUœ}","target":"Chroma-OtYDg","targetHandle":"{œfieldNameœ:œdocumentsœ,œidœ:œChroma-OtYDgœ,œinputTypesœ:null,œtypeœ:œDocumentœ}","data":{"targetHandle":{"fieldName":"documents","id":"Chroma-OtYDg","inputTypes":null,"type":"Document"},"sourceHandle":{"baseClasses":["Document"],"dataType":"CharacterTextSplitter","id":"CharacterTextSplitter-WVMFU"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-CharacterTextSplitter-WVMFU{œbaseClassesœ:[œDocumentœ],œdataTypeœ:œCharacterTextSplitterœ,œidœ:œCharacterTextSplitter-WVMFUœ}-Chroma-OtYDg{œfieldNameœ:œdocumentsœ,œidœ:œChroma-OtYDgœ,œinputTypesœ:null,œtypeœ:œDocumentœ}"},{"source":"OpenAIEmbeddings-9yqtI","sourceHandle":"{œbaseClassesœ:[œEmbeddingsœ,œOpenAIEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9yqtIœ}","target":"Chroma-OtYDg","targetHandle":"{œfieldNameœ:œembeddingœ,œidœ:œChroma-OtYDgœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}","data":{"targetHandle":{"fieldName":"embedding","id":"Chroma-OtYDg","inputTypes":null,"type":"Embeddings"},"sourceHandle":{"baseClasses":["Embeddings","OpenAIEmbeddings"],"dataType":"OpenAIEmbeddings","id":"OpenAIEmbeddings-9yqtI"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-OpenAIEmbeddings-9yqtI{œbaseClassesœ:[œEmbeddingsœ,œOpenAIEmbeddingsœ],œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-9yqtIœ}-Chroma-OtYDg{œfieldNameœ:œembeddingœ,œidœ:œChroma-OtYDgœ,œinputTypesœ:null,œtypeœ:œEmbeddingsœ}"},{"source":"Chroma-OtYDg","sourceHandle":"{œbaseClassesœ:[œVectorStoreœ,œBaseRetrieverœ],œdataTypeœ:œChromaœ,œidœ:œChroma-OtYDgœ}","target":"RetrievalQA-DpylI","targetHandle":"{œfieldNameœ:œretrieverœ,œidœ:œRetrievalQA-DpylIœ,œinputTypesœ:null,œtypeœ:œBaseRetrieverœ}","data":{"targetHandle":{"fieldName":"retriever","id":"RetrievalQA-DpylI","inputTypes":null,"type":"BaseRetriever"},"sourceHandle":{"baseClasses":["VectorStore","BaseRetriever"],"dataType":"Chroma","id":"Chroma-OtYDg"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-Chroma-OtYDg{œbaseClassesœ:[œVectorStoreœ,œBaseRetrieverœ],œdataTypeœ:œChromaœ,œidœ:œChroma-OtYDgœ}-RetrievalQA-DpylI{œfieldNameœ:œretrieverœ,œidœ:œRetrievalQA-DpylIœ,œinputTypesœ:null,œtypeœ:œBaseRetrieverœ}"},{"source":"ChatOpenAI-4Mfuz","sourceHandle":"{œbaseClassesœ:[œBaseLanguageModelœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLLMœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-4Mfuzœ}","target":"CombineDocsChain-afKOq","targetHandle":"{œfieldNameœ:œllmœ,œidœ:œCombineDocsChain-afKOqœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}","data":{"targetHandle":{"fieldName":"llm","id":"CombineDocsChain-afKOq","inputTypes":null,"type":"BaseLanguageModel"},"sourceHandle":{"baseClasses":["BaseLanguageModel","BaseChatModel","ChatOpenAI","BaseLLM"],"dataType":"ChatOpenAI","id":"ChatOpenAI-4Mfuz"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-ChatOpenAI-4Mfuz{œbaseClassesœ:[œBaseLanguageModelœ,œBaseChatModelœ,œChatOpenAIœ,œBaseLLMœ],œdataTypeœ:œChatOpenAIœ,œidœ:œChatOpenAI-4Mfuzœ}-CombineDocsChain-afKOq{œfieldNameœ:œllmœ,œidœ:œCombineDocsChain-afKOqœ,œinputTypesœ:null,œtypeœ:œBaseLanguageModelœ}"},{"source":"CombineDocsChain-afKOq","sourceHandle":"{œbaseClassesœ:[œBaseCombineDocumentsChainœ,œCallableœ],œdataTypeœ:œCombineDocsChainœ,œidœ:œCombineDocsChain-afKOqœ}","target":"RetrievalQA-DpylI","targetHandle":"{œfieldNameœ:œcombine_documents_chainœ,œidœ:œRetrievalQA-DpylIœ,œinputTypesœ:null,œtypeœ:œBaseCombineDocumentsChainœ}","data":{"targetHandle":{"fieldName":"combine_documents_chain","id":"RetrievalQA-DpylI","inputTypes":null,"type":"BaseCombineDocumentsChain"},"sourceHandle":{"baseClasses":["BaseCombineDocumentsChain","Callable"],"dataType":"CombineDocsChain","id":"CombineDocsChain-afKOq"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-CombineDocsChain-afKOq{œbaseClassesœ:[œBaseCombineDocumentsChainœ,œCallableœ],œdataTypeœ:œCombineDocsChainœ,œidœ:œCombineDocsChain-afKOqœ}-RetrievalQA-DpylI{œfieldNameœ:œcombine_documents_chainœ,œidœ:œRetrievalQA-DpylIœ,œinputTypesœ:null,œtypeœ:œBaseCombineDocumentsChainœ}"},{"source":"SearchApi-kZmEj","sourceHandle":"{œbaseClassesœ:[œDocumentœ],œdataTypeœ:œSearchApiœ,œidœ:œSearchApi-kZmEjœ}","target":"CharacterTextSplitter-WVMFU","targetHandle":"{œfieldNameœ:œdocumentsœ,œidœ:œCharacterTextSplitter-WVMFUœ,œinputTypesœ:null,œtypeœ:œDocumentœ}","data":{"targetHandle":{"fieldName":"documents","id":"CharacterTextSplitter-WVMFU","inputTypes":null,"type":"Document"},"sourceHandle":{"baseClasses":["Document"],"dataType":"SearchApi","id":"SearchApi-kZmEj"}},"style":{"stroke":"#555"},"className":"stroke-gray-900 stroke-connection","animated":false,"id":"reactflow__edge-SearchApi-kZmEj{œbaseClassesœ:[œDocumentœ],œdataTypeœ:œSearchApiœ,œidœ:œSearchApi-kZmEjœ}-CharacterTextSplitter-WVMFU{œfieldNameœ:œdocumentsœ,œidœ:œCharacterTextSplitter-WVMFUœ,œinputTypesœ:null,œtypeœ:œDocumentœ}"}],"viewport":{"x":2046.3642433866817,"y":1270.2852546488134,"zoom":0.6177254407441625}},"description":"Real-time Google Search engine q&a.","name":"SearchApi Tool","last_tested_version":"0.6.5a9","is_component":false} \ No newline at end of file diff --git a/docs/static/videos/langflow_api.mp4 b/docs/static/videos/langflow_api.mp4 index 7bb270f6b..f0daa5266 100644 Binary files a/docs/static/videos/langflow_api.mp4 and b/docs/static/videos/langflow_api.mp4 differ diff --git a/docs/static/videos/langflow_build.mp4 b/docs/static/videos/langflow_build.mp4 index fffd21aec..9d068fa01 100644 Binary files a/docs/static/videos/langflow_build.mp4 and b/docs/static/videos/langflow_build.mp4 differ diff --git a/docs/static/videos/langflow_collection.mp4 b/docs/static/videos/langflow_collection.mp4 index f240d1be0..69d172776 100644 Binary files a/docs/static/videos/langflow_collection.mp4 and b/docs/static/videos/langflow_collection.mp4 differ diff --git a/docs/static/videos/langflow_collection_example.mp4 b/docs/static/videos/langflow_collection_example.mp4 index 31cc94961..e58ea31e4 100644 Binary files a/docs/static/videos/langflow_collection_example.mp4 and b/docs/static/videos/langflow_collection_example.mp4 differ diff --git a/docs/static/videos/langflow_fork.mp4 b/docs/static/videos/langflow_fork.mp4 index c9b75bc23..03c280c35 100644 Binary files a/docs/static/videos/langflow_fork.mp4 and b/docs/static/videos/langflow_fork.mp4 differ diff --git a/docs/static/videos/langflow_parameters.mp4 b/docs/static/videos/langflow_parameters.mp4 index c7599e649..370ca5f36 100644 Binary files a/docs/static/videos/langflow_parameters.mp4 and b/docs/static/videos/langflow_parameters.mp4 differ diff --git a/docs/static/videos/langflow_widget.mp4 b/docs/static/videos/langflow_widget.mp4 index d5514a948..7894316f7 100644 Binary files a/docs/static/videos/langflow_widget.mp4 and b/docs/static/videos/langflow_widget.mp4 differ diff --git a/poetry.lock b/poetry.lock index 9e3d5480d..2ec2d889e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -418,17 +418,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.50" +version = "1.34.52" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.8" files = [ - {file = "boto3-1.34.50-py3-none-any.whl", hash = "sha256:8d709365231234bc4f0ca98fdf33a25eeebf78072853c6aa3d259f0f5cf09877"}, - {file = "boto3-1.34.50.tar.gz", hash = "sha256:290952be7899560039cb0042e8a2354f61a7dead0d0ca8bea6ba901930df0468"}, + {file = "boto3-1.34.52-py3-none-any.whl", hash = "sha256:898ad2123b18cae8efd85adc56ac2d1925be54592aebc237020d4f16e9a9e7a9"}, + {file = "boto3-1.34.52.tar.gz", hash = "sha256:66303b5f26d92afb72656ff490b22ea72dfff8bf1a29e4a0c5d5f11ec56245dd"}, ] [package.dependencies] -botocore = ">=1.34.50,<1.35.0" +botocore = ">=1.34.52,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -437,13 +437,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.50" +version = "1.34.52" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.8" files = [ - {file = "botocore-1.34.50-py3-none-any.whl", hash = "sha256:fda510559dbe796eefdb59561cc81be1b99afba3dee53fd23db9a3d587adc0ab"}, - {file = "botocore-1.34.50.tar.gz", hash = "sha256:33ab82cb96c4bb684f0dbafb071808e4817d83debc88b223e7d988256370c6d7"}, + {file = "botocore-1.34.52-py3-none-any.whl", hash = "sha256:05567d8aba344826060481ea309555432c96f0febe22bee7cf5a3b6d3a03cec8"}, + {file = "botocore-1.34.52.tar.gz", hash = "sha256:187da93aec3f2e87d8a31eced16fa2cb9c71fe2d69b0a797f9f7a9220f5bf7ae"}, ] [package.dependencies] @@ -889,13 +889,13 @@ numpy = "*" [[package]] name = "chromadb" -version = "0.4.23" +version = "0.4.24" description = "Chroma." optional = false python-versions = ">=3.8" files = [ - {file = "chromadb-0.4.23-py3-none-any.whl", hash = "sha256:3d3c2ffb4ff560721e3daf8c1a3729fd149c551525b6f75543eddb81a4f29e16"}, - {file = "chromadb-0.4.23.tar.gz", hash = "sha256:54d9a770640704c6cedc15317faab9fd45beb9833e7484c00037e7a8801a349f"}, + {file = "chromadb-0.4.24-py3-none-any.whl", hash = "sha256:3a08e237a4ad28b5d176685bd22429a03717fe09d35022fb230d516108da01da"}, + {file = "chromadb-0.4.24.tar.gz", hash = "sha256:a5c80b4e4ad9b236ed2d4899a5b9e8002b489293f2881cb2cadab5b199ee1c72"}, ] [package.dependencies] @@ -2268,13 +2268,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.119.0" +version = "2.120.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-python-client-2.119.0.tar.gz", hash = "sha256:ff9ef7539eaf7e088a481b25d1af4704210b07863e1d51b5ee498b910a3a46a3"}, - {file = "google_api_python_client-2.119.0-py2.py3-none-any.whl", hash = "sha256:84e43bdb58dd8d2301669513863996378ffe9a3bf6d23b5ccd4f1e021323dbeb"}, + {file = "google-api-python-client-2.120.0.tar.gz", hash = "sha256:a0c8769cad9576768bcb3191cb1f550f6ab3290cba042badb0fb17bba03f70cc"}, + {file = "google_api_python_client-2.120.0-py2.py3-none-any.whl", hash = "sha256:e2cdf4497bfc758fb44a4b487920cc1ca0571c2428187697a8e43e3b9feba1c9"}, ] [package.dependencies] @@ -2375,13 +2375,13 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "gotrue" -version = "2.1.0" +version = "2.4.1" description = "Python Client Library for GoTrue" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "gotrue-2.1.0-py3-none-any.whl", hash = "sha256:6483d9a3ac9be1d1ad510be24171e133aa1cec702cc10a8f323b9e7519642447"}, - {file = "gotrue-2.1.0.tar.gz", hash = "sha256:b21d48ee64f0f6a1ed111efe4871a83e542529f1a75a264833b50e6433cd3c98"}, + {file = "gotrue-2.4.1-py3-none-any.whl", hash = "sha256:9647bb7a585c969d26667df21168fa20b18f91c5d6afe286af08d7a0610fd2cc"}, + {file = "gotrue-2.4.1.tar.gz", hash = "sha256:8b260ef285f45a3a2f9b5a006f12afb9fad7a36a28fa277f19e733f22eb88584"}, ] [package.dependencies] @@ -3332,13 +3332,13 @@ extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15. [[package]] name = "langchain-core" -version = "0.1.26" +version = "0.1.27" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_core-0.1.26-py3-none-any.whl", hash = "sha256:4f54cd26c27473172d7a214a5507a4c0e3255c6d8c25d9087afdc967f5588516"}, - {file = "langchain_core-0.1.26.tar.gz", hash = "sha256:6186758d62015723aac67ef1a2055695d03e82c4dd4074217975b0c62faf4b17"}, + {file = "langchain_core-0.1.27-py3-none-any.whl", hash = "sha256:68eb89dc4a932baf4fb6b4b75b7119eec9e5405e892d2137e9fe0a1d24a40d0c"}, + {file = "langchain_core-0.1.27.tar.gz", hash = "sha256:698414223525c0bc130d85a614e1493905d588ab72fe0c9ad3b537b1dc62067f"}, ] [package.dependencies] @@ -3356,18 +3356,18 @@ extended-testing = ["jinja2 (>=3,<4)"] [[package]] name = "langchain-experimental" -version = "0.0.52" +version = "0.0.53" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain_experimental-0.0.52-py3-none-any.whl", hash = "sha256:30bc6f4aba3ceef75a29b92d775110bbfeb35a7ddb50555fa3b09d4acbf20caa"}, - {file = "langchain_experimental-0.0.52.tar.gz", hash = "sha256:c8f896d8b9fec363038c9a7f0acb16d0b69d0ed31134eed79ea9c31fd5569256"}, + {file = "langchain_experimental-0.0.53-py3-none-any.whl", hash = "sha256:0e086d163891c7781f61d01739e37a7230fd68dfd73a12e81aa4506f82338956"}, + {file = "langchain_experimental-0.0.53.tar.gz", hash = "sha256:f8c1df800e70e7f8d7b969d2bf4c0188d183036a8707105ba469e25f44ec7b2f"}, ] [package.dependencies] langchain = ">=0.1.8,<0.2.0" -langchain-core = ">=0.1.24,<0.2.0" +langchain-core = ">=0.1.27,<0.2.0" [package.extras] extended-testing = ["faker (>=19.3.1,<20.0.0)", "jinja2 (>=3,<4)", "pandas (>=2.0.1,<3.0.0)", "presidio-analyzer (>=2.2.352,<3.0.0)", "presidio-anonymizer (>=2.2.352,<3.0.0)", "sentence-transformers (>=2,<3)", "tabulate (>=0.9.0,<0.10.0)", "vowpal-wabbit-next (==0.6.0)"] @@ -3423,37 +3423,37 @@ six = "*" [[package]] name = "langfuse" -version = "2.16.2" +version = "2.19.0" description = "A client library for accessing langfuse" optional = false -python-versions = ">=3.8.1,<3.13" +python-versions = ">=3.8.1,<4.0" files = [ - {file = "langfuse-2.16.2-py3-none-any.whl", hash = "sha256:6aa6911a9fb9cb1a9ffc67c9afb88e741ff95888ca711b03278e49b73a36adb1"}, - {file = "langfuse-2.16.2.tar.gz", hash = "sha256:17bec8a86497a836a75fd87aeebd8d333800570b5988eae71d72d1d99fe22431"}, + {file = "langfuse-2.19.0-py3-none-any.whl", hash = "sha256:33c8833e4a6b55ef2b2f3342f861a3c9960155da26554bc7eb2fd1bfeb5bea4f"}, + {file = "langfuse-2.19.0.tar.gz", hash = "sha256:a445b90b9047754d6a0f0fa0fbb93a191bdce48ba7a685798d0d92fc45f625c6"}, ] [package.dependencies] backoff = ">=2.2.1,<3.0.0" chevron = ">=0.14.0,<0.15.0" -httpx = ">=0.15.4,<0.26.0" +httpx = ">=0.15.4,<1.0" openai = ">=0.27.8" packaging = ">=23.2,<24.0" pydantic = ">=1.10.7,<3.0" -wrapt = "1.14" +wrapt = ">=1.14,<2.0" [package.extras] langchain = ["langchain (>=0.0.309)"] -llama-index = ["llama-index (>=0.10.6,<0.11.0)"] +llama-index = ["llama-index (>=0.10.12,<0.11.0)"] [[package]] name = "langsmith" -version = "0.1.9" +version = "0.1.10" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.1.9-py3-none-any.whl", hash = "sha256:f821b3cb07a87eac5cb2181ff0b61051811e4eef09ae4b46e700981f7ae5dfb9"}, - {file = "langsmith-0.1.9.tar.gz", hash = "sha256:9bd3e80607722c3d2db84cf3440005491a859b80b5e499bc988032d5c2da91f0"}, + {file = "langsmith-0.1.10-py3-none-any.whl", hash = "sha256:2997a80aea60ed235d83502a7ccdc1f62ffb4dd6b3b7dd4218e8fa4de68a6725"}, + {file = "langsmith-0.1.10.tar.gz", hash = "sha256:13e7e8b52e694aa4003370cefbb9e79cce3540c65dbf1517902bf7aa4dbbb653"}, ] [package.dependencies] @@ -3480,12 +3480,12 @@ regex = ["regex"] [[package]] name = "llama-cpp-python" -version = "0.2.52" +version = "0.2.53" description = "Python bindings for the llama.cpp library" optional = true python-versions = ">=3.8" files = [ - {file = "llama_cpp_python-0.2.52.tar.gz", hash = "sha256:cc3f670ea5b315547396b0bbc108fcc9602d19b8af858e03c4c0fae385fb9a04"}, + {file = "llama_cpp_python-0.2.53.tar.gz", hash = "sha256:f7ff8eda538ca6c80521a8bbf80d3ef4527ecb28f6d08fa9b3bb1f0cfc3b684e"}, ] [package.dependencies] @@ -3502,19 +3502,19 @@ test = ["httpx (>=0.24.1)", "pytest (>=7.4.0)", "scipy (>=1.10)"] [[package]] name = "llama-index" -version = "0.10.13.post1" +version = "0.10.14" description = "Interface between LLMs and your data" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "llama_index-0.10.13.post1-py3-none-any.whl", hash = "sha256:3a1281eb5b5505d3c4b5d8da036561e267c5b9311bd3ddbeeab3e1eeb92df86a"}, - {file = "llama_index-0.10.13.post1.tar.gz", hash = "sha256:55a8bb34b4f538fb33f6db914d89ad2dbc7ae5e0ec24d8bc4238ed05ff502ee2"}, + {file = "llama_index-0.10.14-py3-none-any.whl", hash = "sha256:31883c563b1a8d296910c2d5fa054ebc60539064d5dcac25114e4bb9749883e5"}, + {file = "llama_index-0.10.14.tar.gz", hash = "sha256:bfc25753ea0c3c59918b4f5925cb470a478b3b0da083a45c48f1992ab16a695f"}, ] [package.dependencies] llama-index-agent-openai = ">=0.1.4,<0.2.0" llama-index-cli = ">=0.1.2,<0.2.0" -llama-index-core = ">=0.10.13,<0.11.0" +llama-index-core = ">=0.10.14,<0.11.0" llama-index-embeddings-openai = ">=0.1.5,<0.2.0" llama-index-indices-managed-llama-cloud = ">=0.1.2,<0.2.0" llama-index-legacy = ">=0.9.48,<0.10.0" @@ -3542,13 +3542,13 @@ llama-index-llms-openai = ">=0.1.5,<0.2.0" [[package]] name = "llama-index-cli" -version = "0.1.5" +version = "0.1.6" description = "llama-index cli" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "llama_index_cli-0.1.5-py3-none-any.whl", hash = "sha256:a0fcfc3239d8b05158558423ca5c1a426d2a455eab44128b2b786cab566f74ad"}, - {file = "llama_index_cli-0.1.5.tar.gz", hash = "sha256:e2493ff7ecfd1983fd15c28c6c0c7bfdba66662c1d8960f6aea229db3d7fafda"}, + {file = "llama_index_cli-0.1.6-py3-none-any.whl", hash = "sha256:403c1b0be437d5fa3ca677dbc61dcebbf095ad4daf565fcc0f9db28e94be5df1"}, + {file = "llama_index_cli-0.1.6.tar.gz", hash = "sha256:bf94e6c61ab75240dbe59b867b9b3e4788b0f66b2cb1c2efb18320735a0bf612"}, ] [package.dependencies] @@ -3559,13 +3559,13 @@ llama-index-vector-stores-chroma = ">=0.1.1,<0.2.0" [[package]] name = "llama-index-core" -version = "0.10.13" +version = "0.10.14" description = "Interface between LLMs and your data" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "llama_index_core-0.10.13-py3-none-any.whl", hash = "sha256:40c76fc02be7cd948a333ca541f2ff38cf02774e1c960674e2b68c61943bac90"}, - {file = "llama_index_core-0.10.13.tar.gz", hash = "sha256:826fded00767923fba8aca94f46c32b259e8879f517016ab7a3801b1b37187a1"}, + {file = "llama_index_core-0.10.14-py3-none-any.whl", hash = "sha256:52e99ae101a32b2894477e49a0c4bc93de721a71d598fea61e4d9e8e68a35633"}, + {file = "llama_index_core-0.10.14.tar.gz", hash = "sha256:db6c66948c51751545a73bb3acecfe401649e05296d8865d71d22bcb5a1e55e7"}, ] [package.dependencies] @@ -3764,13 +3764,13 @@ llama-parse = ">=0.3.3,<0.4.0" [[package]] name = "llama-index-vector-stores-chroma" -version = "0.1.4" +version = "0.1.5" description = "llama-index vector_stores chroma integration" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "llama_index_vector_stores_chroma-0.1.4-py3-none-any.whl", hash = "sha256:f475a450431ee4d9b2915ba9da2112dfdfacaee1ea220b8603720be1c116786c"}, - {file = "llama_index_vector_stores_chroma-0.1.4.tar.gz", hash = "sha256:7364f2a3f8a51b83d350da39da7e7046704cfa9c848ebe8fd1c6cb39ad4878f9"}, + {file = "llama_index_vector_stores_chroma-0.1.5-py3-none-any.whl", hash = "sha256:40692f8bcc4b44d4a28b6ed578bad71fbc33ce5d95220c29b00e5ba7ab00d8a0"}, + {file = "llama_index_vector_stores_chroma-0.1.5.tar.gz", hash = "sha256:5e6ed1bc0b0e4c54a030b7ec95cc19015af4a8a22d3c37deb66f76b017d54b14"}, ] [package.dependencies] @@ -3781,13 +3781,13 @@ tokenizers = ">=0.15.1,<0.16.0" [[package]] name = "llama-parse" -version = "0.3.4" +version = "0.3.5" description = "Parse files into RAG-Optimized formats." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "llama_parse-0.3.4-py3-none-any.whl", hash = "sha256:b667c78d4c32fc5d0561e6e3ca6c53648a6701b436f21d0d252cd46774927660"}, - {file = "llama_parse-0.3.4.tar.gz", hash = "sha256:5a30569c390ab9089dad66cf2a8c967f8c21d77641deec0a922672df4e16cfa3"}, + {file = "llama_parse-0.3.5-py3-none-any.whl", hash = "sha256:8e6e7a0986ad30cb82c5c67a29b7e2c3892620dd2a422afc909654a9d0f1c82c"}, + {file = "llama_parse-0.3.5.tar.gz", hash = "sha256:736a80e4fc5970b9cbef1048171908021ebd26be43f07b806889f0d1bb3875fe"}, ] [package.dependencies] @@ -3810,13 +3810,13 @@ pydantic = ">=1.10" [[package]] name = "locust" -version = "2.23.1" +version = "2.24.0" description = "Developer friendly load testing framework" optional = false python-versions = ">=3.8" files = [ - {file = "locust-2.23.1-py3-none-any.whl", hash = "sha256:96013a460a4b4d6d4fd46c70e6ff1fd2b6e03b48ddb1b48d1513d3134ba2cecf"}, - {file = "locust-2.23.1.tar.gz", hash = "sha256:6cc729729e5ebf5852fc9d845302cfcf0ab0132f198e68b3eb0c88b438b6a863"}, + {file = "locust-2.24.0-py3-none-any.whl", hash = "sha256:1b6b878b4fd0108fec956120815e69775d2616c8f4d1e9f365c222a7a5c17d9a"}, + {file = "locust-2.24.0.tar.gz", hash = "sha256:6cffa378d995244a7472af6be1d6139331f19aee44e907deee73e0281252804d"}, ] [package.dependencies] @@ -3832,6 +3832,7 @@ pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" requests = ">=2.26.0" roundrobin = ">=0.0.2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} Werkzeug = ">=2.0.0" [[package]] @@ -4906,13 +4907,13 @@ sympy = "*" [[package]] name = "openai" -version = "1.12.0" +version = "1.13.3" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.12.0-py3-none-any.whl", hash = "sha256:a54002c814e05222e413664f651b5916714e4700d041d5cf5724d3ae1a3e3481"}, - {file = "openai-1.12.0.tar.gz", hash = "sha256:99c5d257d09ea6533d689d1cc77caa0ac679fa21efef8893d8b0832a86877f1b"}, + {file = "openai-1.13.3-py3-none-any.whl", hash = "sha256:5769b62abd02f350a8dd1a3a242d8972c947860654466171d60fb0972ae0a41c"}, + {file = "openai-1.13.3.tar.gz", hash = "sha256:ff6c6b3bc7327e715e4b3592a923a5a1c7519ff5dd764a83d69f633d49e77a7b"}, ] [package.dependencies] @@ -5488,13 +5489,13 @@ tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "p [[package]] name = "postgrest" -version = "0.15.0" +version = "0.16.1" description = "PostgREST client for Python. This library provides an ORM interface to PostgREST." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "postgrest-0.15.0-py3-none-any.whl", hash = "sha256:f405b3c4adfa3fe61732fabb1d5d7c55111159d25fc595663ea75ff992cafd5b"}, - {file = "postgrest-0.15.0.tar.gz", hash = "sha256:2e6b4b2b721be2c4e2dbc8de49f8b6a8ed74663b3b0f6b04976c04e222b283cb"}, + {file = "postgrest-0.16.1-py3-none-any.whl", hash = "sha256:412ec6bf61c58f38c92b6b61f57ab50e25c73ca9ef415a6f56ed9cf5429614cb"}, + {file = "postgrest-0.16.1.tar.gz", hash = "sha256:d955824d37e7123a8313cbf10c8e0a8d42418fcb942cd8e1526e8509fb71574d"}, ] [package.dependencies] @@ -6042,13 +6043,13 @@ files = [ [[package]] name = "pydantic" -version = "2.6.2" +version = "2.6.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, - {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, ] [package.dependencies] @@ -6289,42 +6290,37 @@ zstd = ["zstandard"] [[package]] name = "pymupdf" -version = "1.23.25" +version = "1.23.26" description = "A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents." optional = false python-versions = ">=3.8" files = [ - {file = "PyMuPDF-1.23.25-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:6be2b20fbff40602f673fc8e60fde3e5911397f8ca9ed6aa2d15be94b12cc2c4"}, - {file = "PyMuPDF-1.23.25-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:0f6923a44fbeaeefaabb2fa10955dcef3624e8826db661201951f3b3409fed32"}, - {file = "PyMuPDF-1.23.25-cp310-none-manylinux2014_aarch64.whl", hash = "sha256:8eeb2e97347586ec293fddaf61e8dfc58d6b2763406e8f7a6e45b560bf9b15a3"}, - {file = "PyMuPDF-1.23.25-cp310-none-manylinux2014_x86_64.whl", hash = "sha256:dca46799c152051697c5e88d66c17ba6d0244668d0c4dd8a2ba2d8d3cb745988"}, - {file = "PyMuPDF-1.23.25-cp310-none-win32.whl", hash = "sha256:88bfed1bd13ec84869489fc7b97381016cb8b99956073f4c3e8ac8c840bbb15a"}, - {file = "PyMuPDF-1.23.25-cp310-none-win_amd64.whl", hash = "sha256:98a78582c8a0c61b372e2bcd63dc61efc873e40b7d1f0b896a195e1a9ef9ffa7"}, - {file = "PyMuPDF-1.23.25-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:d7792810634036a745ea3eb3c4ccf2b6adab55ca9644e3352747d2b5aa5327f9"}, - {file = "PyMuPDF-1.23.25-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:03bd1985b0234c3d2b8e26bb3e9ab1d2641dbada1e199b838a6bf884f35224c8"}, - {file = "PyMuPDF-1.23.25-cp311-none-manylinux2014_aarch64.whl", hash = "sha256:638fcb1f7551eb5ab582e412e204e8ded94acbbc37bc7f1e891a5dfc428881ee"}, - {file = "PyMuPDF-1.23.25-cp311-none-manylinux2014_x86_64.whl", hash = "sha256:067c88b4e6609cb7e74d98d0b0a35c11eb8e29f4fc51dc7ed1dd448b81d347c7"}, - {file = "PyMuPDF-1.23.25-cp311-none-win32.whl", hash = "sha256:a694f160d1701285cf3152951430740878d168511cd9ea0a3adcfaf3cac00322"}, - {file = "PyMuPDF-1.23.25-cp311-none-win_amd64.whl", hash = "sha256:514bcb679926b33413637b0bd73b223c90fb0d19352caf3395d0f23b1d47e8af"}, - {file = "PyMuPDF-1.23.25-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:bba342321e1b5574631894d7d34ec046605d953a23553b7d2f9c0e4d3c27254b"}, - {file = "PyMuPDF-1.23.25-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:b2cb058c8229f9697deebe0574f7d95e4b9a5e295ceafd554346bbd464141e89"}, - {file = "PyMuPDF-1.23.25-cp312-none-manylinux2014_aarch64.whl", hash = "sha256:2479473b533936593428ce78499a1e9901570110ac602f03f1f3174efa0fa6a8"}, - {file = "PyMuPDF-1.23.25-cp312-none-manylinux2014_x86_64.whl", hash = "sha256:a247a4be1e43a6127ee305eae9f65767ee7519a2aa0cb1a2aa6acfd4e7fe7a9b"}, - {file = "PyMuPDF-1.23.25-cp312-none-win32.whl", hash = "sha256:b062be400bbaff6e8b17c0a8da9481e01ec935f97967e0870e9aacd7ba60a52a"}, - {file = "PyMuPDF-1.23.25-cp312-none-win_amd64.whl", hash = "sha256:b12e608761e1586a65f6e96a34417a91f814dbab29f2929b41d825ab32fab6ef"}, - {file = "PyMuPDF-1.23.25-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:ac97691c0e0e23607626d394bd660a46ea33f64921dc9288cf24daee207f9fe3"}, - {file = "PyMuPDF-1.23.25-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:c0a16cda5dc9b59d494ae23bdd9c4a3db53d04f2b6390265f5c0fe6269777975"}, - {file = "PyMuPDF-1.23.25-cp38-none-manylinux2014_aarch64.whl", hash = "sha256:23d735db51722a889bb50636d161d2747f08fa0b82cc2e4a7eb8e228b25d1c4e"}, - {file = "PyMuPDF-1.23.25-cp38-none-manylinux2014_x86_64.whl", hash = "sha256:cbc1407dcf01b2e3e547b2d7643b97cc44c0950d2bb4b12c74322664c5cb37d7"}, - {file = "PyMuPDF-1.23.25-cp38-none-win32.whl", hash = "sha256:c29518701d6360beb01c25cf69a77b6426db90a9e7cd11179b3bd783c7fb4cb1"}, - {file = "PyMuPDF-1.23.25-cp38-none-win_amd64.whl", hash = "sha256:c1bb6fa9e00c846e6829dec2bee8326754adaef5c80626b99233c01923f0342c"}, - {file = "PyMuPDF-1.23.25-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:514b272bfcd897f9ae29384da04167dcdea3b13ce0f2b9099b645314355d037d"}, - {file = "PyMuPDF-1.23.25-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:ef345a5b050d0869ef404845075edd5f4bd7fd99e235f4d32ce85f423779a120"}, - {file = "PyMuPDF-1.23.25-cp39-none-manylinux2014_aarch64.whl", hash = "sha256:b3ade5b349c38ddffb24f8c266fbcd7161f488c43960ff0f03f977d40d4df967"}, - {file = "PyMuPDF-1.23.25-cp39-none-manylinux2014_x86_64.whl", hash = "sha256:111d795a3e840aec2ad66beebd90a5327994ec85ed56fd68312f5463062dbbfa"}, - {file = "PyMuPDF-1.23.25-cp39-none-win32.whl", hash = "sha256:2237ce9897771f4af686cc0c81517ffb020fc1a011b95ccf5ccf05383492bd6d"}, - {file = "PyMuPDF-1.23.25-cp39-none-win_amd64.whl", hash = "sha256:251c9c321a2112716068d5ae11deedd1911d0387cbdd0ef19adb216a3adf882c"}, - {file = "PyMuPDF-1.23.25.tar.gz", hash = "sha256:eb414e92f08107f43576a1fedea28aa837220b15ad58c8e32015435fe96cc03e"}, + {file = "PyMuPDF-1.23.26-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:645a05321aecc8c45739f71f0eb574ce33138d19189582ffa5241fea3a8e2549"}, + {file = "PyMuPDF-1.23.26-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:2dfc9e010669ae92fade6fb72aaea49ebe3b8dcd7ee4dcbbe50115abcaa4d3fe"}, + {file = "PyMuPDF-1.23.26-cp310-none-manylinux2014_x86_64.whl", hash = "sha256:b22f8d854f8196ad5b20308c1cebad3d5189ed9f0988acbafa043947ea7e6c55"}, + {file = "PyMuPDF-1.23.26-cp310-none-win32.whl", hash = "sha256:cc0f794e3466bc96b5bf79d42fbc1551428751e3fef38ebc10ac70396b676144"}, + {file = "PyMuPDF-1.23.26-cp310-none-win_amd64.whl", hash = "sha256:2eb701247d8e685a24e45899d1175f01a3ce5fc792a4431c91fbb68633b29298"}, + {file = "PyMuPDF-1.23.26-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:e2804a64bb57da414781e312fb0561f6be67658ad57ed4a73dce008b23fc70a6"}, + {file = "PyMuPDF-1.23.26-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:97b40bb22e3056874634617a90e0ed24a5172cf71791b9e25d1d91c6743bc567"}, + {file = "PyMuPDF-1.23.26-cp311-none-manylinux2014_x86_64.whl", hash = "sha256:f25aafd3e7fb9d7761a22acf2b67d704f04cc36d4dc33a3773f0eb3f4ec3606f"}, + {file = "PyMuPDF-1.23.26-cp311-none-win32.whl", hash = "sha256:05e672ed3e82caca7ef02a88ace30130b1dd392a1190f03b2b58ffe7aa331400"}, + {file = "PyMuPDF-1.23.26-cp311-none-win_amd64.whl", hash = "sha256:92b3c4dd4d0491d495f333be2d41f4e1c155a409bc9d04b5ff29655dccbf4655"}, + {file = "PyMuPDF-1.23.26-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:a217689ede18cc6991b4e6a78afee8a440b3075d53b9dec4ba5ef7487d4547e9"}, + {file = "PyMuPDF-1.23.26-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:42ad2b819b90ce1947e11b90ec5085889df0a2e3aa0207bc97ecacfc6157cabc"}, + {file = "PyMuPDF-1.23.26-cp312-none-manylinux2014_x86_64.whl", hash = "sha256:bb42d4b8407b4de7cb58c28f01449f16f32a6daed88afb41108f1aeb3552bdd4"}, + {file = "PyMuPDF-1.23.26-cp312-none-win32.whl", hash = "sha256:c40d044411615e6f0baa7d3d933b3032cf97e168c7fa77d1be8a46008c109aee"}, + {file = "PyMuPDF-1.23.26-cp312-none-win_amd64.whl", hash = "sha256:3f876533aa7f9a94bcd9a0225ce72571b7808260903fec1d95c120bc842fb52d"}, + {file = "PyMuPDF-1.23.26-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:52df831d46beb9ff494f5fba3e5d069af6d81f49abf6b6e799ee01f4f8fa6799"}, + {file = "PyMuPDF-1.23.26-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:0bbb0cf6593e53524f3fc26fb5e6ead17c02c64791caec7c4afe61b677dedf80"}, + {file = "PyMuPDF-1.23.26-cp38-none-manylinux2014_x86_64.whl", hash = "sha256:d7cd88842b2e7f4c71eef4d87c98c35646b80b60e6375392d7ce40e519261f59"}, + {file = "PyMuPDF-1.23.26-cp38-none-win32.whl", hash = "sha256:6577e2f473625e2d0df5f5a3bf1e4519e94ae749733cc9937994d1b256687bfa"}, + {file = "PyMuPDF-1.23.26-cp38-none-win_amd64.whl", hash = "sha256:fbe1a3255b2cd0d769b2da2c4efdd0c0f30d4961a1aac02c0f75cf951b337aa4"}, + {file = "PyMuPDF-1.23.26-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:73fce034f2afea886a59ead2d0caedf27e2b2a8558b5da16d0286882e0b1eb82"}, + {file = "PyMuPDF-1.23.26-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:b3de8618b7cb5b36db611083840b3bcf09b11a893e2d8262f4e042102c7e65de"}, + {file = "PyMuPDF-1.23.26-cp39-none-manylinux2014_x86_64.whl", hash = "sha256:deee96c2fd415ded7b5070d8d5b2c60679aee6ed0e28ac0d2cb998060d835c2c"}, + {file = "PyMuPDF-1.23.26-cp39-none-win32.whl", hash = "sha256:9f7f4ef99dd8ac97fb0b852efa3dcbee515798078b6c79a6a13c7b1e7c5d41a4"}, + {file = "PyMuPDF-1.23.26-cp39-none-win_amd64.whl", hash = "sha256:ba9a54552c7afb9ec85432c765e2fa9a81413acfaa7d70db7c9b528297749e5b"}, + {file = "PyMuPDF-1.23.26.tar.gz", hash = "sha256:a904261b317b761b0aa2bd2c1f6cd25d25aa4258be67a90c02a878efc5dca649"}, ] [package.dependencies] @@ -7076,17 +7072,17 @@ files = [ [[package]] name = "redis" -version = "5.0.1" +version = "5.0.2" description = "Python client for Redis database and key-value store" optional = true python-versions = ">=3.7" files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, + {file = "redis-5.0.2-py3-none-any.whl", hash = "sha256:4caa8e1fcb6f3c0ef28dba99535101d80934b7d4cd541bbb47f4a3826ee472d1"}, + {file = "redis-5.0.2.tar.gz", hash = "sha256:3f82cc80d350e93042c8e6e7a5d0596e4dd68715babffba79492733e1f367037"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} +async-timeout = ">=4.0.3" [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -7235,13 +7231,13 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] name = "rich" -version = "13.7.0" +version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, ] [package.dependencies] @@ -7555,13 +7551,13 @@ test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", [[package]] name = "sentence-transformers" -version = "2.4.0" +version = "2.5.0" description = "Multilingual text embeddings" optional = true python-versions = ">=3.8.0" files = [ - {file = "sentence-transformers-2.4.0.tar.gz", hash = "sha256:5134d3d8d1c55bab9e99599cfc90c6c18bc298f7dcba94f2095d47950e32c88b"}, - {file = "sentence_transformers-2.4.0-py3-none-any.whl", hash = "sha256:e14d70b5a1a01ac0fe9ddef7131afa10791e1b96edf52400cfb8f3176dd1e115"}, + {file = "sentence-transformers-2.5.0.tar.gz", hash = "sha256:42cbd4130d58e8e08ea966bf94b012136f0939bbe692ab28dcd00d3e69c57989"}, + {file = "sentence_transformers-2.5.0-py3-none-any.whl", hash = "sha256:2a8df56b1c2171a2c625294bd371ebd61bbbfd1208f4fbac0f8cf95aeaffb79d"}, ] [package.dependencies] @@ -7813,19 +7809,19 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "supabase" -version = "2.3.7" +version = "2.4.0" description = "Supabase client for Python." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "supabase-2.3.7-py3-none-any.whl", hash = "sha256:a4616aa9149231d20f6e61884b90b7e5bdbde0ef0c2f0c12ced14536f39055bc"}, - {file = "supabase-2.3.7.tar.gz", hash = "sha256:d70dc986b7cd2a97c1916da1fa0ea6abae25690521cc9dd78016ab0e0c07116e"}, + {file = "supabase-2.4.0-py3-none-any.whl", hash = "sha256:f2f02b0e7903247ef9e2b3cb5dde067924a19a068f1c8befbdf40fb091bf8dd3"}, + {file = "supabase-2.4.0.tar.gz", hash = "sha256:d51556d3884f2e6f4588c33f1fcac954d4304238253bc35e9a87fdd22c43bafb"}, ] [package.dependencies] gotrue = ">=1.3,<3.0" httpx = ">=0.24,<0.26" -postgrest = ">=0.10.8,<0.16.0" +postgrest = ">=0.10.8,<0.17.0" realtime = ">=1.0.0,<2.0.0" storage3 = ">=0.5.3,<0.8.0" supafunc = ">=0.3.1,<0.4.0" @@ -8383,13 +8379,13 @@ files = [ [[package]] name = "types-pyopenssl" -version = "24.0.0.20240130" +version = "24.0.0.20240228" description = "Typing stubs for pyOpenSSL" optional = false python-versions = ">=3.8" files = [ - {file = "types-pyOpenSSL-24.0.0.20240130.tar.gz", hash = "sha256:c812e5c1c35249f75ef5935708b2a997d62abf9745be222e5f94b9595472ab25"}, - {file = "types_pyOpenSSL-24.0.0.20240130-py3-none-any.whl", hash = "sha256:24a255458b5b8a7fca8139cf56f2a8ad5a4f1a5f711b73a5bb9cb50dc688fab5"}, + {file = "types-pyOpenSSL-24.0.0.20240228.tar.gz", hash = "sha256:cd990717d8aa3743ef0e73e0f462e64b54d90c304249232d48fece4f0f7c3c6a"}, + {file = "types_pyOpenSSL-24.0.0.20240228-py3-none-any.whl", hash = "sha256:a472cf877a873549175e81972f153f44e975302a3cf17381eb5f3d41ccfb75a4"}, ] [package.dependencies] @@ -8552,13 +8548,13 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3) [[package]] name = "unstructured" -version = "0.12.4" +version = "0.12.5" description = "A library that prepares raw documents for downstream ML tasks." optional = false python-versions = ">=3.9.0,<3.12" files = [ - {file = "unstructured-0.12.4-py3-none-any.whl", hash = "sha256:f1aa046297a3afba3aa16895e513aca6a93802ef73b7a18080656435c4deb217"}, - {file = "unstructured-0.12.4.tar.gz", hash = "sha256:019cf52e9e2bfa286e61ffa0d7d336e1645280f9a0f165e697583143fcfe708a"}, + {file = "unstructured-0.12.5-py3-none-any.whl", hash = "sha256:cce7de36964f556810adb8728d0639d8e9b3ef4567443877609f3c66a54e24d1"}, + {file = "unstructured-0.12.5.tar.gz", hash = "sha256:5ea6c881049e7d98a88c07192bcb6ab750de41b4e3b594972ed1034bda99dbae"}, ] [package.dependencies] @@ -8585,6 +8581,7 @@ wrapt = "*" [package.extras] airtable = ["pyairtable"] all-docs = ["markdown", "msg-parser", "networkx", "onnx", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pikepdf", "pillow-heif", "pypandoc", "pypdf", "python-docx", "python-pptx (<=0.6.23)", "unstructured-inference (==0.7.23)", "unstructured.pytesseract (>=0.3.12)", "xlrd"] +astra = ["astrapy"] azure = ["adlfs", "fsspec"] azure-cognitive-search = ["azure-search-documents"] bedrock = ["boto3", "langchain-community"] @@ -9087,75 +9084,81 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [[package]] name = "wrapt" -version = "1.14.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"}, - {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9a3ff5fb015f6feb78340143584d9f8a0b91b6293d6b5cf4295b3e95d179b88c"}, - {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4b847029e2d5e11fd536c9ac3136ddc3f54bc9488a75ef7d040a3900406a91eb"}, - {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9a5a544861b21e0e7575b6023adebe7a8c6321127bb1d238eb40d99803a0e8bd"}, - {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:88236b90dda77f0394f878324cfbae05ae6fde8a84d548cfe73a75278d760291"}, - {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f0408e2dbad9e82b4c960274214af533f856a199c9274bd4aff55d4634dedc33"}, - {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9d8c68c4145041b4eeae96239802cfdfd9ef927754a5be3f50505f09f309d8c6"}, - {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:22626dca56fd7f55a0733e604f1027277eb0f4f3d95ff28f15d27ac25a45f71b"}, - {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:65bf3eb34721bf18b5a021a1ad7aa05947a1767d1aa272b725728014475ea7d5"}, - {file = "wrapt-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09d16ae7a13cff43660155383a2372b4aa09109c7127aa3f24c3cf99b891c330"}, - {file = "wrapt-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:debaf04f813ada978d7d16c7dfa16f3c9c2ec9adf4656efdc4defdf841fc2f0c"}, - {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748df39ed634851350efa87690c2237a678ed794fe9ede3f0d79f071ee042561"}, - {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1807054aa7b61ad8d8103b3b30c9764de2e9d0c0978e9d3fc337e4e74bf25faa"}, - {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763a73ab377390e2af26042f685a26787c402390f682443727b847e9496e4a2a"}, - {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8529b07b49b2d89d6917cfa157d3ea1dfb4d319d51e23030664a827fe5fd2131"}, - {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:68aeefac31c1f73949662ba8affaf9950b9938b712fb9d428fa2a07e40ee57f8"}, - {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59d7d92cee84a547d91267f0fea381c363121d70fe90b12cd88241bd9b0e1763"}, - {file = "wrapt-1.14.0-cp310-cp310-win32.whl", hash = "sha256:3a88254881e8a8c4784ecc9cb2249ff757fd94b911d5df9a5984961b96113fff"}, - {file = "wrapt-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a242871b3d8eecc56d350e5e03ea1854de47b17f040446da0e47dc3e0b9ad4d"}, - {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a65bffd24409454b889af33b6c49d0d9bcd1a219b972fba975ac935f17bdf627"}, - {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9d9fcd06c952efa4b6b95f3d788a819b7f33d11bea377be6b8980c95e7d10775"}, - {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:db6a0ddc1282ceb9032e41853e659c9b638789be38e5b8ad7498caac00231c23"}, - {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:14e7e2c5f5fca67e9a6d5f753d21f138398cad2b1159913ec9e9a67745f09ba3"}, - {file = "wrapt-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:6d9810d4f697d58fd66039ab959e6d37e63ab377008ef1d63904df25956c7db0"}, - {file = "wrapt-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:d808a5a5411982a09fef6b49aac62986274ab050e9d3e9817ad65b2791ed1425"}, - {file = "wrapt-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b77159d9862374da213f741af0c361720200ab7ad21b9f12556e0eb95912cd48"}, - {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a76a7527df8583112b24adc01748cd51a2d14e905b337a6fefa8b96fc708fb"}, - {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0057b5435a65b933cbf5d859cd4956624df37b8bf0917c71756e4b3d9958b9e"}, - {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0a4ca02752ced5f37498827e49c414d694ad7cf451ee850e3ff160f2bee9d3"}, - {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8c6be72eac3c14baa473620e04f74186c5d8f45d80f8f2b4eda6e1d18af808e8"}, - {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:21b1106bff6ece8cb203ef45b4f5778d7226c941c83aaaa1e1f0f4f32cc148cd"}, - {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:493da1f8b1bb8a623c16552fb4a1e164c0200447eb83d3f68b44315ead3f9036"}, - {file = "wrapt-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:89ba3d548ee1e6291a20f3c7380c92f71e358ce8b9e48161401e087e0bc740f8"}, - {file = "wrapt-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:729d5e96566f44fccac6c4447ec2332636b4fe273f03da128fff8d5559782b06"}, - {file = "wrapt-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:891c353e95bb11abb548ca95c8b98050f3620a7378332eb90d6acdef35b401d4"}, - {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23f96134a3aa24cc50614920cc087e22f87439053d886e474638c68c8d15dc80"}, - {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6807bcee549a8cb2f38f73f469703a1d8d5d990815c3004f21ddb68a567385ce"}, - {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6915682f9a9bc4cf2908e83caf5895a685da1fbd20b6d485dafb8e218a338279"}, - {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f2f3bc7cd9c9fcd39143f11342eb5963317bd54ecc98e3650ca22704b69d9653"}, - {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3a71dbd792cc7a3d772ef8cd08d3048593f13d6f40a11f3427c000cf0a5b36a0"}, - {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5a0898a640559dec00f3614ffb11d97a2666ee9a2a6bad1259c9facd01a1d4d9"}, - {file = "wrapt-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:167e4793dc987f77fd476862d32fa404d42b71f6a85d3b38cbce711dba5e6b68"}, - {file = "wrapt-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d066ffc5ed0be00cd0352c95800a519cf9e4b5dd34a028d301bdc7177c72daf3"}, - {file = "wrapt-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9bdfa74d369256e4218000a629978590fd7cb6cf6893251dad13d051090436d"}, - {file = "wrapt-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2498762814dd7dd2a1d0248eda2afbc3dd9c11537bc8200a4b21789b6df6cd38"}, - {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f24ca7953f2643d59a9c87d6e272d8adddd4a53bb62b9208f36db408d7aafc7"}, - {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b835b86bd5a1bdbe257d610eecab07bf685b1af2a7563093e0e69180c1d4af1"}, - {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b21650fa6907e523869e0396c5bd591cc326e5c1dd594dcdccac089561cacfb8"}, - {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:354d9fc6b1e44750e2a67b4b108841f5f5ea08853453ecbf44c81fdc2e0d50bd"}, - {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f83e9c21cd5275991076b2ba1cd35418af3504667affb4745b48937e214bafe"}, - {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61e1a064906ccba038aa3c4a5a82f6199749efbbb3cef0804ae5c37f550eded0"}, - {file = "wrapt-1.14.0-cp38-cp38-win32.whl", hash = "sha256:28c659878f684365d53cf59dc9a1929ea2eecd7ac65da762be8b1ba193f7e84f"}, - {file = "wrapt-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:b0ed6ad6c9640671689c2dbe6244680fe8b897c08fd1fab2228429b66c518e5e"}, - {file = "wrapt-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3f7e671fb19734c872566e57ce7fc235fa953d7c181bb4ef138e17d607dc8a1"}, - {file = "wrapt-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87fa943e8bbe40c8c1ba4086971a6fefbf75e9991217c55ed1bcb2f1985bd3d4"}, - {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4775a574e9d84e0212f5b18886cace049a42e13e12009bb0491562a48bb2b758"}, - {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d57677238a0c5411c76097b8b93bdebb02eb845814c90f0b01727527a179e4d"}, - {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00108411e0f34c52ce16f81f1d308a571df7784932cc7491d1e94be2ee93374b"}, - {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d332eecf307fca852d02b63f35a7872de32d5ba8b4ec32da82f45df986b39ff6"}, - {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:01f799def9b96a8ec1ef6b9c1bbaf2bbc859b87545efbecc4a78faea13d0e3a0"}, - {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47045ed35481e857918ae78b54891fac0c1d197f22c95778e66302668309336c"}, - {file = "wrapt-1.14.0-cp39-cp39-win32.whl", hash = "sha256:2eca15d6b947cfff51ed76b2d60fd172c6ecd418ddab1c5126032d27f74bc350"}, - {file = "wrapt-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb36fbb48b22985d13a6b496ea5fb9bb2a076fea943831643836c9f6febbcfdc"}, - {file = "wrapt-1.14.0.tar.gz", hash = "sha256:8323a43bd9c91f62bb7d4be74cc9ff10090e7ef820e27bfe8815c57e68261311"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [[package]] @@ -9385,4 +9388,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "e34d70b4ca2e9bdab5478d4b0b31dc39379c4506d1cc6962e378090570ce757c" +content-hash = "524743a03769e472c83325641463bddb09f51dfc6ad50f8454c204bba8f484b5" diff --git a/pyproject.toml b/pyproject.toml index a52871cf6..c0b41cec7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ python-multipart = "^0.0.7" sqlmodel = "^0.0.14" faiss-cpu = "^1.7.4" anthropic = "^0.15.0" -orjson = "^3.9.3" +orjson = "3.9.15" multiprocess = "^0.70.14" cachetools = "^5.3.1" types-cachetools = "^5.3.0.5" diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index 8e12a3cf9..bc430e941 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -109,7 +109,11 @@ def version_callback(value: bool): @app.callback() def main_entry_point( version: bool = typer.Option( - None, "--version", callback=version_callback, is_eager=True, help="Show the version and exit." + None, + "--version", + callback=version_callback, + is_eager=True, + help="Show the version and exit.", ), ): """ diff --git a/src/backend/langflow/alembic.ini b/src/backend/langflow/alembic.ini index 379661422..9739c069d 100644 --- a/src/backend/langflow/alembic.ini +++ b/src/backend/langflow/alembic.ini @@ -63,7 +63,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # This is the path to the db in the root of the project. # When the user runs the Langflow the database url will # be set dinamically. -sqlalchemy.url = sqlite:///../../../langflow.db +sqlalchemy.url = sqlite:///./langflow.db [post_write_hooks] @@ -98,7 +98,7 @@ handlers = qualname = sqlalchemy.engine [logger_alembic] -level = INFO +level = DEBUG handlers = qualname = alembic diff --git a/src/backend/langflow/alembic/env.py b/src/backend/langflow/alembic/env.py index 283b24a6f..479db05bb 100644 --- a/src/backend/langflow/alembic/env.py +++ b/src/backend/langflow/alembic/env.py @@ -1,10 +1,11 @@ +import os from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool - from alembic import context +from loguru import logger +from sqlalchemy import engine_from_config, pool +from langflow.services.database.models import * # noqa from langflow.services.database.service import SQLModel # this is the Alembic Config object, which provides @@ -40,7 +41,8 @@ def run_migrations_offline() -> None: script output. """ - url = config.get_main_option("sqlalchemy.url") + url = os.getenv("LANGFLOW_DATABASE_URL") + url = url or config.get_main_option("sqlalchemy.url") context.configure( url=url, target_metadata=target_metadata, @@ -60,12 +62,17 @@ def run_migrations_online() -> None: and associate a connection with the context. """ - connectable = engine_from_config( - config.get_section(config.config_ini_section, {}), - prefix="sqlalchemy.", - poolclass=pool.NullPool, - ) + from langflow.services.deps import get_db_service + try: + connectable = get_db_service().engine + except Exception as e: + logger.error(f"Error getting database engine: {e}") + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) with connectable.connect() as connection: context.configure( connection=connection, target_metadata=target_metadata, render_as_batch=True diff --git a/src/backend/langflow/alembic/script.py.mako b/src/backend/langflow/alembic/script.py.mako index 6ce335109..2fbdc930d 100644 --- a/src/backend/langflow/alembic/script.py.mako +++ b/src/backend/langflow/alembic/script.py.mako @@ -10,6 +10,7 @@ from typing import Sequence, Union from alembic import op import sqlalchemy as sa import sqlmodel +from sqlalchemy.engine.reflection import Inspector ${imports if imports else ""} # revision identifiers, used by Alembic. @@ -20,8 +21,12 @@ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} def upgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore ${upgrades if upgrades else "pass"} def downgrade() -> None: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore ${downgrades if downgrades else "pass"} diff --git a/src/backend/langflow/alembic/versions/006b3990db50_add_unique_constraints.py b/src/backend/langflow/alembic/versions/006b3990db50_add_unique_constraints.py index dd3ccbe32..e5958ab73 100644 --- a/src/backend/langflow/alembic/versions/006b3990db50_add_unique_constraints.py +++ b/src/backend/langflow/alembic/versions/006b3990db50_add_unique_constraints.py @@ -5,28 +5,43 @@ Revises: 1ef9c4f3765d Create Date: 2023-12-13 18:55:52.587360 """ + from typing import Sequence, Union from alembic import op +from sqlalchemy.engine.reflection import Inspector # revision identifiers, used by Alembic. -revision: str = '006b3990db50' -down_revision: Union[str, None] = '1ef9c4f3765d' +revision: str = "006b3990db50" +down_revision: Union[str, None] = "1ef9c4f3765d" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + api_key_constraints = inspector.get_unique_constraints("apikey") + flow_constraints = inspector.get_unique_constraints("flow") + user_constraints = inspector.get_unique_constraints("user") try: - 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_apikey_id" for constraint in api_key_constraints + ): + with op.batch_alter_table("apikey", schema=None) as batch_op: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.create_unique_constraint('uq_flow_id', ['id']) - - with op.batch_alter_table('user', schema=None) as batch_op: - batch_op.create_unique_constraint('uq_user_id', ['id']) + batch_op.create_unique_constraint("uq_apikey_id", ["id"]) + 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 + ): + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.create_unique_constraint("uq_user_id", ["id"]) except Exception as e: print(e) pass @@ -36,15 +51,24 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + api_key_constraints = inspector.get_unique_constraints("apikey") + flow_constraints = inspector.get_unique_constraints("flow") + user_constraints = inspector.get_unique_constraints("user") try: - 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_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('flow', schema=None) as batch_op: - batch_op.drop_constraint('uq_flow_id', type_='unique') - - with op.batch_alter_table('apikey', schema=None) as batch_op: - batch_op.drop_constraint('uq_apikey_id', type_='unique') + with op.batch_alter_table("apikey", schema=None) as batch_op: + batch_op.drop_constraint("uq_apikey_id", type_="unique") except Exception as e: print(e) pass diff --git a/src/backend/langflow/alembic/versions/0b8757876a7c_.py b/src/backend/langflow/alembic/versions/0b8757876a7c_.py index 61b769694..da9e612f8 100644 --- a/src/backend/langflow/alembic/versions/0b8757876a7c_.py +++ b/src/backend/langflow/alembic/versions/0b8757876a7c_.py @@ -5,67 +5,25 @@ Revises: 006b3990db50 Create Date: 2024-01-17 10:32:56.686287 """ + from typing import Sequence, Union -from alembic import op - # revision identifiers, used by Alembic. -revision: str = '0b8757876a7c' -down_revision: Union[str, None] = '006b3990db50' +revision: str = "0b8757876a7c" +down_revision: Union[str, None] = "006b3990db50" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - try: - 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_name'), ['name'], unique=False) - batch_op.create_index(batch_op.f('ix_apikey_user_id'), ['user_id'], unique=False) - except Exception as e: - print(e) - pass - try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.create_index(batch_op.f('ix_flow_description'), ['description'], unique=False) - batch_op.create_index(batch_op.f('ix_flow_name'), ['name'], unique=False) - batch_op.create_index(batch_op.f('ix_flow_user_id'), ['user_id'], unique=False) - except Exception as e: - print(e) - pass + pass - try: - with op.batch_alter_table('user', schema=None) as batch_op: - batch_op.create_index(batch_op.f('ix_user_username'), ['username'], unique=True) - except Exception as e: - print(e) - pass # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - try: - with op.batch_alter_table('user', schema=None) as batch_op: - batch_op.drop_index(batch_op.f('ix_user_username')) - except Exception as e: - print(e) - pass - try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.drop_index(batch_op.f('ix_flow_user_id')) - batch_op.drop_index(batch_op.f('ix_flow_name')) - batch_op.drop_index(batch_op.f('ix_flow_description')) - except Exception as e: - print(e) - pass - try: - with op.batch_alter_table('apikey', schema=None) as batch_op: - batch_op.drop_index(batch_op.f('ix_apikey_user_id')) - batch_op.drop_index(batch_op.f('ix_apikey_name')) - batch_op.drop_index(batch_op.f('ix_apikey_api_key')) - except Exception as e: - print(e) - pass - # ### end Alembic commands ### \ No newline at end of file + + pass + # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/1ef9c4f3765d_.py b/src/backend/langflow/alembic/versions/1ef9c4f3765d_.py index f2bc42917..df92f1f02 100644 --- a/src/backend/langflow/alembic/versions/1ef9c4f3765d_.py +++ b/src/backend/langflow/alembic/versions/1ef9c4f3765d_.py @@ -6,6 +6,7 @@ Revises: fd531f8868b1 Create Date: 2023-12-04 15:00:27.968998 """ + from typing import Sequence, Union import sqlalchemy as sa @@ -13,8 +14,8 @@ import sqlmodel from alembic import op # revision identifiers, used by Alembic. -revision: str = '1ef9c4f3765d' -down_revision: Union[str, None] = 'fd531f8868b1' +revision: str = "1ef9c4f3765d" +down_revision: Union[str, None] = "fd531f8868b1" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None @@ -22,10 +23,10 @@ depends_on: Union[str, Sequence[str], None] = None 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) + 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: pass # ### end Alembic commands ### @@ -34,10 +35,8 @@ def upgrade() -> None: def downgrade() -> 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=sa.VARCHAR(), - nullable=False) + 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: pass # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py b/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py index 48c56e90d..0d7eed582 100644 --- a/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py +++ b/src/backend/langflow/alembic/versions/260dbcc8b680_adds_tables.py @@ -5,6 +5,7 @@ Revises: Create Date: 2023-08-27 19:49:02.681355 """ + from typing import Sequence, Union import sqlalchemy as sa @@ -33,7 +34,9 @@ def upgrade() -> None: 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") + op.drop_index( + "ix_flowstyle_flow_id", table_name="flowstyle", if_exists=True + ) existing_indices_flow = [] existing_fks_flow = [] @@ -80,8 +83,7 @@ def upgrade() -> None: 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"], + ["user_id"], ["user.id"], name="fk_apikey_user_id_user" ), sa.PrimaryKeyConstraint("id", name="pk_apikey"), sa.UniqueConstraint("id", name="uq_apikey_id"), @@ -103,8 +105,7 @@ def upgrade() -> None: 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"], + ["user_id"], ["user.id"], name="fk_flow_user_id_user" ), sa.PrimaryKeyConstraint("id", name="pk_flow"), sa.UniqueConstraint("id", name="uq_flow_id"), @@ -151,21 +152,21 @@ def downgrade() -> None: existing_tables = inspector.get_table_names() if "flow" in existing_tables: with op.batch_alter_table("flow", schema=None) as batch_op: - batch_op.drop_index(batch_op.f("ix_flow_user_id")) - batch_op.drop_index(batch_op.f("ix_flow_name")) - batch_op.drop_index(batch_op.f("ix_flow_description")) + batch_op.drop_index(batch_op.f("ix_flow_user_id"), if_exists=True) + batch_op.drop_index(batch_op.f("ix_flow_name"), if_exists=True) + batch_op.drop_index(batch_op.f("ix_flow_description"), if_exists=True) op.drop_table("flow") if "apikey" in existing_tables: with op.batch_alter_table("apikey", schema=None) as batch_op: - batch_op.drop_index(batch_op.f("ix_apikey_user_id")) - batch_op.drop_index(batch_op.f("ix_apikey_name")) - batch_op.drop_index(batch_op.f("ix_apikey_api_key")) + batch_op.drop_index(batch_op.f("ix_apikey_user_id"), if_exists=True) + batch_op.drop_index(batch_op.f("ix_apikey_name"), if_exists=True) + batch_op.drop_index(batch_op.f("ix_apikey_api_key"), if_exists=True) op.drop_table("apikey") if "user" in existing_tables: with op.batch_alter_table("user", schema=None) as batch_op: - batch_op.drop_index(batch_op.f("ix_user_username")) + batch_op.drop_index(batch_op.f("ix_user_username"), if_exists=True) op.drop_table("user") diff --git a/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py b/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py index 1ac3e1a13..ce2d2cd76 100644 --- a/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py +++ b/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py @@ -5,34 +5,44 @@ Revises: 7d2162acc8b2 Create Date: 2023-11-24 10:45:38.465302 """ + 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 = '2ac71eb9c3ae' -down_revision: Union[str, None] = '7d2162acc8b2' +revision: str = "2ac71eb9c3ae" +down_revision: Union[str, None] = "7d2162acc8b2" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + tables = inspector.get_table_names() try: - op.create_table('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('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), - sa.Column('updated_at', sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint('id'), - ) + if "credential" not in tables: + op.create_table( + "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("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), + sa.Column("updated_at", sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) except Exception as e: print(e) + pass # ### end Alembic commands ### @@ -40,7 +50,7 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### try: - op.drop_table('credential') + op.drop_table("credential") except Exception as e: print(e) pass diff --git a/src/backend/langflow/alembic/versions/67cc006d50bf_add_profile_image_column.py b/src/backend/langflow/alembic/versions/67cc006d50bf_add_profile_image_column.py index 6ce9316ac..0d97df314 100644 --- a/src/backend/langflow/alembic/versions/67cc006d50bf_add_profile_image_column.py +++ b/src/backend/langflow/alembic/versions/67cc006d50bf_add_profile_image_column.py @@ -5,6 +5,7 @@ Revises: 260dbcc8b680 Create Date: 2023-09-08 07:36:13.387318 """ + from typing import Sequence, Union import sqlalchemy as sa @@ -21,29 +22,36 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - conn = op.get_bind() - inspector = Inspector.from_engine(conn) # type: ignore - if "user" in inspector.get_table_names() and "profile_image" not in [ - column["name"] for column in inspector.get_columns("user") - ]: - with op.batch_alter_table("user", schema=None) as batch_op: - batch_op.add_column( - sa.Column( - "profile_image", sqlmodel.sql.sqltypes.AutoString(), nullable=True + try: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + if "user" in inspector.get_table_names() and "profile_image" not in [ + column["name"] for column in inspector.get_columns("user") + ]: + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.add_column( + sa.Column( + "profile_image", + sqlmodel.sql.sqltypes.AutoString(), + nullable=True, + ) ) - ) - + except Exception as e: + print(e) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - conn = op.get_bind() - inspector = Inspector.from_engine(conn) # type: ignore - if "user" in inspector.get_table_names() and "profile_image" in [ - column["name"] for column in inspector.get_columns("user") - ]: - with op.batch_alter_table("user", schema=None) as batch_op: - batch_op.drop_column("profile_image") + try: + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + if "user" in inspector.get_table_names() and "profile_image" in [ + column["name"] for column in inspector.get_columns("user") + ]: + with op.batch_alter_table("user", schema=None) as batch_op: + batch_op.drop_column("profile_image") + except Exception as e: + print(e) # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/7843803a87b5_store_updates.py b/src/backend/langflow/alembic/versions/7843803a87b5_store_updates.py index e0b844b61..b1565cd0f 100644 --- a/src/backend/langflow/alembic/versions/7843803a87b5_store_updates.py +++ b/src/backend/langflow/alembic/versions/7843803a87b5_store_updates.py @@ -5,12 +5,13 @@ Revises: eb5866d51fd2 Create Date: 2023-10-18 23:08:57.744906 """ + from typing import Sequence, Union import sqlalchemy as sa import sqlmodel from alembic import op -from loguru import logger +from sqlalchemy.engine.reflection import Inspector # revision identifiers, used by Alembic. revision: str = "7843803a87b5" @@ -21,19 +22,26 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + flow_columns = [column["name"] for column in inspector.get_columns("flow")] + user_columns = [column["name"] for column in inspector.get_columns("user")] try: - with op.batch_alter_table("flow", schema=None) as batch_op: - batch_op.add_column(sa.Column("is_component", sa.Boolean(), nullable=True)) - - with op.batch_alter_table("user", schema=None) as batch_op: - batch_op.add_column( - sa.Column( - "store_api_key", sqlmodel.AutoString(), nullable=True + 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: - logger.exception(e) - + 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: + pass # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py b/src/backend/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py index 01dd38cfd..5ed929568 100644 --- a/src/backend/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py +++ b/src/backend/langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py @@ -5,88 +5,74 @@ Revises: f5ee9749d1a6 Create Date: 2023-11-21 20:56:53.998781 """ + 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 = '7d2162acc8b2' -down_revision: Union[str, None] = 'f5ee9749d1a6' +revision: str = "7d2162acc8b2" +down_revision: Union[str, None] = "f5ee9749d1a6" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + api_key_columns = [column["name"] for column in inspector.get_columns("apikey")] + flow_columns = [column["name"] for column in inspector.get_columns("flow")] + try: - with op.batch_alter_table('component', schema=None) as batch_op: - batch_op.drop_index('ix_component_frontend_node_id') - batch_op.drop_index('ix_component_name') - op.drop_table('component') - op.drop_table('flowstyle') + 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 + ) except Exception as e: print(e) - pass - with op.batch_alter_table('apikey', schema=None) as batch_op: - batch_op.alter_column('name', - existing_type=sa.VARCHAR(), - nullable=False) - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.add_column(sa.Column('updated_at', sa.DateTime(), nullable=True)) - batch_op.add_column(sa.Column('folder', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) + pass + 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) + ) + if "folder" not in flow_columns: + batch_op.add_column( + sa.Column( + "folder", sqlmodel.sql.sqltypes.AutoString(), nullable=True + ) + ) + except Exception as e: + print(e) + + pass + # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.drop_column('folder') - batch_op.drop_column('updated_at') + with op.batch_alter_table("flow", schema=None) as batch_op: + batch_op.drop_column("folder") + batch_op.drop_column("updated_at") except Exception as e: print(e) pass try: - with op.batch_alter_table('apikey', schema=None) as batch_op: - batch_op.alter_column('name', - existing_type=sa.VARCHAR(), - nullable=True) + 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: print(e) pass - try: - op.create_table('flowstyle', - sa.Column('color', sa.VARCHAR(), nullable=False), - sa.Column('emoji', sa.VARCHAR(), nullable=False), - sa.Column('flow_id', sa.CHAR(length=32), nullable=True), - sa.Column('id', sa.CHAR(length=32), nullable=False), - sa.ForeignKeyConstraint(['flow_id'], ['flow.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('id') - ) - op.create_table('component', - sa.Column('id', sa.CHAR(length=32), nullable=False), - sa.Column('frontend_node_id', sa.CHAR(length=32), nullable=False), - sa.Column('name', sa.VARCHAR(), nullable=False), - sa.Column('description', sa.VARCHAR(), nullable=True), - sa.Column('python_code', sa.VARCHAR(), nullable=True), - sa.Column('return_type', sa.VARCHAR(), nullable=True), - sa.Column('is_disabled', sa.BOOLEAN(), nullable=False), - sa.Column('is_read_only', sa.BOOLEAN(), nullable=False), - sa.Column('create_at', sa.DATETIME(), nullable=False), - sa.Column('update_at', sa.DATETIME(), nullable=False), - sa.PrimaryKeyConstraint('id') - ) - with op.batch_alter_table('component', schema=None) as batch_op: - batch_op.create_index('ix_component_name', ['name'], unique=False) - batch_op.create_index('ix_component_frontend_node_id', ['frontend_node_id'], unique=False) - except Exception as e: - print(e) - pass # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py b/src/backend/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py index 8a2e90abc..bb3c0c7cd 100644 --- a/src/backend/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py +++ b/src/backend/langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py @@ -5,55 +5,105 @@ Revises: 0b8757876a7c Create Date: 2024-01-26 13:31:14.797548 """ + 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 = 'b2fa308044b5' -down_revision: Union[str, None] = '0b8757876a7c' +revision: str = "b2fa308044b5" +down_revision: Union[str, None] = "0b8757876a7c" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + tables = inspector.get_table_names() # ### commands auto generated by Alembic - please adjust! ### try: - op.drop_table('flowstyle') - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.add_column(sa.Column('is_component', sa.Boolean(), nullable=True)) - batch_op.add_column(sa.Column('updated_at', sa.DateTime(), nullable=True)) - batch_op.add_column(sa.Column('folder', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - batch_op.add_column(sa.Column('user_id', sqlmodel.sql.sqltypes.GUID(), nullable=True)) - batch_op.create_index(batch_op.f('ix_flow_user_id'), ['user_id'], unique=False) - batch_op.create_foreign_key('fk_flow_user_id_user', 'user', ['user_id'], ['id']) + if "flowstyle" in tables: + op.drop_table("flowstyle") + 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) + ) + 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 + ) + ) + if "user_id" not in flow_columns: + 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 + ) + if "fk_flow_user_id_user" not in indices_names: + batch_op.create_foreign_key( + "fk_flow_user_id_user", "user", ["user_id"], ["id"] + ) + except Exception: pass # ### end Alembic commands ### def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.drop_constraint('fk_flow_user_id_user', type_='foreignkey') - batch_op.drop_index(batch_op.f('ix_flow_user_id')) - batch_op.drop_column('user_id') - batch_op.drop_column('folder') - batch_op.drop_column('updated_at') - batch_op.drop_column('is_component') + # Re-create the dropped table 'flowstyle' if it was previously dropped in upgrade + if "flowstyle" not in inspector.get_table_names(): + op.create_table( + "flowstyle", + sa.Column("color", sa.String(), nullable=False), + sa.Column("emoji", sa.String(), nullable=False), + sa.Column("flow_id", sqlmodel.sql.sqltypes.GUID(), nullable=True), + sa.Column("id", sqlmodel.sql.sqltypes.GUID(), nullable=False), + sa.ForeignKeyConstraint(["flow_id"], ["flow.id"]), + sa.PrimaryKeyConstraint("id"), + sa.UniqueConstraint("id"), + ) - op.create_table('flowstyle', - sa.Column('color', sa.VARCHAR(), nullable=False), - sa.Column('emoji', sa.VARCHAR(), nullable=False), - sa.Column('flow_id', sa.CHAR(length=32), nullable=True), - sa.Column('id', sa.CHAR(length=32), nullable=False), - sa.ForeignKeyConstraint(['flow_id'], ['flow.id'], ), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('id') - ) - except Exception: - pass - # ### end Alembic commands ### + with op.batch_alter_table("flow", schema=None) as batch_op: + # Check and remove newly added columns and constraints in upgrade + flow_columns = [column["name"] for column in inspector.get_columns("flow")] + if "user_id" in flow_columns: + batch_op.drop_column("user_id") + if "folder" in flow_columns: + batch_op.drop_column("folder") + if "updated_at" in flow_columns: + batch_op.drop_column("updated_at") + if "is_component" in flow_columns: + batch_op.drop_column("is_component") + + indices = inspector.get_indexes("flow") + indices_names = [index["name"] for index in indices] + if "ix_flow_user_id" in indices_names: + batch_op.drop_index("ix_flow_user_id") + # Assuming fk_flow_user_id_user is a foreign key constraint's name, not an index + constraints = inspector.get_foreign_keys("flow") + constraint_names = [constraint["name"] for constraint in constraints] + if "fk_flow_user_id_user" in constraint_names: + batch_op.drop_constraint("fk_flow_user_id_user", type_="foreignkey") + + except Exception as e: + # It's generally a good idea to log the exception or handle it in a way other than a bare pass + print(f"Error during downgrade: {e}") diff --git a/src/backend/langflow/alembic/versions/bc2f01c40e4a_new_fixes.py b/src/backend/langflow/alembic/versions/bc2f01c40e4a_new_fixes.py index 3ad7ba5f3..cfbf74f06 100644 --- a/src/backend/langflow/alembic/versions/bc2f01c40e4a_new_fixes.py +++ b/src/backend/langflow/alembic/versions/bc2f01c40e4a_new_fixes.py @@ -5,46 +5,68 @@ Revises: b2fa308044b5 Create Date: 2024-01-26 13:34:14.496769 """ + 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 = 'bc2f01c40e4a' -down_revision: Union[str, None] = 'b2fa308044b5' +revision: str = "bc2f01c40e4a" +down_revision: Union[str, None] = "b2fa308044b5" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.add_column(sa.Column('is_component', sa.Boolean(), nullable=True)) - batch_op.add_column(sa.Column('updated_at', sa.DateTime(), nullable=True)) - batch_op.add_column(sa.Column('folder', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) - batch_op.add_column(sa.Column('user_id', sqlmodel.sql.sqltypes.GUID(), nullable=True)) - batch_op.create_index(batch_op.f('ix_flow_user_id'), ['user_id'], unique=False) - batch_op.create_foreign_key('flow_user_id_fkey' - , 'user', ['user_id'], ['id']) - except Exception: - pass - # ### end Alembic commands ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + flow_columns = {column["name"] for column in inspector.get_columns("flow")} + flow_indexes = {index["name"] for index in inspector.get_indexes("flow")} + flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")} + + with op.batch_alter_table("flow", schema=None) as batch_op: + if "is_component" not in flow_columns: + 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)) + if "folder" not in flow_columns: + 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) + ) + if "ix_flow_user_id" not in flow_indexes: + 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"] + ) def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - try: - with op.batch_alter_table('flow', schema=None) as batch_op: - batch_op.drop_constraint('flow_user_id_fkey', type_='foreignkey') - batch_op.drop_index(batch_op.f('ix_flow_user_id')) - batch_op.drop_column('user_id') - batch_op.drop_column('folder') - batch_op.drop_column('updated_at') - batch_op.drop_column('is_component') - except Exception: - pass + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + flow_columns = {column["name"] for column in inspector.get_columns("flow")} + flow_indexes = {index["name"] for index in inspector.get_indexes("flow")} + flow_fks = {fk["name"] for fk in inspector.get_foreign_keys("flow")} - # ### end Alembic commands ### + with op.batch_alter_table("flow", schema=None) as batch_op: + if "flow_user_id_fkey" in flow_fks: + batch_op.drop_constraint("flow_user_id_fkey", type_="foreignkey") + if "ix_flow_user_id" in flow_indexes: + batch_op.drop_index(batch_op.f("ix_flow_user_id")) + if "user_id" in flow_columns: + batch_op.drop_column("user_id") + if "folder" in flow_columns: + batch_op.drop_column("folder") + if "updated_at" in flow_columns: + batch_op.drop_column("updated_at") + if "is_component" in flow_columns: + batch_op.drop_column("is_component") diff --git a/src/backend/langflow/alembic/versions/eb5866d51fd2_change_columns_to_be_nullable.py b/src/backend/langflow/alembic/versions/eb5866d51fd2_change_columns_to_be_nullable.py index 59b94ecec..4da04c325 100644 --- a/src/backend/langflow/alembic/versions/eb5866d51fd2_change_columns_to_be_nullable.py +++ b/src/backend/langflow/alembic/versions/eb5866d51fd2_change_columns_to_be_nullable.py @@ -5,11 +5,10 @@ Revises: 67cc006d50bf Create Date: 2023-10-04 10:18:25.640458 """ + from typing import Sequence, Union -import sqlalchemy as sa from alembic import op -from sqlalchemy import exc # revision identifiers, used by Alembic. revision: str = "eb5866d51fd2" @@ -21,70 +20,12 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### connection = op.get_bind() - try: - op.drop_table("flowstyle") - with op.batch_alter_table("component", schema=None) as batch_op: - batch_op.drop_index("ix_component_frontend_node_id") - batch_op.drop_index("ix_component_name") - except exc.SQLAlchemyError: - # connection.execute(text("ROLLBACK")) - pass - except Exception as e: - print(e) - pass - try: - op.drop_table("component") - except exc.SQLAlchemyError: - # connection.execute(text("ROLLBACK")) - pass - except Exception as e: - print(e) - pass + pass # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - try: - op.create_table( - "component", - sa.Column("id", sa.CHAR(length=32), nullable=False), - sa.Column("frontend_node_id", sa.CHAR(length=32), nullable=False), - sa.Column("name", sa.VARCHAR(), nullable=False), - sa.Column("description", sa.VARCHAR(), nullable=True), - sa.Column("python_code", sa.VARCHAR(), nullable=True), - sa.Column("return_type", sa.VARCHAR(), nullable=True), - sa.Column("is_disabled", sa.BOOLEAN(), nullable=False), - sa.Column("is_read_only", sa.BOOLEAN(), nullable=False), - sa.Column("create_at", sa.DATETIME(), nullable=False), - sa.Column("update_at", sa.DATETIME(), nullable=False), - sa.PrimaryKeyConstraint("id", name="pk_component"), - ) - with op.batch_alter_table("component", schema=None) as batch_op: - batch_op.create_index("ix_component_name", ["name"], unique=False) - batch_op.create_index( - "ix_component_frontend_node_id", ["frontend_node_id"], unique=False - ) - except Exception as e: - print(e) - pass - - try: - op.create_table( - "flowstyle", - sa.Column("color", sa.VARCHAR(), nullable=False), - sa.Column("emoji", sa.VARCHAR(), nullable=False), - sa.Column("flow_id", sa.CHAR(length=32), nullable=True), - sa.Column("id", sa.CHAR(length=32), nullable=False), - sa.ForeignKeyConstraint( - ["flow_id"], - ["flow.id"], - ), - sa.PrimaryKeyConstraint("id", name="pk_flowstyle"), - sa.UniqueConstraint("id", name="uq_flowstyle_id"), - ) - except Exception as e: - print(e) - pass + pass # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/f5ee9749d1a6_user_id_can_be_null_in_flow.py b/src/backend/langflow/alembic/versions/f5ee9749d1a6_user_id_can_be_null_in_flow.py index d9aab403f..494de22ac 100644 --- a/src/backend/langflow/alembic/versions/f5ee9749d1a6_user_id_can_be_null_in_flow.py +++ b/src/backend/langflow/alembic/versions/f5ee9749d1a6_user_id_can_be_null_in_flow.py @@ -5,6 +5,7 @@ Revises: 7843803a87b5 Create Date: 2023-10-18 23:12:27.297016 """ + from typing import Sequence, Union import sqlalchemy as sa diff --git a/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py b/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py index 2bcaacd68..77e6acd75 100644 --- a/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py +++ b/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py @@ -5,22 +5,35 @@ Revises: 2ac71eb9c3ae Create Date: 2023-11-24 15:07:37.566516 """ -from typing import Sequence, Union + +from typing import Optional, Sequence, Union from alembic import op +from sqlalchemy.engine.reflection import Inspector # revision identifiers, used by Alembic. -revision: str = 'fd531f8868b1' -down_revision: Union[str, None] = '2ac71eb9c3ae' +revision: str = "fd531f8868b1" +down_revision: Union[str, None] = "2ac71eb9c3ae" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + tables = inspector.get_table_names() + foreign_keys_names = [] + if "credential" in tables: + foreign_keys = inspector.get_foreign_keys("credential") + foreign_keys_names = [fk["name"] for fk in foreign_keys] + try: - with op.batch_alter_table('credential', schema=None) as batch_op: - batch_op.create_foreign_key("fk_credential_user_id", 'user', ['user_id'], ['id']) + 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"] + ) except Exception as e: print(e) pass @@ -30,9 +43,17 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + inspector = Inspector.from_engine(conn) # type: ignore + tables = inspector.get_table_names() + foreign_keys_names: list[Optional[str]] = [] + if "credential" in tables: + foreign_keys = inspector.get_foreign_keys("credential") + foreign_keys_names = [fk["name"] for fk in foreign_keys] try: - with op.batch_alter_table('credential', schema=None) as batch_op: - batch_op.drop_constraint("fk_credential_user_id", type_='foreignkey') + if "credential" in tables and "fk_credential_user_id" in foreign_keys_names: + with op.batch_alter_table("credential", schema=None) as batch_op: + batch_op.drop_constraint("fk_credential_user_id", type_="foreignkey") except Exception as e: print(e) pass diff --git a/src/backend/langflow/api/v1/callback.py b/src/backend/langflow/api/v1/callback.py index 1a8d64e78..38737623c 100644 --- a/src/backend/langflow/api/v1/callback.py +++ b/src/backend/langflow/api/v1/callback.py @@ -17,6 +17,11 @@ if TYPE_CHECKING: class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): """Callback handler for streaming LLM responses.""" + @property + def ignore_chain(self) -> bool: + """Whether to ignore chain callbacks.""" + return False + def __init__(self, session_id: str): self.chat_service = get_chat_service() self.client_id = session_id @@ -28,7 +33,9 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): resp = ChatResponse(message=token, type="stream", intermediate_steps="") await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) - async def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> Any: + async def on_tool_start( + self, serialized: Dict[str, Any], input_str: str, **kwargs: Any + ) -> Any: """Run when tool starts running.""" resp = ChatResponse( message="", @@ -66,7 +73,9 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): try: # This is to emulate the stream of tokens for resp in resps: - await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) + await self.socketio_service.emit_token( + to=self.sid, data=resp.model_dump() + ) except Exception as exc: logger.error(f"Error sending response: {exc}") @@ -92,7 +101,9 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): resp = PromptResponse( prompt=text, ) - await self.socketio_service.emit_message(to=self.sid, data=resp.model_dump()) + await self.socketio_service.emit_message( + to=self.sid, data=resp.model_dump() + ) async def on_agent_action(self, action: AgentAction, **kwargs: Any): log = f"Thought: {action.log}" @@ -102,7 +113,9 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): logs = log.split("\n") for log in logs: resp = ChatResponse(message="", type="stream", intermediate_steps=log) - await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) + await self.socketio_service.emit_token( + to=self.sid, data=resp.model_dump() + ) else: resp = ChatResponse(message="", type="stream", intermediate_steps=log) await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) diff --git a/src/backend/langflow/components/embeddings/AzureOpenAIEmbeddings.py b/src/backend/langflow/components/embeddings/AzureOpenAIEmbeddings.py index 09b03e17b..a44259be9 100644 --- a/src/backend/langflow/components/embeddings/AzureOpenAIEmbeddings.py +++ b/src/backend/langflow/components/embeddings/AzureOpenAIEmbeddings.py @@ -9,6 +9,7 @@ class AzureOpenAIEmbeddingsComponent(CustomComponent): description: str = "Embeddings model from Azure OpenAI." documentation: str = "https://python.langchain.com/docs/integrations/text_embedding/azureopenai" beta = False + icon = "Azure" API_VERSION_OPTIONS = [ "2022-12-01", diff --git a/src/backend/langflow/components/io/StoreMessages.py b/src/backend/langflow/components/io/StoreMessages.py deleted file mode 100644 index 0bd051424..000000000 --- a/src/backend/langflow/components/io/StoreMessages.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import List, Optional - -from langflow import CustomComponent -from langflow.field_typing import Text -from langflow.memory import add_messages -from langflow.schema import Record - - -class StoreMessages(CustomComponent): - display_name = "Store Messages" - description = "Used to store messages." - - def build_config(self): - return { - "records": { - "display_name": "Records", - "info": "The list of records to store. Each record should contain the keys 'sender', 'sender_name', and 'session_id'.", - }, - "texts": { - "display_name": "Texts", - "info": "The list of texts to store. If records is not provided, texts must be provided.", - }, - "session_id": { - "display_name": "Session ID", - "info": "The session ID to store.", - }, - "sender": { - "display_name": "Sender", - "info": "The sender to store.", - }, - "sender_name": { - "display_name": "Sender Name", - "info": "The sender name to store.", - }, - } - - def build( - self, - records: Optional[List[Record]] = None, - texts: Optional[List[Text]] = None, - session_id: Optional[str] = None, - sender: Optional[str] = None, - sender_name: Optional[str] = None, - ) -> List[Record]: - # Records is the main way to store messages - # If records is not provided, we can use texts - # but we need to create the records from the texts - # and the other parameters - if not texts and not records: - raise ValueError("Either texts or records must be provided.") - if not texts: - texts = [] - - if not records: - records = [] - if not session_id or not sender or not sender_name: - raise ValueError("If passing texts, session_id, sender, and sender_name must be provided.") - for text in texts: - record = Record( - text=text, - data={ - "session_id": session_id, - "sender": sender, - "sender_name": sender_name, - }, - ) - records.append(record) - elif isinstance(records, Record): - records = [records] - - self.status = records - records = add_messages(records) - return records or [] diff --git a/src/backend/langflow/components/io/MessageHistory.py b/src/backend/langflow/components/memories/MessageHistory.py similarity index 86% rename from src/backend/langflow/components/io/MessageHistory.py rename to src/backend/langflow/components/memories/MessageHistory.py index e9c3f1a87..8b4d11a5f 100644 --- a/src/backend/langflow/components/io/MessageHistory.py +++ b/src/backend/langflow/components/memories/MessageHistory.py @@ -16,10 +16,6 @@ class MessageHistoryComponent(CustomComponent): "display_name": "Sender Type", }, "sender_name": {"display_name": "Sender Name"}, - "file_path": { - "display_name": "File Path", - "info": "Path of the local JSON file to store the messages. It should be a unique path for each chat history.", - }, "n_messages": { "display_name": "Number of Messages", "info": "Number of messages to retrieve.", diff --git a/src/backend/langflow/components/memories/__init__.py b/src/backend/langflow/components/memories/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/components/model_specs/AzureChatOpenAISpecs.py b/src/backend/langflow/components/model_specs/AzureChatOpenAISpecs.py index 6bf9a32af..e6e1b5da5 100644 --- a/src/backend/langflow/components/model_specs/AzureChatOpenAISpecs.py +++ b/src/backend/langflow/components/model_specs/AzureChatOpenAISpecs.py @@ -11,6 +11,7 @@ class AzureChatOpenAISpecsComponent(CustomComponent): description: str = "LLM model from Azure OpenAI." documentation: str = "https://python.langchain.com/docs/integrations/llms/azure_openai" beta = False + icon = "Azure" AZURE_OPENAI_MODELS = [ "gpt-35-turbo", diff --git a/src/backend/langflow/components/tools/SearchApi.py b/src/backend/langflow/components/tools/SearchApi.py new file mode 100644 index 000000000..53da6c741 --- /dev/null +++ b/src/backend/langflow/components/tools/SearchApi.py @@ -0,0 +1,51 @@ +from langflow import CustomComponent +from langchain.schema import Document +from langflow.services.database.models.base import orjson_dumps +from langchain_community.utilities.searchapi import SearchApiAPIWrapper +from typing import Optional + + +class SearchApi(CustomComponent): + display_name: str = "SearchApi" + description: str = "Real-time search engine results API." + output_types: list[str] = ["Document"] + documentation: str = "https://www.searchapi.io/docs/google" + field_config = { + "engine": { + "display_name": "Engine", + "field_type": "str", + "info": "The search engine to use.", + }, + "params": { + "display_name": "Parameters", + "info": "The parameters to send with the request.", + }, + "code": {"show": False}, + "api_key": { + "display_name": "API Key", + "field_type": "str", + "required": True, + "password": True, + "info": "The API key to use SearchApi.", + }, + } + + def build( + self, + engine: str, + api_key: str, + params: Optional[dict] = None, + ) -> Document: + if params is None: + params = {} + + search_api_wrapper = SearchApiAPIWrapper(engine=engine, searchapi_api_key=api_key) + + q = params.pop("q", "SearchApi Langflow") + results = search_api_wrapper.results(q, **params) + + result = orjson_dumps(results, indent_2=False) + + document = Document(page_content=result) + + return document diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 966111d5f..453076e1b 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -631,7 +631,7 @@ class Graph: vertices: List[Vertex], ) -> List[List[str]]: """Performs a layered topological sort of the vertices in the graph.""" - + vertices_ids = {vertex.id for vertex in vertices} # Queue for vertices with no incoming edges queue = deque( vertex.id for vertex in vertices if self.in_degree_map[vertex.id] == 0 @@ -646,6 +646,13 @@ class Graph: vertex_id = queue.popleft() layers[current_layer].append(vertex_id) for neighbor in self.successor_map[vertex_id]: + # only vertices in `vertices_ids` should be considered + # because vertices by have been filtered out + # in a previous step. All dependencies of theirs + # will be built automatically if required + if neighbor not in vertices_ids: + continue + self.in_degree_map[neighbor] -= 1 # 'remove' edge if self.in_degree_map[neighbor] == 0: queue.append(neighbor) diff --git a/src/backend/langflow/interface/custom/utils.py b/src/backend/langflow/interface/custom/utils.py index bf973fa0a..e1c8191ab 100644 --- a/src/backend/langflow/interface/custom/utils.py +++ b/src/backend/langflow/interface/custom/utils.py @@ -27,18 +27,24 @@ from langflow.utils import validate from langflow.utils.util import get_base_classes -def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]): +def add_output_types( + frontend_node: CustomComponentFrontendNode, return_types: List[str] +): """Add output types to the frontend node""" for return_type in return_types: if return_type is None: raise HTTPException( status_code=400, detail={ - "error": ("Invalid return type. Please check your code and try again."), + "error": ( + "Invalid return type. Please check your code and try again." + ), "traceback": traceback.format_exc(), }, ) - if hasattr(return_type, "__name__"): + if return_type == str: + return_type = "Text" + elif hasattr(return_type, "__name__"): return_type = return_type.__name__ elif hasattr(return_type, "__class__"): return_type = return_type.__class__.__name__ @@ -63,14 +69,18 @@ def reorder_fields(frontend_node: CustomComponentFrontendNode, field_order: List frontend_node.template.fields = reordered_fields -def add_base_classes(frontend_node: CustomComponentFrontendNode, return_types: List[str]): +def add_base_classes( + frontend_node: CustomComponentFrontendNode, return_types: List[str] +): """Add base classes to the frontend node""" for return_type_instance in return_types: if return_type_instance is None: raise HTTPException( status_code=400, detail={ - "error": ("Invalid return type. Please check your code and try again."), + "error": ( + "Invalid return type. Please check your code and try again." + ), "traceback": traceback.format_exc(), }, ) @@ -145,10 +155,14 @@ def add_new_custom_field( # If options is a list, then it's a dropdown # If options is None, then it's a list of strings is_list = isinstance(field_config.get("options"), list) - field_config["is_list"] = is_list or field_config.get("is_list", False) or field_contains_list + field_config["is_list"] = ( + is_list or field_config.get("is_list", False) or field_contains_list + ) if "name" in field_config: - warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.") + warnings.warn( + "The 'name' key in field_config is used to build the object and can't be changed." + ) required = field_config.pop("required", field_required) placeholder = field_config.pop("placeholder", "") @@ -179,7 +193,9 @@ def add_extra_fields(frontend_node, field_config, function_args): if "name" not in extra_field or extra_field["name"] == "self": continue - field_name, field_type, field_value, field_required = get_field_properties(extra_field) + field_name, field_type, field_value, field_required = get_field_properties( + extra_field + ) config = field_config.get(field_name, {}) frontend_node = add_new_custom_field( frontend_node, @@ -217,7 +233,9 @@ def run_build_config( raise HTTPException( status_code=400, detail={ - "error": ("Invalid type convertion. Please check your code and try again."), + "error": ( + "Invalid type convertion. Please check your code and try again." + ), "traceback": traceback.format_exc(), }, ) from exc @@ -245,7 +263,9 @@ def run_build_config( raise HTTPException( status_code=400, detail={ - "error": ("Invalid type convertion. Please check your code and try again."), + "error": ( + "Invalid type convertion. Please check your code and try again." + ), "traceback": traceback.format_exc(), }, ) from exc @@ -298,16 +318,24 @@ def build_custom_component_template( try: frontend_node = build_frontend_node(custom_component.template_config) - field_config, custom_instance = run_build_config(custom_component, user_id=user_id, update_field=update_field) + field_config, custom_instance = run_build_config( + custom_component, user_id=user_id, update_field=update_field + ) entrypoint_args = custom_component.get_function_entrypoint_args add_extra_fields(frontend_node, field_config, entrypoint_args) - frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {})) + frontend_node = add_code_field( + frontend_node, custom_component.code, field_config.get("code", {}) + ) - add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type) - add_output_types(frontend_node, custom_component.get_function_entrypoint_return_type) + add_base_classes( + frontend_node, custom_component.get_function_entrypoint_return_type + ) + add_output_types( + frontend_node, custom_component.get_function_entrypoint_return_type + ) reorder_fields(frontend_node, custom_instance._get_field_order()) @@ -318,7 +346,9 @@ def build_custom_component_template( raise HTTPException( status_code=400, detail={ - "error": ("Invalid type convertion. Please check your code and try again."), + "error": ( + "Invalid type convertion. Please check your code and try again." + ), "traceback": traceback.format_exc(), }, ) from exc @@ -342,7 +372,9 @@ def build_custom_components(settings_service): if not settings_service.settings.COMPONENTS_PATH: return {} - logger.info(f"Building custom components from {settings_service.settings.COMPONENTS_PATH}") + logger.info( + f"Building custom components from {settings_service.settings.COMPONENTS_PATH}" + ) custom_components_from_file = {} processed_paths = set() for path in settings_service.settings.COMPONENTS_PATH: @@ -353,7 +385,9 @@ def build_custom_components(settings_service): custom_component_dict = build_custom_component_list_from_path(path_str) if custom_component_dict: category = next(iter(custom_component_dict)) - logger.info(f"Loading {len(custom_component_dict[category])} component(s) from category {category}") + logger.info( + f"Loading {len(custom_component_dict[category])} component(s) from category {category}" + ) custom_components_from_file = merge_nested_dicts_with_renaming( custom_components_from_file, custom_component_dict ) diff --git a/src/backend/langflow/services/chat/utils.py b/src/backend/langflow/services/chat/utils.py index ae0da8152..f0e584f4c 100644 --- a/src/backend/langflow/services/chat/utils.py +++ b/src/backend/langflow/services/chat/utils.py @@ -3,11 +3,10 @@ from typing import Any from langchain.agents import AgentExecutor from langchain.chains.base import Chain from langchain_core.runnables import Runnable -from loguru import logger - from langflow.api.v1.schemas import ChatMessage from langflow.interface.utils import try_setting_streaming_options from langflow.processing.base import get_result_and_steps +from loguru import logger LANGCHAIN_RUNNABLES = (Chain, Runnable, AgentExecutor) @@ -23,7 +22,9 @@ async def process_graph( if build_result is None: # Raise user facing error - raise ValueError("There was an error loading the langchain_object. Please, check all the nodes and try again.") + raise ValueError( + "There was an error loading the langchain_object. Please, check all the nodes and try again." + ) # Generate result and thought try: @@ -39,7 +40,6 @@ async def process_graph( client_id=client_id, session_id=session_id, ) - else: raise TypeError(f"Unknown type {type(build_result)}") logger.debug("Generated result and intermediate_steps") @@ -50,5 +50,7 @@ async def process_graph( raise e -async def run_build_result(build_result: Any, chat_inputs: ChatMessage, client_id: str, session_id: str): +async def run_build_result( + build_result: Any, chat_inputs: ChatMessage, client_id: str, session_id: str +): return build_result(inputs=chat_inputs.message) diff --git a/src/backend/langflow/services/database/service.py b/src/backend/langflow/services/database/service.py index 9765d858f..a74a01472 100644 --- a/src/backend/langflow/services/database/service.py +++ b/src/backend/langflow/services/database/service.py @@ -111,13 +111,11 @@ class DatabaseService(Service): return True - def init_alembic(self): + def init_alembic(self, alembic_cfg): logger.info("Initializing alembic") - alembic_cfg = Config() - alembic_cfg.set_main_option("script_location", str(self.script_location)) - alembic_cfg.set_main_option("sqlalchemy.url", self.database_url) - command.stamp(alembic_cfg, "head") - # command.upgrade(alembic_cfg, "head") + command.ensure_version(alembic_cfg) + # alembic_cfg.attributes["connection"].commit() + command.upgrade(alembic_cfg, "head") logger.info("Alembic initialized") def run_migrations(self, fix=False): @@ -126,6 +124,11 @@ class DatabaseService(Service): # if not self.script_location.exists(): # this is not the correct way to check if alembic has been initialized # We need to check if the alembic_version table exists # if not, we need to initialize alembic + alembic_cfg = Config() + # alembic_cfg.attributes["connection"] = session + alembic_cfg.set_main_option("script_location", str(self.script_location)) + alembic_cfg.set_main_option("sqlalchemy.url", self.database_url) + should_initialize_alembic = False with Session(self.engine) as session: # If the table does not exist it throws an error # so we need to catch it @@ -133,18 +136,19 @@ class DatabaseService(Service): session.exec(text("SELECT * FROM alembic_version")) except Exception: logger.info("Alembic not initialized") - try: - self.init_alembic() - except Exception as exc: - logger.error(f"Error initializing alembic: {exc}") - raise RuntimeError("Error initializing alembic") from exc + should_initialize_alembic = True + else: logger.info("Alembic already initialized") + if should_initialize_alembic: + try: + self.init_alembic(alembic_cfg) + except Exception as exc: + logger.error(f"Error initializing alembic: {exc}") + raise RuntimeError("Error initializing alembic") from exc logger.info(f"Running DB migrations in {self.script_location}") - alembic_cfg = Config() - alembic_cfg.set_main_option("script_location", str(self.script_location)) - alembic_cfg.set_main_option("sqlalchemy.url", self.database_url) + try: command.check(alembic_cfg) except Exception as exc: @@ -155,7 +159,7 @@ class DatabaseService(Service): try: command.check(alembic_cfg) except util.exc.AutogenerateDiffsDetected as e: - logger.exception("AutogenerateDiffsDetected: {exc}") + logger.error("AutogenerateDiffsDetected: {exc}") if not fix: raise RuntimeError( "Something went wrong running migrations. Please, run `langflow migration --fix`" diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index a3cd6fd3e..34f1a042d 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -5,7 +5,10 @@ from langflow.services.auth.utils import create_super_user, verify_password from langflow.services.database.utils import initialize_database from langflow.services.manager import service_manager from langflow.services.schema import ServiceType -from langflow.services.settings.constants import DEFAULT_SUPERUSER, DEFAULT_SUPERUSER_PASSWORD +from langflow.services.settings.constants import ( + DEFAULT_SUPERUSER, + DEFAULT_SUPERUSER_PASSWORD, +) from langflow.services.socket.utils import set_socketio_server from .deps import get_db_service, get_session, get_settings_service @@ -19,7 +22,9 @@ def get_factories_and_deps(): from langflow.services.database import factory as database_factory from langflow.services.monitor import factory as monitor_factory from langflow.services.plugins import factory as plugins_factory - from langflow.services.session import factory as session_service_factory # type: ignore + from langflow.services.session import ( + factory as session_service_factory, + ) # type: ignore from langflow.services.settings import factory as settings_factory from langflow.services.socket import factory as socket_factory from langflow.services.storage import factory as storage_factory @@ -48,8 +53,14 @@ def get_factories_and_deps(): ), (plugins_factory.PluginServiceFactory(), [ServiceType.SETTINGS_SERVICE]), (store_factory.StoreServiceFactory(), [ServiceType.SETTINGS_SERVICE]), - (credentials_factory.CredentialServiceFactory(), [ServiceType.SETTINGS_SERVICE]), - (storage_factory.StorageServiceFactory(), [ServiceType.SESSION_SERVICE, ServiceType.SETTINGS_SERVICE]), + ( + credentials_factory.CredentialServiceFactory(), + [ServiceType.SETTINGS_SERVICE], + ), + ( + storage_factory.StorageServiceFactory(), + [ServiceType.SESSION_SERVICE, ServiceType.SETTINGS_SERVICE], + ), (monitor_factory.MonitorServiceFactory(), [ServiceType.SETTINGS_SERVICE]), (socket_factory.SocketIOFactory(), [ServiceType.CACHE_SERVICE]), ] @@ -81,12 +92,16 @@ def get_or_create_super_user(session: Session, username, password, is_default): ) return None else: - logger.debug("User with superuser credentials exists but is not a superuser.") + logger.debug( + "User with superuser credentials exists but is not a superuser." + ) return None if user: if verify_password(password, user.password): - raise ValueError("User with superuser credentials exists but is not a superuser.") + raise ValueError( + "User with superuser credentials exists but is not a superuser." + ) else: raise ValueError("Incorrect superuser credentials") @@ -115,15 +130,21 @@ def setup_superuser(settings_service, session: Session): username = settings_service.auth_settings.SUPERUSER password = settings_service.auth_settings.SUPERUSER_PASSWORD - is_default = (username == DEFAULT_SUPERUSER) and (password == DEFAULT_SUPERUSER_PASSWORD) + is_default = (username == DEFAULT_SUPERUSER) and ( + password == DEFAULT_SUPERUSER_PASSWORD + ) try: - user = get_or_create_super_user(session=session, username=username, password=password, is_default=is_default) + user = get_or_create_super_user( + session=session, username=username, password=password, is_default=is_default + ) if user is not None: logger.debug("Superuser created successfully.") except Exception as exc: logger.exception(exc) - raise RuntimeError("Could not create superuser. Please create a superuser manually.") from exc + raise RuntimeError( + "Could not create superuser. Please create a superuser manually." + ) from exc finally: settings_service.auth_settings.reset_credentials() @@ -137,7 +158,9 @@ def teardown_superuser(settings_service, session): if not settings_service.auth_settings.AUTO_LOGIN: try: - logger.debug("AUTO_LOGIN is set to False. Removing default superuser if exists.") + logger.debug( + "AUTO_LOGIN is set to False. Removing default superuser if exists." + ) username = DEFAULT_SUPERUSER from langflow.services.database.models.user.model import User @@ -181,11 +204,15 @@ def initialize_session_service(): Initialize the session manager. """ from langflow.services.cache import factory as cache_factory - from langflow.services.session import factory as session_service_factory # type: ignore + from langflow.services.session import ( + factory as session_service_factory, + ) # type: ignore initialize_settings_service() - service_manager.register_factory(cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE]) + service_manager.register_factory( + cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE] + ) service_manager.register_factory( session_service_factory.SessionServiceFactory(), @@ -202,7 +229,9 @@ def initialize_services(fix_migration: bool = False, socketio_server=None): service_manager.register_factory(factory, dependencies=dependencies) except Exception as exc: logger.exception(exc) - raise RuntimeError("Could not initialize services. Please check your settings.") from exc + raise RuntimeError( + "Could not initialize services. Please check your settings." + ) from exc # Test cache connection service_manager.get(ServiceType.CACHE_SERVICE) @@ -210,9 +239,11 @@ def initialize_services(fix_migration: bool = False, socketio_server=None): try: initialize_database(fix_migration=fix_migration) except Exception as exc: - logger.exception(exc) + logger.error(exc) raise exc - setup_superuser(service_manager.get(ServiceType.SETTINGS_SERVICE), next(get_session())) + setup_superuser( + service_manager.get(ServiceType.SETTINGS_SERVICE), next(get_session()) + ) try: get_db_service().migrate_flows_if_auto_login() except Exception as exc: diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 94525831d..ef8ad8d80 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -332,7 +332,7 @@ export default function ParameterComponent({
diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 9b81f93a2..c9844a47d 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -128,7 +128,7 @@ export default function GenericNode({ const showNode = data.showNode ?? true; - const nameEditable = data.node?.flow || data.type === "CustomComponent"; + const nameEditable = true; const emojiRegex = /\p{Emoji}/u; const isEmoji = emojiRegex.test(data?.node?.icon!); @@ -332,8 +332,8 @@ export default function GenericNode({ /> ) : ( - -
+
+
{ if (nameEditable) { @@ -348,24 +348,23 @@ export default function GenericNode({ > {data.node?.display_name}
- - {nameEditable && ( -
{ - setInputName(true); - takeSnapshot(); - event.stopPropagation(); - event.preventDefault(); - }} - > - -
- )} -
- + + {nameEditable && ( +
{ + setInputName(true); + takeSnapshot(); + event.stopPropagation(); + event.preventDefault(); + }} + > + +
+ )} +
)} )} diff --git a/src/frontend/src/components/CrashErrorComponent/index.tsx b/src/frontend/src/components/CrashErrorComponent/index.tsx index f5018f885..0cf376195 100644 --- a/src/frontend/src/components/CrashErrorComponent/index.tsx +++ b/src/frontend/src/components/CrashErrorComponent/index.tsx @@ -1,36 +1,63 @@ +import { XCircle } from "lucide-react"; import { crashComponentPropsType } from "../../types/components"; +import { Button } from "../ui/button"; +import { Card, CardContent, CardFooter, CardHeader } from "../ui/card"; export default function CrashErrorComponent({ error, resetErrorBoundary, }: crashComponentPropsType): JSX.Element { return ( -
-
-

- Oops! An unknown error has occurred. -

-

- Please click the 'Reset Application' button to restore the - application's state. If the error persists, please create an issue on - our GitHub page. We apologize for any inconvenience this may have - caused. -

-
- - - Create Issue - +
+
+
+ + +
+ +
+
+

+ Sorry, we found an unexpected error! +

+
+
+ + +
+

+ Please report errors with detailed tracebacks on the{" "} + + GitHub Issues + {" "} + page. +

+ Thank you! +

+
+
+ + +
+ + + + + +
+
+
diff --git a/src/frontend/src/components/IOview/index.tsx b/src/frontend/src/components/IOview/index.tsx index 8f914c716..73c87f7f4 100644 --- a/src/frontend/src/components/IOview/index.tsx +++ b/src/frontend/src/components/IOview/index.tsx @@ -153,7 +153,7 @@ export default function IOView({ children, open, setOpen }): JSX.Element { trigger={
- {input.id} + {node.data.node.display_name} {haveChat && (
- + {outputsModalTitle}
{nodes diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index d9ce68847..fcf3d71ef 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -701,7 +701,7 @@ export const editTextPlaceholder = "Type message here."; export const inputHandleHover = "Avaliable input components:"; export const outputHandleHover = "Avaliable output components:"; export const textInputModalTitle = "Text Inputs"; -export const outputsModalTitle = "Prompt Outputs"; +export const outputsModalTitle = "Text Outputs"; export const langflowChatTitle = "Langflow Chat"; export const chatInputPlaceholder = "No chat input variables found. Click to run your flow."; diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index e0bc5a7ca..9630cfd71 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -7,6 +7,7 @@ import { requestLogout, } from "../controllers/API"; import useAlertStore from "../stores/alertStore"; +import useFlowsManagerStore from "../stores/flowsManagerStore"; import { Users } from "../types/api"; import { AuthContextType } from "../types/contexts/auth"; @@ -79,6 +80,7 @@ export function AuthProvider({ children }): React.ReactElement { getUser(); } else { setLoading(false); + useFlowsManagerStore.setState({ isLoading: false }); } }); }, [setUserData, setLoading, autoLogin, setIsAdmin]); diff --git a/src/frontend/src/icons/Azure/Azure.jsx b/src/frontend/src/icons/Azure/Azure.jsx new file mode 100644 index 000000000..644fdd9f8 --- /dev/null +++ b/src/frontend/src/icons/Azure/Azure.jsx @@ -0,0 +1,61 @@ +export const SvgAzure = (props) => ( + + + + + + + + + + + + + + + + + + + + + + +); +export default SvgAzure; diff --git a/src/frontend/src/icons/Azure/index.tsx b/src/frontend/src/icons/Azure/index.tsx new file mode 100644 index 000000000..346868ab4 --- /dev/null +++ b/src/frontend/src/icons/Azure/index.tsx @@ -0,0 +1,8 @@ +import React, { forwardRef } from "react"; +import SvgAzure from "./Azure"; + +export const AzureIcon = forwardRef>( + (props, ref) => { + return ; + } +); diff --git a/src/frontend/src/icons/Ollama/Ollama.jsx b/src/frontend/src/icons/Ollama/Ollama.jsx new file mode 100644 index 000000000..70086a373 --- /dev/null +++ b/src/frontend/src/icons/Ollama/Ollama.jsx @@ -0,0 +1,64 @@ +export const SvgOllama = (props) => ( + + + + + + + + + + + + + + + + + + + + + + +); +export default SvgOllama; diff --git a/src/frontend/src/icons/Ollama/Ollama.svg b/src/frontend/src/icons/Ollama/Ollama.svg new file mode 100644 index 000000000..f189d6efb --- /dev/null +++ b/src/frontend/src/icons/Ollama/Ollama.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/icons/Ollama/index.tsx b/src/frontend/src/icons/Ollama/index.tsx new file mode 100644 index 000000000..4d49fa198 --- /dev/null +++ b/src/frontend/src/icons/Ollama/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgOllama from "./Ollama"; + +export const OllamaIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/src/icons/Postgres/Postgres.jsx b/src/frontend/src/icons/Postgres/Postgres.jsx new file mode 100644 index 000000000..95059e729 --- /dev/null +++ b/src/frontend/src/icons/Postgres/Postgres.jsx @@ -0,0 +1,67 @@ +export const SvgPostgres = (props) => ( + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default SvgPostgres; diff --git a/src/frontend/src/icons/Postgres/Postgres.svg b/src/frontend/src/icons/Postgres/Postgres.svg new file mode 100644 index 000000000..d8c30acf8 --- /dev/null +++ b/src/frontend/src/icons/Postgres/Postgres.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/icons/Postgres/index.tsx b/src/frontend/src/icons/Postgres/index.tsx new file mode 100644 index 000000000..0bd7cdaef --- /dev/null +++ b/src/frontend/src/icons/Postgres/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import SvgPostgres from "./Postgres"; + +export const PostgresIcon = forwardRef< + SVGSVGElement, + React.PropsWithChildren<{}> +>((props, ref) => { + return ; +}); diff --git a/src/frontend/src/icons/Redis/Redis.jsx b/src/frontend/src/icons/Redis/Redis.jsx new file mode 100644 index 000000000..1ad7558e2 --- /dev/null +++ b/src/frontend/src/icons/Redis/Redis.jsx @@ -0,0 +1,67 @@ +export const SvgRedis = (props) => ( + + + + + + + + + + + + + + + + + + + + + + + + + +); +export default SvgRedis; diff --git a/src/frontend/src/icons/Redis/Redis.svg b/src/frontend/src/icons/Redis/Redis.svg new file mode 100644 index 000000000..6075a2b7f --- /dev/null +++ b/src/frontend/src/icons/Redis/Redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/icons/Redis/index.tsx b/src/frontend/src/icons/Redis/index.tsx new file mode 100644 index 000000000..b1624e4a5 --- /dev/null +++ b/src/frontend/src/icons/Redis/index.tsx @@ -0,0 +1,8 @@ +import React, { forwardRef } from "react"; +import { SvgRedis } from "./Redis"; + +export const RedisIcon = forwardRef>( + (props, ref) => { + return ; + } +); diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index 62320239c..06b395895 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -47,12 +47,6 @@ export default function CodeAreaModal({ const [error, setError] = useState<{ detail: { error: string | undefined; traceback: string | undefined }; } | null>(null); - const handleModalWShortcut = useFlowStore( - (state) => state.handleModalWShortcut - ); - const openCodeModalWShortcut = useFlowStore( - (state) => state.openCodeModalWShortcut - ); const [open, setOpen] = useState(false); const nodes = useFlowStore((state) => state.nodes); @@ -62,26 +56,7 @@ export default function CodeAreaModal({ if (dynamic && Object.keys(nodeClass!.template).length > 2) { return; } - }, []); - - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - (event.key === "C" || event.key === "c") && - (event.metaKey || event.ctrlKey) && - selected - ) { - event.preventDefault(); - console.log("entrou") - setOpen((oldState) => !oldState); - } - }; - document.addEventListener("keydown", handleKeyDown); - return () => { - document.removeEventListener("keydown", handleKeyDown); - }; }, []); - useEffect(() => { console.log(open) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 638de133c..cac8b8faa 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -488,4 +488,4 @@ export default function Page({
); -} +} \ No newline at end of file diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 725d97f2e..b348896c6 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -90,13 +90,6 @@ export default function NodeToolbarComponent({ }, [showModalAdvanced]); const updateNodeInternals = useUpdateNodeInternals(); - const openCodeModalWShortcut = useFlowStore( - (state) => state.openCodeModalWShortcut - ); - const handleModalWShortcut = useFlowStore( - (state) => state.handleModalWShortcut - ); - const setLastCopiedSelection = useFlowStore( (state) => state.setLastCopiedSelection ); diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 1f4a494bb..1725de2a0 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -30,6 +30,7 @@ import { } from "../types/zustand/flow"; import { buildVertices } from "../utils/buildUtils"; import { + checkChatInput, cleanEdges, getHandleId, getNodeId, @@ -56,16 +57,6 @@ const useFlowStore = create((set, get) => ({ flowPool: {}, inputs: [], outputs: [], - openCodeModalWShortcut: false, - handleModalWShortcut: (modal) => { - switch (modal) { - case "code": - set((state) => ({ - openCodeModalWShortcut: !state.openCodeModalWShortcut, - })); - break; - } - }, setFlowPool: (flowPool) => { set({ flowPool }); }, @@ -228,6 +219,10 @@ const useFlowStore = create((set, get) => ({ ); }, paste: (selection, position) => { + if(selection.nodes.some((node) => node.data.type === "ChatInput") && checkChatInput(get().nodes)){ + useAlertStore.getState().setErrorData({title: "Error pasting components", list: ["You can only have one ChatInput component in the flow"]}); + return; + } let minimumX = Infinity; let minimumY = Infinity; let idsMap = {}; diff --git a/src/frontend/src/stores/typesStore.ts b/src/frontend/src/stores/typesStore.ts index 1a0ae3634..557a3a30d 100644 --- a/src/frontend/src/stores/typesStore.ts +++ b/src/frontend/src/stores/typesStore.ts @@ -16,7 +16,7 @@ export const useTypesStore = create((set, get) => ({ setLoading(true); getAll() .then((response) => { - const data = response.data; + const data = response?.data; useAlertStore.setState({ loading: false }); set((old) => ({ types: typesGenerator(data), diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index 75044f921..c969d8d6b 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -40,8 +40,6 @@ export type FlowPoolType = { }; export type FlowStoreType = { - openCodeModalWShortcut: boolean; - handleModalWShortcut: (modal: string) => void; flowPool: FlowPoolType; inputs: Array<{ type: string; id: string }>; outputs: Array<{ type: string; id: string }>; diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 7def5d274..1d9e81d94 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -44,6 +44,10 @@ import { } from "./utils"; const uid = new ShortUniqueId({ length: 5 }); +export function checkChatInput(nodes: Node[]) { + return nodes.some((node) => node.data.type === "ChatInput"); +} + export function cleanEdges(nodes: Node[], edges: Edge[]) { let newEdges = cloneDeep(edges); edges.forEach((edge) => { diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index aa1b818a5..efc9414d4 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -42,6 +42,7 @@ import { FileSearch, FileSearch2, FileText, + FileType2, FileUp, Fingerprint, FlaskConical, @@ -124,10 +125,11 @@ import { XCircle, Zap, } from "lucide-react"; -import { FaApple, FaGithub } from "react-icons/fa"; +import { FaApple, FaGithub, FaRobot } from "react-icons/fa"; import { AWSIcon } from "../icons/AWS"; import { AirbyteIcon } from "../icons/Airbyte"; import { AnthropicIcon } from "../icons/Anthropic"; +import { AzureIcon } from "../icons/Azure"; import { BingIcon } from "../icons/Bing"; import { ChromaIcon } from "../icons/ChromaIcon"; import { CohereIcon } from "../icons/Cohere"; @@ -147,9 +149,12 @@ import { MetaIcon } from "../icons/Meta"; import { MidjourneyIcon } from "../icons/Midjorney"; import { MongoDBIcon } from "../icons/MongoDB"; import { NotionIcon } from "../icons/Notion"; +import { OllamaIcon } from "../icons/Ollama"; import { OpenAiIcon } from "../icons/OpenAi"; import { PineconeIcon } from "../icons/Pinecone"; +import { PostgresIcon } from "../icons/Postgres"; import { QDrantIcon } from "../icons/QDrant"; +import { RedisIcon } from "../icons/Redis"; import { SearxIcon } from "../icons/Searx"; import { ShareIcon } from "../icons/Share"; import { Share2Icon } from "../icons/Share2"; @@ -253,6 +258,20 @@ export const nodeNames: { [char: string]: string } = { }; export const nodeIconsLucide: iconsType = { + AzureChatOpenAi: AzureIcon, + Ollama: OllamaIcon, + ChatOllama: OllamaIcon, + AzureOpenAiEmbeddings: AzureIcon, + Azure: AzureIcon, + OllamaEmbeddings: OllamaIcon, + ChatOllamaModel: OllamaIcon, + Faiss: MetaIcon, + FaissSearch: MetaIcon, + AzureOpenAiModel: AzureIcon, + Redis: RedisIcon, + RedisSearch: RedisIcon, + PostgresChatMessageHistory: PostgresIcon, + BaiduQianfan: FaRobot, Play, Vectara: VectaraIcon, ArrowUpToLine: ArrowUpToLine, @@ -354,6 +373,7 @@ export const nodeIconsLucide: iconsType = { Plus, Redo, Settings2, + FileType2, Undo, FileSearch2, ChevronRight, diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index 6a2f9cff4..e133844d2 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -29,7 +29,10 @@ def poll_task_status(client, headers, href, max_attempts=20, sleep_time=1): href, headers=headers, ) - if task_status_response.status_code == 200 and task_status_response.json()["status"] == "SUCCESS": + if ( + task_status_response.status_code == 200 + and task_status_response.json()["status"] == "SUCCESS" + ): return task_status_response.json() time.sleep(sleep_time) return None # Return None if task did not complete in time @@ -123,7 +126,11 @@ def created_api_key(active_user): ) db_manager = get_db_service() with session_getter(db_manager) as session: - if existing_api_key := session.query(ApiKey).filter(ApiKey.api_key == api_key.api_key).first(): + if ( + existing_api_key := session.query(ApiKey) + .filter(ApiKey.api_key == api_key.api_key) + .first() + ): return existing_api_key session.add(api_key) session.commit() @@ -289,7 +296,11 @@ def test_get_all(client: TestClient, logged_in_headers): dir_reader = DirectoryReader(settings.COMPONENTS_PATH[0]) files = dir_reader.get_files() # json_response is a dict of dicts - all_names = [component_name for _, components in response.json().items() for component_name in components] + all_names = [ + component_name + for _, components in response.json().items() + for component_name in components + ] json_response = response.json() # We need to test the custom nodes assert len(all_names) > len(files) @@ -414,13 +425,19 @@ def test_various_prompts(client, prompt, expected_input_variables): def test_get_vertices_flow_not_found(client, logged_in_headers): - response = client.get("/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers) - assert response.status_code == 500 # Or whatever status code you've set for invalid ID + response = client.get( + "/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers + ) + assert ( + response.status_code == 500 + ) # Or whatever status code you've set for invalid ID def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_headers): flow_id = added_flow_with_prompt_and_history["id"] - response = client.get(f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers) + response = client.get( + f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers + ) assert response.status_code == 200 assert "ids" in response.json() # The response should contain the list in this order @@ -436,13 +453,19 @@ def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_head def test_build_vertex_invalid_flow_id(client, logged_in_headers): - response = client.post("/api/v1/build/nonexistent_id/vertices/vertex_id", headers=logged_in_headers) + response = client.post( + "/api/v1/build/nonexistent_id/vertices/vertex_id", headers=logged_in_headers + ) assert response.status_code == 500 -def test_build_vertex_invalid_vertex_id(client, added_flow_with_prompt_and_history, logged_in_headers): +def test_build_vertex_invalid_vertex_id( + client, added_flow_with_prompt_and_history, logged_in_headers +): flow_id = added_flow_with_prompt_and_history["id"] - response = client.post(f"/api/v1/build/{flow_id}/vertices/invalid_vertex_id", headers=logged_in_headers) + response = client.post( + f"/api/v1/build/{flow_id}/vertices/invalid_vertex_id", headers=logged_in_headers + ) assert response.status_code == 500 diff --git a/tests/test_prompts_template.py b/tests/test_prompts_template.py index 39eb1212e..06989cad0 100644 --- a/tests/test_prompts_template.py +++ b/tests/test_prompts_template.py @@ -1,4 +1,5 @@ from fastapi.testclient import TestClient + from langflow.services.deps import get_settings_service @@ -9,42 +10,3 @@ def test_prompts_settings(client: TestClient, logged_in_headers): json_response = response.json() prompts = json_response["prompts"] assert set(prompts.keys()) == set(settings_service.settings.PROMPTS) - - -def test_prompt_template(client: TestClient, logged_in_headers): - response = client.get("api/v1/all", headers=logged_in_headers) - assert response.status_code == 200 - json_response = response.json() - prompts = json_response["prompts"] - - prompt = prompts["PromptTemplate"] - template = prompt["template"] - assert template["input_variables"] == { - "required": True, - "dynamic": True, - "placeholder": "", - "show": False, - "multiline": False, - "password": False, - "name": "input_variables", - "type": "str", - "list": True, - "advanced": False, - "info": "", - "fileTypes": [], - } - - assert template["template"] == { - "required": True, - "dynamic": True, - "placeholder": "", - "show": True, - "multiline": True, - "password": False, - "name": "template", - "type": "prompt", - "list": False, - "advanced": False, - "info": "", - "fileTypes": [], - }