diff --git a/nodes/src/nodes/core/gcp_auth.py b/nodes/src/nodes/core/gcp_auth.py new file mode 100644 index 000000000..28c64a921 --- /dev/null +++ b/nodes/src/nodes/core/gcp_auth.py @@ -0,0 +1,68 @@ +import base64 +import json +from typing import Optional, Tuple, Any + +class GCPAuthError(Exception): + """Raised when GCP authentication fails or config is invalid.""" + pass + +def get_gcp_credentials(config: dict, scopes: Optional[list[str]] = None) -> Tuple[Any, Optional[str]]: + """ + Resolves GCP credentials from the given node configuration. + + Returns: + tuple[google.auth.credentials.Credentials, str]: The credentials and the resolved project ID. + + Raises: + GCPAuthError: If configuration is invalid or missing. + """ + try: + import google.auth + from google.oauth2 import service_account + except ImportError: + raise GCPAuthError("google-auth library is not installed. Ensure node requirements include 'google-auth'.") + + auth_type = config.get("gcp.authType", "adc") + project_id = config.get("gcp.projectId") + + if auth_type == "service_account": + key_data = config.get("gcp.serviceAccountKey") + if not key_data: + raise GCPAuthError("Service Account JSON key is required when authType is 'service_account', but missing.") + + # RocketRide UI usually uploads files as base64 data-url: data:application/json;base64,... + try: + if "," in key_data: + _, b64_data = key_data.split(",", 1) + json_bytes = base64.b64decode(b64_data) + key_info = json.loads(json_bytes.decode('utf-8')) + else: + # Fallback if raw JSON string is passed directly + key_info = json.loads(key_data) + except Exception as e: + raise GCPAuthError(f"Failed to parse Service Account JSON key: {e}") + + try: + creds = service_account.Credentials.from_service_account_info(key_info) + if scopes: + creds = creds.with_scopes(scopes) + except Exception as e: + raise GCPAuthError(f"Invalid Service Account format: {e}") + + if not project_id: + project_id = key_info.get("project_id") + + return creds, project_id + + elif auth_type == "adc": + # Application Default Credentials + try: + creds, default_project_id = google.auth.default(scopes=scopes) + if not project_id: + project_id = default_project_id + return creds, project_id + except Exception as e: + raise GCPAuthError(f"Failed to acquire Application Default Credentials: {e}") + + else: + raise GCPAuthError(f"Unknown gcp.authType: {auth_type}") diff --git a/nodes/src/nodes/core/services.common.gcp.json b/nodes/src/nodes/core/services.common.gcp.json new file mode 100644 index 000000000..4aa69e624 --- /dev/null +++ b/nodes/src/nodes/core/services.common.gcp.json @@ -0,0 +1,32 @@ +{ + "fields": { + "gcp.authType": { + "type": "string", + "title": "Authentication Type", + "default": "adc", + "enum": ["adc", "service_account"], + "enumNames": ["Application Default Credentials", "Service Account JSON"], + "description": "Choose how to authenticate to Google Cloud Platform.", + "conditional": [ + { + "value": "service_account", + "properties": ["gcp.serviceAccountKey"] + } + ] + }, + "gcp.serviceAccountKey": { + "type": "string", + "format": "data-url", + "title": "Service Account Key JSON", + "description": "Upload the JSON key file for your Google Cloud service account.", + "ui:options:accept": ".json", + "secure": true + }, + "gcp.projectId": { + "type": "string", + "title": "Project ID", + "description": "Optional: Specify the Google Cloud Project ID explicitly. Leave blank to infer from credentials.", + "optional": true + } + } +} diff --git a/nodes/src/nodes/db_firestore/IGlobal.py b/nodes/src/nodes/db_firestore/IGlobal.py new file mode 100644 index 000000000..758e0cd64 --- /dev/null +++ b/nodes/src/nodes/db_firestore/IGlobal.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from ai.common.config import Config +from rocketlib import IGlobalBase, OPEN_MODE, debug, warning +from nodes.core.gcp_auth import get_gcp_credentials, GCPAuthError + +try: + from google.cloud import firestore +except ImportError: + firestore = None + +class IGlobal(IGlobalBase): + """Global state for Firestore node.""" + + client: firestore.Client | None = None + database: str = '(default)' + collection: str = '' + + def beginGlobal(self) -> None: + if self.IEndpoint.endpoint.openMode == OPEN_MODE.CONFIG: + return + + if firestore is None: + raise ImportError("google-cloud-firestore is not installed.") + + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + + self.database = str((cfg.get('database') or '(default)')).strip() or '(default)' + self.collection = str((cfg.get('collection') or '')).strip() + + # Auth + try: + creds, project_id = get_gcp_credentials(cfg) + except Exception as e: + warning(f"Firestore authentication failed: {e}") + raise + + self.client = firestore.Client( + project=project_id, + credentials=creds, + database=self.database + ) + + # Fail fast connection check + try: + # simple check to verify connectivity/auth + next(self.client.collections(page_size=1), None) + debug(f'db_firestore: connected to project {self.client.project}, database={self.database}') + except Exception as e: + warning(f"Firestore connection check failed: {e}") + raise + + def validateConfig(self) -> None: + try: + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + get_gcp_credentials(cfg) # Validates credentials parse successfully + if not str(cfg.get('collection') or '').strip(): + warning('collection is recommended') + except GCPAuthError as e: + warning(f"Auth configuration error: {e}") + except Exception as e: + warning(str(e)) + + def endGlobal(self) -> None: + if self.client is not None: + self.client.close() + self.client = None diff --git a/nodes/src/nodes/db_firestore/IInstance.py b/nodes/src/nodes/db_firestore/IInstance.py new file mode 100644 index 000000000..d8db45c74 --- /dev/null +++ b/nodes/src/nodes/db_firestore/IInstance.py @@ -0,0 +1,58 @@ +from ai.common.tool import tool_function +from rocketlib import IInstanceBase +from typing import Dict, Any + +class IInstance(IInstanceBase): + """Firestore instance, providing tool functions for reading and writing documents.""" + + @tool_function( + description="Insert or update a document in a Firestore collection. If the document exists, it merges the data.", + args={ + "collection": "The collection name.", + "document_id": "The ID of the document to set. If empty, a new ID will be generated.", + "data": "The JSON dictionary to store in the document." + } + ) + def set_document(self, collection: str, document_id: str, data: Dict[str, Any]) -> str: + client = self.glb.client + if not client: + return "Error: Firestore client is not connected." + + if not collection: + collection = self.glb.collection + + try: + coll_ref = client.collection(collection) + if document_id: + doc_ref = coll_ref.document(document_id) + doc_ref.set(data, merge=True) + return f"Successfully set document {document_id} in {collection}." + else: + _, doc_ref = coll_ref.add(data) + return f"Successfully added document with ID {doc_ref.id} to {collection}." + except Exception as e: + return f"Failed to set document: {e}" + + @tool_function( + description="Get a single document from a Firestore collection.", + args={ + "collection": "The collection name.", + "document_id": "The document ID." + } + ) + def get_document(self, collection: str, document_id: str) -> Dict[str, Any]: + client = self.glb.client + if not client: + return {"error": "Firestore client is not connected."} + + if not collection: + collection = self.glb.collection + + try: + doc = client.collection(collection).document(document_id).get() + if doc.exists: + return doc.to_dict() + else: + return {"error": f"Document {document_id} not found."} + except Exception as e: + return {"error": f"Failed to get document: {e}"} diff --git a/nodes/src/nodes/db_firestore/README.md b/nodes/src/nodes/db_firestore/README.md new file mode 100644 index 000000000..48155cc3c --- /dev/null +++ b/nodes/src/nodes/db_firestore/README.md @@ -0,0 +1,16 @@ +# Firestore Node + +A standard node for interacting with Google Cloud Firestore (Datastore mode or Native mode). + +## Authentication +This node uses the shared RocketRide Google Cloud authentication logic. You can authenticate by either: +1. Uploading a **Service Account JSON Key**. +2. Leaving the key blank and relying on **Application Default Credentials (ADC)** if your RocketRide server is hosted on Google Cloud Run, GKE, or a Compute Engine VM with attached service accounts. + +## Usage +When placed in a pipeline as a tool node, the LLM can: +- **`get_document`**: Fetch an existing document by its collection and document ID. +- **`set_document`**: Create or update (merge) a document with JSON data. + + + diff --git a/nodes/src/nodes/db_firestore/__init__.py b/nodes/src/nodes/db_firestore/__init__.py new file mode 100644 index 000000000..ae74f1650 --- /dev/null +++ b/nodes/src/nodes/db_firestore/__init__.py @@ -0,0 +1,10 @@ +import os +from depends import depends # type: ignore + +requirements = os.path.dirname(os.path.realpath(__file__)) + '/requirements.txt' +depends(requirements) + +from .IGlobal import IGlobal # noqa: E402 +from .IInstance import IInstance # noqa: E402 + +__all__ = ['IGlobal', 'IInstance'] diff --git a/nodes/src/nodes/db_firestore/requirements.txt b/nodes/src/nodes/db_firestore/requirements.txt new file mode 100644 index 000000000..431262873 --- /dev/null +++ b/nodes/src/nodes/db_firestore/requirements.txt @@ -0,0 +1,2 @@ +google-auth>=2.23.3 +google-cloud-firestore>=2.13.0 diff --git a/nodes/src/nodes/db_firestore/services.json b/nodes/src/nodes/db_firestore/services.json new file mode 100644 index 000000000..66abed480 --- /dev/null +++ b/nodes/src/nodes/db_firestore/services.json @@ -0,0 +1,74 @@ +{ + "title": "Firestore", + "protocol": "db_firestore://", + "classType": ["database", "tool"], + "capabilities": ["noremote", "invoke"], + "register": "filter", + "node": "python", + "path": "nodes.db_firestore", + "prefix": "firestore", + "description": ["A processing component that connects to Google Cloud Firestore (Datastore Mode or Native)."], + "icon": "db_firestore.svg", + "documentation": "https://docs.rocketride.org", + "invoke": { + "llm": { + "description": "LLM to use to craft NoSQL queries", + "min": 1, + "optional": true + } + }, + "lanes": { + "answers": [], + "questions": ["table", "text", "answers"] + }, + "preconfig": { + "default": "default", + "profiles": { + "default": { + "database": "(default)" + } + } + }, + "fields": { + "firestore.database": { + "type": "string", + "title": "Database ID", + "default": "(default)", + "description": "The Firestore database ID. Usually '(default)'." + }, + "firestore.collection": { + "type": "string", + "title": "Collection", + "description": "The Firestore collection to query or insert into." + }, + "firestore.default": { + "object": "default", + "properties": [ + "gcp.authType", + "gcp.serviceAccountKey", + "gcp.projectId", + "firestore.database", + "firestore.collection" + ] + }, + "firestore.profile": { + "hidden": true, + "type": "string", + "default": "default", + "enum": [["default", "Default"]], + "conditional": [ + { + "value": "default", + "properties": ["firestore.default"] + } + ] + } + }, + "shape": [ + { + "section": "Pipe", + "title": "Firestore", + "properties": ["firestore.profile"] + } + ] +} diff --git a/nodes/src/nodes/tool_gcs/IGlobal.py b/nodes/src/nodes/tool_gcs/IGlobal.py new file mode 100644 index 000000000..9d46dc1f4 --- /dev/null +++ b/nodes/src/nodes/tool_gcs/IGlobal.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +from ai.common.config import Config +from rocketlib import IGlobalBase, OPEN_MODE, debug, warning +from nodes.core.gcp_auth import get_gcp_credentials, GCPAuthError + +try: + from google.cloud import storage +except ImportError: + storage = None + +class IGlobal(IGlobalBase): + """Global state for Google Cloud Storage node.""" + + client: storage.Client | None = None + bucket_name: str = '' + prefix: str = '' + + def beginGlobal(self) -> None: + if self.IEndpoint.endpoint.openMode == OPEN_MODE.CONFIG: + return + + if storage is None: + raise ImportError("google-cloud-storage is not installed.") + + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + + self.bucket_name = str((cfg.get('bucketName') or '')).strip() + self.prefix = str((cfg.get('prefix') or '')).strip() + + # Auth + try: + creds, project_id = get_gcp_credentials(cfg) + except Exception as e: + warning(f"GCS authentication failed: {e}") + raise + + self.client = storage.Client( + project=project_id, + credentials=creds + ) + + # Fail fast connection check + try: + if self.bucket_name: + self.client.get_bucket(self.bucket_name) + debug(f'tool_gcs: connected to project {self.client.project}, bucket={self.bucket_name}') + else: + debug(f'tool_gcs: connected to project {self.client.project} with no specific bucket configured') + except Exception as e: + warning(f"GCS connection check failed: {e}") + raise + + def validateConfig(self) -> None: + try: + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + get_gcp_credentials(cfg) + if not str(cfg.get('bucketName') or '').strip(): + warning('bucketName is required') + except GCPAuthError as e: + warning(f"Auth configuration error: {e}") + except Exception as e: + warning(str(e)) + + def endGlobal(self) -> None: + if self.client is not None: + self.client.close() + self.client = None diff --git a/nodes/src/nodes/tool_gcs/IInstance.py b/nodes/src/nodes/tool_gcs/IInstance.py new file mode 100644 index 000000000..05bcd8e4f --- /dev/null +++ b/nodes/src/nodes/tool_gcs/IInstance.py @@ -0,0 +1,70 @@ +from ai.common.tool import tool_function +from rocketlib import IInstanceBase +from typing import List, Dict, Any +import tempfile +import os + +class IInstance(IInstanceBase): + """GCS instance, providing tool functions for reading and listing files.""" + + @tool_function( + description="Download a file from Google Cloud Storage. Returns a dictionary containing the local temporary path of the downloaded file.", + args={ + "file_name": "The name/path of the file in the bucket to download." + } + ) + def download_file(self, file_name: str) -> Dict[str, Any]: + client = self.glb.client + if not client: + return {"error": "GCS client is not connected."} + + bucket_name = self.glb.bucket_name + if not bucket_name: + return {"error": "Bucket name not configured."} + + # Optional prefix prefixing + if self.glb.prefix: + file_name = f"{self.glb.prefix.rstrip('/')}/{file_name.lstrip('/')}" + + try: + bucket = client.bucket(bucket_name) + blob = bucket.blob(file_name) + + # Download to a temporary file + fd, temp_path = tempfile.mkstemp(prefix="gcs_") + os.close(fd) + blob.download_to_filename(temp_path) + + return {"success": True, "local_path": temp_path} + except Exception as e: + return {"error": f"Failed to download file: {e}"} + + @tool_function( + description="List files in the configured Google Cloud Storage bucket.", + args={ + "prefix": "Optional prefix to filter files.", + "max_results": "Maximum number of files to return (default 10)." + } + ) + def list_files(self, prefix: str = "", max_results: int = 10) -> List[str]: + client = self.glb.client + if not client: + return ["Error: GCS client is not connected."] + + bucket_name = self.glb.bucket_name + if not bucket_name: + return ["Error: Bucket name not configured."] + + # Combine node-level prefix and runtime prefix + full_prefix = "" + if self.glb.prefix: + full_prefix = self.glb.prefix.rstrip('/') + '/' + if prefix: + full_prefix += prefix.lstrip('/') + + try: + bucket = client.bucket(bucket_name) + blobs = bucket.list_blobs(prefix=full_prefix, max_results=max_results) + return [blob.name for blob in blobs] + except Exception as e: + return [f"Failed to list files: {e}"] diff --git a/nodes/src/nodes/tool_gcs/README.md b/nodes/src/nodes/tool_gcs/README.md new file mode 100644 index 000000000..cc85edcb8 --- /dev/null +++ b/nodes/src/nodes/tool_gcs/README.md @@ -0,0 +1,16 @@ +# Google Cloud Storage (GCS) Node + +A tool node for interacting with Google Cloud Storage buckets. + +## Authentication +This node uses the shared RocketRide Google Cloud authentication logic. You can authenticate by either: +1. Uploading a **Service Account JSON Key**. +2. Leaving the key blank and relying on **Application Default Credentials (ADC)** if your RocketRide server is hosted on Google Cloud Run, GKE, or a Compute Engine VM with attached service accounts. + +## Usage +When placed in a pipeline as a tool node, the LLM can: +- **`list_files`**: List objects in the configured bucket (with optional prefix filtering). +- **`download_file`**: Download an object from the bucket to a temporary local file on the server. + + + diff --git a/nodes/src/nodes/tool_gcs/__init__.py b/nodes/src/nodes/tool_gcs/__init__.py new file mode 100644 index 000000000..ae74f1650 --- /dev/null +++ b/nodes/src/nodes/tool_gcs/__init__.py @@ -0,0 +1,10 @@ +import os +from depends import depends # type: ignore + +requirements = os.path.dirname(os.path.realpath(__file__)) + '/requirements.txt' +depends(requirements) + +from .IGlobal import IGlobal # noqa: E402 +from .IInstance import IInstance # noqa: E402 + +__all__ = ['IGlobal', 'IInstance'] diff --git a/nodes/src/nodes/tool_gcs/requirements.txt b/nodes/src/nodes/tool_gcs/requirements.txt new file mode 100644 index 000000000..47a44788a --- /dev/null +++ b/nodes/src/nodes/tool_gcs/requirements.txt @@ -0,0 +1,2 @@ +google-auth>=2.23.3 +google-cloud-storage>=2.13.0 diff --git a/nodes/src/nodes/tool_gcs/services.json b/nodes/src/nodes/tool_gcs/services.json new file mode 100644 index 000000000..596d4d069 --- /dev/null +++ b/nodes/src/nodes/tool_gcs/services.json @@ -0,0 +1,65 @@ +{ + "title": "Google Cloud Storage", + "protocol": "tool_gcs://", + "classType": ["tool"], + "capabilities": ["noremote", "invoke"], + "register": "filter", + "node": "python", + "path": "nodes.tool_gcs", + "prefix": "gcs", + "description": ["A tool component that interacts with Google Cloud Storage buckets."], + "icon": "tool_gcs.svg", + "documentation": "https://docs.rocketride.org", + "invoke": {}, + "lanes": { + "answers": [], + "questions": ["text", "answers"] + }, + "preconfig": { + "default": "default", + "profiles": { + "default": {} + } + }, + "fields": { + "gcs.bucketName": { + "type": "string", + "title": "Bucket Name", + "description": "The Google Cloud Storage bucket name." + }, + "gcs.prefix": { + "type": "string", + "title": "Path Prefix", + "description": "Optional path prefix inside the bucket." + }, + "gcs.default": { + "object": "default", + "properties": [ + "gcp.authType", + "gcp.serviceAccountKey", + "gcp.projectId", + "gcs.bucketName", + "gcs.prefix" + ] + }, + "gcs.profile": { + "hidden": true, + "type": "string", + "default": "default", + "enum": [["default", "Default"]], + "conditional": [ + { + "value": "default", + "properties": ["gcs.default"] + } + ] + } + }, + "shape": [ + { + "section": "Pipe", + "title": "Google Cloud Storage", + "properties": ["gcs.profile"] + } + ] +} diff --git a/nodes/src/nodes/vectordb_vertex/IGlobal.py b/nodes/src/nodes/vectordb_vertex/IGlobal.py new file mode 100644 index 000000000..c46538d2e --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/IGlobal.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from ai.common.config import Config +from rocketlib import IGlobalBase, OPEN_MODE, debug, warning +from nodes.core.gcp_auth import get_gcp_credentials, GCPAuthError + +try: + from google.cloud import aiplatform +except ImportError: + aiplatform = None + +class IGlobal(IGlobalBase): + """Global state for Vertex AI Vector Search node.""" + + index_endpoint = None + deployed_index_id: str = '' + location: str = 'us-central1' + project_id: str = '' + + def beginGlobal(self) -> None: + if self.IEndpoint.endpoint.openMode == OPEN_MODE.CONFIG: + return + + if aiplatform is None: + raise ImportError("google-cloud-aiplatform is not installed.") + + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + + self.location = str((cfg.get('location') or 'us-central1')).strip() + index_endpoint_id = str((cfg.get('indexEndpointId') or '')).strip() + self.deployed_index_id = str((cfg.get('deployedIndexId') or '')).strip() + + if not index_endpoint_id or not self.deployed_index_id: + warning("indexEndpointId and deployedIndexId are required for Vertex AI Vector Search.") + + # Auth + try: + creds, self.project_id = get_gcp_credentials(cfg) + except Exception as e: + warning(f"Vertex AI authentication failed: {e}") + raise + + aiplatform.init( + project=self.project_id, + location=self.location, + credentials=creds + ) + + # Connect to Index Endpoint + try: + if index_endpoint_id: + self.index_endpoint = aiplatform.MatchingEngineIndexEndpoint( + index_endpoint_name=index_endpoint_id + ) + debug(f'vectordb_vertex: connected to index endpoint {index_endpoint_id}') + except Exception as e: + warning(f"Vertex AI connection check failed: {e}") + raise + + def validateConfig(self) -> None: + try: + cfg = Config.getNodeConfig(self.glb.logicalType, self.glb.connConfig) + get_gcp_credentials(cfg) + if not str(cfg.get('indexEndpointId') or '').strip(): + warning('indexEndpointId is required') + if not str(cfg.get('deployedIndexId') or '').strip(): + warning('deployedIndexId is required') + except GCPAuthError as e: + warning(f"Auth configuration error: {e}") + except Exception as e: + warning(str(e)) + + def endGlobal(self) -> None: + self.index_endpoint = None diff --git a/nodes/src/nodes/vectordb_vertex/IInstance.py b/nodes/src/nodes/vectordb_vertex/IInstance.py new file mode 100644 index 000000000..763c5f819 --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/IInstance.py @@ -0,0 +1,40 @@ +from ai.common.tool import tool_function +from rocketlib import IInstanceBase +from typing import List, Dict, Any + +class IInstance(IInstanceBase): + """Vertex AI Vector Search instance.""" + + @tool_function( + description="Search for nearest neighbors in Vertex AI Vector Search.", + args={ + "query_vector": "A list of floats representing the query embedding.", + "top_k": "Number of nearest neighbors to return.", + "score_threshold": "Optional minimum distance score to return." + } + ) + def search(self, query_vector: List[float], top_k: int = 10, score_threshold: float = 0.0) -> List[Dict[str, Any]]: + index_endpoint = self.glb.index_endpoint + if not index_endpoint: + return [{"error": "Vertex AI Index Endpoint is not connected."}] + + try: + response = index_endpoint.find_neighbors( + deployed_index_id=self.glb.deployed_index_id, + queries=[query_vector], + num_neighbors=top_k + ) + + results = [] + if response and len(response) > 0: + for neighbor in response[0]: + if score_threshold > 0.0 and neighbor.distance < score_threshold: + continue + + results.append({ + "id": neighbor.id, + "distance": neighbor.distance + }) + return results + except Exception as e: + return [{"error": f"Failed to search Vertex AI: {e}"}] diff --git a/nodes/src/nodes/vectordb_vertex/README.md b/nodes/src/nodes/vectordb_vertex/README.md new file mode 100644 index 000000000..5b5cb1401 --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/README.md @@ -0,0 +1,14 @@ +# Vertex AI Vector Search Node + +A tool node for interacting with Google Cloud Vertex AI Vector Search (formerly Matching Engine). + +## Authentication +This node uses the shared RocketRide Google Cloud authentication logic. You can authenticate by either: +1. Uploading a **Service Account JSON Key**. +2. Leaving the key blank and relying on **Application Default Credentials (ADC)** if your RocketRide server is hosted on Google Cloud Run, GKE, or a Compute Engine VM with attached service accounts. + +## Usage +When placed in a pipeline as a tool node, it provides the `search` tool for finding K-nearest neighbors to a given embedding vector, honoring `top_k` and `score_threshold` filters as requested in #1411. + + + diff --git a/nodes/src/nodes/vectordb_vertex/__init__.py b/nodes/src/nodes/vectordb_vertex/__init__.py new file mode 100644 index 000000000..ae74f1650 --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/__init__.py @@ -0,0 +1,10 @@ +import os +from depends import depends # type: ignore + +requirements = os.path.dirname(os.path.realpath(__file__)) + '/requirements.txt' +depends(requirements) + +from .IGlobal import IGlobal # noqa: E402 +from .IInstance import IInstance # noqa: E402 + +__all__ = ['IGlobal', 'IInstance'] diff --git a/nodes/src/nodes/vectordb_vertex/requirements.txt b/nodes/src/nodes/vectordb_vertex/requirements.txt new file mode 100644 index 000000000..f3c3a2902 --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/requirements.txt @@ -0,0 +1,2 @@ +google-auth>=2.23.3 +google-cloud-aiplatform>=1.40.0 diff --git a/nodes/src/nodes/vectordb_vertex/services.json b/nodes/src/nodes/vectordb_vertex/services.json new file mode 100644 index 000000000..574fe77db --- /dev/null +++ b/nodes/src/nodes/vectordb_vertex/services.json @@ -0,0 +1,72 @@ +{ + "title": "Vertex AI Vector Search", + "protocol": "vectordb_vertex://", + "classType": ["vector", "tool"], + "capabilities": ["noremote", "invoke"], + "register": "filter", + "node": "python", + "path": "nodes.vectordb_vertex", + "prefix": "vertex", + "description": ["A processing component that interacts with Google Vertex AI Vector Search."], + "icon": "vertex.svg", + "documentation": "https://docs.rocketride.org", + "invoke": {}, + "lanes": { + "answers": [], + "questions": ["text", "answers"] + }, + "preconfig": { + "default": "default", + "profiles": { + "default": {} + } + }, + "fields": { + "vertex.location": { + "type": "string", + "title": "Location", + "default": "us-central1", + "description": "The Google Cloud region, e.g. us-central1." + }, + "vertex.indexEndpointId": { + "type": "string", + "title": "Index Endpoint ID", + "description": "The ID of the Vector Search Index Endpoint." + }, + "vertex.deployedIndexId": { + "type": "string", + "title": "Deployed Index ID", + "description": "The ID of the deployed index." + }, + "vertex.default": { + "object": "default", + "properties": [ + "gcp.authType", + "gcp.serviceAccountKey", + "gcp.projectId", + "vertex.location", + "vertex.indexEndpointId", + "vertex.deployedIndexId" + ] + }, + "vertex.profile": { + "hidden": true, + "type": "string", + "default": "default", + "enum": [["default", "Default"]], + "conditional": [ + { + "value": "default", + "properties": ["vertex.default"] + } + ] + } + }, + "shape": [ + { + "section": "Pipe", + "title": "Vertex Vector Search", + "properties": ["vertex.profile"] + } + ] +}