Merge branch 'release' into langfuse_integration
This commit is contained in:
commit
2fe8e29546
71 changed files with 1279 additions and 2105 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
|
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
|
||||||
{
|
{
|
||||||
"name": "LangChain Demo Container",
|
"name": "Langflow Demo Container",
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
"image": "mcr.microsoft.com/devcontainers/python:3.10",
|
"image": "mcr.microsoft.com/devcontainers/python:3.10",
|
||||||
"features": {
|
"features": {
|
||||||
|
|
@ -15,7 +15,8 @@
|
||||||
"actboy168.tasks",
|
"actboy168.tasks",
|
||||||
"GitHub.copilot",
|
"GitHub.copilot",
|
||||||
"ms-python.python",
|
"ms-python.python",
|
||||||
"eamodio.gitlens"
|
"eamodio.gitlens",
|
||||||
|
"GitHub.vscode-pull-request-github"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,40 @@
|
||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
|
// README at: https://github.com/devcontainers/templates/tree/main/src/universal
|
||||||
{
|
{
|
||||||
"name": "LangChain Dev Container",
|
"name": "Langflow Dev Container",
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
"image": "mcr.microsoft.com/devcontainers/universal:2-linux",
|
"image": "mcr.microsoft.com/devcontainers/python:1-3.10-bullseye",
|
||||||
"features": {
|
|
||||||
"ghcr.io/devcontainers/features/aws-cli:1": {},
|
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker": {}
|
|
||||||
},
|
|
||||||
"customizations": {
|
|
||||||
"vscode": {"extensions": [
|
|
||||||
"actboy168.tasks",
|
|
||||||
"GitHub.copilot",
|
|
||||||
"ms-python.python",
|
|
||||||
"sourcery.sourcery",
|
|
||||||
"eamodio.gitlens"
|
|
||||||
]}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
// "features": {},
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/node": {},
|
||||||
|
"ghcr.io/devcontainers-contrib/features/poetry": {}
|
||||||
|
},
|
||||||
|
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
// "forwardPorts": [],
|
// "forwardPorts": [],
|
||||||
|
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
"postCreateCommand": "poetry install"
|
"postCreateCommand": "make install_frontend && make install_backend",
|
||||||
|
|
||||||
|
"containerEnv": {
|
||||||
|
"POETRY_VIRTUALENVS_IN_PROJECT": "true"
|
||||||
|
},
|
||||||
|
|
||||||
// Configure tool-specific properties.
|
// Configure tool-specific properties.
|
||||||
// "customizations": {},
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"actboy168.tasks",
|
||||||
|
"GitHub.copilot",
|
||||||
|
"ms-python.python",
|
||||||
|
"sourcery.sourcery",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"ms-vscode.makefile-tools",
|
||||||
|
"GitHub.vscode-pull-request-github"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
// "remoteUser": "root"
|
// "remoteUser": "root"
|
||||||
|
|
|
||||||
3
Makefile
3
Makefile
|
|
@ -27,7 +27,8 @@ format:
|
||||||
cd src/frontend && npm run format
|
cd src/frontend && npm run format
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
poetry run mypy .
|
# skip .venv folder
|
||||||
|
poetry run mypy --exclude .venv .
|
||||||
poetry run black . --check
|
poetry run black . --check
|
||||||
poetry run ruff . --fix
|
poetry run ruff . --fix
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import Admonition from '@theme/Admonition';
|
import Admonition from "@theme/Admonition";
|
||||||
|
|
||||||
# Text Splitters
|
# Text Splitters
|
||||||
|
|
||||||
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
|
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
|
||||||
<p>
|
<p>
|
||||||
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝
|
We appreciate your understanding as we polish our documentation – it may
|
||||||
|
contain some rough edges. Share your feedback or report issues to help us
|
||||||
|
improve! 🛠️📝
|
||||||
</p>
|
</p>
|
||||||
</Admonition>
|
</Admonition>
|
||||||
|
|
||||||
|
|
@ -44,6 +46,18 @@ The `RecursiveCharacterTextSplitter` splits the text by trying to keep paragra
|
||||||
|
|
||||||
- **chunk_size:** Determines the maximum number of characters in each chunk when splitting a text. It specifies the size or length of each chunk.
|
- **chunk_size:** Determines the maximum number of characters in each chunk when splitting a text. It specifies the size or length of each chunk.
|
||||||
|
|
||||||
- **separator_type:** The parameter allows the user to split the code with multiple language support. It supports various languages such as Text, Ruby, Python, Solidity, Java, and more. Defaults to `Text`.
|
- **separators:** The `separators` in RecursiveCharacterTextSplitter are the characters used to split the text into chunks. The text splitter tries to create chunks based on splitting on the first character in the list of `separators`. If any chunks are too large, it moves on to the next character in the list and continues splitting. Defaults to ["\n\n", "\n", " ", ""].
|
||||||
|
|
||||||
- **separators:** The `separators` in RecursiveCharacterTextSplitter are the characters used to split the text into chunks. The text splitter tries to create chunks based on splitting on the first character in the list of `separators`. If any chunks are too large, it moves on to the next character in the list and continues splitting. Defaults to `.`
|
### LanguageRecursiveTextSplitter
|
||||||
|
|
||||||
|
The `LanguageRecursiveTextSplitter` is a text splitter that splits the text into smaller chunks based on the (programming) language of the text.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
- **Documents:** Input documents to split.
|
||||||
|
|
||||||
|
- **chunk_overlap:** Determines the number of characters that overlap between consecutive chunks when splitting text. It specifies how much of the previous chunk should be included in the next chunk.
|
||||||
|
|
||||||
|
- **chunk_size:** Determines the maximum number of characters in each chunk when splitting a text. It specifies the size or length of each chunk.
|
||||||
|
|
||||||
|
- **separator_type:** The parameter allows the user to split the code with multiple language support. It supports various languages such as Ruby, Python, Solidity, Java, and more. Defaults to `Python`.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,76 @@
|
||||||
import Admonition from '@theme/Admonition';
|
import Admonition from "@theme/Admonition";
|
||||||
|
|
||||||
# Utilities
|
# Utilities
|
||||||
|
|
||||||
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
|
<Admonition type="caution" icon="🚧" title="ZONE UNDER CONSTRUCTION">
|
||||||
<p>
|
<p>
|
||||||
We appreciate your understanding as we polish our documentation – it may contain some rough edges. Share your feedback or report issues to help us improve! 🛠️📝
|
We appreciate your understanding as we polish our documentation – it may
|
||||||
|
contain some rough edges. Share your feedback or report issues to help us
|
||||||
|
improve! 🛠️📝
|
||||||
</p>
|
</p>
|
||||||
</Admonition>
|
</Admonition>
|
||||||
|
|
||||||
|
Utilities are a set of actions that can be used to perform common tasks in a flow. They are available in the **Utilities** section in the sidebar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### GET Request
|
||||||
|
|
||||||
|
Make a GET request to the given URL.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
- **URL:** The URL to make the request to. There can be more than one URL, in which case the request will be made to each URL in order.
|
||||||
|
- **Headers:** A dictionary of headers to send with the request.
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
- **List of Documents:** A list of Documents containing the JSON response from each request.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### POST Request
|
||||||
|
|
||||||
|
Make a POST request to the given URL.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
- **URL:** The URL to make the request to.
|
||||||
|
- **Headers:** A dictionary of headers to send with the request.
|
||||||
|
- **Document:** The Document containing a JSON object to send with the request.
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
- **Document:** The JSON response from the request as a Document.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Update Request
|
||||||
|
|
||||||
|
Make a PATCH or PUT request to the given URL.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
- **URL:** The URL to make the request to.
|
||||||
|
- **Headers:** A dictionary of headers to send with the request.
|
||||||
|
- **Document:** The Document containing a JSON object to send with the request.
|
||||||
|
- **Method:** The HTTP method to use for the request. Can be either `PATCH` or `PUT`.
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
- **Document:** The JSON response from the request as a Document.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### JSON Document Builder
|
||||||
|
|
||||||
|
Build a Document containing a JSON object using a key and another Document page content.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
- **Key:** The key to use for the JSON object.
|
||||||
|
- **Document:** The Document page to use for the JSON object.
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
- **List of Documents:** A list containing the Document with the JSON object.
|
||||||
|
|
|
||||||
71
docs/package-lock.json
generated
71
docs/package-lock.json
generated
|
|
@ -16,7 +16,7 @@
|
||||||
"@docusaurus/theme-classic": "^2.4.1",
|
"@docusaurus/theme-classic": "^2.4.1",
|
||||||
"@docusaurus/theme-search-algolia": "^2.4.1",
|
"@docusaurus/theme-search-algolia": "^2.4.1",
|
||||||
"@mdx-js/react": "^2.3.0",
|
"@mdx-js/react": "^2.3.0",
|
||||||
"@mendable/search": "^0.0.114",
|
"@mendable/search": "^0.0.154",
|
||||||
"@pbe/react-yandex-maps": "^1.2.4",
|
"@pbe/react-yandex-maps": "^1.2.4",
|
||||||
"@prismicio/client": "^7.0.1",
|
"@prismicio/client": "^7.0.1",
|
||||||
"@uiball/loaders": "^1.2.6",
|
"@uiball/loaders": "^1.2.6",
|
||||||
|
|
@ -3250,10 +3250,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mendable/search": {
|
"node_modules/@mendable/search": {
|
||||||
"version": "0.0.114",
|
"version": "0.0.154",
|
||||||
"resolved": "https://registry.npmjs.org/@mendable/search/-/search-0.0.114.tgz",
|
"resolved": "https://registry.npmjs.org/@mendable/search/-/search-0.0.154.tgz",
|
||||||
"integrity": "sha512-0uR+zxONuu/16bpLli49Jocr5fee1WIjs06KzU1AnHsR+fdFBmfrlpgTDWctgGuXPzS5Dorlw4VMlR5dPW5qVQ==",
|
"integrity": "sha512-adNwXlIaMXVMCkPU2uUdghfn05Dmxb0BnE95SRLQJ6evHajsNFQdRl5Ltj3WijG+qo4ozTIJcPOBYrDPKMTPVw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"html-react-parser": "^4.2.0",
|
||||||
"posthog-js": "^1.45.1"
|
"posthog-js": "^1.45.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
@ -9351,6 +9352,33 @@
|
||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-dom-parser": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TUa3wIwi80f5NF8CVWzkopBVqVAtlawUzJoLwVLHns0XSJGynss4jiY0mTWpiDOsuyw+afP+ujjMgRh9CoZcXw==",
|
||||||
|
"dependencies": {
|
||||||
|
"domhandler": "5.0.3",
|
||||||
|
"htmlparser2": "9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/html-dom-parser/node_modules/htmlparser2": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-uxbSI98wmFT/G4P2zXx4OVx04qWUmyFPrD2/CNepa2Zo3GPNaCaaxElDgwUrwYWkK1nr9fft0Ya8dws8coDLLQ==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.1.0",
|
||||||
|
"entities": "^4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/html-entities": {
|
"node_modules/html-entities": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
|
||||||
|
|
@ -9394,6 +9422,20 @@
|
||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-react-parser": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-Dxzdowj5Zu/+7mr8X8PzCFbPXGuwCwGB2u4cB6oxZGES9inw85qlvnlfPD75VGKUGjcgsXs+9Dpj+THWNQyOBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"domhandler": "5.0.3",
|
||||||
|
"html-dom-parser": "4.0.0",
|
||||||
|
"react-property": "2.0.0",
|
||||||
|
"style-to-js": "1.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "0.14 || 15 || 16 || 17 || 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/html-tags": {
|
"node_modules/html-tags": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
|
||||||
|
|
@ -15324,6 +15366,11 @@
|
||||||
"react": ">=16.6.0"
|
"react": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-property": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw=="
|
||||||
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "5.3.4",
|
"version": "5.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
||||||
|
|
@ -17510,6 +17557,22 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/style-to-js": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-zKI5gN/zb7LS/Vm0eUwjmjrXWw8IMtyA8aPBJZdYiQTXj4+wQ3IucOLIOnF7zCHxvW8UhIGh/uZh/t9zEHXNTQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"style-to-object": "0.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/style-to-js/node_modules/style-to-object": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==",
|
||||||
|
"dependencies": {
|
||||||
|
"inline-style-parser": "0.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/style-to-object": {
|
"node_modules/style-to-object": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
"@docusaurus/theme-classic": "^2.4.1",
|
"@docusaurus/theme-classic": "^2.4.1",
|
||||||
"@docusaurus/theme-search-algolia": "^2.4.1",
|
"@docusaurus/theme-search-algolia": "^2.4.1",
|
||||||
"@mdx-js/react": "^2.3.0",
|
"@mdx-js/react": "^2.3.0",
|
||||||
"@mendable/search": "^0.0.114",
|
"@mendable/search": "^0.0.154",
|
||||||
"@pbe/react-yandex-maps": "^1.2.4",
|
"@pbe/react-yandex-maps": "^1.2.4",
|
||||||
"@prismicio/client": "^7.0.1",
|
"@prismicio/client": "^7.0.1",
|
||||||
"@uiball/loaders": "^1.2.6",
|
"@uiball/loaders": "^1.2.6",
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ module.exports = {
|
||||||
"components/text-splitters",
|
"components/text-splitters",
|
||||||
"components/toolkits",
|
"components/toolkits",
|
||||||
"components/tools",
|
"components/tools",
|
||||||
|
"components/utilities",
|
||||||
"components/vector-stores",
|
"components/vector-stores",
|
||||||
"components/wrappers",
|
"components/wrappers",
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default function FooterWrapper(props) {
|
||||||
|
|
||||||
const mendableFloatingButton = React.createElement(MendableFloatingButton, {
|
const mendableFloatingButton = React.createElement(MendableFloatingButton, {
|
||||||
floatingButtonStyle: { color: "#000000", backgroundColor: "#f6f6f6" },
|
floatingButtonStyle: { color: "#000000", backgroundColor: "#f6f6f6" },
|
||||||
anon_key: customFields.mendableAnonKey, // Mendable Search Public ANON key, ok to be public
|
anon_key: 'b7f52734-297c-41dc-8737-edbd13196394', // Mendable Search Public ANON key, ok to be public
|
||||||
showSimpleSearch: true,
|
showSimpleSearch: true,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
1551
package-lock.json
generated
1551
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"@svgr/cli": "^8.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
255
poetry.lock
generated
255
poetry.lock
generated
|
|
@ -206,17 +206,6 @@ files = [
|
||||||
{file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
|
{file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "argilla"
|
|
||||||
version = "0.0.1"
|
|
||||||
description = ""
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "argilla-0.0.1-py3-none-any.whl", hash = "sha256:8bdc3c505bcfb47ba4b91f5658034eae53bf7d4f9317980397605c0c55817396"},
|
|
||||||
{file = "argilla-0.0.1.tar.gz", hash = "sha256:5017854754e89f573b31af25b25b803f51cea9ca1fa0bcf00505dee1f45cf7c9"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asgiref"
|
name = "asgiref"
|
||||||
version = "3.7.2"
|
version = "3.7.2"
|
||||||
|
|
@ -1235,16 +1224,19 @@ gmpy = ["gmpy"]
|
||||||
gmpy2 = ["gmpy2"]
|
gmpy2 = ["gmpy2"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "et-xmlfile"
|
name = "emoji"
|
||||||
version = "1.1.0"
|
version = "2.8.0"
|
||||||
description = "An implementation of lxml.xmlfile for the standard library"
|
description = "Emoji for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
files = [
|
files = [
|
||||||
{file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"},
|
{file = "emoji-2.8.0-py2.py3-none-any.whl", hash = "sha256:a8468fd836b7ecb6d1eac054c9a591701ce0ccd6c6f7779ad71b66f76664df90"},
|
||||||
{file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"},
|
{file = "emoji-2.8.0.tar.gz", hash = "sha256:8d8b5dec3c507444b58890e598fc895fcec022b3f5acb49497c6ccc5208b8b00"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["coverage", "coveralls", "pytest"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "exceptiongroup"
|
name = "exceptiongroup"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
|
@ -3160,24 +3152,6 @@ docs = ["sphinx (>=1.6.0)", "sphinx-bootstrap-theme"]
|
||||||
flake8 = ["flake8"]
|
flake8 = ["flake8"]
|
||||||
tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"]
|
tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "markdown"
|
|
||||||
version = "3.4.4"
|
|
||||||
description = "Python implementation of John Gruber's Markdown."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"},
|
|
||||||
{file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"]
|
|
||||||
testing = ["coverage", "pyyaml"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown-it-py"
|
name = "markdown-it-py"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
|
|
@ -3327,6 +3301,21 @@ files = [
|
||||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "metal-sdk"
|
||||||
|
version = "2.0.2"
|
||||||
|
description = "SDK for getmetal.io"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "metal_sdk-2.0.2-py3-none-any.whl", hash = "sha256:a5a95fb3796979085965667ffc41fd9eeddc87b60671619671a0eaebd0bec4a1"},
|
||||||
|
{file = "metal_sdk-2.0.2.tar.gz", hash = "sha256:e5e35d230f00b1b838cfcffbcb7042f450b23b59448f37bdd385761871a1490d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
httpx = "*"
|
||||||
|
typing-extensions = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metaphor-python"
|
name = "metaphor-python"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
|
@ -3380,23 +3369,6 @@ docs = ["sphinx"]
|
||||||
gmpy = ["gmpy2 (>=2.1.0a4)"]
|
gmpy = ["gmpy2 (>=2.1.0a4)"]
|
||||||
tests = ["pytest (>=4.6)"]
|
tests = ["pytest (>=4.6)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "msg-parser"
|
|
||||||
version = "1.2.0"
|
|
||||||
description = "This module enables reading, parsing and converting Microsoft Outlook MSG E-Mail files."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.4"
|
|
||||||
files = [
|
|
||||||
{file = "msg_parser-1.2.0-py2.py3-none-any.whl", hash = "sha256:d47a2f0b2a359cb189fad83cc991b63ea781ecc70d91410324273fbf93e95375"},
|
|
||||||
{file = "msg_parser-1.2.0.tar.gz", hash = "sha256:0de858d4fcebb6c8f6f028da83a17a20fe01cdce67c490779cf43b3b0162aa66"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
olefile = ">=0.46"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
rtf = ["compressed-rtf (>=1.0.5)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multidict"
|
name = "multidict"
|
||||||
version = "6.0.4"
|
version = "6.0.4"
|
||||||
|
|
@ -3695,16 +3667,6 @@ files = [
|
||||||
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
|
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "olefile"
|
|
||||||
version = "0.46"
|
|
||||||
description = "Python package to parse, read and write Microsoft OLE2 files (Structured Storage or Compound Document, Microsoft Office)"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
files = [
|
|
||||||
{file = "olefile-0.46.zip", hash = "sha256:133b031eaf8fd2c9399b78b8bc5b8fcbe4c31e85295749bb17a87cba8f3c3964"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "onnxruntime"
|
name = "onnxruntime"
|
||||||
version = "1.15.1"
|
version = "1.15.1"
|
||||||
|
|
@ -3782,20 +3744,6 @@ files = [
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pydantic = ">=1.8.2"
|
pydantic = ">=1.8.2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openpyxl"
|
|
||||||
version = "3.1.2"
|
|
||||||
description = "A Python library to read/write Excel 2010 xlsx/xlsm files"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"},
|
|
||||||
{file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
et-xmlfile = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry-api"
|
name = "opentelemetry-api"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
|
|
@ -4254,40 +4202,6 @@ files = [
|
||||||
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pdf2image"
|
|
||||||
version = "1.16.3"
|
|
||||||
description = "A wrapper around the pdftoppm and pdftocairo command line tools to convert PDF to a PIL Image list."
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "pdf2image-1.16.3-py3-none-any.whl", hash = "sha256:b6154164af3677211c22cbb38b2bd778b43aca02758e962fe1e231f6d3b0e380"},
|
|
||||||
{file = "pdf2image-1.16.3.tar.gz", hash = "sha256:74208810c2cef4d9e347769b8e62a52303982ddb4f2dfd744c7ab4b940ae287e"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pillow = "*"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pdfminer-six"
|
|
||||||
version = "20221105"
|
|
||||||
description = "PDF parser and analyzer"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "pdfminer.six-20221105-py3-none-any.whl", hash = "sha256:1eaddd712d5b2732f8ac8486824533514f8ba12a0787b3d5fe1e686cd826532d"},
|
|
||||||
{file = "pdfminer.six-20221105.tar.gz", hash = "sha256:8448ab7b939d18b64820478ecac5394f482d7a79f5f7eaa7703c6c959c175e1d"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
charset-normalizer = ">=2.0.0"
|
|
||||||
cryptography = ">=36.0.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["black", "mypy (==0.931)", "nox", "pytest"]
|
|
||||||
docs = ["sphinx", "sphinx-argparse"]
|
|
||||||
image = ["Pillow"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pexpect"
|
name = "pexpect"
|
||||||
version = "4.8.0"
|
version = "4.8.0"
|
||||||
|
|
@ -5088,17 +5002,6 @@ ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3
|
||||||
snappy = ["python-snappy"]
|
snappy = ["python-snappy"]
|
||||||
zstd = ["zstandard"]
|
zstd = ["zstandard"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pypandoc"
|
|
||||||
version = "1.11"
|
|
||||||
description = "Thin wrapper for pandoc."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "pypandoc-1.11-py3-none-any.whl", hash = "sha256:b260596934e9cfc6513056110a7c8600171d414f90558bf4407e68b209be8007"},
|
|
||||||
{file = "pypandoc-1.11.tar.gz", hash = "sha256:7f6d68db0e57e0f6961bec2190897118c4d305fc2d31c22cd16037f22ee084a5"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyparsing"
|
name = "pyparsing"
|
||||||
version = "3.1.1"
|
version = "3.1.1"
|
||||||
|
|
@ -5212,19 +5115,6 @@ files = [
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
six = ">=1.5"
|
six = ">=1.5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "python-docx"
|
|
||||||
version = "0.8.11"
|
|
||||||
description = "Create and update Microsoft Word .docx files."
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "python-docx-0.8.11.tar.gz", hash = "sha256:1105d233a0956dd8dd1e710d20b159e2d72ac3c301041b95f4d4ceb3e0ebebc4"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lxml = ">=2.3.2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -5304,21 +5194,6 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"]
|
dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "python-pptx"
|
|
||||||
version = "0.6.21"
|
|
||||||
description = "Generate and manipulate Open XML PowerPoint (.pptx) files"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "python-pptx-0.6.21.tar.gz", hash = "sha256:7798a2aaf89563565b3c7120c0acfe9aff775db0db3580544e3bf4840c2e378f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lxml = ">=3.1.0"
|
|
||||||
Pillow = ">=3.3.2"
|
|
||||||
XlsxWriter = ">=0.5.7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-semantic-release"
|
name = "python-semantic-release"
|
||||||
version = "7.33.2"
|
version = "7.33.2"
|
||||||
|
|
@ -6995,50 +6870,67 @@ test = ["coverage", "pytest", "pytest-cov"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unstructured"
|
name = "unstructured"
|
||||||
version = "0.7.12"
|
version = "0.10.9"
|
||||||
description = "A library that prepares raw documents for downstream ML tasks."
|
description = "A library that prepares raw documents for downstream ML tasks."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
files = [
|
files = [
|
||||||
{file = "unstructured-0.7.12-py3-none-any.whl", hash = "sha256:6dec4f23574e213f30bccb680a4fb84c95617092ce4abf5d8955cc71af402fef"},
|
{file = "unstructured-0.10.9-py3-none-any.whl", hash = "sha256:182062983cf5ade923e871be52154829d92e5b72dfd7575847618fb44f7debd6"},
|
||||||
{file = "unstructured-0.7.12.tar.gz", hash = "sha256:3dcddea34f52e1070f38fd10063b3b0f64bc4cbe5b778d6b86b5d33262d625cd"},
|
{file = "unstructured-0.10.9.tar.gz", hash = "sha256:fd62f84abf12c85ef8b81567a4fcb841b7450f010454b69754bfc5b10b68d869"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
argilla = "*"
|
beautifulsoup4 = "*"
|
||||||
chardet = "*"
|
chardet = "*"
|
||||||
|
emoji = "*"
|
||||||
filetype = "*"
|
filetype = "*"
|
||||||
lxml = "*"
|
lxml = "*"
|
||||||
markdown = "*"
|
|
||||||
msg-parser = "*"
|
|
||||||
nltk = "*"
|
nltk = "*"
|
||||||
openpyxl = "*"
|
|
||||||
pandas = "*"
|
|
||||||
pdf2image = "*"
|
|
||||||
"pdfminer.six" = "*"
|
|
||||||
pillow = "*"
|
|
||||||
pypandoc = "*"
|
|
||||||
python-docx = "*"
|
|
||||||
python-magic = "*"
|
python-magic = "*"
|
||||||
python-pptx = "*"
|
|
||||||
requests = "*"
|
requests = "*"
|
||||||
tabulate = "*"
|
tabulate = "*"
|
||||||
xlrd = "*"
|
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
airtable = ["pyairtable"]
|
||||||
|
all-docs = ["Pillow (<10)", "ebooklib", "markdown", "msg-parser", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pypandoc", "python-docx", "python-pptx", "unstructured-inference", "xlrd"]
|
||||||
azure = ["adlfs", "fsspec"]
|
azure = ["adlfs", "fsspec"]
|
||||||
|
biomed = ["bs4"]
|
||||||
|
box = ["boxfs", "fsspec"]
|
||||||
|
confluence = ["atlassian-python-api"]
|
||||||
|
csv = ["pandas"]
|
||||||
|
delta-table = ["deltalake", "fsspec"]
|
||||||
discord = ["discord-py"]
|
discord = ["discord-py"]
|
||||||
|
doc = ["python-docx"]
|
||||||
|
docx = ["python-docx"]
|
||||||
dropbox = ["dropboxdrivefs", "fsspec"]
|
dropbox = ["dropboxdrivefs", "fsspec"]
|
||||||
gcs = ["fsspec", "gcsfs"]
|
elasticsearch = ["elasticsearch", "jq"]
|
||||||
github = ["pygithub (==1.58.2)"]
|
epub = ["ebooklib"]
|
||||||
|
gcs = ["bs4", "fsspec", "gcsfs"]
|
||||||
|
github = ["pygithub (>1.58.0)"]
|
||||||
gitlab = ["python-gitlab"]
|
gitlab = ["python-gitlab"]
|
||||||
google-drive = ["google-api-python-client"]
|
google-drive = ["google-api-python-client"]
|
||||||
huggingface = ["langdetect", "sacremoses", "sentencepiece", "torch", "transformers"]
|
huggingface = ["langdetect", "sacremoses", "sentencepiece", "torch", "transformers"]
|
||||||
local-inference = ["unstructured-inference (==0.5.4)"]
|
image = ["Pillow (<10)", "pdf2image", "pdfminer.six", "unstructured-inference"]
|
||||||
|
local-inference = ["Pillow (<10)", "ebooklib", "markdown", "msg-parser", "openpyxl", "pandas", "pdf2image", "pdfminer.six", "pypandoc", "python-docx", "python-pptx", "unstructured-inference", "xlrd"]
|
||||||
|
md = ["markdown"]
|
||||||
|
msg = ["msg-parser"]
|
||||||
|
notion = ["htmlBuilder", "notion-client"]
|
||||||
|
odt = ["pypandoc", "python-docx"]
|
||||||
|
onedrive = ["Office365-REST-Python-Client (<2.4.3)", "bs4", "msal"]
|
||||||
|
org = ["pypandoc"]
|
||||||
|
outlook = ["Office365-REST-Python-Client (<2.4.3)", "msal"]
|
||||||
|
pdf = ["Pillow (<10)", "pdf2image", "pdfminer.six", "unstructured-inference"]
|
||||||
|
ppt = ["python-pptx"]
|
||||||
|
pptx = ["python-pptx"]
|
||||||
reddit = ["praw"]
|
reddit = ["praw"]
|
||||||
|
rst = ["pypandoc"]
|
||||||
|
rtf = ["pypandoc"]
|
||||||
s3 = ["fsspec", "s3fs"]
|
s3 = ["fsspec", "s3fs"]
|
||||||
|
sharepoint = ["Office365-REST-Python-Client (<2.4.3)", "msal"]
|
||||||
slack = ["slack-sdk"]
|
slack = ["slack-sdk"]
|
||||||
|
tsv = ["pandas"]
|
||||||
wikipedia = ["wikipedia"]
|
wikipedia = ["wikipedia"]
|
||||||
|
xlsx = ["openpyxl", "pandas", "xlrd"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uritemplate"
|
name = "uritemplate"
|
||||||
|
|
@ -7443,33 +7335,6 @@ files = [
|
||||||
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
{file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xlrd"
|
|
||||||
version = "2.0.1"
|
|
||||||
description = "Library for developers to extract data from Microsoft Excel (tm) .xls spreadsheet files"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
|
||||||
files = [
|
|
||||||
{file = "xlrd-2.0.1-py2.py3-none-any.whl", hash = "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd"},
|
|
||||||
{file = "xlrd-2.0.1.tar.gz", hash = "sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
build = ["twine", "wheel"]
|
|
||||||
docs = ["sphinx"]
|
|
||||||
test = ["pytest", "pytest-cov"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xlsxwriter"
|
|
||||||
version = "3.1.2"
|
|
||||||
description = "A Python module for creating Excel XLSX files."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "XlsxWriter-3.1.2-py3-none-any.whl", hash = "sha256:331508ff39d610ecdaf979e458840bc1eab6e6a02cfd5d08f044f0f73636236f"},
|
|
||||||
{file = "XlsxWriter-3.1.2.tar.gz", hash = "sha256:78751099a770273f1c98b8d6643351f68f98ae8e6acf9d09d37dc6798f8cd3de"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yarl"
|
name = "yarl"
|
||||||
version = "1.9.2"
|
version = "1.9.2"
|
||||||
|
|
@ -7638,4 +7503,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.9,<3.11"
|
python-versions = ">=3.9,<3.11"
|
||||||
content-hash = "3517d8ba2744a059d3f107a826392c25ed57b5279ccf45ffdb8e188f959b256a"
|
content-hash = "2390a7da4e661d287aa15bfe00ba84789301af5cca5dbc584f0093461670364e"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "langflow"
|
name = "langflow"
|
||||||
version = "0.4.9"
|
version = "0.4.17"
|
||||||
description = "A Python package with a built-in web application"
|
description = "A Python package with a built-in web application"
|
||||||
authors = ["Logspace <contact@logspace.ai>"]
|
authors = ["Logspace <contact@logspace.ai>"]
|
||||||
maintainers = [
|
maintainers = [
|
||||||
|
|
@ -32,33 +32,33 @@ beautifulsoup4 = "^4.12.2"
|
||||||
google-search-results = "^2.4.1"
|
google-search-results = "^2.4.1"
|
||||||
google-api-python-client = "^2.79.0"
|
google-api-python-client = "^2.79.0"
|
||||||
typer = "^0.9.0"
|
typer = "^0.9.0"
|
||||||
gunicorn = "^21.1.0"
|
gunicorn = "^21.2.0"
|
||||||
langchain = "^0.0.256"
|
langchain = "^0.0.256"
|
||||||
openai = "^0.27.8"
|
openai = "^0.27.8"
|
||||||
pandas = "^2.0.0"
|
pandas = "^2.0.0"
|
||||||
chromadb = "^0.3.21"
|
chromadb = "^0.3.0"
|
||||||
huggingface-hub = { version = "^0.16.0", extras = ["inference"] }
|
huggingface-hub = { version = "^0.16.0", extras = ["inference"] }
|
||||||
rich = "^13.4.2"
|
rich = "^13.5.0"
|
||||||
llama-cpp-python = { version = "~0.1.0", optional = true }
|
llama-cpp-python = { version = "~0.1.0", optional = true }
|
||||||
networkx = "^3.1"
|
networkx = "^3.1"
|
||||||
unstructured = "^0.7.0"
|
unstructured = "^0.10.0"
|
||||||
pypdf = "^3.11.0"
|
pypdf = "^3.15.0"
|
||||||
lxml = "^4.9.2"
|
lxml = "^4.9.2"
|
||||||
pysrt = "^1.1.2"
|
pysrt = "^1.1.2"
|
||||||
fake-useragent = "^1.1.3"
|
fake-useragent = "^1.2.1"
|
||||||
docstring-parser = "^0.15"
|
docstring-parser = "^0.15"
|
||||||
psycopg2-binary = "^2.9.6"
|
psycopg2-binary = "^2.9.6"
|
||||||
pyarrow = "^12.0.0"
|
pyarrow = "^12.0.0"
|
||||||
tiktoken = "~0.4.0"
|
tiktoken = "~0.4.0"
|
||||||
wikipedia = "^1.4.0"
|
wikipedia = "^1.4.0"
|
||||||
langchain-serve = { version = ">0.0.51", optional = true }
|
langchain-serve = { version = ">0.0.51", optional = true }
|
||||||
qdrant-client = "^1.3.0"
|
qdrant-client = "^1.4.0"
|
||||||
websockets = "^10.3"
|
websockets = "^10.3"
|
||||||
weaviate-client = "^3.21.0"
|
weaviate-client = "^3.23.0"
|
||||||
jina = "3.15.2"
|
jina = "3.15.2"
|
||||||
sentence-transformers = { version = "^2.2.2", optional = true }
|
sentence-transformers = { version = "^2.2.2", optional = true }
|
||||||
ctransformers = { version = "^0.2.10", optional = true }
|
ctransformers = { version = "^0.2.10", optional = true }
|
||||||
cohere = "^4.11.0"
|
cohere = "^4.21.0"
|
||||||
python-multipart = "^0.0.6"
|
python-multipart = "^0.0.6"
|
||||||
sqlmodel = "^0.0.8"
|
sqlmodel = "^0.0.8"
|
||||||
faiss-cpu = "^1.7.4"
|
faiss-cpu = "^1.7.4"
|
||||||
|
|
@ -80,6 +80,8 @@ fastavro = "^1.8.0"
|
||||||
langchain-experimental = "^0.0.8"
|
langchain-experimental = "^0.0.8"
|
||||||
metaphor-python = "^0.1.11"
|
metaphor-python = "^0.1.11"
|
||||||
langfuse = "^1.0.13"
|
langfuse = "^1.0.13"
|
||||||
|
pillow = "^10.0.0"
|
||||||
|
metal-sdk = "^2.0.2"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^23.1.0"
|
black = "^23.1.0"
|
||||||
|
|
|
||||||
|
|
@ -104,14 +104,9 @@ async def stream_build(flow_id: str):
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Building langchain object")
|
logger.debug("Building langchain object")
|
||||||
try:
|
|
||||||
# Some error could happen when building the graph
|
# Some error could happen when building the graph
|
||||||
graph = Graph.from_payload(graph_data)
|
graph = Graph.from_payload(graph_data)
|
||||||
except Exception as exc:
|
|
||||||
logger.exception(exc)
|
|
||||||
error_message = str(exc)
|
|
||||||
yield str(StreamData(event="error", data={"error": error_message}))
|
|
||||||
return
|
|
||||||
|
|
||||||
number_of_nodes = len(graph.nodes)
|
number_of_nodes = len(graph.nodes)
|
||||||
flow_data_store[flow_id]["status"] = BuildStatus.IN_PROGRESS
|
flow_data_store[flow_id]["status"] = BuildStatus.IN_PROGRESS
|
||||||
|
|
@ -126,7 +121,9 @@ async def stream_build(flow_id: str):
|
||||||
params = vertex._built_object_repr()
|
params = vertex._built_object_repr()
|
||||||
valid = True
|
valid = True
|
||||||
logger.debug(f"Building node {str(vertex.vertex_type)}")
|
logger.debug(f"Building node {str(vertex.vertex_type)}")
|
||||||
logger.debug(f"Output: {params}")
|
logger.debug(
|
||||||
|
f"Output: {params[:100]}{'...' if len(params) > 100 else ''}"
|
||||||
|
)
|
||||||
if vertex.artifacts:
|
if vertex.artifacts:
|
||||||
# The artifacts will be prompt variables
|
# The artifacts will be prompt variables
|
||||||
# passed to build_input_keys_response
|
# passed to build_input_keys_response
|
||||||
|
|
|
||||||
|
|
@ -56,12 +56,9 @@ def get_all():
|
||||||
|
|
||||||
logger.info(f"Loading {len(custom_component_dicts)} category(ies)")
|
logger.info(f"Loading {len(custom_component_dicts)} category(ies)")
|
||||||
for custom_component_dict in custom_component_dicts:
|
for custom_component_dict in custom_component_dicts:
|
||||||
# custom_component_dict is a dict of dicts
|
logger.debug(
|
||||||
category = list(custom_component_dict.keys())[0]
|
{key: len(value) for key, value in custom_component_dict.items()}
|
||||||
logger.info(
|
|
||||||
f"Loading {len(custom_component_dict[category])} component(s) from category {category}"
|
|
||||||
)
|
)
|
||||||
logger.debug(custom_component_dict)
|
|
||||||
custom_components_from_file = merge_nested_dicts_with_renaming(
|
custom_components_from_file = merge_nested_dicts_with_renaming(
|
||||||
custom_components_from_file, custom_component_dict
|
custom_components_from_file, custom_component_dict
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
from fastapi.encoders import jsonable_encoder
|
||||||
from langflow.settings import settings
|
from langflow.settings import settings
|
||||||
from langflow.api.utils import remove_api_keys
|
from langflow.api.utils import remove_api_keys
|
||||||
from langflow.api.v1.schemas import FlowListCreate, FlowListRead
|
from langflow.api.v1.schemas import FlowListCreate, FlowListRead
|
||||||
|
|
@ -11,12 +12,11 @@ from langflow.database.models.flow import (
|
||||||
FlowUpdate,
|
FlowUpdate,
|
||||||
)
|
)
|
||||||
from langflow.database.base import get_session
|
from langflow.database.base import get_session
|
||||||
|
import orjson
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from fastapi.encoders import jsonable_encoder
|
|
||||||
|
|
||||||
from fastapi import File, UploadFile
|
from fastapi import File, UploadFile
|
||||||
import json
|
|
||||||
|
|
||||||
# build router
|
# build router
|
||||||
router = APIRouter(prefix="/flows", tags=["Flows"])
|
router = APIRouter(prefix="/flows", tags=["Flows"])
|
||||||
|
|
@ -105,7 +105,7 @@ async def upload_file(
|
||||||
):
|
):
|
||||||
"""Upload flows from a file."""
|
"""Upload flows from a file."""
|
||||||
contents = await file.read()
|
contents = await file.read()
|
||||||
data = json.loads(contents)
|
data = orjson.loads(contents)
|
||||||
if "flows" in data:
|
if "flows" in data:
|
||||||
flow_list = FlowListCreate(**data)
|
flow_list = FlowListCreate(**data)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Dict, List, Optional, Union
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
from langflow.database.models.flow import FlowCreate, FlowRead
|
from langflow.database.models.flow import FlowCreate, FlowRead
|
||||||
from pydantic import BaseModel, Field, validator
|
from pydantic import BaseModel, Field, validator
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
class BuildStatus(Enum):
|
class BuildStatus(Enum):
|
||||||
|
|
@ -115,7 +115,9 @@ class StreamData(BaseModel):
|
||||||
data: dict
|
data: dict
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"event: {self.event}\ndata: {json.dumps(self.data)}\n\n"
|
return (
|
||||||
|
f"event: {self.event}\ndata: {orjson_dumps(self.data, indent_2=False)}\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomComponentCode(BaseModel):
|
class CustomComponentCode(BaseModel):
|
||||||
|
|
|
||||||
5
src/backend/langflow/cache/utils.py
vendored
5
src/backend/langflow/cache/utils.py
vendored
|
|
@ -2,13 +2,13 @@ import base64
|
||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
from appdirs import user_cache_dir
|
from appdirs import user_cache_dir
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
|
||||||
CACHE: Dict[str, Any] = {}
|
CACHE: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
|
@ -76,7 +76,8 @@ def clear_old_cache_files(max_cache_size: int = 3):
|
||||||
def compute_dict_hash(graph_data):
|
def compute_dict_hash(graph_data):
|
||||||
graph_data = filter_json(graph_data)
|
graph_data = filter_json(graph_data)
|
||||||
|
|
||||||
cleaned_graph_json = json.dumps(graph_data, sort_keys=True)
|
cleaned_graph_json = orjson_dumps(graph_data, sort_keys=True)
|
||||||
|
|
||||||
return hashlib.sha256(cleaned_graph_json.encode("utf-8")).hexdigest()
|
return hashlib.sha256(cleaned_graph_json.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ from langflow.utils.logger import logger
|
||||||
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from langflow.cache.flow import InMemoryCache
|
from langflow.cache.flow import InMemoryCache
|
||||||
|
import orjson
|
||||||
|
|
||||||
|
|
||||||
class ChatHistory(Subject):
|
class ChatHistory(Subject):
|
||||||
|
|
@ -193,8 +193,8 @@ class ChatManager:
|
||||||
while True:
|
while True:
|
||||||
json_payload = await websocket.receive_json()
|
json_payload = await websocket.receive_json()
|
||||||
try:
|
try:
|
||||||
payload = json.loads(json_payload)
|
payload = orjson.loads(json_payload)
|
||||||
except TypeError:
|
except Exception:
|
||||||
payload = json_payload
|
payload = json_payload
|
||||||
if "clear_history" in payload:
|
if "clear_history" in payload:
|
||||||
self.chat_history.history[client_id] = []
|
self.chat_history.history[client_id] = []
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ class ConversationalAgent(CustomComponent):
|
||||||
self,
|
self,
|
||||||
model_name: str,
|
model_name: str,
|
||||||
openai_api_key: str,
|
openai_api_key: str,
|
||||||
openai_api_base: str,
|
|
||||||
tools: Tool,
|
tools: Tool,
|
||||||
|
openai_api_base: Optional[str] = None,
|
||||||
memory: Optional[BaseMemory] = None,
|
memory: Optional[BaseMemory] = None,
|
||||||
system_message: Optional[SystemMessagePromptTemplate] = None,
|
system_message: Optional[SystemMessagePromptTemplate] = None,
|
||||||
max_token_limit: int = 2000,
|
max_token_limit: int = 2000,
|
||||||
|
|
|
||||||
42
src/backend/langflow/components/llms/HuggingFaceEndpoints.py
Normal file
42
src/backend/langflow/components/llms/HuggingFaceEndpoints.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
from typing import Optional
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.llms import HuggingFaceEndpoint
|
||||||
|
from langchain.llms.base import BaseLLM
|
||||||
|
|
||||||
|
|
||||||
|
class HuggingFaceEndpointsComponent(CustomComponent):
|
||||||
|
display_name: str = "Hugging Face Inference API"
|
||||||
|
description: str = "LLM model from Hugging Face Inference API."
|
||||||
|
|
||||||
|
def build_config(self):
|
||||||
|
return {
|
||||||
|
"endpoint_url": {"display_name": "Endpoint URL", "password": True},
|
||||||
|
"task": {
|
||||||
|
"display_name": "Task",
|
||||||
|
"type": "select",
|
||||||
|
"options": ["text2text-generation", "text-generation", "summarization"],
|
||||||
|
},
|
||||||
|
"huggingfacehub_api_token": {"display_name": "API token", "password": True},
|
||||||
|
"model_kwargs": {
|
||||||
|
"display_name": "Model Keyword Arguments",
|
||||||
|
"field_type": "code",
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
endpoint_url: str,
|
||||||
|
task="text2text-generation",
|
||||||
|
huggingfacehub_api_token: Optional[str] = None,
|
||||||
|
model_kwargs: Optional[dict] = None,
|
||||||
|
) -> BaseLLM:
|
||||||
|
try:
|
||||||
|
output = HuggingFaceEndpoint(
|
||||||
|
endpoint_url=endpoint_url,
|
||||||
|
task=task,
|
||||||
|
huggingfacehub_api_token=huggingfacehub_api_token,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Could not connect to HuggingFace Endpoints API.") from e
|
||||||
|
return output
|
||||||
0
src/backend/langflow/components/llms/__init__.py
Normal file
0
src/backend/langflow/components/llms/__init__.py
Normal file
28
src/backend/langflow/components/retrievers/MetalRetriever.py
Normal file
28
src/backend/langflow/components/retrievers/MetalRetriever.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
from typing import Optional
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.retrievers import MetalRetriever
|
||||||
|
from langchain.schema import BaseRetriever
|
||||||
|
from metal_sdk.metal import Metal # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class MetalRetrieverComponent(CustomComponent):
|
||||||
|
display_name: str = "Metal Retriever"
|
||||||
|
description: str = "Retriever that uses the Metal API."
|
||||||
|
|
||||||
|
def build_config(self):
|
||||||
|
return {
|
||||||
|
"api_key": {"display_name": "API Key", "password": True},
|
||||||
|
"client_id": {"display_name": "Client ID", "password": True},
|
||||||
|
"index_id": {"display_name": "Index ID"},
|
||||||
|
"params": {"display_name": "Parameters", "field_type": "code"},
|
||||||
|
"code": {"show": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self, api_key: str, client_id: str, index_id: str, params: Optional[dict] = None
|
||||||
|
) -> BaseRetriever:
|
||||||
|
try:
|
||||||
|
metal = Metal(api_key=api_key, client_id=client_id, index_id=index_id)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Could not connect to Metal API.") from e
|
||||||
|
return MetalRetriever(client=metal, params=params or {})
|
||||||
0
src/backend/langflow/components/retrievers/__init__.py
Normal file
0
src/backend/langflow/components/retrievers/__init__.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
from typing import Optional
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.text_splitter import Language
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langflow.utils.util import build_loader_repr_from_documents
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageRecursiveTextSplitterComponent(CustomComponent):
|
||||||
|
display_name: str = "Language Recursive Text Splitter"
|
||||||
|
description: str = "Split text into chunks of a specified length based on language."
|
||||||
|
documentation: str = "https://docs.langflow.org/components/text-splitters#languagerecursivetextsplitter"
|
||||||
|
|
||||||
|
def build_config(self):
|
||||||
|
options = [x.value for x in Language]
|
||||||
|
return {
|
||||||
|
"documents": {
|
||||||
|
"display_name": "Documents",
|
||||||
|
"info": "The documents to split.",
|
||||||
|
},
|
||||||
|
"separator_type": {
|
||||||
|
"display_name": "Separator Type",
|
||||||
|
"info": "The type of separator to use.",
|
||||||
|
"field_type": "str",
|
||||||
|
"options": options,
|
||||||
|
"value": "Python",
|
||||||
|
},
|
||||||
|
"separators": {
|
||||||
|
"display_name": "Separators",
|
||||||
|
"info": "The characters to split on.",
|
||||||
|
"is_list": True,
|
||||||
|
},
|
||||||
|
"chunk_size": {
|
||||||
|
"display_name": "Chunk Size",
|
||||||
|
"info": "The maximum length of each chunk.",
|
||||||
|
"field_type": "int",
|
||||||
|
"value": 1000,
|
||||||
|
},
|
||||||
|
"chunk_overlap": {
|
||||||
|
"display_name": "Chunk Overlap",
|
||||||
|
"info": "The amount of overlap between chunks.",
|
||||||
|
"field_type": "int",
|
||||||
|
"value": 200,
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
documents: list[Document],
|
||||||
|
chunk_size: Optional[int] = 1000,
|
||||||
|
chunk_overlap: Optional[int] = 200,
|
||||||
|
separator_type: Optional[str] = "Python",
|
||||||
|
) -> list[Document]:
|
||||||
|
"""
|
||||||
|
Split text into chunks of a specified length.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
separators (list[str]): The characters to split on.
|
||||||
|
chunk_size (int): The maximum length of each chunk.
|
||||||
|
chunk_overlap (int): The amount of overlap between chunks.
|
||||||
|
length_function (function): The function to use to calculate the length of the text.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: The chunks of text.
|
||||||
|
"""
|
||||||
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
|
|
||||||
|
# Make sure chunk_size and chunk_overlap are ints
|
||||||
|
if isinstance(chunk_size, str):
|
||||||
|
chunk_size = int(chunk_size)
|
||||||
|
if isinstance(chunk_overlap, str):
|
||||||
|
chunk_overlap = int(chunk_overlap)
|
||||||
|
|
||||||
|
splitter = RecursiveCharacterTextSplitter.from_language(
|
||||||
|
language=Language(separator_type),
|
||||||
|
chunk_size=chunk_size,
|
||||||
|
chunk_overlap=chunk_overlap,
|
||||||
|
)
|
||||||
|
|
||||||
|
docs = splitter.split_documents(documents)
|
||||||
|
self.repr_value = build_loader_repr_from_documents(docs)
|
||||||
|
return docs
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
from typing import Optional
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.schema import Document
|
||||||
|
|
||||||
|
|
||||||
|
class RecursiveCharacterTextSplitterComponent(CustomComponent):
|
||||||
|
display_name: str = "Recursive Character Text Splitter"
|
||||||
|
description: str = "Split text into chunks of a specified length."
|
||||||
|
documentation: str = "https://docs.langflow.org/components/text-splitters#recursivecharactertextsplitter"
|
||||||
|
|
||||||
|
def build_config(self):
|
||||||
|
return {
|
||||||
|
"documents": {
|
||||||
|
"display_name": "Documents",
|
||||||
|
"info": "The documents to split.",
|
||||||
|
},
|
||||||
|
"separators": {
|
||||||
|
"display_name": "Separators",
|
||||||
|
"info": 'The characters to split on.\nIf left empty defaults to ["\\n\\n", "\\n", " ", ""].',
|
||||||
|
"is_list": True,
|
||||||
|
},
|
||||||
|
"chunk_size": {
|
||||||
|
"display_name": "Chunk Size",
|
||||||
|
"info": "The maximum length of each chunk.",
|
||||||
|
"field_type": "int",
|
||||||
|
"value": 1000,
|
||||||
|
},
|
||||||
|
"chunk_overlap": {
|
||||||
|
"display_name": "Chunk Overlap",
|
||||||
|
"info": "The amount of overlap between chunks.",
|
||||||
|
"field_type": "int",
|
||||||
|
"value": 200,
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
documents: list[Document],
|
||||||
|
separators: Optional[list[str]] = None,
|
||||||
|
chunk_size: Optional[int] = 1000,
|
||||||
|
chunk_overlap: Optional[int] = 200,
|
||||||
|
) -> list[Document]:
|
||||||
|
"""
|
||||||
|
Split text into chunks of a specified length.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
separators (list[str]): The characters to split on.
|
||||||
|
chunk_size (int): The maximum length of each chunk.
|
||||||
|
chunk_overlap (int): The amount of overlap between chunks.
|
||||||
|
length_function (function): The function to use to calculate the length of the text.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: The chunks of text.
|
||||||
|
"""
|
||||||
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
|
|
||||||
|
if separators == "":
|
||||||
|
separators = None
|
||||||
|
elif separators:
|
||||||
|
# check if the separators list has escaped characters
|
||||||
|
# if there are escaped characters, unescape them
|
||||||
|
separators = [x.encode().decode("unicode-escape") for x in separators]
|
||||||
|
|
||||||
|
# Make sure chunk_size and chunk_overlap are ints
|
||||||
|
if isinstance(chunk_size, str):
|
||||||
|
chunk_size = int(chunk_size)
|
||||||
|
if isinstance(chunk_overlap, str):
|
||||||
|
chunk_overlap = int(chunk_overlap)
|
||||||
|
splitter = RecursiveCharacterTextSplitter(
|
||||||
|
separators=separators,
|
||||||
|
chunk_size=chunk_size,
|
||||||
|
chunk_overlap=chunk_overlap,
|
||||||
|
)
|
||||||
|
|
||||||
|
docs = splitter.split_documents(documents)
|
||||||
|
# self.repr_value = build_loader_repr_from_documents(docs)
|
||||||
|
self.repr_value = separators
|
||||||
|
return docs
|
||||||
76
src/backend/langflow/components/utilities/GetRequest.py
Normal file
76
src/backend/langflow/components/utilities/GetRequest.py
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
import requests
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class GetRequest(CustomComponent):
|
||||||
|
display_name: str = "GET Request"
|
||||||
|
description: str = "Make a GET request to the given URL."
|
||||||
|
output_types: list[str] = ["Document"]
|
||||||
|
documentation: str = "https://docs.langflow.org/components/utilities#get-request"
|
||||||
|
beta = True
|
||||||
|
field_config = {
|
||||||
|
"url": {
|
||||||
|
"display_name": "URL",
|
||||||
|
"info": "The URL to make the request to",
|
||||||
|
"is_list": True,
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"display_name": "Headers",
|
||||||
|
"field_type": "code",
|
||||||
|
"info": "The headers to send with the request.",
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
"timeout": {
|
||||||
|
"display_name": "Timeout",
|
||||||
|
"field_type": "int",
|
||||||
|
"info": "The timeout to use for the request.",
|
||||||
|
"value": 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_document(
|
||||||
|
self, session: requests.Session, url: str, headers: Optional[dict], timeout: int
|
||||||
|
) -> Document:
|
||||||
|
try:
|
||||||
|
response = session.get(url, headers=headers, timeout=int(timeout))
|
||||||
|
try:
|
||||||
|
response_json = response.json()
|
||||||
|
result = orjson_dumps(response_json, indent_2=False)
|
||||||
|
except Exception:
|
||||||
|
result = response.text
|
||||||
|
self.repr_value = result
|
||||||
|
return Document(
|
||||||
|
page_content=result,
|
||||||
|
metadata={
|
||||||
|
"source": url,
|
||||||
|
"headers": headers,
|
||||||
|
"status_code": response.status_code,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except requests.Timeout:
|
||||||
|
return Document(
|
||||||
|
page_content="Request Timed Out",
|
||||||
|
metadata={"source": url, "headers": headers, "status_code": 408},
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
return Document(
|
||||||
|
page_content=str(exc),
|
||||||
|
metadata={"source": url, "headers": headers, "status_code": 500},
|
||||||
|
)
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
url: str,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
timeout: int = 5,
|
||||||
|
) -> list[Document]:
|
||||||
|
if headers is None:
|
||||||
|
headers = {}
|
||||||
|
urls = url if isinstance(url, list) else [url]
|
||||||
|
with requests.Session() as session:
|
||||||
|
documents = [self.get_document(session, u, headers, timeout) for u in urls]
|
||||||
|
self.repr_value = documents
|
||||||
|
return documents
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
### JSON Document Builder
|
||||||
|
|
||||||
|
# Build a Document containing a JSON object using a key and another Document page content.
|
||||||
|
|
||||||
|
# **Params**
|
||||||
|
|
||||||
|
# - **Key:** The key to use for the JSON object.
|
||||||
|
# - **Document:** The Document page to use for the JSON object.
|
||||||
|
|
||||||
|
# **Output**
|
||||||
|
|
||||||
|
# - **Document:** The Document containing the JSON object.
|
||||||
|
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
|
||||||
|
|
||||||
|
class JSONDocumentBuilder(CustomComponent):
|
||||||
|
display_name: str = "JSON Document Builder"
|
||||||
|
description: str = "Build a Document containing a JSON object using a key and another Document page content."
|
||||||
|
output_types: list[str] = ["Document"]
|
||||||
|
beta = True
|
||||||
|
documentation: str = (
|
||||||
|
"https://docs.langflow.org/components/utilities#json-document-builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
field_config = {
|
||||||
|
"key": {"display_name": "Key"},
|
||||||
|
"document": {"display_name": "Document"},
|
||||||
|
}
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
key: str,
|
||||||
|
document: Document,
|
||||||
|
) -> Document:
|
||||||
|
documents = None
|
||||||
|
if isinstance(document, list):
|
||||||
|
documents = [
|
||||||
|
Document(
|
||||||
|
page_content=orjson_dumps({key: doc.page_content}, indent_2=False)
|
||||||
|
)
|
||||||
|
for doc in document
|
||||||
|
]
|
||||||
|
elif isinstance(document, Document):
|
||||||
|
documents = Document(
|
||||||
|
page_content=orjson_dumps({key: document.page_content}, indent_2=False)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise TypeError(
|
||||||
|
f"Expected Document or list of Documents, got {type(document)}"
|
||||||
|
)
|
||||||
|
self.repr_value = documents
|
||||||
|
return documents
|
||||||
81
src/backend/langflow/components/utilities/PostRequest.py
Normal file
81
src/backend/langflow/components/utilities/PostRequest.py
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
import requests
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class PostRequest(CustomComponent):
|
||||||
|
display_name: str = "POST Request"
|
||||||
|
description: str = "Make a POST request to the given URL."
|
||||||
|
output_types: list[str] = ["Document"]
|
||||||
|
documentation: str = "https://docs.langflow.org/components/utilities#post-request"
|
||||||
|
beta = True
|
||||||
|
field_config = {
|
||||||
|
"url": {"display_name": "URL", "info": "The URL to make the request to."},
|
||||||
|
"headers": {
|
||||||
|
"display_name": "Headers",
|
||||||
|
"field_type": "code",
|
||||||
|
"info": "The headers to send with the request.",
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
"document": {"display_name": "Document"},
|
||||||
|
}
|
||||||
|
|
||||||
|
def post_document(
|
||||||
|
self,
|
||||||
|
session: requests.Session,
|
||||||
|
document: Document,
|
||||||
|
url: str,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
) -> Document:
|
||||||
|
try:
|
||||||
|
response = session.post(url, headers=headers, data=document.page_content)
|
||||||
|
try:
|
||||||
|
response_json = response.json()
|
||||||
|
result = orjson_dumps(response_json, indent_2=False)
|
||||||
|
except Exception:
|
||||||
|
result = response.text
|
||||||
|
self.repr_value = result
|
||||||
|
return Document(
|
||||||
|
page_content=result,
|
||||||
|
metadata={
|
||||||
|
"source": url,
|
||||||
|
"headers": headers,
|
||||||
|
"status_code": response,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
return Document(
|
||||||
|
page_content=str(exc),
|
||||||
|
metadata={
|
||||||
|
"source": url,
|
||||||
|
"headers": headers,
|
||||||
|
"status_code": 500,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
document: Document,
|
||||||
|
url: str,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
) -> list[Document]:
|
||||||
|
if headers is None:
|
||||||
|
headers = {}
|
||||||
|
|
||||||
|
if not isinstance(document, list) and isinstance(document, Document):
|
||||||
|
documents: list[Document] = [document]
|
||||||
|
elif isinstance(document, list) and all(
|
||||||
|
isinstance(doc, Document) for doc in document
|
||||||
|
):
|
||||||
|
documents = document
|
||||||
|
else:
|
||||||
|
raise ValueError("document must be a Document or a list of Documents")
|
||||||
|
|
||||||
|
with requests.Session() as session:
|
||||||
|
documents = [
|
||||||
|
self.post_document(session, doc, url, headers) for doc in documents
|
||||||
|
]
|
||||||
|
self.repr_value = documents
|
||||||
|
return documents
|
||||||
94
src/backend/langflow/components/utilities/UpdateRequest.py
Normal file
94
src/backend/langflow/components/utilities/UpdateRequest.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
from typing import List, Optional
|
||||||
|
import requests
|
||||||
|
from langflow import CustomComponent
|
||||||
|
from langchain.schema import Document
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateRequest(CustomComponent):
|
||||||
|
display_name: str = "Update Request"
|
||||||
|
description: str = "Make a PATCH request to the given URL."
|
||||||
|
output_types: list[str] = ["Document"]
|
||||||
|
documentation: str = "https://docs.langflow.org/components/utilities#update-request"
|
||||||
|
beta = True
|
||||||
|
field_config = {
|
||||||
|
"url": {"display_name": "URL", "info": "The URL to make the request to."},
|
||||||
|
"headers": {
|
||||||
|
"display_name": "Headers",
|
||||||
|
"field_type": "code",
|
||||||
|
"info": "The headers to send with the request.",
|
||||||
|
},
|
||||||
|
"code": {"show": False},
|
||||||
|
"document": {"display_name": "Document"},
|
||||||
|
"method": {
|
||||||
|
"display_name": "Method",
|
||||||
|
"field_type": "str",
|
||||||
|
"info": "The HTTP method to use.",
|
||||||
|
"options": ["PATCH", "PUT"],
|
||||||
|
"value": "PATCH",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_document(
|
||||||
|
self,
|
||||||
|
session: requests.Session,
|
||||||
|
document: Document,
|
||||||
|
url: str,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
method: str = "PATCH",
|
||||||
|
) -> Document:
|
||||||
|
try:
|
||||||
|
if method == "PATCH":
|
||||||
|
response = session.patch(
|
||||||
|
url, headers=headers, data=document.page_content
|
||||||
|
)
|
||||||
|
elif method == "PUT":
|
||||||
|
response = session.put(url, headers=headers, data=document.page_content)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported method: {method}")
|
||||||
|
try:
|
||||||
|
response_json = response.json()
|
||||||
|
result = orjson_dumps(response_json, indent_2=False)
|
||||||
|
except Exception:
|
||||||
|
result = response.text
|
||||||
|
self.repr_value = result
|
||||||
|
return Document(
|
||||||
|
page_content=result,
|
||||||
|
metadata={
|
||||||
|
"source": url,
|
||||||
|
"headers": headers,
|
||||||
|
"status_code": response.status_code,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
return Document(
|
||||||
|
page_content=str(exc),
|
||||||
|
metadata={"source": url, "headers": headers, "status_code": 500},
|
||||||
|
)
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
method: str,
|
||||||
|
document: Document,
|
||||||
|
url: str,
|
||||||
|
headers: Optional[dict] = None,
|
||||||
|
) -> List[Document]:
|
||||||
|
if headers is None:
|
||||||
|
headers = {}
|
||||||
|
|
||||||
|
if not isinstance(document, list) and isinstance(document, Document):
|
||||||
|
documents: list[Document] = [document]
|
||||||
|
elif isinstance(document, list) and all(
|
||||||
|
isinstance(doc, Document) for doc in document
|
||||||
|
):
|
||||||
|
documents = document
|
||||||
|
else:
|
||||||
|
raise ValueError("document must be a Document or a list of Documents")
|
||||||
|
|
||||||
|
with requests.Session() as session:
|
||||||
|
documents = [
|
||||||
|
self.update_document(session, doc, url, headers, method)
|
||||||
|
for doc in documents
|
||||||
|
]
|
||||||
|
self.repr_value = documents
|
||||||
|
return documents
|
||||||
|
|
@ -169,8 +169,6 @@ prompts:
|
||||||
textsplitters:
|
textsplitters:
|
||||||
CharacterTextSplitter:
|
CharacterTextSplitter:
|
||||||
documentation: "https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter"
|
documentation: "https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/character_text_splitter"
|
||||||
RecursiveCharacterTextSplitter:
|
|
||||||
documentation: "https://python.langchain.com/docs/modules/data_connection/document_transformers/text_splitters/recursive_text_splitter"
|
|
||||||
toolkits:
|
toolkits:
|
||||||
OpenAPIToolkit:
|
OpenAPIToolkit:
|
||||||
documentation: ""
|
documentation: ""
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,20 @@ from sqlmodel import SQLModel
|
||||||
import orjson
|
import orjson
|
||||||
|
|
||||||
|
|
||||||
def orjson_dumps(v, *, default):
|
def orjson_dumps(v, *, default=None, sort_keys=False, indent_2=True):
|
||||||
|
option = orjson.OPT_SORT_KEYS if sort_keys else None
|
||||||
|
if indent_2:
|
||||||
# orjson.dumps returns bytes, to match standard json.dumps we need to decode
|
# orjson.dumps returns bytes, to match standard json.dumps we need to decode
|
||||||
return orjson.dumps(v, default=default).decode()
|
# option
|
||||||
|
# To modify how data is serialized, specify option. Each option is an integer constant in orjson.
|
||||||
|
# To specify multiple options, mask them together, e.g., option=orjson.OPT_STRICT_INTEGER | orjson.OPT_NAIVE_UTC
|
||||||
|
if option is None:
|
||||||
|
option = orjson.OPT_INDENT_2
|
||||||
|
else:
|
||||||
|
option |= orjson.OPT_INDENT_2
|
||||||
|
if default is None:
|
||||||
|
return orjson.dumps(v, option=option).decode()
|
||||||
|
return orjson.dumps(v, default=default, option=option).decode()
|
||||||
|
|
||||||
|
|
||||||
class SQLModelSerializable(SQLModel):
|
class SQLModelSerializable(SQLModel):
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ class Edge:
|
||||||
if no_matched_type:
|
if no_matched_type:
|
||||||
logger.debug(self.source_types)
|
logger.debug(self.source_types)
|
||||||
logger.debug(self.target_reqs)
|
logger.debug(self.target_reqs)
|
||||||
if no_matched_type:
|
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Edge between {self.source.vertex_type} and {self.target.vertex_type} "
|
f"Edge between {self.source.vertex_type} and {self.target.vertex_type} "
|
||||||
f"has no matched type"
|
f"has no matched type"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from fastapi import HTTPException
|
||||||
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||||
from langflow.interface.custom.component import Component
|
from langflow.interface.custom.component import Component
|
||||||
from langflow.interface.custom.directory_reader import DirectoryReader
|
from langflow.interface.custom.directory_reader import DirectoryReader
|
||||||
|
from langflow.interface.custom.utils import extract_inner_type
|
||||||
|
|
||||||
from langflow.utils import validate
|
from langflow.utils import validate
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ class CustomComponent(Component, extra=Extra.allow):
|
||||||
function_entrypoint_name = "build"
|
function_entrypoint_name = "build"
|
||||||
function: Optional[Callable] = None
|
function: Optional[Callable] = None
|
||||||
return_type_valid_list = list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())
|
return_type_valid_list = list(CUSTOM_COMPONENT_SUPPORTED_TYPES.keys())
|
||||||
repr_value: Optional[str] = ""
|
repr_value: Optional[Any] = ""
|
||||||
|
|
||||||
def __init__(self, **data):
|
def __init__(self, **data):
|
||||||
super().__init__(**data)
|
super().__init__(**data)
|
||||||
|
|
@ -122,6 +123,10 @@ class CustomComponent(Component, extra=Extra.allow):
|
||||||
return_type = build_method["return_type"]
|
return_type = build_method["return_type"]
|
||||||
if not return_type:
|
if not return_type:
|
||||||
return []
|
return []
|
||||||
|
# If list or List is in the return type, then we remove it and return the inner type
|
||||||
|
if return_type.startswith("list") or return_type.startswith("List"):
|
||||||
|
return_type = extract_inner_type(return_type)
|
||||||
|
|
||||||
# If the return type is not a Union, then we just return it as a list
|
# If the return type is not a Union, then we just return it as a list
|
||||||
if "Union" not in return_type:
|
if "Union" not in return_type:
|
||||||
return [return_type] if return_type in self.return_type_valid_list else []
|
return [return_type] if return_type in self.return_type_valid_list else []
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class DirectoryReader:
|
||||||
]
|
]
|
||||||
filtered = [menu for menu in items if menu["components"]]
|
filtered = [menu for menu in items if menu["components"]]
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'Filtered components {"with errors" if with_errors else ""}: {filtered}'
|
f'Filtered components {"with errors" if with_errors else ""}: {len(filtered)}'
|
||||||
)
|
)
|
||||||
return {"menu": filtered}
|
return {"menu": filtered}
|
||||||
|
|
||||||
|
|
|
||||||
10
src/backend/langflow/interface/custom/utils.py
Normal file
10
src/backend/langflow/interface/custom/utils.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def extract_inner_type(return_type: str) -> str:
|
||||||
|
"""
|
||||||
|
Extracts the inner type from a type hint that is a list.
|
||||||
|
"""
|
||||||
|
if match := re.match(r"list\[(.*)\]", return_type, re.IGNORECASE):
|
||||||
|
return match[1]
|
||||||
|
return return_type
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import json
|
import json
|
||||||
|
import orjson
|
||||||
from typing import Any, Callable, Dict, Sequence, Type
|
from typing import Any, Callable, Dict, Sequence, Type
|
||||||
|
|
||||||
from langchain.agents import agent as agent_module
|
from langchain.agents import agent as agent_module
|
||||||
|
|
@ -66,7 +67,7 @@ def convert_kwargs(params):
|
||||||
for key in kwargs_keys:
|
for key in kwargs_keys:
|
||||||
if isinstance(params[key], str):
|
if isinstance(params[key], str):
|
||||||
try:
|
try:
|
||||||
params[key] = json.loads(params[key])
|
params[key] = orjson.loads(params[key])
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
# if the string is not a valid json string, we will
|
# if the string is not a valid json string, we will
|
||||||
# remove the key from the params
|
# remove the key from the params
|
||||||
|
|
@ -306,7 +307,7 @@ def instantiate_documentloader(class_object: Type[BaseLoader], params: Dict):
|
||||||
metadata = params.pop("metadata", None)
|
metadata = params.pop("metadata", None)
|
||||||
if metadata and isinstance(metadata, str):
|
if metadata and isinstance(metadata, str):
|
||||||
try:
|
try:
|
||||||
metadata = json.loads(metadata)
|
metadata = orjson.loads(metadata)
|
||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The metadata you provided is not a valid JSON string."
|
"The metadata you provided is not a valid JSON string."
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import json
|
import json
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
import orjson
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
from langchain.agents import ZeroShotAgent
|
from langchain.agents import ZeroShotAgent
|
||||||
|
|
@ -95,9 +97,11 @@ def format_content(variable):
|
||||||
|
|
||||||
def try_to_load_json(content):
|
def try_to_load_json(content):
|
||||||
with contextlib.suppress(json.JSONDecodeError):
|
with contextlib.suppress(json.JSONDecodeError):
|
||||||
content = json.loads(content)
|
content = orjson.loads(content)
|
||||||
if isinstance(content, list):
|
if isinstance(content, list):
|
||||||
content = ",".join([str(item) for item in content])
|
content = ",".join([str(item) for item in content])
|
||||||
|
else:
|
||||||
|
content = orjson_dumps(content)
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
from typing import Any, Callable, Dict, Type
|
from typing import Any, Callable, Dict, Type
|
||||||
from langchain.vectorstores import (
|
from langchain.vectorstores import (
|
||||||
Pinecone,
|
Pinecone,
|
||||||
|
|
@ -12,6 +11,8 @@ from langchain.vectorstores import (
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import orjson
|
||||||
|
|
||||||
|
|
||||||
def docs_in_params(params: dict) -> bool:
|
def docs_in_params(params: dict) -> bool:
|
||||||
"""Check if params has documents OR texts and one of them is not an empty list,
|
"""Check if params has documents OR texts and one of them is not an empty list,
|
||||||
|
|
@ -92,7 +93,7 @@ def initialize_weaviate(class_object: Type[Weaviate], params: dict):
|
||||||
import weaviate # type: ignore
|
import weaviate # type: ignore
|
||||||
|
|
||||||
client_kwargs_json = params.get("client_kwargs", "{}")
|
client_kwargs_json = params.get("client_kwargs", "{}")
|
||||||
client_kwargs = json.loads(client_kwargs_json)
|
client_kwargs = orjson.loads(client_kwargs_json)
|
||||||
client_params = {
|
client_params = {
|
||||||
"url": params.get("weaviate_url"),
|
"url": params.get("weaviate_url"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from langflow.api.utils import merge_nested_dicts_with_renaming
|
||||||
from langflow.interface.agents.base import agent_creator
|
from langflow.interface.agents.base import agent_creator
|
||||||
from langflow.interface.chains.base import chain_creator
|
from langflow.interface.chains.base import chain_creator
|
||||||
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
from langflow.interface.custom.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES
|
||||||
|
from langflow.interface.custom.utils import extract_inner_type
|
||||||
from langflow.interface.document_loaders.base import documentloader_creator
|
from langflow.interface.document_loaders.base import documentloader_creator
|
||||||
from langflow.interface.embeddings.base import embedding_creator
|
from langflow.interface.embeddings.base import embedding_creator
|
||||||
from langflow.interface.importing.utils import get_function_custom
|
from langflow.interface.importing.utils import get_function_custom
|
||||||
|
|
@ -84,6 +85,8 @@ def build_langchain_types_dict(): # sourcery skip: dict-assign-update-to-union
|
||||||
|
|
||||||
|
|
||||||
def process_type(field_type: str):
|
def process_type(field_type: str):
|
||||||
|
if field_type.startswith("list") or field_type.startswith("List"):
|
||||||
|
return extract_inner_type(field_type)
|
||||||
return "prompt" if field_type == "Prompt" else field_type
|
return "prompt" if field_type == "Prompt" else field_type
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -100,6 +103,7 @@ def add_new_custom_field(
|
||||||
# if it is, update the value
|
# if it is, update the value
|
||||||
display_name = field_config.pop("display_name", field_name)
|
display_name = field_config.pop("display_name", field_name)
|
||||||
field_type = field_config.pop("field_type", field_type)
|
field_type = field_config.pop("field_type", field_type)
|
||||||
|
field_contains_list = "list" in field_type.lower()
|
||||||
field_type = process_type(field_type)
|
field_type = process_type(field_type)
|
||||||
field_value = field_config.pop("value", field_value)
|
field_value = field_config.pop("value", field_value)
|
||||||
field_advanced = field_config.pop("advanced", False)
|
field_advanced = field_config.pop("advanced", False)
|
||||||
|
|
@ -110,7 +114,9 @@ def add_new_custom_field(
|
||||||
# If options is a list, then it's a dropdown
|
# If options is a list, then it's a dropdown
|
||||||
# If options is None, then it's a list of strings
|
# If options is None, then it's a list of strings
|
||||||
is_list = isinstance(field_config.get("options"), list)
|
is_list = isinstance(field_config.get("options"), list)
|
||||||
field_config["is_list"] = is_list or field_config.get("is_list", False)
|
field_config["is_list"] = (
|
||||||
|
is_list or field_config.get("is_list", False) or field_contains_list
|
||||||
|
)
|
||||||
|
|
||||||
if "name" in field_config:
|
if "name" in field_config:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
|
|
@ -172,7 +178,7 @@ def extract_type_from_optional(field_type):
|
||||||
Returns:
|
Returns:
|
||||||
str: The extracted type, or an empty string if no type was found.
|
str: The extracted type, or an empty string if no type was found.
|
||||||
"""
|
"""
|
||||||
match = re.search(r"\[(.*?)\]", field_type)
|
match = re.search(r"\[(.*?)\]$", field_type)
|
||||||
return match[1] if match else None
|
return match[1] if match else None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -190,17 +196,16 @@ def build_frontend_node(custom_component: CustomComponent):
|
||||||
|
|
||||||
def update_attributes(frontend_node, template_config):
|
def update_attributes(frontend_node, template_config):
|
||||||
"""Update the display name and description of a frontend node"""
|
"""Update the display name and description of a frontend node"""
|
||||||
if "display_name" in template_config:
|
attributes = [
|
||||||
frontend_node["display_name"] = template_config["display_name"]
|
"display_name",
|
||||||
|
"description",
|
||||||
if "description" in template_config:
|
"beta",
|
||||||
frontend_node["description"] = template_config["description"]
|
"documentation",
|
||||||
|
"output_types",
|
||||||
if "beta" in template_config:
|
]
|
||||||
frontend_node["beta"] = template_config["beta"]
|
for attribute in attributes:
|
||||||
|
if attribute in template_config:
|
||||||
if "documentation" in template_config:
|
frontend_node[attribute] = template_config[attribute]
|
||||||
frontend_node["documentation"] = template_config["documentation"]
|
|
||||||
|
|
||||||
|
|
||||||
def build_field_config(custom_component: CustomComponent):
|
def build_field_config(custom_component: CustomComponent):
|
||||||
|
|
@ -338,7 +343,9 @@ def build_valid_menu(valid_components):
|
||||||
valid_menu[menu_name] = {}
|
valid_menu[menu_name] = {}
|
||||||
|
|
||||||
for component in menu_item["components"]:
|
for component in menu_item["components"]:
|
||||||
logger.debug(f"Building component: {component}")
|
logger.debug(
|
||||||
|
f"Building component: {component.get('name'), component.get('output_types')}"
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
component_name = component["name"]
|
component_name = component["name"]
|
||||||
component_code = component["code"]
|
component_code = component["code"]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from langchain.schema import AgentAction
|
from langchain.schema import AgentAction
|
||||||
import json
|
|
||||||
from langflow.interface.run import (
|
from langflow.interface.run import (
|
||||||
build_sorted_vertices_with_caching,
|
build_sorted_vertices_with_caching,
|
||||||
get_memory_key,
|
get_memory_key,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import json
|
import json
|
||||||
|
import orjson
|
||||||
import os
|
import os
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -130,7 +131,7 @@ class Settings(BaseSettings):
|
||||||
if isinstance(getattr(self, key), list):
|
if isinstance(getattr(self, key), list):
|
||||||
# value might be a '[something]' string
|
# value might be a '[something]' string
|
||||||
with contextlib.suppress(json.decoder.JSONDecodeError):
|
with contextlib.suppress(json.decoder.JSONDecodeError):
|
||||||
value = json.loads(str(value))
|
value = orjson.loads(str(value))
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
for item in value:
|
for item in value:
|
||||||
if isinstance(item, Path):
|
if isinstance(item, Path):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import json
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
|
||||||
from langflow.template.field.base import TemplateField
|
from langflow.template.field.base import TemplateField
|
||||||
from langflow.template.frontend_node.base import FrontendNode
|
from langflow.template.frontend_node.base import FrontendNode
|
||||||
|
|
@ -89,7 +89,7 @@ class LLMFrontendNode(FrontendNode):
|
||||||
if field.name == "config":
|
if field.name == "config":
|
||||||
field.show = True
|
field.show = True
|
||||||
field.advanced = True
|
field.advanced = True
|
||||||
field.value = json.dumps(CTRANSFORMERS_DEFAULT_CONFIG, indent=2)
|
field.value = orjson_dumps(CTRANSFORMERS_DEFAULT_CONFIG, indent_2=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_field(field: TemplateField, name: Optional[str] = None) -> None:
|
def format_field(field: TemplateField, name: Optional[str] = None) -> None:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import ast
|
import ast
|
||||||
import json
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
|
||||||
from langflow.template.field.base import TemplateField
|
from langflow.template.field.base import TemplateField
|
||||||
from langflow.template.frontend_node.base import FrontendNode
|
from langflow.template.frontend_node.base import FrontendNode
|
||||||
|
|
@ -22,4 +22,4 @@ class UtilitiesFrontendNode(FrontendNode):
|
||||||
|
|
||||||
if isinstance(field.value, dict):
|
if isinstance(field.value, dict):
|
||||||
field.field_type = "code"
|
field.field_type = "code"
|
||||||
field.value = json.dumps(field.value, indent=4)
|
field.value = orjson_dumps(field.value)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import re
|
||||||
import inspect
|
import inspect
|
||||||
import importlib
|
import importlib
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Optional, Dict, Any, Union
|
from typing import List, Optional, Dict, Any, Union
|
||||||
|
|
||||||
from docstring_parser import parse # type: ignore
|
from docstring_parser import parse # type: ignore
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@ from langflow.template.frontend_node.constants import FORCE_SHOW_FIELDS
|
||||||
from langflow.utils import constants
|
from langflow.utils import constants
|
||||||
from langflow.utils.logger import logger
|
from langflow.utils.logger import logger
|
||||||
from multiprocess import cpu_count # type: ignore
|
from multiprocess import cpu_count # type: ignore
|
||||||
|
from langchain.schema import Document
|
||||||
|
|
||||||
|
|
||||||
def build_template_from_function(
|
def build_template_from_function(
|
||||||
|
|
@ -462,3 +463,12 @@ def get_number_of_workers(workers=None):
|
||||||
workers = (cpu_count() * 2) + 1
|
workers = (cpu_count() * 2) + 1
|
||||||
logger.debug(f"Number of workers: {workers}")
|
logger.debug(f"Number of workers: {workers}")
|
||||||
return workers
|
return workers
|
||||||
|
|
||||||
|
|
||||||
|
def build_loader_repr_from_documents(documents: List[Document]) -> str:
|
||||||
|
if documents:
|
||||||
|
avg_length = sum(len(doc.page_content) for doc in documents) / len(documents)
|
||||||
|
return f"""{len(documents)} documents
|
||||||
|
\nAvg. Document Length (characters): {int(avg_length)}
|
||||||
|
Documents: {documents[:3]}..."""
|
||||||
|
return "0 documents"
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,16 @@ import ErrorAlert from "./alerts/error";
|
||||||
import NoticeAlert from "./alerts/notice";
|
import NoticeAlert from "./alerts/notice";
|
||||||
import SuccessAlert from "./alerts/success";
|
import SuccessAlert from "./alerts/success";
|
||||||
import CrashErrorComponent from "./components/CrashErrorComponent";
|
import CrashErrorComponent from "./components/CrashErrorComponent";
|
||||||
import Header from "./components/headerComponent";
|
import FetchErrorComponent from "./components/fetchErrorComponent";
|
||||||
|
import LoadingComponent from "./components/loadingComponent";
|
||||||
|
import {
|
||||||
|
FETCH_ERROR_DESCRIPION,
|
||||||
|
FETCH_ERROR_MESSAGE,
|
||||||
|
} from "./constants/constants";
|
||||||
import { alertContext } from "./contexts/alertContext";
|
import { alertContext } from "./contexts/alertContext";
|
||||||
import { locationContext } from "./contexts/locationContext";
|
import { locationContext } from "./contexts/locationContext";
|
||||||
import { TabsContext } from "./contexts/tabsContext";
|
import { TabsContext } from "./contexts/tabsContext";
|
||||||
|
import { typesContext } from "./contexts/typesContext";
|
||||||
import Router from "./routes";
|
import Router from "./routes";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
|
@ -25,6 +31,7 @@ export default function App() {
|
||||||
setIsStackedOpen(true);
|
setIsStackedOpen(true);
|
||||||
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
|
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
|
||||||
const { hardReset } = useContext(TabsContext);
|
const { hardReset } = useContext(TabsContext);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
errorData,
|
errorData,
|
||||||
errorOpen,
|
errorOpen,
|
||||||
|
|
@ -35,7 +42,9 @@ export default function App() {
|
||||||
successData,
|
successData,
|
||||||
successOpen,
|
successOpen,
|
||||||
setSuccessOpen,
|
setSuccessOpen,
|
||||||
|
loading,
|
||||||
} = useContext(alertContext);
|
} = useContext(alertContext);
|
||||||
|
const { fetchError } = useContext(typesContext);
|
||||||
|
|
||||||
// Initialize state variable for the list of alerts
|
// Initialize state variable for the list of alerts
|
||||||
const [alertsList, setAlertsList] = useState<
|
const [alertsList, setAlertsList] = useState<
|
||||||
|
|
@ -133,8 +142,22 @@ export default function App() {
|
||||||
}}
|
}}
|
||||||
FallbackComponent={CrashErrorComponent}
|
FallbackComponent={CrashErrorComponent}
|
||||||
>
|
>
|
||||||
<Header />
|
{loading ? (
|
||||||
|
<div className="loading-page-panel">
|
||||||
|
{fetchError ? (
|
||||||
|
<FetchErrorComponent
|
||||||
|
description={FETCH_ERROR_DESCRIPION}
|
||||||
|
message={FETCH_ERROR_MESSAGE}
|
||||||
|
></FetchErrorComponent>
|
||||||
|
) : (
|
||||||
|
<LoadingComponent remSize={50} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<Router />
|
<Router />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="app-div" style={{ zIndex: 999 }}>
|
<div className="app-div" style={{ zIndex: 999 }}>
|
||||||
|
|
|
||||||
|
|
@ -54,21 +54,9 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setName(value);
|
setName(value);
|
||||||
setCurrentName(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const [currentName, setCurrentName] = useState(name);
|
|
||||||
|
|
||||||
const [currentDescription, setCurrentDescription] = useState(description);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCurrentName(name);
|
|
||||||
setCurrentDescription(description);
|
|
||||||
}, [name, description]);
|
|
||||||
|
|
||||||
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
flows.find((f) => f.id === tabId).description = event.target.value;
|
|
||||||
setCurrentDescription(flows.find((f) => f.id === tabId).description);
|
|
||||||
setDescription(event.target.value);
|
setDescription(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -89,7 +77,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
onChange={handleNameChange}
|
onChange={handleNameChange}
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
value={currentName ?? ""}
|
value={name ?? ""}
|
||||||
placeholder="File name"
|
placeholder="File name"
|
||||||
id="name"
|
id="name"
|
||||||
maxLength={maxLength}
|
maxLength={maxLength}
|
||||||
|
|
@ -104,7 +92,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
||||||
name="description"
|
name="description"
|
||||||
id="description"
|
id="description"
|
||||||
onChange={handleDescriptionChange}
|
onChange={handleDescriptionChange}
|
||||||
value={currentDescription}
|
value={description}
|
||||||
placeholder="Flow description"
|
placeholder="Flow description"
|
||||||
className="mt-2 max-h-[100px] font-normal"
|
className="mt-2 max-h-[100px] font-normal"
|
||||||
rows={3}
|
rows={3}
|
||||||
|
|
|
||||||
16
src/frontend/src/components/fetchErrorComponent/index.tsx
Normal file
16
src/frontend/src/components/fetchErrorComponent/index.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { fetchErrorComponentType } from "../../types/components";
|
||||||
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
||||||
|
export default function FetchErrorComponent({
|
||||||
|
message,
|
||||||
|
description,
|
||||||
|
}: fetchErrorComponentType) {
|
||||||
|
return (
|
||||||
|
<div role="status" className="m-auto flex flex-col items-center">
|
||||||
|
<IconComponent className={`h-16 w-16`} name="Unplug"></IconComponent>
|
||||||
|
<br></br>
|
||||||
|
<span className="text-lg text-almost-medium-blue">{message}</span>
|
||||||
|
<span className="text-lg text-almost-medium-blue">{description}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -7,5 +7,11 @@ export default function IconComponent({
|
||||||
iconColor,
|
iconColor,
|
||||||
}: IconComponentProps): JSX.Element {
|
}: IconComponentProps): JSX.Element {
|
||||||
const TargetIcon = nodeIconsLucide[name] ?? nodeIconsLucide["unknown"];
|
const TargetIcon = nodeIconsLucide[name] ?? nodeIconsLucide["unknown"];
|
||||||
return <TargetIcon className={className} style={{ color: iconColor }} />;
|
return (
|
||||||
|
<TargetIcon
|
||||||
|
className={className}
|
||||||
|
style={{ color: iconColor }}
|
||||||
|
stroke-width={1.5}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ export default function InputListComponent({
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
|
// @TODO Recursive Character Text Splitter - the value might be in string format, whereas the InputListComponent specifically requires an array format. To ensure smooth operation and prevent potential errors, it's crucial that we handle the conversion from a string to an array with the string as its element.
|
||||||
|
typeof value === 'string' ? value = [value] : value = value;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
type LoadingComponentProps = {
|
import { LoadingComponentProps } from "../../types/components";
|
||||||
remSize: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function LoadingComponent({ remSize }: LoadingComponentProps) {
|
export default function LoadingComponent({ remSize }: LoadingComponentProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -509,3 +509,9 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [
|
||||||
"/api/v1/custom_component",
|
"/api/v1/custom_component",
|
||||||
"/api/v1/validate/prompt",
|
"/api/v1/validate/prompt",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const skipNodeUpdate = ["CustomComponent"];
|
||||||
|
|
||||||
|
export const FETCH_ERROR_MESSAGE = "Couldn't establish a connection.";
|
||||||
|
export const FETCH_ERROR_DESCRIPION =
|
||||||
|
"Check if everything is working properly and try again.";
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,16 @@ type alertContextType = {
|
||||||
pushNotificationList: (Object: AlertItemType) => void;
|
pushNotificationList: (Object: AlertItemType) => void;
|
||||||
clearNotificationList: () => void;
|
clearNotificationList: () => void;
|
||||||
removeFromNotificationList: (index: string) => void;
|
removeFromNotificationList: (index: string) => void;
|
||||||
|
loading: boolean;
|
||||||
|
setLoading: (newState: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
//initial values to alertContextType
|
//initial values to alertContextType
|
||||||
const initialValue: alertContextType = {
|
const initialValue: alertContextType = {
|
||||||
errorData: { title: "", list: [] },
|
errorData: { title: "", list: [] },
|
||||||
setErrorData: () => {},
|
setErrorData: () => {},
|
||||||
|
loading: true,
|
||||||
|
setLoading: () => {},
|
||||||
errorOpen: false,
|
errorOpen: false,
|
||||||
setErrorOpen: () => {},
|
setErrorOpen: () => {},
|
||||||
noticeData: { title: "", link: "" },
|
noticeData: { title: "", link: "" },
|
||||||
|
|
@ -55,6 +59,7 @@ export function AlertProvider({ children }: { children: ReactNode }) {
|
||||||
list?: Array<string>;
|
list?: Array<string>;
|
||||||
}>({ title: "", list: [] });
|
}>({ title: "", list: [] });
|
||||||
const [errorOpen, setErrorOpen] = useState(false);
|
const [errorOpen, setErrorOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
const [noticeData, setNoticeDataState] = useState<{
|
const [noticeData, setNoticeDataState] = useState<{
|
||||||
title: string;
|
title: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
|
|
@ -141,6 +146,8 @@ export function AlertProvider({ children }: { children: ReactNode }) {
|
||||||
removeFromNotificationList,
|
removeFromNotificationList,
|
||||||
clearNotificationList,
|
clearNotificationList,
|
||||||
notificationList,
|
notificationList,
|
||||||
|
loading,
|
||||||
|
setLoading,
|
||||||
pushNotificationList,
|
pushNotificationList,
|
||||||
setNotificationCenter,
|
setNotificationCenter,
|
||||||
notificationCenter,
|
notificationCenter,
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,17 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<DarkProvider>
|
<DarkProvider>
|
||||||
|
<AlertProvider>
|
||||||
<TypesProvider>
|
<TypesProvider>
|
||||||
<LocationProvider>
|
<LocationProvider>
|
||||||
<AlertProvider>
|
|
||||||
<SSEProvider>
|
<SSEProvider>
|
||||||
<TabsProvider>
|
<TabsProvider>
|
||||||
<UndoRedoProvider>{children}</UndoRedoProvider>
|
<UndoRedoProvider>{children}</UndoRedoProvider>
|
||||||
</TabsProvider>
|
</TabsProvider>
|
||||||
</SSEProvider>
|
</SSEProvider>
|
||||||
</AlertProvider>
|
|
||||||
</LocationProvider>
|
</LocationProvider>
|
||||||
</TypesProvider>
|
</TypesProvider>
|
||||||
|
</AlertProvider>
|
||||||
</DarkProvider>
|
</DarkProvider>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
} from "react";
|
} from "react";
|
||||||
import { addEdge } from "reactflow";
|
import { addEdge } from "reactflow";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
|
import { skipNodeUpdate } from "../constants/constants";
|
||||||
import {
|
import {
|
||||||
deleteFlowFromDatabase,
|
deleteFlowFromDatabase,
|
||||||
downloadFlowsFromDatabase,
|
downloadFlowsFromDatabase,
|
||||||
|
|
@ -163,6 +164,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
function processFlowNodes(flow) {
|
function processFlowNodes(flow) {
|
||||||
if (!flow.data || !flow.data.nodes) return;
|
if (!flow.data || !flow.data.nodes) return;
|
||||||
flow.data.nodes.forEach((node: NodeType) => {
|
flow.data.nodes.forEach((node: NodeType) => {
|
||||||
|
if (skipNodeUpdate.includes(node.data.type)) return;
|
||||||
const template = templates[node.data.type];
|
const template = templates[node.data.type];
|
||||||
if (!template) {
|
if (!template) {
|
||||||
setErrorData({ title: `Unknown node type: ${node.data.type}` });
|
setErrorData({ title: `Unknown node type: ${node.data.type}` });
|
||||||
|
|
@ -506,6 +508,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
|
|
||||||
const updateNodes = (nodes, edges) => {
|
const updateNodes = (nodes, edges) => {
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
|
if (skipNodeUpdate.includes(node.data.type)) return;
|
||||||
const template = templates[node.data.type];
|
const template = templates[node.data.type];
|
||||||
if (!template) {
|
if (!template) {
|
||||||
setErrorData({ title: `Unknown node type: ${node.data.type}` });
|
setErrorData({ title: `Unknown node type: ${node.data.type}` });
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
import { createContext, ReactNode, useEffect, useState } from "react";
|
import {
|
||||||
|
createContext,
|
||||||
|
ReactNode,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { Node } from "reactflow";
|
import { Node } from "reactflow";
|
||||||
import { getAll } from "../controllers/API";
|
import { getAll, getHealth } from "../controllers/API";
|
||||||
import { APIKindType } from "../types/api";
|
import { APIKindType } from "../types/api";
|
||||||
import { typesContextType } from "../types/typesContext";
|
import { typesContextType } from "../types/typesContext";
|
||||||
|
import { alertContext } from "./alertContext";
|
||||||
|
|
||||||
//context to share types adn functions from nodes to flow
|
//context to share types adn functions from nodes to flow
|
||||||
|
|
||||||
|
|
@ -16,6 +23,8 @@ const initialValue: typesContextType = {
|
||||||
setTemplates: () => {},
|
setTemplates: () => {},
|
||||||
data: {},
|
data: {},
|
||||||
setData: () => {},
|
setData: () => {},
|
||||||
|
setFetchError: () => {},
|
||||||
|
fetchError: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const typesContext = createContext<typesContextType>(initialValue);
|
export const typesContext = createContext<typesContextType>(initialValue);
|
||||||
|
|
@ -25,13 +34,10 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
||||||
const [templates, setTemplates] = useState({});
|
const [templates, setTemplates] = useState({});
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
|
const [fetchError, setFetchError] = useState(false);
|
||||||
|
const { setLoading } = useContext(alertContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let delay = 1000; // Start delay of 1 second
|
|
||||||
let intervalId = null;
|
|
||||||
let retryCount = 0; // Count of retry attempts
|
|
||||||
const maxRetryCount = 5; // Max retry attempts
|
|
||||||
|
|
||||||
// We will keep a flag to handle the case where the component is unmounted before the API call resolves.
|
// We will keep a flag to handle the case where the component is unmounted before the API call resolves.
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
|
|
||||||
|
|
@ -39,7 +45,8 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
try {
|
try {
|
||||||
const result = await getAll();
|
const result = await getAll();
|
||||||
// Make sure to only update the state if the component is still mounted.
|
// Make sure to only update the state if the component is still mounted.
|
||||||
if (isMounted) {
|
if (isMounted && result?.status === 200) {
|
||||||
|
setLoading(false);
|
||||||
setData(result.data);
|
setData(result.data);
|
||||||
setTemplates(
|
setTemplates(
|
||||||
Object.keys(result.data).reduce((acc, curr) => {
|
Object.keys(result.data).reduce((acc, curr) => {
|
||||||
|
|
@ -68,22 +75,15 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
}, {})
|
}, {})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Clear the interval if successful.
|
|
||||||
clearInterval(intervalId);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("An error has occurred while fetching types.");
|
console.error("An error has occurred while fetching types.");
|
||||||
|
await getHealth().catch((e) => {
|
||||||
|
setFetchError(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the initial interval.
|
getTypes();
|
||||||
intervalId = setInterval(getTypes, delay);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change.
|
|
||||||
clearInterval(intervalId);
|
|
||||||
// Indicate that the component has been unmounted.
|
|
||||||
isMounted = false;
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function deleteNode(idx: string) {
|
function deleteNode(idx: string) {
|
||||||
|
|
@ -108,6 +108,8 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
||||||
templates,
|
templates,
|
||||||
data,
|
data,
|
||||||
setData,
|
setData,
|
||||||
|
fetchError,
|
||||||
|
setFetchError,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { CardComponent } from "../../components/cardComponent";
|
import { CardComponent } from "../../components/cardComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
|
import Header from "../../components/headerComponent";
|
||||||
import { getExamples } from "../../controllers/API";
|
import { getExamples } from "../../controllers/API";
|
||||||
import { FlowType } from "../../types/flow";
|
import { FlowType } from "../../types/flow";
|
||||||
export default function CommunityPage() {
|
export default function CommunityPage() {
|
||||||
|
|
@ -42,6 +43,9 @@ export default function CommunityPage() {
|
||||||
handleExamples();
|
handleExamples();
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
|
||||||
<div className="community-page-arrangement">
|
<div className="community-page-arrangement">
|
||||||
<div className="community-page-nav-arrangement">
|
<div className="community-page-nav-arrangement">
|
||||||
<span className="community-page-nav-title">
|
<span className="community-page-nav-title">
|
||||||
|
|
@ -98,5 +102,6 @@ export default function CommunityPage() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,13 @@ const nodeTypes = {
|
||||||
genericNode: GenericNode,
|
genericNode: GenericNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Page({ flow }: { flow: FlowType }) {
|
export default function Page({
|
||||||
|
flow,
|
||||||
|
view,
|
||||||
|
}: {
|
||||||
|
flow: FlowType;
|
||||||
|
view?: boolean;
|
||||||
|
}) {
|
||||||
let {
|
let {
|
||||||
updateFlow,
|
updateFlow,
|
||||||
uploadFlow,
|
uploadFlow,
|
||||||
|
|
@ -357,7 +363,7 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
<ExtraSidebar />
|
{!view && <ExtraSidebar />}
|
||||||
{/* Main area */}
|
{/* Main area */}
|
||||||
<main className="flex flex-1">
|
<main className="flex flex-1">
|
||||||
{/* Primary column */}
|
{/* Primary column */}
|
||||||
|
|
@ -399,14 +405,21 @@ export default function Page({ flow }: { flow: FlowType }) {
|
||||||
className="theme-attribution"
|
className="theme-attribution"
|
||||||
minZoom={0.01}
|
minZoom={0.01}
|
||||||
maxZoom={8}
|
maxZoom={8}
|
||||||
|
zoomOnScroll={!view}
|
||||||
|
zoomOnPinch={!view}
|
||||||
|
panOnDrag={!view}
|
||||||
>
|
>
|
||||||
<Background className="" />
|
<Background className="" />
|
||||||
|
{!view && (
|
||||||
<Controls
|
<Controls
|
||||||
className="bg-muted fill-foreground stroke-foreground text-primary
|
className="bg-muted fill-foreground stroke-foreground text-primary
|
||||||
[&>button]:border-b-border hover:[&>button]:bg-border"
|
[&>button]:border-b-border hover:[&>button]:bg-border"
|
||||||
></Controls>
|
></Controls>
|
||||||
|
)}
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
{!view && (
|
||||||
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
|
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
import Header from "../../components/headerComponent";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
import { getVersion } from "../../controllers/API";
|
import { getVersion } from "../../controllers/API";
|
||||||
import Page from "./components/PageComponent";
|
import Page from "./components/PageComponent";
|
||||||
|
|
@ -22,6 +23,8 @@ export default function FlowPage() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
<div className="flow-page-positioning">
|
<div className="flow-page-positioning">
|
||||||
{flows.length > 0 &&
|
{flows.length > 0 &&
|
||||||
tabId !== "" &&
|
tabId !== "" &&
|
||||||
|
|
@ -37,5 +40,6 @@ export default function FlowPage() {
|
||||||
<div className={version ? "mt-2" : "mt-1"}>Created by Logspace</div>
|
<div className={version ? "mt-2" : "mt-1"}>Created by Logspace</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useContext, useEffect } from "react";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { CardComponent } from "../../components/cardComponent";
|
import { CardComponent } from "../../components/cardComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
|
import Header from "../../components/headerComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||||
import { TabsContext } from "../../contexts/tabsContext";
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
|
@ -17,6 +18,8 @@ export default function HomePage() {
|
||||||
|
|
||||||
// Personal flows display
|
// Personal flows display
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
<div className="main-page-panel">
|
<div className="main-page-panel">
|
||||||
<div className="main-page-nav-arrangement">
|
<div className="main-page-nav-arrangement">
|
||||||
<span className="main-page-nav-title">
|
<span className="main-page-nav-title">
|
||||||
|
|
@ -86,5 +89,6 @@ export default function HomePage() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
src/frontend/src/pages/ViewPage/index.tsx
Normal file
33
src/frontend/src/pages/ViewPage/index.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { TabsContext } from "../../contexts/tabsContext";
|
||||||
|
import { getVersion } from "../../controllers/API";
|
||||||
|
import Page from "../FlowPage/components/PageComponent";
|
||||||
|
|
||||||
|
export default function ViewPage() {
|
||||||
|
const { flows, tabId, setTabId } = useContext(TabsContext);
|
||||||
|
const { id } = useParams();
|
||||||
|
|
||||||
|
// Set flow tab id
|
||||||
|
useEffect(() => {
|
||||||
|
setTabId(id);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
// Initialize state variable for the version
|
||||||
|
const [version, setVersion] = useState("");
|
||||||
|
useEffect(() => {
|
||||||
|
getVersion().then((data) => {
|
||||||
|
setVersion(data.version);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flow-page-positioning">
|
||||||
|
{flows.length > 0 &&
|
||||||
|
tabId !== "" &&
|
||||||
|
flows.findIndex((flow) => flow.id === tabId) !== -1 && (
|
||||||
|
<Page view flow={flows.find((flow) => flow.id === tabId)} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import { Route, Routes } from "react-router-dom";
|
||||||
import CommunityPage from "./pages/CommunityPage";
|
import CommunityPage from "./pages/CommunityPage";
|
||||||
import FlowPage from "./pages/FlowPage";
|
import FlowPage from "./pages/FlowPage";
|
||||||
import HomePage from "./pages/MainPage";
|
import HomePage from "./pages/MainPage";
|
||||||
|
import ViewPage from "./pages/ViewPage";
|
||||||
|
|
||||||
const Router = () => {
|
const Router = () => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -10,6 +11,7 @@ const Router = () => {
|
||||||
<Route path="/community" element={<CommunityPage />} />
|
<Route path="/community" element={<CommunityPage />} />
|
||||||
<Route path="/flow/:id/">
|
<Route path="/flow/:id/">
|
||||||
<Route path="" element={<FlowPage />} />
|
<Route path="" element={<FlowPage />} />
|
||||||
|
<Route path="view" element={<ViewPage />} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="*" element={<HomePage />} />
|
<Route path="*" element={<HomePage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,10 @@
|
||||||
@apply flex w-full;
|
@apply flex w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading-page-panel {
|
||||||
|
@apply h-full w-full flex justify-center items-center bg-muted;
|
||||||
|
}
|
||||||
|
|
||||||
.main-page-panel {
|
.main-page-panel {
|
||||||
@apply flex-max-width h-full flex-col overflow-auto bg-muted px-16;
|
@apply flex-max-width h-full flex-col overflow-auto bg-muted px-16;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,3 +171,11 @@ export type IconComponentProps = {
|
||||||
export interface languageMap {
|
export interface languageMap {
|
||||||
[key: string]: string | undefined;
|
[key: string]: string | undefined;
|
||||||
}
|
}
|
||||||
|
export type fetchErrorComponentType = {
|
||||||
|
message: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LoadingComponentProps = {
|
||||||
|
remSize: number;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,6 @@ export type typesContextType = {
|
||||||
setTemplates: (newState: {}) => void;
|
setTemplates: (newState: {}) => void;
|
||||||
data: typeof data;
|
data: typeof data;
|
||||||
setData: (newState: {}) => void;
|
setData: (newState: {}) => void;
|
||||||
|
fetchError: boolean;
|
||||||
|
setFetchError: (newState: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import {
|
||||||
TerminalSquare,
|
TerminalSquare,
|
||||||
Trash2,
|
Trash2,
|
||||||
Undo,
|
Undo,
|
||||||
|
Unplug,
|
||||||
Upload,
|
Upload,
|
||||||
Users2,
|
Users2,
|
||||||
Variable,
|
Variable,
|
||||||
|
|
@ -275,4 +276,5 @@ export const nodeIconsLucide = {
|
||||||
Upload,
|
Upload,
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
|
Unplug,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
import orjson
|
||||||
from langflow.graph import Graph
|
from langflow.graph import Graph
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -63,9 +65,9 @@ def test_cache_size_limit(basic_data_graph):
|
||||||
nodes = modified_data_graph["nodes"]
|
nodes = modified_data_graph["nodes"]
|
||||||
node_id = nodes[0]["id"]
|
node_id = nodes[0]["id"]
|
||||||
# Now we replace all instances ode node_id with a new id in the json
|
# Now we replace all instances ode node_id with a new id in the json
|
||||||
json_string = json.dumps(modified_data_graph)
|
json_string = orjson_dumps(modified_data_graph)
|
||||||
modified_json_string = json_string.replace(node_id, f"{node_id}_{i}")
|
modified_json_string = json_string.replace(node_id, f"{node_id}_{i}")
|
||||||
modified_data_graph_new_id = json.loads(modified_json_string)
|
modified_data_graph_new_id = orjson.loads(modified_json_string)
|
||||||
build_langchain_object_with_caching(modified_data_graph_new_id)
|
build_langchain_object_with_caching(modified_data_graph_new_id)
|
||||||
|
|
||||||
assert len(build_langchain_object_with_caching.cache) == 10
|
assert len(build_langchain_object_with_caching.cache) == 10
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import json
|
from fastapi.encoders import jsonable_encoder
|
||||||
|
from langflow.database.models.base import orjson_dumps
|
||||||
|
import orjson
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from fastapi.encoders import jsonable_encoder
|
|
||||||
|
|
||||||
from langflow.api.v1.schemas import FlowListCreate
|
from langflow.api.v1.schemas import FlowListCreate
|
||||||
from langflow.database.models.flow import Flow, FlowCreate, FlowUpdate
|
from langflow.database.models.flow import Flow, FlowCreate, FlowUpdate
|
||||||
|
|
@ -23,7 +24,7 @@ def json_style():
|
||||||
# color: str = Field(index=True)
|
# color: str = Field(index=True)
|
||||||
# emoji: str = Field(index=False)
|
# emoji: str = Field(index=False)
|
||||||
# flow_id: UUID = Field(default=None, foreign_key="flow.id")
|
# flow_id: UUID = Field(default=None, foreign_key="flow.id")
|
||||||
return json.dumps(
|
return orjson_dumps(
|
||||||
{
|
{
|
||||||
"color": "red",
|
"color": "red",
|
||||||
"emoji": "👍",
|
"emoji": "👍",
|
||||||
|
|
@ -32,7 +33,7 @@ def json_style():
|
||||||
|
|
||||||
|
|
||||||
def test_create_flow(client: TestClient, json_flow: str):
|
def test_create_flow(client: TestClient, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
response = client.post("api/v1/flows/", json=flow.dict())
|
response = client.post("api/v1/flows/", json=flow.dict())
|
||||||
|
|
@ -48,7 +49,7 @@ def test_create_flow(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_read_flows(client: TestClient, json_flow: str):
|
def test_read_flows(client: TestClient, json_flow: str):
|
||||||
flow_data = json.loads(json_flow)
|
flow_data = orjson.loads(json_flow)
|
||||||
data = flow_data["data"]
|
data = flow_data["data"]
|
||||||
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
response = client.post("api/v1/flows/", json=flow.dict())
|
response = client.post("api/v1/flows/", json=flow.dict())
|
||||||
|
|
@ -89,7 +90,7 @@ def test_read_flows(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_read_flow(client: TestClient, json_flow: str):
|
def test_read_flow(client: TestClient, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
response = client.post("api/v1/flows/", json=flow.dict())
|
response = client.post("api/v1/flows/", json=flow.dict())
|
||||||
|
|
@ -115,7 +116,7 @@ def test_read_flow(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_update_flow(client: TestClient, json_flow: str):
|
def test_update_flow(client: TestClient, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
|
|
||||||
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
|
|
@ -136,7 +137,7 @@ def test_update_flow(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_delete_flow(client: TestClient, json_flow: str):
|
def test_delete_flow(client: TestClient, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
flow = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
response = client.post("api/v1/flows/", json=flow.dict())
|
response = client.post("api/v1/flows/", json=flow.dict())
|
||||||
|
|
@ -147,7 +148,7 @@ def test_delete_flow(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_create_flows(client: TestClient, session: Session, json_flow: str):
|
def test_create_flows(client: TestClient, session: Session, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
# Create test data
|
# Create test data
|
||||||
flow_list = FlowListCreate(
|
flow_list = FlowListCreate(
|
||||||
|
|
@ -172,7 +173,7 @@ def test_create_flows(client: TestClient, session: Session, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_upload_file(client: TestClient, session: Session, json_flow: str):
|
def test_upload_file(client: TestClient, session: Session, json_flow: str):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
# Create test data
|
# Create test data
|
||||||
flow_list = FlowListCreate(
|
flow_list = FlowListCreate(
|
||||||
|
|
@ -181,7 +182,7 @@ def test_upload_file(client: TestClient, session: Session, json_flow: str):
|
||||||
FlowCreate(name="Flow 2", description="description", data=data),
|
FlowCreate(name="Flow 2", description="description", data=data),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
file_contents = json.dumps(flow_list.dict())
|
file_contents = orjson_dumps(flow_list.dict())
|
||||||
response = client.post(
|
response = client.post(
|
||||||
"api/v1/flows/upload/",
|
"api/v1/flows/upload/",
|
||||||
files={"file": ("examples.json", file_contents, "application/json")},
|
files={"file": ("examples.json", file_contents, "application/json")},
|
||||||
|
|
@ -200,7 +201,7 @@ def test_upload_file(client: TestClient, session: Session, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_download_file(client: TestClient, session: Session, json_flow):
|
def test_download_file(client: TestClient, session: Session, json_flow):
|
||||||
flow = json.loads(json_flow)
|
flow = orjson.loads(json_flow)
|
||||||
data = flow["data"]
|
data = flow["data"]
|
||||||
# Create test data
|
# Create test data
|
||||||
flow_list = FlowListCreate(
|
flow_list = FlowListCreate(
|
||||||
|
|
@ -241,7 +242,7 @@ def test_get_nonexistent_flow(client: TestClient):
|
||||||
|
|
||||||
|
|
||||||
def test_update_flow_idempotency(client: TestClient, json_flow: str):
|
def test_update_flow_idempotency(client: TestClient, json_flow: str):
|
||||||
flow_data = json.loads(json_flow)
|
flow_data = orjson.loads(json_flow)
|
||||||
data = flow_data["data"]
|
data = flow_data["data"]
|
||||||
flow_data = FlowCreate(name="Test Flow", description="description", data=data)
|
flow_data = FlowCreate(name="Test Flow", description="description", data=data)
|
||||||
response = client.post("api/v1/flows/", json=flow_data.dict())
|
response = client.post("api/v1/flows/", json=flow_data.dict())
|
||||||
|
|
@ -253,7 +254,7 @@ def test_update_flow_idempotency(client: TestClient, json_flow: str):
|
||||||
|
|
||||||
|
|
||||||
def test_update_nonexistent_flow(client: TestClient, json_flow: str):
|
def test_update_nonexistent_flow(client: TestClient, json_flow: str):
|
||||||
flow_data = json.loads(json_flow)
|
flow_data = orjson.loads(json_flow)
|
||||||
data = flow_data["data"]
|
data = flow_data["data"]
|
||||||
uuid = uuid4()
|
uuid = uuid4()
|
||||||
updated_flow = FlowCreate(
|
updated_flow = FlowCreate(
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from langflow.settings import settings
|
|
||||||
|
|
||||||
|
|
||||||
def test_llms_settings(client: TestClient):
|
# def test_llms_settings(client: TestClient):
|
||||||
response = client.get("api/v1/all")
|
# response = client.get("api/v1/all")
|
||||||
assert response.status_code == 200
|
# assert response.status_code == 200
|
||||||
json_response = response.json()
|
# json_response = response.json()
|
||||||
llms = json_response["llms"]
|
# llms = json_response["llms"]
|
||||||
assert set(llms.keys()) == set(settings.LLMS)
|
# assert set(llms.keys()) == set(settings.LLMS)
|
||||||
|
|
||||||
|
|
||||||
# def test_hugging_face_hub(client: TestClient):
|
# def test_hugging_face_hub(client: TestClient):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from langchain.chains.base import Chain
|
from langchain.chains.base import Chain
|
||||||
from langflow.processing.process import load_flow_from_json
|
from langflow.processing.process import load_flow_from_json
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue