diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..153590eae --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# Set update schedule for GitHub Actions + +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "monthly" + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a34aedc32..d4a67f8f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,10 +16,10 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Cache Docker layers - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b480496ef..c7975830d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,11 +30,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -48,7 +48,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -61,6 +61,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/deploy_gh-pages.yml b/.github/workflows/deploy_gh-pages.yml index ffb52f941..aec8a39c8 100644 --- a/.github/workflows/deploy_gh-pages.yml +++ b/.github/workflows/deploy_gh-pages.yml @@ -12,8 +12,8 @@ jobs: name: Deploy to GitHub Pages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: 18 cache: npm diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 58d953e9e..29360e4a5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,12 +17,12 @@ jobs: - "3.9" - "3.10" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install poetry run: | pipx install poetry==$POETRY_VERSION - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: poetry diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index da449dae3..58bdd219e 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -18,11 +18,11 @@ jobs: if: ${{ (github.event.pull_request.merged == true) && contains(github.event.pull_request.labels.*.name, 'pre-release') }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install poetry run: pipx install poetry==$POETRY_VERSION - name: Set up Python 3.10 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.10" cache: "poetry" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b14fbc17b..21d8d27eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,11 +17,11 @@ jobs: if: ${{ (github.event.pull_request.merged == true) && contains(github.event.pull_request.labels.*.name, 'Release') }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install poetry run: pipx install poetry==$POETRY_VERSION - name: Set up Python 3.10 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.10" cache: "poetry" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc2e193c6..01050a45c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,11 +19,11 @@ jobs: env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install poetry run: pipx install poetry==$POETRY_VERSION - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: "poetry" diff --git a/docker-compose.yml b/docker-compose.yml index 7616600da..c74447899 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,8 @@ services: dockerfile: ./cdk.Dockerfile args: - BACKEND_URL=http://backend:7860 + depends_on: + - backend environment: - VITE_PROXY_TARGET=http://backend:7860 ports: diff --git a/pyproject.toml b/pyproject.toml index 1884f1a0f..8de9e0394 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow" -version = "0.6.7a1" +version = "0.6.7a2" description = "A Python package with a built-in web application" authors = ["Logspace "] maintainers = [ diff --git a/src/backend/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py b/src/backend/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py new file mode 100644 index 000000000..184613faf --- /dev/null +++ b/src/backend/langflow/components/embeddings/HuggingFaceInferenceAPIEmbeddings.py @@ -0,0 +1,42 @@ +from langflow import CustomComponent +from typing import Optional, Dict +from langchain_community.embeddings.huggingface import HuggingFaceInferenceAPIEmbeddings + + +class HuggingFaceInferenceAPIEmbeddingsComponent(CustomComponent): + display_name = "HuggingFaceInferenceAPIEmbeddings" + description = "HuggingFace sentence_transformers embedding models, API version." + documentation = ( + "https://github.com/huggingface/text-embeddings-inference" + ) + + def build_config(self): + return { + "api_key": {"display_name": "API Key", "password": True, "advanced": True}, + "api_url": {"display_name": "API URL", "advanced": True}, + "model_name": {"display_name": "Model Name"}, + "cache_folder": {"display_name": "Cache Folder", "advanced": True}, + "encode_kwargs": {"display_name": "Encode Kwargs", "advanced": True, "field_type": "dict"}, + "model_kwargs": {"display_name": "Model Kwargs", "field_type": "dict", "advanced": True}, + "multi_process": {"display_name": "Multi Process", "advanced": True}, + } + + def build( + self, + api_key: Optional[str] = "", + api_url: str = "http://localhost:8080", + model_name: str = "BAAI/bge-large-en-v1.5", + cache_folder: Optional[str] = None, + encode_kwargs: Optional[Dict] = {}, + model_kwargs: Optional[Dict] = {}, + multi_process: bool = False, + ) -> HuggingFaceInferenceAPIEmbeddings: + return HuggingFaceInferenceAPIEmbeddings( + api_key=api_key, + api_url=api_url, + model_name=model_name, + cache_folder=cache_folder, + encode_kwargs=encode_kwargs, + model_kwargs=model_kwargs, + multi_process=multi_process, + ) diff --git a/src/backend/langflow/components/vectorstores/Qdrant.py b/src/backend/langflow/components/vectorstores/Qdrant.py index ee38406df..50b9ea365 100644 --- a/src/backend/langflow/components/vectorstores/Qdrant.py +++ b/src/backend/langflow/components/vectorstores/Qdrant.py @@ -15,7 +15,7 @@ class QdrantComponent(CustomComponent): return { "documents": {"display_name": "Documents"}, "embedding": {"display_name": "Embedding"}, - "api_key": {"display_name": "API Key", "password": True}, + "api_key": {"display_name": "API Key", "password": True, "advanced": True}, "collection_name": {"display_name": "Collection Name"}, "content_payload_key": {"display_name": "Content Payload Key", "advanced": True}, "distance_func": {"display_name": "Distance Function", "advanced": True}, @@ -36,7 +36,7 @@ class QdrantComponent(CustomComponent): def build( self, embedding: Embeddings, - documents: List[Document], + documents: Optional[Document] = None, api_key: Optional[str] = None, collection_name: Optional[str] = None, content_payload_key: str = "page_content", @@ -44,7 +44,7 @@ class QdrantComponent(CustomComponent): grpc_port: Optional[int] = 6334, host: Optional[str] = None, https: bool = False, - location: str = ":memory:", + location: Optional[str] = None, metadata_payload_key: str = "metadata", path: Optional[str] = None, port: Optional[int] = 6333, @@ -54,23 +54,50 @@ class QdrantComponent(CustomComponent): timeout: Optional[float] = None, url: Optional[str] = None, ) -> Union[VectorStore, Qdrant, BaseRetriever]: - return Qdrant.from_documents( - documents=documents, - embedding=embedding, - api_key=api_key, - collection_name=collection_name, - content_payload_key=content_payload_key, - distance_func=distance_func, - grpc_port=grpc_port, - host=host, - https=https, - location=location, - metadata_payload_key=metadata_payload_key, - path=path, - port=port, - prefer_grpc=prefer_grpc, - prefix=prefix, - search_kwargs=search_kwargs, - timeout=timeout, - url=url, - ) + if documents is None: + from qdrant_client import QdrantClient + client = QdrantClient( + location=location, + url=host, + port=port, + grpc_port=grpc_port, + https=https, + prefix=prefix, + timeout=timeout, + prefer_grpc=prefer_grpc, + metadata_payload_key=metadata_payload_key, + content_payload_key=content_payload_key, + api_key=api_key, + collection_name=collection_name, + host=host, + path=path, + ) + vs = Qdrant(client=client, + collection_name=collection_name, + embeddings=embedding, + search_kwargs=search_kwargs, + distance_func=distance_func, + ) + return vs + else: + vs = Qdrant.from_documents( + documents=documents, + embedding=embedding, + api_key=api_key, + collection_name=collection_name, + content_payload_key=content_payload_key, + distance_func=distance_func, + grpc_port=grpc_port, + host=host, + https=https, + location=location, + metadata_payload_key=metadata_payload_key, + path=path, + port=port, + prefer_grpc=prefer_grpc, + prefix=prefix, + search_kwargs=search_kwargs, + timeout=timeout, + url=url, + ) + return vs diff --git a/src/backend/langflow/interface/custom/utils.py b/src/backend/langflow/interface/custom/utils.py index 650047efc..39bbcf1e0 100644 --- a/src/backend/langflow/interface/custom/utils.py +++ b/src/backend/langflow/interface/custom/utils.py @@ -7,8 +7,6 @@ from typing import Any, Dict, List, Optional, Union from uuid import UUID from fastapi import HTTPException -from loguru import logger - from langflow.field_typing.range_spec import RangeSpec from langflow.interface.custom.code_parser.utils import extract_inner_type from langflow.interface.custom.custom_component import CustomComponent @@ -22,6 +20,7 @@ from langflow.template.field.base import TemplateField from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode from langflow.utils import validate from langflow.utils.util import get_base_classes +from loguru import logger def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]): @@ -151,9 +150,6 @@ def add_extra_fields(frontend_node, field_config, function_args): if not function_args: return - # sort function_args which is a list of dicts - function_args.sort(key=lambda x: x["name"]) - for extra_field in function_args: if "name" not in extra_field or extra_field["name"] == "self": continue diff --git a/src/backend/langflow/processing/base.py b/src/backend/langflow/processing/base.py index b887f2192..d86984080 100644 --- a/src/backend/langflow/processing/base.py +++ b/src/backend/langflow/processing/base.py @@ -2,10 +2,13 @@ from typing import TYPE_CHECKING, List, Union from langchain.agents.agent import AgentExecutor from langchain.callbacks.base import BaseCallbackHandler +from loguru import logger + from langflow.api.v1.callback import AsyncStreamingLLMCallbackHandler, StreamingLLMCallbackHandler from langflow.processing.process import fix_memory_inputs, format_actions from langflow.services.deps import get_plugins_service -from loguru import logger +from langflow.processing.process import fix_memory_inputs, format_actions +from langflow.services.deps import get_plugins_service if TYPE_CHECKING: from langfuse.callback import CallbackHandler # type: ignore @@ -28,13 +31,12 @@ def setup_callbacks(sync, trace_id, **kwargs): def get_langfuse_callback(trace_id): from langflow.services.deps import get_plugins_service - from langfuse.callback import CreateTrace logger.debug("Initializing langfuse callback") if langfuse := get_plugins_service().get("langfuse"): logger.debug("Langfuse credentials found") try: - trace = langfuse.trace(CreateTrace(name="langflow-" + trace_id, id=trace_id)) + trace = langfuse.trace(name="langflow-" + trace_id, id=trace_id) return trace.getNewHandler() except Exception as exc: logger.error(f"Error initializing langfuse callback: {exc}") diff --git a/src/backend/langflow/services/plugins/langfuse_plugin.py b/src/backend/langflow/services/plugins/langfuse_plugin.py index 424279342..e5d3afdd6 100644 --- a/src/backend/langflow/services/plugins/langfuse_plugin.py +++ b/src/backend/langflow/services/plugins/langfuse_plugin.py @@ -64,14 +64,13 @@ class LangfusePlugin(CallbackPlugin): def get_callback(self, _id: Optional[str] = None): if _id is None: _id = "default" - from langfuse.callback import CreateTrace # type: ignore logger.debug("Initializing langfuse callback") try: langfuse_instance = self.get() if langfuse_instance is not None and hasattr(langfuse_instance, "trace"): - trace = langfuse_instance.trace(CreateTrace(name="langflow-" + _id, id=_id)) + trace = langfuse_instance.trace(name="langflow-" + _id, id=_id) if trace: return trace.getNewHandler() diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index d83580b53..d120fe48a 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -99,7 +99,7 @@ "pretty-quick": "^3.1.3", "tailwindcss": "^3.3.3", "typescript": "^5.2.2", - "vite": "^4.5.1" + "vite": "^4.5.2" } }, "node_modules/@adobe/css-tools": { diff --git a/src/frontend/package.json b/src/frontend/package.json index 663fef991..1d74df9a3 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -121,6 +121,6 @@ "pretty-quick": "^3.1.3", "tailwindcss": "^3.3.3", "typescript": "^5.2.2", - "vite": "^4.5.1" + "vite": "^4.5.2" } } diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 7d2641c78..c639cd257 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -139,12 +139,16 @@ export function groupByFamily( }))) ); }; + console.log(flow); if (flow) { + // se existir o flow for (const node of flow) { + // para cada node do flow + if (node!.data!.node!.flow) break; // não faz nada se o node for um group const nodeData = node.data; - const foundNode = checkedNodes.get(nodeData.type); + const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado checkedNodes.set(nodeData.type, { hasBaseClassInTemplate: foundNode?.hasBaseClassInTemplate || @@ -153,7 +157,7 @@ export function groupByFamily( foundNode?.hasBaseClassInBaseClasses || nodeData.node!.base_classes.some((baseClass) => baseClassesSet.has(baseClass) - ), + ), //seta como anterior ou verifica se o node tem base class displayName: nodeData.node?.display_name, }); }