From fed093e830e055459a915d8217898375805c4d1c Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Sun, 6 Aug 2023 14:52:31 -0500 Subject: [PATCH 01/14] potential fix for ChatVertexAI component bug --- src/backend/langflow/interface/initialize/loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index f52b2e56c..a9d0bce4d 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -139,7 +139,7 @@ def instantiate_llm(node_type, class_object, params: Dict): # This is a workaround so JinaChat works until streaming is implemented # if "openai_api_base" in params and "jina" in params["openai_api_base"]: # False if condition is True - if node_type == "VertexAI": + if "VertexAI" in node_type: return initialize_vertexai(class_object=class_object, params=params) # max_tokens sometimes is a string and should be an int if "max_tokens" in params: From c7635b5b7c464e63ddfc09d94059589c0b538f70 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Sun, 6 Aug 2023 14:53:37 -0500 Subject: [PATCH 02/14] Update config.yaml to enable ChatVertexAI --- src/backend/langflow/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 63e8cdf99..41627827a 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -127,9 +127,9 @@ llms: # There's a bug in this component deactivating until we get it sorted: _language_models.py", line 804, in send_message # is_blocked=safety_attributes.get("blocked", False), # AttributeError: 'list' object has no attribute 'get' - # ChatVertexAI: - # documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/google_vertex_ai_palm" ### + ChatVertexAI: + documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/google_vertex_ai_palm" memories: # https://github.com/supabase-community/supabase-py/issues/482 # ZepChatMessageHistory: From 8e8e97149a42b95a2df948fa02a4eb7d932f48c5 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Mon, 7 Aug 2023 08:19:37 -0500 Subject: [PATCH 03/14] Update docker-compose.yml to fix uvicorn factory path --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 961cd0e33..13d39e1f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: - "7860:7860" volumes: - ./:/app - command: bash -c "uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload" + command: bash -c "uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload" frontend: build: From 50df00cd0d7287aa2282c544a2ea507b6a9babd3 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Mon, 7 Aug 2023 08:20:04 -0500 Subject: [PATCH 04/14] Update docker-compose.debug.yml to fix uvicorn factory path --- docker-compose.debug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml index 25cddd9f7..6a9802e38 100644 --- a/docker-compose.debug.yml +++ b/docker-compose.debug.yml @@ -11,7 +11,7 @@ services: [ "sh", "-c", - "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload", + "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m uvicorn --factory src.backend.langflow.main:create_app --host 0.0.0.0 --port 7860 --reload", ] ports: - 7860:7860 From 6386a321930ae3663c48c8f75d50bd95c6bd59a6 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Mon, 7 Aug 2023 08:20:34 -0500 Subject: [PATCH 05/14] Update dev.Dockerfile to fix uvicorn factory path --- dev.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev.Dockerfile b/dev.Dockerfile index 3fcc0803d..ed3631516 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -15,4 +15,4 @@ COPY ./ ./ # Install dependencies RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi -CMD ["uvicorn","--factory", "langflow.main:create_app", "--host", "0.0.0.0", "--port", "5003", "--reload", "log-level", "debug"] \ No newline at end of file +CMD ["uvicorn", "--factory", "src.backend.langflow.main:create_app", "--host", "0.0.0.0", "--port", "7860", "--reload", "--log-level", "debug"] From b54231e584a9ee0bebd49c951a3ae1f4e3f19677 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Mon, 7 Aug 2023 08:21:57 -0500 Subject: [PATCH 06/14] Update Dockerfile to fix uvicorn factory path --- src/backend/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/Dockerfile b/src/backend/Dockerfile index 13f2dc62e..d93227b4a 100644 --- a/src/backend/Dockerfile +++ b/src/backend/Dockerfile @@ -11,4 +11,5 @@ RUN rm *.whl EXPOSE 80 -CMD [ "uvicorn", "--host", "0.0.0.0", "--port", "80", "langflow.backend.app:app" ] +CMD [ "uvicorn", "--host", "0.0.0.0", "--port", "7860", "--factory", "langflow.main:create_app" ] + From bb2b8fbb3d2e837973f7002878444cd446dde699 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Tue, 8 Aug 2023 17:35:50 -0500 Subject: [PATCH 07/14] add support for VertexAIEmbeddings node --- .dockerignore | 1 + docs/docs/components/embeddings.mdx | 22 ++++++ docs/docs/components/llms.mdx | 22 ++++++ src/backend/Dockerfile | 1 - .../langflow/interface/initialize/loading.py | 8 ++- .../template/frontend_node/embeddings.py | 67 +++++++++++++++++++ src/frontend/src/utils/styleUtils.ts | 1 + src/frontend/vite.config.ts | 3 +- 8 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..0cafc1cde --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.venv/ \ No newline at end of file diff --git a/docs/docs/components/embeddings.mdx b/docs/docs/components/embeddings.mdx index 644d91fee..5b134f08d 100644 --- a/docs/docs/components/embeddings.mdx +++ b/docs/docs/components/embeddings.mdx @@ -73,3 +73,25 @@ Used to load [OpenAI’s](https://openai.com/) embedding models. - **request_timeout:** Used to specify the maximum amount of time, in milliseconds, to wait for a response from the OpenAI API when generating embeddings for a given text. - **tiktoken_model_name:** Used to count the number of tokens in documents to constrain them to be under a certain limit. By default, when set to None, this will be the same as the embedding model name. + +--- + +### VertexAIEmbeddings + +Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) [Embeddings API](https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-embeddings). + +:::info +Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. +::: + +- **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. +- **location:** The default location to use when making API calls – defaults to `us-central1`. +- **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. +- **model_name:** The name of the Vertex AI large language model – defaults to `text-bison`. +- **project:** The default GCP project to use when making Vertex API calls. +- **request_parallelism:** The amount of parallelism allowed for requests issued to VertexAI models – defaults to `5`. +- **temperature:** Tunes the degree of randomness in text generations. Should be a non-negative value – defaults to `0`. +- **top_k:** How the model selects tokens for output, the next token is selected from – defaults to `40`. +- **top_p:** Tokens are selected from most probable to least until the sum of their – defaults to `0.95`. +- **tuned_model_name:** The name of a tuned model. If provided, model_name is ignored. +- **verbose:** This parameter is used to control the level of detail in the output of the chain. When set to True, it will print out some internal states of the chain while it is being run, which can help debug and understand the chain's behavior. If set to False, it will suppress the verbose output – defaults to `False`. \ No newline at end of file diff --git a/docs/docs/components/llms.mdx b/docs/docs/components/llms.mdx index ccca8fdd4..088556d2f 100644 --- a/docs/docs/components/llms.mdx +++ b/docs/docs/components/llms.mdx @@ -185,6 +185,28 @@ Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large lang Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. ::: +- **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. +- **location:** The default location to use when making API calls – defaults to `us-central1`. +- **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. +- **model_name:** The name of the Vertex AI large language model – defaults to `text-bison`. +- **project:** The default GCP project to use when making Vertex API calls. +- **request_parallelism:** The amount of parallelism allowed for requests issued to VertexAI models – defaults to `5`. +- **temperature:** Tunes the degree of randomness in text generations. Should be a non-negative value – defaults to `0`. +- **top_k:** How the model selects tokens for output, the next token is selected from – defaults to `40`. +- **top_p:** Tokens are selected from most probable to least until the sum of their – defaults to `0.95`. +- **tuned_model_name:** The name of a tuned model. If provided, model_name is ignored. +- **verbose:** This parameter is used to control the level of detail in the output of the chain. When set to True, it will print out some internal states of the chain while it is being run, which can help debug and understand the chain's behavior. If set to False, it will suppress the verbose output – defaults to `False`. + +--- + +### ChatVertexAI + +Wrapper around [Google Vertex AI](https://cloud.google.com/vertex-ai) large language models. + +:::info +Vertex AI is a cloud computing platform offered by Google Cloud Platform (GCP). It provides access, management, and development of applications and services through global data centers. To use Vertex AI PaLM, you need to have the [google-cloud-aiplatform](https://pypi.org/project/google-cloud-aiplatform/) Python package installed and credentials configured for your environment. +::: + - **credentials:** The default custom credentials (google.auth.credentials.Credentials) to use. - **location:** The default location to use when making API calls – defaults to `us-central1`. - **max_output_tokens:** Token limit determines the maximum amount of text output from one prompt – defaults to `128`. diff --git a/src/backend/Dockerfile b/src/backend/Dockerfile index d93227b4a..8257d89b0 100644 --- a/src/backend/Dockerfile +++ b/src/backend/Dockerfile @@ -12,4 +12,3 @@ RUN rm *.whl EXPOSE 80 CMD [ "uvicorn", "--host", "0.0.0.0", "--port", "7860", "--factory", "langflow.main:create_app" ] - diff --git a/src/backend/langflow/interface/initialize/loading.py b/src/backend/langflow/interface/initialize/loading.py index 590fa4727..db876c76a 100644 --- a/src/backend/langflow/interface/initialize/loading.py +++ b/src/backend/langflow/interface/initialize/loading.py @@ -88,7 +88,7 @@ def instantiate_based_on_type(class_object, base_type, node_type, params): elif base_type == "toolkits": return instantiate_toolkit(node_type, class_object, params) elif base_type == "embeddings": - return instantiate_embedding(class_object, params) + return instantiate_embedding(node_type, class_object, params) elif base_type == "vectorstores": return instantiate_vectorstore(class_object, params) elif base_type == "documentloaders": @@ -258,9 +258,13 @@ def instantiate_toolkit(node_type, class_object: Type[BaseToolkit], params: Dict return loaded_toolkit -def instantiate_embedding(class_object, params: Dict): +def instantiate_embedding(node_type, class_object, params: Dict): params.pop("model", None) params.pop("headers", None) + + if "VertexAI" in node_type: + return initialize_vertexai(class_object=class_object, params=params) + try: return class_object(**params) except ValidationError: diff --git a/src/backend/langflow/template/frontend_node/embeddings.py b/src/backend/langflow/template/frontend_node/embeddings.py index d466b11a4..4e7e25112 100644 --- a/src/backend/langflow/template/frontend_node/embeddings.py +++ b/src/backend/langflow/template/frontend_node/embeddings.py @@ -5,6 +5,47 @@ from langflow.template.frontend_node.base import FrontendNode class EmbeddingFrontendNode(FrontendNode): + def add_extra_fields(self) -> None: + if "VertexAI" in self.template.type_name: + # Add credentials field which should of type file. + self.template.add_field( + TemplateField( + field_type="file", + required=False, + show=True, + name="credentials", + value="", + suffixes=[".json"], + file_types=["json"], + ) + ) + + @staticmethod + def format_vertex_field(field: TemplateField, name: str): + if "VertexAI" in name: + advanced_fields = [ + "verbose", + "top_p", + "top_k", + "max_output_tokens", + ] + if field.name in advanced_fields: + field.advanced = True + show_fields = [ + "verbose", + "project", + "location", + "credentials", + "max_output_tokens", + "model_name", + "temperature", + "top_p", + "top_k", + ] + + if field.name in show_fields: + field.show = True + @staticmethod def format_jina_fields(field: TemplateField): if "jina" in field.name: @@ -41,10 +82,36 @@ class EmbeddingFrontendNode(FrontendNode): @staticmethod def format_field(field: TemplateField, name: Optional[str] = None) -> None: FrontendNode.format_field(field, name) + if name and "vertex" in name.lower(): + EmbeddingFrontendNode.format_vertex_field(field, name) field.advanced = not field.required field.show = True if field.name == "headers": field.show = False + if field.name == "model_kwargs": + field.field_type = "code" + field.advanced = True + field.show = True + elif field.name in [ + "model_name", + "temperature", + "model_file", + "model_type", + "deployment_name", + "credentials", + ]: + field.advanced = False + field.show = True + if field.name == "credentials": + field.field_type = "file" + if name == "VertexAI" and field.name not in [ + "callbacks", + "client", + "stop", + "tags", + "cache", + ]: + field.show = True # Format Jina fields EmbeddingFrontendNode.format_jina_fields(field) diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 42fbe8773..5b40e8c05 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -205,6 +205,7 @@ export const nodeIconsLucide = { SupabaseVectorStore: SupabaseIcon, VertexAI: VertexAIIcon, ChatVertexAI: VertexAIIcon, + VertexAIEmbeddings: VertexAIIcon, agents: Rocket, WikipediaAPIWrapper: SvgWikipedia, chains: Link, diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index f051c2eee..c361b7ea4 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -5,6 +5,7 @@ const apiRoutes = ["^/api/v1/", "/health"]; // Use environment variable to determine the target. const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860"; +const port = process.env.VITE_PROXY_PORT || 3000; const proxyTargets = apiRoutes.reduce((proxyObj, route) => { proxyObj[route] = { @@ -22,7 +23,7 @@ export default defineConfig(() => { }, plugins: [react(), svgr()], server: { - port: 3000, + port: port, proxy: { ...proxyTargets, }, From aa20ae5a560c9ca025cde25e6c678425dd561848 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Tue, 8 Aug 2023 20:25:27 -0500 Subject: [PATCH 08/14] rename environment variable for vite server port --- src/frontend/vite.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index c361b7ea4..d477ce539 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -5,7 +5,9 @@ const apiRoutes = ["^/api/v1/", "/health"]; // Use environment variable to determine the target. const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860"; -const port = process.env.VITE_PROXY_PORT || 3000; + +// Use environment variable to determine the UI server port +const port = process.env.VITE_PORT || 3000; const proxyTargets = apiRoutes.reduce((proxyObj, route) => { proxyObj[route] = { From e922978f27c2f14e19793631da9db06d7d338bac Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Wed, 9 Aug 2023 08:07:59 -0500 Subject: [PATCH 09/14] adding VertexAIEmbeddings into config.yaml --- src/backend/langflow/config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 41627827a..d25893c25 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -104,6 +104,8 @@ embeddings: documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/sentence_transformers" CohereEmbeddings: documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/cohere" + VertexAIEmbeddings: + documentation: "https://python.langchain.com/docs/modules/data_connection/text_embedding/integrations/google_vertex_ai_palm" llms: OpenAI: documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/openai" @@ -127,9 +129,9 @@ llms: # There's a bug in this component deactivating until we get it sorted: _language_models.py", line 804, in send_message # is_blocked=safety_attributes.get("blocked", False), # AttributeError: 'list' object has no attribute 'get' - ### ChatVertexAI: documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/google_vertex_ai_palm" + ### memories: # https://github.com/supabase-community/supabase-py/issues/482 # ZepChatMessageHistory: From 97bf39143d619868fe88e9198457b731e19d8e94 Mon Sep 17 00:00:00 2001 From: Dave Morris Date: Wed, 9 Aug 2023 20:08:36 -0500 Subject: [PATCH 10/14] fix to allow running the backend on port 443 without https (wss protocol is required even without an SSL certificate) --- src/frontend/src/modals/formModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 81b15559c..89e7c687b 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -160,7 +160,7 @@ export default function FormModal({ } function getWebSocketUrl(chatId, isDevelopment = false) { - const isSecureProtocol = window.location.protocol === "https:"; + const isSecureProtocol = window.location.protocol === "https:" || window.location.port === "443"; const webSocketProtocol = isSecureProtocol ? "wss" : "ws"; const host = isDevelopment ? "localhost:7860" : window.location.host; const chatEndpoint = `/api/v1/chat/${chatId}`; From 73474665630d8f3923ba22d5026dfbc0e996d3c2 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Fri, 11 Aug 2023 01:07:33 +0200 Subject: [PATCH 11/14] Update pyproject.toml Update fake-useragent to latest version (1.2.1). Disclaimer: I'm the maintainer. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 750e1853c..7ba79ca1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ unstructured = "^0.7.0" pypdf = "^3.11.0" lxml = "^4.9.2" pysrt = "^1.1.2" -fake-useragent = "^1.1.3" +fake-useragent = "^1.2.1" docstring-parser = "^0.15" psycopg2-binary = "^2.9.6" pyarrow = "^12.0.0" From cb66255b84d5156a1daa5a5934b87430134c835b Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 13 Aug 2023 20:40:56 -0300 Subject: [PATCH 12/14] Refactor: Refactor api modal constant --- src/frontend/src/constants/constants.ts | 81 --------------- src/frontend/src/modals/ApiModal/index.tsx | 111 +-------------------- src/frontend/src/utils/utils.ts | 79 +++++++++++++++ 3 files changed, 84 insertions(+), 187 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index ab9de7f63..0ff77cf45 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -508,84 +508,3 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [ "/api/v1/custom_component", "/api/v1/validate/prompt", ]; - -export const tabsCode = []; - -export function tabsArray(codes: string[], method: number) { - if (!method) return; - if (method === 0) { - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - ]; - } - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[4], - }, - ]; -} diff --git a/src/frontend/src/modals/ApiModal/index.tsx b/src/frontend/src/modals/ApiModal/index.tsx index 307e48208..8410ee7d4 100644 --- a/src/frontend/src/modals/ApiModal/index.tsx +++ b/src/frontend/src/modals/ApiModal/index.tsx @@ -22,6 +22,7 @@ import { getPythonApiCode, getPythonCode, getWidgetCode, + tabsArray, } from "../../utils/utils"; import BaseModal from "../baseModal"; @@ -48,39 +49,8 @@ const ApiModal = forwardRef( const pythonCode = getPythonCode(flow, tweak.current, tabsState); const widgetCode = getWidgetCode(flow, tabsState); const tweaksCode = buildTweaks(flow); - const [tabs, setTabs] = useState([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - ]); + const codesArray = [curl_code, pythonApiCode, pythonCode, widgetCode, pythonCode]; + const [tabs, setTabs] = useState(tabsArray(codesArray, 0)); function startState() { tweak.current = []; @@ -101,80 +71,9 @@ const ApiModal = forwardRef( if (Object.keys(tweaksCode).length > 0) { setActiveTab("0"); - setTabs([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - ]); + setTabs(tabsArray(codesArray, 1)); } else { - setTabs([ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: curl_code, - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: pythonApiCode, - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: pythonCode, - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: widgetCode, - }, - ]); + setTabs(tabsArray(codesArray, 1)); } }, [flow["data"]["nodes"], open]); diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index dec07fbe7..ea1c137b0 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -410,3 +410,82 @@ chat_input_field: Input key that you want the chat to send the user message with }host_url="http://localhost:7860" >`; } + +export function tabsArray(codes: string[], method: number) { + if (!method) return; + if (method === 0) { + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + ]; + } + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + language: "py", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + { + name: "Tweaks", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[4], + }, + ]; +} From c752872fc3f17231ce0981642e567459c5e97764 Mon Sep 17 00:00:00 2001 From: gustavoschaedler Date: Tue, 15 Aug 2023 16:50:40 +0100 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=90=9B=20fix(auth.py):=20add=20opti?= =?UTF-8?q?onal=20parameter=20'update=5Flast=5Flogin'=20to=20'create=5Fuse?= =?UTF-8?q?r=5Ftokens'=20function=20to=20allow=20updating=20last=20login?= =?UTF-8?q?=20only=20when=20needed=20=F0=9F=90=9B=20fix(auth.py):=20add=20?= =?UTF-8?q?optional=20parameter=20'db'=20to=20'create=5Frefresh=5Ftoken'?= =?UTF-8?q?=20function=20to=20allow=20passing=20the=20database=20session?= =?UTF-8?q?=20=E2=9C=A8=20feat(login.py):=20pass=20'update=5Flast=5Flogin?= =?UTF-8?q?=3DTrue'=20to=20'create=5Fuser=5Ftokens'=20function=20to=20upda?= =?UTF-8?q?te=20last=20login=20when=20user=20successfully=20logs=20in=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(ApiModal/index.tsx):=20fix=20formatting=20of?= =?UTF-8?q?=20'codesArray'=20array=20to=20improve=20readability=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(formModal/index.tsx):=20fix=20formatting=20o?= =?UTF-8?q?f=20'getWebSocketUrl'=20function=20to=20improve=20readability?= =?UTF-8?q?=20=F0=9F=90=9B=20fix(vite.config.ts):=20fix=20typo=20in=20comm?= =?UTF-8?q?ent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 192 ++++++++++---------- src/backend/langflow/auth/auth.py | 11 +- src/backend/langflow/routers/login.py | 2 +- src/frontend/src/modals/ApiModal/index.tsx | 8 +- src/frontend/src/modals/formModal/index.tsx | 3 +- src/frontend/vite.config.ts | 2 +- 6 files changed, 110 insertions(+), 108 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4c0fd2a0c..77ec70668 100644 --- a/poetry.lock +++ b/poetry.lock @@ -165,13 +165,13 @@ tz = ["python-dateutil"] [[package]] name = "anthropic" -version = "0.3.8" +version = "0.3.9" description = "Client library for the anthropic API" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "anthropic-0.3.8-py3-none-any.whl", hash = "sha256:97ffe1bacc4214dc89b19f496cf2769746971e86f7c835a05aa21b76f260d279"}, - {file = "anthropic-0.3.8.tar.gz", hash = "sha256:6651099807456c3b95b3879f5ad7d00f7e7e4f7649a2394d18032ab8be54ef16"}, + {file = "anthropic-0.3.9-py3-none-any.whl", hash = "sha256:23e8daf266c707faa0b85328ada03dcf885e62c2f236eb0159352e29b9c4e2e3"}, + {file = "anthropic-0.3.9.tar.gz", hash = "sha256:c19b75308c07cb1ecbea03ffcdde9ba68e5ca22a22479217712396385678bde3"}, ] [package.dependencies] @@ -180,7 +180,7 @@ distro = ">=1.7.0,<2" httpx = ">=0.23.0,<1" pydantic = ">=1.9.0,<2.0.0" tokenizers = ">=0.13.0" -typing-extensions = ">=4.1.1,<5" +typing-extensions = ">=4.5,<5" [[package]] name = "anyio" @@ -792,13 +792,13 @@ sqlalchemy = ["sqlalchemy (>1.3.21,<2.0)"] [[package]] name = "cohere" -version = "4.19.3" +version = "4.20.0" description = "" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "cohere-4.19.3-py3-none-any.whl", hash = "sha256:6c98f1e58b93b6316c824385c1d2032ed352280e9efa5695ba98306258abf84f"}, - {file = "cohere-4.19.3.tar.gz", hash = "sha256:c3aaa716c4da7d7a8ed68705fcdc92f1b1a2260b737cee6bd27af5c347f31496"}, + {file = "cohere-4.20.0-py3-none-any.whl", hash = "sha256:bebe4b1d21da0719aaa7db2cc180b5f3d0a802c19ad2d893d627971286e50497"}, + {file = "cohere-4.20.0.tar.gz", hash = "sha256:a16e86981945c201bab67ad6d47e57f42a37bf2a774f6ac6b8b12233aae6409a"}, ] [package.dependencies] @@ -858,71 +858,63 @@ typing = ["mypy (>=0.990)"] [[package]] name = "coverage" -version = "7.2.7" +version = "7.3.0" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, + {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, + {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, + {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, + {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, + {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, + {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, + {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, + {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, + {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, + {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, + {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, + {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, ] [package.dependencies] @@ -978,13 +970,13 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "ctransformers" -version = "0.2.21" +version = "0.2.22" description = "Python bindings for the Transformer models implemented in C/C++ using GGML library." optional = true python-versions = "*" files = [ - {file = "ctransformers-0.2.21-py3-none-any.whl", hash = "sha256:18a0555d02f55a3935f5544b885038562f80e497a6197d8e871941a087dba546"}, - {file = "ctransformers-0.2.21.tar.gz", hash = "sha256:58e7a699050a106688b967faa59f377886e22a581fde6cd36821dfa541995677"}, + {file = "ctransformers-0.2.22-py3-none-any.whl", hash = "sha256:cce72b4ffff3f29d49ea6488110686453b3354c285e96b9c7dd16f273c4b4fc4"}, + {file = "ctransformers-0.2.22.tar.gz", hash = "sha256:ffd15dfe8a6ad45568ac0423bbbb13d7d71b680a7d0b59871a193df8a4b8fdca"}, ] [package.dependencies] @@ -1309,13 +1301,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.2" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, - {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] @@ -1697,13 +1689,13 @@ six = "*" [[package]] name = "google-cloud-aiplatform" -version = "1.30.0" +version = "1.30.1" description = "Vertex AI API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-aiplatform-1.30.0.tar.gz", hash = "sha256:26c16069553d177c3277a4371279871c38e31eab1134906cf83ea905e4203ec4"}, - {file = "google_cloud_aiplatform-1.30.0-py2.py3-none-any.whl", hash = "sha256:8a5d47378babb491cf4737e4f1951289b33b9254bed1e3d8c07be4896cae83ce"}, + {file = "google-cloud-aiplatform-1.30.1.tar.gz", hash = "sha256:7552a6b2e66d7a9ff3c4b2bb95b0e9c182e7475dfb35d6347e9299f78779135a"}, + {file = "google_cloud_aiplatform-1.30.1-py2.py3-none-any.whl", hash = "sha256:ab1bbd4cf83cf583b7dea7e53421ad076f18b63e93cb22fb53c03176d5aa9258"}, ] [package.dependencies] @@ -2987,17 +2979,17 @@ test = ["psutil", "pytest", "pytest-asyncio"] [[package]] name = "langsmith" -version = "0.0.21" +version = "0.0.22" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.21-py3-none-any.whl", hash = "sha256:a04c6eb3b4fc6205b15a559705f726fd0114ee2b3bd8668a0bd11cf29d5c5992"}, - {file = "langsmith-0.0.21.tar.gz", hash = "sha256:ec90ddab6beee6c344cf0ed8ae7d68948740cf98e119dd97c571f3190555644e"}, + {file = "langsmith-0.0.22-py3-none-any.whl", hash = "sha256:1bc94a2e5bfa355ca15d9e658c2c2d04c8cc45c61892a1be08a7c3b40f2fd3f4"}, + {file = "langsmith-0.0.22.tar.gz", hash = "sha256:5726c7841294db2a9e5863e20718878d16e28722bdaf3169a278ff3bda2f0be7"}, ] [package.dependencies] -pydantic = ">=1,<2" +pydantic = ">=1,<3" requests = ">=2,<3" [[package]] @@ -3400,13 +3392,13 @@ files = [ [[package]] name = "metaphor-python" -version = "0.1.12" +version = "0.1.14" description = "A Python package for the Metaphor API." optional = false python-versions = "*" files = [ - {file = "metaphor-python-0.1.12.tar.gz", hash = "sha256:fb3c33326ad1862954d2a77e5d81a6304219314b958283620cef757df331312c"}, - {file = "metaphor_python-0.1.12-py3-none-any.whl", hash = "sha256:86210ba825c047461221833c6fe3c010651457b2c733804bca4cf0e5eef89f95"}, + {file = "metaphor-python-0.1.14.tar.gz", hash = "sha256:9c9be35d1270e1e2984637711c15b614ad852fbd2b51d428b4cc478e95018fab"}, + {file = "metaphor_python-0.1.14-py3-none-any.whl", hash = "sha256:9435fb702d62032e4affbf7825fe4b1f0c6099d33b4867f4238c07f4515eb9a2"}, ] [package.dependencies] @@ -4281,17 +4273,17 @@ xml = ["lxml (>=4.6.3)"] [[package]] name = "pandas-stubs" -version = "2.0.2.230605" +version = "2.0.3.230814" description = "Type annotations for pandas" optional = false python-versions = ">=3.8" files = [ - {file = "pandas_stubs-2.0.2.230605-py3-none-any.whl", hash = "sha256:39106b602f3cb6dc5f728b84e1b32bde6ecf41ee34ee714c66228009609fbada"}, - {file = "pandas_stubs-2.0.2.230605.tar.gz", hash = "sha256:624c7bb06d38145a44b61be459ccd19b038e0bf20364a025ecaab78fea65e858"}, + {file = "pandas_stubs-2.0.3.230814-py3-none-any.whl", hash = "sha256:4b3dfc027d49779176b7daa031a3405f7b839bcb6e312f4b9f29fea5feec5b4f"}, + {file = "pandas_stubs-2.0.3.230814.tar.gz", hash = "sha256:1d5cc09e36e3d9f9a1ed9dceae4e03eeb26d1b898dd769996925f784365c8769"}, ] [package.dependencies] -numpy = ">=1.24.3" +numpy = {version = ">=1.25.0", markers = "python_version >= \"3.9\""} types-pytz = ">=2022.1.1" [[package]] @@ -5193,13 +5185,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pypdf" -version = "3.15.0" +version = "3.15.1" description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files" optional = false python-versions = ">=3.6" files = [ - {file = "pypdf-3.15.0-py3-none-any.whl", hash = "sha256:2e29ddb62561ec91157c784783714703ddd3ce08f070ecbc57404fb86cd9fc97"}, - {file = "pypdf-3.15.0.tar.gz", hash = "sha256:8a6264e1c47c63dc2484e29bdfa76b121435896a84e94b7c5ae82c6ae96354bb"}, + {file = "pypdf-3.15.1-py3-none-any.whl", hash = "sha256:99b337af7da8046d1e2e94354846e8c56753e1cdc817ac0fbe770c1e2281902b"}, + {file = "pypdf-3.15.1.tar.gz", hash = "sha256:d0dfaf4f10dfb06ac39e1d6a9cbffd63e77621d1e89c0ef08f346fd902df7b4b"}, ] [package.dependencies] @@ -6508,13 +6500,13 @@ widechars = ["wcwidth"] [[package]] name = "tenacity" -version = "8.2.2" +version = "8.2.3" description = "Retry code until it succeeds" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "tenacity-8.2.2-py3-none-any.whl", hash = "sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0"}, - {file = "tenacity-8.2.2.tar.gz", hash = "sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0"}, + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, ] [package.extras] @@ -6960,13 +6952,13 @@ files = [ [[package]] name = "types-pytz" -version = "2023.3.0.0" +version = "2023.3.0.1" description = "Typing stubs for pytz" optional = false python-versions = "*" files = [ - {file = "types-pytz-2023.3.0.0.tar.gz", hash = "sha256:ecdc70d543aaf3616a7e48631543a884f74205f284cefd6649ddf44c6a820aac"}, - {file = "types_pytz-2023.3.0.0-py3-none-any.whl", hash = "sha256:4fc2a7fbbc315f0b6630e0b899fd6c743705abe1094d007b0e612d10da15e0f3"}, + {file = "types-pytz-2023.3.0.1.tar.gz", hash = "sha256:1a7b8d4aac70981cfa24478a41eadfcd96a087c986d6f150d77e3ceb3c2bdfab"}, + {file = "types_pytz-2023.3.0.1-py3-none-any.whl", hash = "sha256:65152e872137926bb67a8fe6cc9cfd794365df86650c5d5fdc7b167b0f38892e"}, ] [[package]] @@ -7701,4 +7693,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "18156a4c5ecf05bf430bf2a00da1771c6e16e6408cfb05fe36fc3ff0ad29e213" +content-hash = "0f7d3f932eb130e7f3b6d234fc36e403ef409d63cfc825ba9f4c470203425ad2" diff --git a/src/backend/langflow/auth/auth.py b/src/backend/langflow/auth/auth.py index 5c2bf7343..1537f4d7e 100644 --- a/src/backend/langflow/auth/auth.py +++ b/src/backend/langflow/auth/auth.py @@ -76,7 +76,9 @@ def create_token(data: dict, expires_delta: timedelta): return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) -def create_user_tokens(user_id: UUID, db: Session = Depends(get_session)) -> dict: +def create_user_tokens( + user_id: UUID, db: Session = Depends(get_session), update_last_login: bool = False +) -> dict: access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_token( data={"sub": str(user_id)}, @@ -90,7 +92,8 @@ def create_user_tokens(user_id: UUID, db: Session = Depends(get_session)) -> dic ) # Update: last_login_at - update_user_last_login_at(user_id, db) + if update_last_login: + update_user_last_login_at(user_id, db) return { "access_token": access_token, @@ -99,7 +102,7 @@ def create_user_tokens(user_id: UUID, db: Session = Depends(get_session)) -> dic } -def create_refresh_token(refresh_token: str): +def create_refresh_token(refresh_token: str, db: Session = Depends(get_session)): try: payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM]) user_id: UUID = payload.get("sub") # type: ignore @@ -110,7 +113,7 @@ def create_refresh_token(refresh_token: str): status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token" ) - return create_user_tokens(user_id) + return create_user_tokens(user_id, db) except JWTError as e: raise HTTPException( diff --git a/src/backend/langflow/routers/login.py b/src/backend/langflow/routers/login.py index c7a2c05c4..f1c29fe28 100644 --- a/src/backend/langflow/routers/login.py +++ b/src/backend/langflow/routers/login.py @@ -20,7 +20,7 @@ async def login_to_get_access_token( # _: Session = Depends(get_current_active_user) ): if user := authenticate_user(form_data.username, form_data.password, db): - return create_user_tokens(user_id=user.id, db=db) + return create_user_tokens(user_id=user.id, db=db, update_last_login=True) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/src/frontend/src/modals/ApiModal/index.tsx b/src/frontend/src/modals/ApiModal/index.tsx index 8410ee7d4..5bd93df45 100644 --- a/src/frontend/src/modals/ApiModal/index.tsx +++ b/src/frontend/src/modals/ApiModal/index.tsx @@ -49,7 +49,13 @@ const ApiModal = forwardRef( const pythonCode = getPythonCode(flow, tweak.current, tabsState); const widgetCode = getWidgetCode(flow, tabsState); const tweaksCode = buildTweaks(flow); - const codesArray = [curl_code, pythonApiCode, pythonCode, widgetCode, pythonCode]; + const codesArray = [ + curl_code, + pythonApiCode, + pythonCode, + widgetCode, + pythonCode, + ]; const [tabs, setTabs] = useState(tabsArray(codesArray, 0)); function startState() { diff --git a/src/frontend/src/modals/formModal/index.tsx b/src/frontend/src/modals/formModal/index.tsx index 68137c0da..0e2f9b3c4 100644 --- a/src/frontend/src/modals/formModal/index.tsx +++ b/src/frontend/src/modals/formModal/index.tsx @@ -160,7 +160,8 @@ export default function FormModal({ } function getWebSocketUrl(chatId, isDevelopment = false) { - const isSecureProtocol = window.location.protocol === "https:" || window.location.port === "443"; + const isSecureProtocol = + window.location.protocol === "https:" || window.location.port === "443"; const webSocketProtocol = isSecureProtocol ? "wss" : "ws"; const host = isDevelopment ? "localhost:7860" : window.location.host; const chatEndpoint = `/api/v1/chat/${chatId}`; diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index d477ce539..b513e36bb 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -6,7 +6,7 @@ const apiRoutes = ["^/api/v1/", "/health"]; // Use environment variable to determine the target. const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860"; -// Use environment variable to determine the UI server port +// Use environment variable to determine the UI server port const port = process.env.VITE_PORT || 3000; const proxyTargets = apiRoutes.reduce((proxyObj, route) => { From 695a337c6c7c6e93f4e77e7870bc22cc946c8fe3 Mon Sep 17 00:00:00 2001 From: gustavoschaedler Date: Tue, 15 Aug 2023 20:00:02 +0100 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=94=A7=20fix(auth.py):=20move=20SEC?= =?UTF-8?q?RET=5FKEY,=20ALGORITHM,=20ACCESS=5FTOKEN=5FEXPIRE=5FMINUTES,=20?= =?UTF-8?q?and=20REFRESH=5FTOKEN=5FEXPIRE=5FMINUTES=20to=20environment=20v?= =?UTF-8?q?ariables=20for=20better=20security=20and=20configurability=20?= =?UTF-8?q?=E2=9C=A8=20feat(auth.py):=20add=20support=20for=20loading=20se?= =?UTF-8?q?ttings=20from=20environment=20variables=20in=20create=5Ftoken?= =?UTF-8?q?=20and=20create=5Fuser=5Ftokens=20functions=20=F0=9F=94=A7=20fi?= =?UTF-8?q?x(auth.py):=20use=20settings=5Fmanager=20to=20access=20SECRET?= =?UTF-8?q?=5FKEY,=20ALGORITHM,=20ACCESS=5FTOKEN=5FEXPIRE=5FMINUTES,=20and?= =?UTF-8?q?=20REFRESH=5FTOKEN=5FEXPIRE=5FMINUTES=20in=20create=5Ftoken=20a?= =?UTF-8?q?nd=20create=5Fuser=5Ftokens=20functions=20=F0=9F=94=A7=20fix(au?= =?UTF-8?q?th.py):=20use=20settings=5Fmanager=20to=20access=20SECRET=5FKEY?= =?UTF-8?q?=20and=20ALGORITHM=20in=20get=5Fcurrent=5Fuser=20function=20?= =?UTF-8?q?=E2=9C=A8=20feat(auth.py):=20add=20create=5Fuser=5Flongterm=5Ft?= =?UTF-8?q?oken=20function=20to=20create=20long-term=20access=20token=20fo?= =?UTF-8?q?r=20auto=20login=20=E2=9C=A8=20feat(login.py):=20add=20auto=5Fl?= =?UTF-8?q?ogin=20endpoint=20to=20automatically=20log=20in=20as=20a=20supe?= =?UTF-8?q?r=20user=20if=20AUTO=5FLOGIN=20is=20enabled=20in=20the=20settin?= =?UTF-8?q?gs=20=F0=9F=94=A7=20fix(settings/base.py):=20add=20SECRET=5FKEY?= =?UTF-8?q?,=20ALGORITHM,=20ACCESS=5FTOKEN=5FEXPIRE=5FMINUTES,=20REFRESH?= =?UTF-8?q?=5FTOKEN=5FEXPIRE=5FMINUTES,=20and=20AUTO=5FLOGIN=20settings=20?= =?UTF-8?q?to=20the=20base=20settings=20class=20=E2=9C=A8=20feat(settings/?= =?UTF-8?q?base.py):=20add=20AUTO=5FLOGIN=20setting=20to=20control=20wheth?= =?UTF-8?q?er=20auto=20login=20is=20enabled=20or=20not=20=F0=9F=94=A7=20fi?= =?UTF-8?q?x(settings/base.py):=20use=20secrets.token=5Fhex(32)=20to=20gen?= =?UTF-8?q?erate=20a=20random=20SECRET=5FKEY=20instead=20of=20hardcoding?= =?UTF-8?q?=20it=20=F0=9F=94=A7=20fix(settings/base.py):=20update=20commen?= =?UTF-8?q?ts=20and=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=E2=9C=A8=20feat(settings/base.py):=20add=20AUTO=5FLOGIN=20sett?= =?UTF-8?q?ing=20to=20control=20whether=20auto=20login=20is=20enabled=20or?= =?UTF-8?q?=20not=20=F0=9F=94=A7=20fix(settings/base.py):=20update=20comme?= =?UTF-8?q?nts=20and=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings=20class=20?= =?UTF-8?q?=F0=9F=94=A7=20fix(settings/base.py):=20update=20comments=20and?= =?UTF-8?q?=20formatting=20in=20the=20base=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔥 refactor(settings.py): remove unused imports and code, clean up formatting and comments 🔀 chore(settings.py): merge duplicated code into reusable functions 📝 docs(settings.py): add missing docstrings and comments for better code documentation 🔧 chore(settings.py): update settings file to improve readability and maintainability --- src/backend/langflow/auth/auth.py | 63 +++++-- src/backend/langflow/routers/login.py | 21 +++ .../langflow/services/settings/base.py | 10 + .../langflow/services/settings/settings.py | 171 ------------------ 4 files changed, 82 insertions(+), 183 deletions(-) delete mode 100644 src/backend/langflow/services/settings/settings.py diff --git a/src/backend/langflow/auth/auth.py b/src/backend/langflow/auth/auth.py index 1537f4d7e..b9e8dba3a 100644 --- a/src/backend/langflow/auth/auth.py +++ b/src/backend/langflow/auth/auth.py @@ -7,6 +7,8 @@ from fastapi.security import OAuth2PasswordBearer from fastapi import Depends, HTTPException, status from datetime import datetime, timedelta, timezone +from langflow.services.utils import get_settings_manager + from langflow.services.utils import get_session from langflow.database.models.user import ( User, @@ -16,12 +18,6 @@ from langflow.database.models.user import ( ) -# TODO: Move to env - JUST FOR TEST!!!!! -SECRET_KEY = "698619adad2d916f1f32d264540976964b3c0d3828e0870a65add5800a8cc6b9" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 60 -REFRESH_TOKEN_EXPIRE_MINUTES = 70 - pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") @@ -29,6 +25,8 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") async def get_current_user( token: Annotated[str, Depends(oauth2_scheme)], db: Session = Depends(get_session) ) -> User: + settings_manager = get_settings_manager() + credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", @@ -36,7 +34,11 @@ async def get_current_user( ) try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + payload = jwt.decode( + token, + settings_manager.settings.SECRET_KEY, + algorithms=[settings_manager.settings.ALGORITHM], + ) user_id: UUID = payload.get("sub") # type: ignore token_type: str = payload.get("type") # type: ignore @@ -68,24 +70,55 @@ def get_password_hash(password): def create_token(data: dict, expires_delta: timedelta): - to_encode = data.copy() + settings_manager = get_settings_manager() + to_encode = data.copy() expire = datetime.now(timezone.utc) + expires_delta to_encode["exp"] = expire - return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return jwt.encode( + to_encode, + settings_manager.settings.SECRET_KEY, + algorithm=settings_manager.settings.ALGORITHM, + ) + + +def create_user_longterm_token( + user_id: UUID, db: Session = Depends(get_session), update_last_login: bool = False +) -> dict: + access_token_expires_longterm = timedelta(days=365) + access_token = create_token( + data={"sub": str(user_id)}, + expires_delta=access_token_expires_longterm, + ) + + # Update: last_login_at + if update_last_login: + update_user_last_login_at(user_id, db) + + return { + "access_token": access_token, + "refresh_token": None, + "token_type": "bearer", + } def create_user_tokens( user_id: UUID, db: Session = Depends(get_session), update_last_login: bool = False ) -> dict: - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + settings_manager = get_settings_manager() + + access_token_expires = timedelta( + minutes=settings_manager.settings.ACCESS_TOKEN_EXPIRE_MINUTES + ) access_token = create_token( data={"sub": str(user_id)}, expires_delta=access_token_expires, ) - refresh_token_expires = timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES) + refresh_token_expires = timedelta( + minutes=settings_manager.settings.REFRESH_TOKEN_EXPIRE_MINUTES + ) refresh_token = create_token( data={"sub": str(user_id), "type": "rf"}, expires_delta=refresh_token_expires, @@ -103,8 +136,14 @@ def create_user_tokens( def create_refresh_token(refresh_token: str, db: Session = Depends(get_session)): + settings_manager = get_settings_manager() + try: - payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM]) + payload = jwt.decode( + refresh_token, + settings_manager.settings.SECRET_KEY, + algorithms=[settings_manager.settings.ALGORITHM], + ) user_id: UUID = payload.get("sub") # type: ignore token_type: str = payload.get("type") # type: ignore diff --git a/src/backend/langflow/routers/login.py b/src/backend/langflow/routers/login.py index f1c29fe28..7d114473d 100644 --- a/src/backend/langflow/routers/login.py +++ b/src/backend/langflow/routers/login.py @@ -1,3 +1,4 @@ +from uuid import UUID from sqlalchemy.orm import Session from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm @@ -8,8 +9,11 @@ from langflow.auth.auth import ( authenticate_user, create_user_tokens, create_refresh_token, + create_user_longterm_token, ) +from langflow.services.utils import get_settings_manager + router = APIRouter() @@ -29,6 +33,23 @@ async def login_to_get_access_token( ) +@router.get("/auto_login") +async def auto_login(db: Session = Depends(get_session)): + settings_manager = get_settings_manager() + + if settings_manager.settings.AUTO_LOGIN: + user_id = UUID("3fa85f64-5717-4562-b3fc-2c963f66afa6") + return create_user_longterm_token(user_id, db) + + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail={ + "message": "Auto login is disabled. Please enable it in the settings", + "auto_login": False, + }, + ) + + @router.post("/refresh") async def refresh_token(token: str): if token: diff --git a/src/backend/langflow/services/settings/base.py b/src/backend/langflow/services/settings/base.py index 1eb2793b3..d8b3f3ad6 100644 --- a/src/backend/langflow/services/settings/base.py +++ b/src/backend/langflow/services/settings/base.py @@ -1,6 +1,7 @@ import contextlib import json import os +import secrets from typing import Optional, List from pathlib import Path @@ -35,6 +36,15 @@ class Settings(BaseSettings): REMOVE_API_KEYS: bool = False COMPONENTS_PATH: List[str] = [] + # Login settings + SECRET_KEY: str = secrets.token_hex(32) + ALGORITHM: str = "HS256" + ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 + REFRESH_TOKEN_EXPIRE_MINUTES: int = 70 + # If AUTO_LOGIN = True + # > The application does not request login and logs in automatically as a super user. + AUTO_LOGIN: bool = True + @validator("DATABASE_URL", pre=True) def set_database_url(cls, value): if not value: diff --git a/src/backend/langflow/services/settings/settings.py b/src/backend/langflow/services/settings/settings.py deleted file mode 100644 index 439b3a1e4..000000000 --- a/src/backend/langflow/services/settings/settings.py +++ /dev/null @@ -1,171 +0,0 @@ -import contextlib -import json -import os -from typing import Optional, List -from pathlib import Path - -import yaml -from pydantic import BaseSettings, root_validator, validator -from langflow.utils.logger import logger - -BASE_COMPONENTS_PATH = str(Path(__file__).parent / "components") - - -class Settings(BaseSettings): - CHAINS: dict = {} - AGENTS: dict = {} - PROMPTS: dict = {} - LLMS: dict = {} - TOOLS: dict = {} - MEMORIES: dict = {} - EMBEDDINGS: dict = {} - VECTORSTORES: dict = {} - DOCUMENTLOADERS: dict = {} - WRAPPERS: dict = {} - RETRIEVERS: dict = {} - TOOLKITS: dict = {} - TEXTSPLITTERS: dict = {} - UTILITIES: dict = {} - OUTPUT_PARSERS: dict = {} - CUSTOM_COMPONENTS: dict = {} - - DEV: bool = False - DATABASE_URL: Optional[str] = None - CACHE: str = "InMemoryCache" - REMOVE_API_KEYS: bool = False - COMPONENTS_PATH: List[str] = [] - - @validator("DATABASE_URL", pre=True) - def set_database_url(cls, value): - if not value: - logger.debug( - "No database_url provided, trying LANGFLOW_DATABASE_URL env variable" - ) - if langflow_database_url := os.getenv("LANGFLOW_DATABASE_URL"): - value = langflow_database_url - logger.debug("Using LANGFLOW_DATABASE_URL env variable.") - else: - logger.debug("No DATABASE_URL env variable, using sqlite database") - value = "sqlite:///./langflow.db" - - return value - - @validator("COMPONENTS_PATH", pre=True) - def set_components_path(cls, value): - if os.getenv("LANGFLOW_COMPONENTS_PATH"): - logger.debug("Adding LANGFLOW_COMPONENTS_PATH to components_path") - langflow_component_path = os.getenv("LANGFLOW_COMPONENTS_PATH") - if ( - Path(langflow_component_path).exists() - and langflow_component_path not in value - ): - if isinstance(langflow_component_path, list): - for path in langflow_component_path: - if path not in value: - value.append(path) - logger.debug( - f"Extending {langflow_component_path} to components_path" - ) - elif langflow_component_path not in value: - value.append(langflow_component_path) - logger.debug( - f"Appending {langflow_component_path} to components_path" - ) - - if not value: - value = [BASE_COMPONENTS_PATH] - logger.debug("Setting default components path to components_path") - elif BASE_COMPONENTS_PATH not in value: - value.append(BASE_COMPONENTS_PATH) - logger.debug("Adding default components path to components_path") - - logger.debug(f"Components path: {value}") - return value - - class Config: - validate_assignment = True - extra = "ignore" - env_prefix = "LANGFLOW_" - - @root_validator(allow_reuse=True) - def validate_lists(cls, values): - for key, value in values.items(): - if key != "dev" and not value: - values[key] = [] - return values - - def update_from_yaml(self, file_path: str, dev: bool = False): - new_settings = load_settings_from_yaml(file_path) - self.CHAINS = new_settings.CHAINS or {} - self.AGENTS = new_settings.AGENTS or {} - self.PROMPTS = new_settings.PROMPTS or {} - self.LLMS = new_settings.LLMS or {} - self.TOOLS = new_settings.TOOLS or {} - self.MEMORIES = new_settings.MEMORIES or {} - self.WRAPPERS = new_settings.WRAPPERS or {} - self.TOOLKITS = new_settings.TOOLKITS or {} - self.TEXTSPLITTERS = new_settings.TEXTSPLITTERS or {} - self.UTILITIES = new_settings.UTILITIES or {} - self.EMBEDDINGS = new_settings.EMBEDDINGS or {} - self.VECTORSTORES = new_settings.VECTORSTORES or {} - self.DOCUMENTLOADERS = new_settings.DOCUMENTLOADERS or {} - self.RETRIEVERS = new_settings.RETRIEVERS or {} - self.OUTPUT_PARSERS = new_settings.OUTPUT_PARSERS or {} - self.CUSTOM_COMPONENTS = new_settings.CUSTOM_COMPONENTS or {} - self.COMPONENTS_PATH = new_settings.COMPONENTS_PATH or [] - self.DEV = dev - - def update_settings(self, **kwargs): - logger.debug("Updating settings") - for key, value in kwargs.items(): - # value may contain sensitive information, so we don't want to log it - if not hasattr(self, key): - logger.debug(f"Key {key} not found in settings") - continue - logger.debug(f"Updating {key}") - if isinstance(getattr(self, key), list): - # value might be a '[something]' string - with contextlib.suppress(json.decoder.JSONDecodeError): - value = json.loads(str(value)) - if isinstance(value, list): - for item in value: - if item not in getattr(self, key): - getattr(self, key).append(item) - logger.debug(f"Extended {key}") - else: - getattr(self, key).append(value) - logger.debug(f"Appended {key}") - - else: - setattr(self, key, value) - logger.debug(f"Updated {key}") - logger.debug(f"{key}: {getattr(self, key)}") - - -def save_settings_to_yaml(settings: Settings, file_path: str): - with open(file_path, "w") as f: - settings_dict = settings.dict() - yaml.dump(settings_dict, f) - - -def load_settings_from_yaml(file_path: str) -> Settings: - # Check if a string is a valid path or a file name - if "/" not in file_path: - # Get current path - current_path = os.path.dirname(os.path.abspath(__file__)) - - file_path = os.path.join(current_path, file_path) - - with open(file_path, "r") as f: - settings_dict = yaml.safe_load(f) - settings_dict = {k.upper(): v for k, v in settings_dict.items()} - - for key in settings_dict: - if key not in Settings.__fields__.keys(): - raise KeyError(f"Key {key} not found in settings") - logger.debug(f"Loading {len(settings_dict[key])} {key} from {file_path}") - - return Settings(**settings_dict) - - -settings = load_settings_from_yaml("config.yaml")