cp
This commit is contained in:
parent
c00f0e641f
commit
38d5cb8d98
@ -4,7 +4,8 @@ import base64
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional
|
||||||
import functions_framework
|
import functions_framework
|
||||||
from google.cloud import vision
|
import vertexai
|
||||||
|
from vertexai.vision_models import MultiModalEmbeddingModel, Image as VertexImage
|
||||||
from google.cloud import firestore
|
from google.cloud import firestore
|
||||||
from google.cloud import storage
|
from google.cloud import storage
|
||||||
from qdrant_client import QdrantClient
|
from qdrant_client import QdrantClient
|
||||||
@ -20,8 +21,15 @@ import uuid
|
|||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Initialize clients
|
# Initialize Vertex AI
|
||||||
vision_client = vision.ImageAnnotatorClient()
|
PROJECT_ID = os.environ.get('GOOGLE_CLOUD_PROJECT') or os.environ.get('GCP_PROJECT')
|
||||||
|
LOCATION = os.environ.get('VERTEX_AI_LOCATION', 'us-central1')
|
||||||
|
|
||||||
|
if PROJECT_ID:
|
||||||
|
vertexai.init(project=PROJECT_ID, location=LOCATION)
|
||||||
|
logger.info(f"Initialized Vertex AI with project {PROJECT_ID} in location {LOCATION}")
|
||||||
|
else:
|
||||||
|
logger.error("PROJECT_ID not found in environment variables")
|
||||||
|
|
||||||
# Get Firestore configuration from environment variables
|
# Get Firestore configuration from environment variables
|
||||||
FIRESTORE_PROJECT_ID = os.environ.get('FIRESTORE_PROJECT_ID')
|
FIRESTORE_PROJECT_ID = os.environ.get('FIRESTORE_PROJECT_ID')
|
||||||
@ -63,7 +71,7 @@ try:
|
|||||||
qdrant_client.create_collection(
|
qdrant_client.create_collection(
|
||||||
collection_name=QDRANT_COLLECTION,
|
collection_name=QDRANT_COLLECTION,
|
||||||
vectors_config=VectorParams(
|
vectors_config=VectorParams(
|
||||||
size=512, # Fixed size for image embeddings
|
size=1408, # Vertex AI multimodal embedding size
|
||||||
distance=Distance.COSINE
|
distance=Distance.COSINE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -161,7 +169,7 @@ def process_image(image_id: str, storage_path: str, team_id: str, retry_count: i
|
|||||||
# Download image data
|
# Download image data
|
||||||
image_data = blob.download_as_bytes()
|
image_data = blob.download_as_bytes()
|
||||||
|
|
||||||
# Generate embeddings using Google Cloud Vision
|
# Generate embeddings using Vertex AI
|
||||||
embeddings = generate_image_embeddings(image_data)
|
embeddings = generate_image_embeddings(image_data)
|
||||||
|
|
||||||
if embeddings is None:
|
if embeddings is None:
|
||||||
@ -178,7 +186,7 @@ def process_image(image_id: str, storage_path: str, team_id: str, retry_count: i
|
|||||||
'team_id': team_id,
|
'team_id': team_id,
|
||||||
'storage_path': storage_path,
|
'storage_path': storage_path,
|
||||||
'created_at': datetime.utcnow().isoformat(),
|
'created_at': datetime.utcnow().isoformat(),
|
||||||
'model': 'google-vision-v1'
|
'model': 'vertex-ai-multimodal'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create point for Qdrant
|
# Create point for Qdrant
|
||||||
@ -197,7 +205,7 @@ def process_image(image_id: str, storage_path: str, team_id: str, retry_count: i
|
|||||||
logger.info(f"Stored embeddings for image {image_id} in Qdrant with point ID {point_id}")
|
logger.info(f"Stored embeddings for image {image_id} in Qdrant with point ID {point_id}")
|
||||||
|
|
||||||
# Update Firestore with embedding info
|
# Update Firestore with embedding info
|
||||||
update_image_embedding_info(image_id, point_id, 'google-vision-v1')
|
update_image_embedding_info(image_id, point_id, 'vertex-ai-multimodal')
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -207,7 +215,7 @@ def process_image(image_id: str, storage_path: str, team_id: str, retry_count: i
|
|||||||
|
|
||||||
def generate_image_embeddings(image_data: bytes) -> Optional[np.ndarray]:
|
def generate_image_embeddings(image_data: bytes) -> Optional[np.ndarray]:
|
||||||
"""
|
"""
|
||||||
Generate image embeddings using Google Cloud Vision API
|
Generate image embeddings using Vertex AI multimodal embedding model
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
image_data: Binary image data
|
image_data: Binary image data
|
||||||
@ -216,88 +224,30 @@ def generate_image_embeddings(image_data: bytes) -> Optional[np.ndarray]:
|
|||||||
Numpy array of embeddings or None if failed
|
Numpy array of embeddings or None if failed
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Create Vision API image object
|
# Create Vertex AI image object
|
||||||
image = vision.Image(content=image_data)
|
vertex_image = VertexImage(image_data)
|
||||||
|
|
||||||
# Use object localization to get feature vectors
|
# Use multimodal embedding model to get embeddings
|
||||||
# This provides rich semantic information about the image
|
model = MultiModalEmbeddingModel.from_pretrained("multimodalembedding@001")
|
||||||
response = vision_client.object_localization(image=image)
|
embeddings = model.get_embeddings(image=vertex_image)
|
||||||
|
|
||||||
if response.error.message:
|
if embeddings is None or embeddings.image_embedding is None:
|
||||||
logger.error(f"Vision API error: {response.error.message}")
|
logger.error("Failed to generate embeddings - no image embedding returned")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Extract features from detected objects
|
# Get the image embedding vector
|
||||||
features = []
|
embedding_vector = embeddings.image_embedding
|
||||||
|
|
||||||
# Get object detection features
|
# Convert to numpy array
|
||||||
for obj in response.localized_object_annotations:
|
embeddings_array = np.array(embedding_vector, dtype=np.float32)
|
||||||
# Use object name and confidence as features
|
|
||||||
features.extend([
|
|
||||||
hash(obj.name) % 1000 / 1000.0, # Normalized hash of object name
|
|
||||||
obj.score, # Confidence score
|
|
||||||
obj.bounding_poly.normalized_vertices[0].x, # Bounding box features
|
|
||||||
obj.bounding_poly.normalized_vertices[0].y,
|
|
||||||
obj.bounding_poly.normalized_vertices[2].x - obj.bounding_poly.normalized_vertices[0].x, # Width
|
|
||||||
obj.bounding_poly.normalized_vertices[2].y - obj.bounding_poly.normalized_vertices[0].y, # Height
|
|
||||||
])
|
|
||||||
|
|
||||||
# Also get label detection for additional semantic information
|
|
||||||
label_response = vision_client.label_detection(image=image)
|
|
||||||
|
|
||||||
for label in label_response.label_annotations[:10]: # Top 10 labels
|
|
||||||
features.extend([
|
|
||||||
hash(label.description) % 1000 / 1000.0, # Normalized hash of label
|
|
||||||
label.score # Confidence score
|
|
||||||
])
|
|
||||||
|
|
||||||
# Get text detection for additional context
|
|
||||||
text_response = vision_client.text_detection(image=image)
|
|
||||||
|
|
||||||
if text_response.text_annotations:
|
|
||||||
# Add text features
|
|
||||||
text_content = text_response.text_annotations[0].description if text_response.text_annotations else ""
|
|
||||||
text_hash = hash(text_content.lower()) % 1000 / 1000.0
|
|
||||||
features.extend([text_hash, len(text_content) / 1000.0]) # Normalized text length
|
|
||||||
|
|
||||||
# Get face detection for additional features
|
|
||||||
face_response = vision_client.face_detection(image=image)
|
|
||||||
|
|
||||||
face_count = len(face_response.face_annotations)
|
|
||||||
features.append(min(face_count / 10.0, 1.0)) # Normalized face count
|
|
||||||
|
|
||||||
# Add image properties
|
|
||||||
try:
|
|
||||||
# Get image properties
|
|
||||||
properties_response = vision_client.image_properties(image=image)
|
|
||||||
|
|
||||||
if properties_response.image_properties_annotation:
|
|
||||||
# Add dominant colors as features
|
|
||||||
colors = properties_response.image_properties_annotation.dominant_colors.colors
|
|
||||||
for i, color in enumerate(colors[:5]): # Top 5 colors
|
|
||||||
features.extend([
|
|
||||||
color.color.red / 255.0,
|
|
||||||
color.color.green / 255.0,
|
|
||||||
color.color.blue / 255.0,
|
|
||||||
color.score
|
|
||||||
])
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Could not extract image properties: {e}")
|
|
||||||
|
|
||||||
# Pad or truncate to fixed size (512 dimensions)
|
|
||||||
target_size = 512
|
|
||||||
if len(features) < target_size:
|
|
||||||
features.extend([0.0] * (target_size - len(features)))
|
|
||||||
else:
|
|
||||||
features = features[:target_size]
|
|
||||||
|
|
||||||
# Normalize the feature vector
|
# Normalize the feature vector
|
||||||
features_array = np.array(features, dtype=np.float32)
|
norm = np.linalg.norm(embeddings_array)
|
||||||
norm = np.linalg.norm(features_array)
|
|
||||||
if norm > 0:
|
if norm > 0:
|
||||||
features_array = features_array / norm
|
embeddings_array = embeddings_array / norm
|
||||||
|
|
||||||
return features_array
|
logger.info(f"Generated embeddings with shape: {embeddings_array.shape}")
|
||||||
|
return embeddings_array
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error generating embeddings: {e}")
|
logger.error(f"Error generating embeddings: {e}")
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
functions-framework==3.4.0
|
functions-framework==3.4.0
|
||||||
google-cloud-vision==3.4.5
|
google-cloud-aiplatform==1.38.0
|
||||||
google-cloud-firestore==2.11.1
|
google-cloud-firestore==2.11.1
|
||||||
google-cloud-storage==2.12.0
|
google-cloud-storage==2.12.0
|
||||||
qdrant-client==1.7.0
|
qdrant-client==1.7.0
|
||||||
|
|||||||
107
deployment/cloud-function/test_vertex_ai_embeddings.py
Normal file
107
deployment/cloud-function/test_vertex_ai_embeddings.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Simple test script to verify Vertex AI multimodal embeddings work correctly.
|
||||||
|
Run this script to test the embedding generation before deploying.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Add the current directory to the path so we can import main
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# Set up logging
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def create_test_image():
|
||||||
|
"""Create a simple test image"""
|
||||||
|
# Create a simple 100x100 RGB image with a red square
|
||||||
|
img = Image.new('RGB', (100, 100), color='white')
|
||||||
|
pixels = img.load()
|
||||||
|
|
||||||
|
# Draw a red square in the center
|
||||||
|
for i in range(25, 75):
|
||||||
|
for j in range(25, 75):
|
||||||
|
pixels[i, j] = (255, 0, 0) # Red
|
||||||
|
|
||||||
|
# Convert to bytes
|
||||||
|
img_bytes = io.BytesIO()
|
||||||
|
img.save(img_bytes, format='PNG')
|
||||||
|
return img_bytes.getvalue()
|
||||||
|
|
||||||
|
def test_vertex_ai_embeddings():
|
||||||
|
"""Test Vertex AI embedding generation"""
|
||||||
|
try:
|
||||||
|
# Set required environment variables for testing
|
||||||
|
os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ.get('GOOGLE_CLOUD_PROJECT', 'your-project-id')
|
||||||
|
os.environ['VERTEX_AI_LOCATION'] = os.environ.get('VERTEX_AI_LOCATION', 'us-central1')
|
||||||
|
|
||||||
|
# Import the function we want to test
|
||||||
|
from main import generate_image_embeddings
|
||||||
|
|
||||||
|
# Create test image
|
||||||
|
logger.info("Creating test image...")
|
||||||
|
test_image_data = create_test_image()
|
||||||
|
logger.info(f"Created test image with {len(test_image_data)} bytes")
|
||||||
|
|
||||||
|
# Generate embeddings
|
||||||
|
logger.info("Generating embeddings using Vertex AI...")
|
||||||
|
embeddings = generate_image_embeddings(test_image_data)
|
||||||
|
|
||||||
|
if embeddings is None:
|
||||||
|
logger.error("Failed to generate embeddings!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Verify embeddings
|
||||||
|
logger.info(f"Generated embeddings with shape: {embeddings.shape}")
|
||||||
|
logger.info(f"Embeddings dtype: {embeddings.dtype}")
|
||||||
|
logger.info(f"Embeddings range: [{embeddings.min():.4f}, {embeddings.max():.4f}]")
|
||||||
|
logger.info(f"Embeddings norm: {np.linalg.norm(embeddings):.4f}")
|
||||||
|
|
||||||
|
# Basic validation
|
||||||
|
assert isinstance(embeddings, np.ndarray), "Embeddings should be numpy array"
|
||||||
|
assert embeddings.dtype == np.float32, "Embeddings should be float32"
|
||||||
|
assert len(embeddings.shape) == 1, "Embeddings should be 1D array"
|
||||||
|
assert embeddings.shape[0] == 1408, f"Expected 1408 dimensions, got {embeddings.shape[0]}"
|
||||||
|
|
||||||
|
# Check if normalized (should be close to 1.0)
|
||||||
|
norm = np.linalg.norm(embeddings)
|
||||||
|
assert 0.9 <= norm <= 1.1, f"Embeddings should be normalized, norm is {norm}"
|
||||||
|
|
||||||
|
logger.info("✅ All tests passed! Vertex AI embeddings are working correctly.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
|
logger.error(f"Import error: {e}")
|
||||||
|
logger.error("Make sure you have installed the required dependencies:")
|
||||||
|
logger.error("pip install google-cloud-aiplatform")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Test failed with error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logger.info("Testing Vertex AI multimodal embeddings...")
|
||||||
|
|
||||||
|
# Check if required environment variables are set
|
||||||
|
project_id = os.environ.get('GOOGLE_CLOUD_PROJECT')
|
||||||
|
if not project_id:
|
||||||
|
logger.error("Please set GOOGLE_CLOUD_PROJECT environment variable")
|
||||||
|
logger.error("Example: export GOOGLE_CLOUD_PROJECT=your-project-id")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logger.info(f"Using project: {project_id}")
|
||||||
|
|
||||||
|
success = test_vertex_ai_embeddings()
|
||||||
|
|
||||||
|
if success:
|
||||||
|
logger.info("🎉 Test completed successfully!")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
logger.error("❌ Test failed!")
|
||||||
|
sys.exit(1)
|
||||||
135
deployment/fix-cloud-run-deployment.sh
Normal file
135
deployment/fix-cloud-run-deployment.sh
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PROJECT_ID="gen-lang-client-0424120530"
|
||||||
|
REGION="us-central1"
|
||||||
|
SERVICE_NAME="sereact"
|
||||||
|
|
||||||
|
echo "=== Cloud Run Deployment Fix Script ==="
|
||||||
|
echo "Project: $PROJECT_ID"
|
||||||
|
echo "Region: $REGION"
|
||||||
|
echo "Service: $SERVICE_NAME"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to check if gcloud is authenticated
|
||||||
|
check_auth() {
|
||||||
|
if ! gcloud auth list --filter=status:ACTIVE --format="value(account)" | grep -q .; then
|
||||||
|
echo "ERROR: No active gcloud authentication found."
|
||||||
|
echo "Please run: gcloud auth login"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to clean up problematic revisions
|
||||||
|
cleanup_revisions() {
|
||||||
|
echo "Step 1: Cleaning up problematic revisions..."
|
||||||
|
|
||||||
|
# Get all revisions for the service
|
||||||
|
REVISIONS=$(gcloud run revisions list --service=$SERVICE_NAME --region=$REGION --project=$PROJECT_ID --format="value(metadata.name)" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -z "$REVISIONS" ]; then
|
||||||
|
echo "No revisions found or service doesn't exist."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Found revisions:"
|
||||||
|
echo "$REVISIONS"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Delete old revisions (keep the latest one for now)
|
||||||
|
REVISION_COUNT=$(echo "$REVISIONS" | wc -l)
|
||||||
|
if [ $REVISION_COUNT -gt 1 ]; then
|
||||||
|
echo "Deleting old revisions to prevent conflicts..."
|
||||||
|
echo "$REVISIONS" | head -n -1 | while read revision; do
|
||||||
|
if [ ! -z "$revision" ]; then
|
||||||
|
echo "Deleting revision: $revision"
|
||||||
|
gcloud run revisions delete "$revision" --region=$REGION --project=$PROJECT_ID --quiet || echo "Failed to delete $revision (may be in use)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to force a new deployment
|
||||||
|
force_redeploy() {
|
||||||
|
echo "Step 2: Forcing a new deployment with Terraform..."
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/terraform"
|
||||||
|
|
||||||
|
# Taint the Cloud Run service to force recreation
|
||||||
|
echo "Tainting Cloud Run service to force recreation..."
|
||||||
|
terraform taint google_cloud_run_service.sereact || echo "Service not in state or already tainted"
|
||||||
|
|
||||||
|
# Apply the configuration
|
||||||
|
echo "Applying Terraform configuration..."
|
||||||
|
terraform apply -auto-approve
|
||||||
|
|
||||||
|
cd - > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to verify deployment
|
||||||
|
verify_deployment() {
|
||||||
|
echo "Step 3: Verifying deployment..."
|
||||||
|
|
||||||
|
# Wait a moment for the service to be ready
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Check service status
|
||||||
|
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --region=$REGION --project=$PROJECT_ID --format="value(status.url)" 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ ! -z "$SERVICE_URL" ]; then
|
||||||
|
echo "✅ Service deployed successfully!"
|
||||||
|
echo "Service URL: $SERVICE_URL"
|
||||||
|
|
||||||
|
# Test the service
|
||||||
|
echo "Testing service health..."
|
||||||
|
if curl -s -o /dev/null -w "%{http_code}" "$SERVICE_URL/health" | grep -q "200"; then
|
||||||
|
echo "✅ Service is responding correctly!"
|
||||||
|
else
|
||||||
|
echo "⚠️ Service deployed but health check failed. Check logs:"
|
||||||
|
echo "gcloud logging read \"resource.type=cloud_run_revision AND resource.labels.service_name=$SERVICE_NAME\" --limit=10 --project=$PROJECT_ID"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ Service deployment failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
echo "Starting Cloud Run deployment fix..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
check_auth
|
||||||
|
cleanup_revisions
|
||||||
|
force_redeploy
|
||||||
|
verify_deployment
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Deployment Fix Complete ==="
|
||||||
|
echo "If you continue to have issues, try:"
|
||||||
|
echo "1. Building a new image: ./deployment/deploy.sh --deploy --build"
|
||||||
|
echo "2. Checking logs: gcloud logging read \"resource.type=cloud_run_revision AND resource.labels.service_name=$SERVICE_NAME\" --limit=10 --project=$PROJECT_ID"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Help function
|
||||||
|
show_help() {
|
||||||
|
echo "Usage: $0 [--help]"
|
||||||
|
echo ""
|
||||||
|
echo "This script fixes Cloud Run deployment issues by:"
|
||||||
|
echo "1. Cleaning up problematic revisions"
|
||||||
|
echo "2. Forcing a new deployment with Terraform"
|
||||||
|
echo "3. Verifying the deployment"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --help Show this help message"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
if [ "$1" = "--help" ]; then
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
@ -60,8 +60,9 @@ resource "google_cloudfunctions2_function" "image_processor" {
|
|||||||
# Google Cloud Storage configuration
|
# Google Cloud Storage configuration
|
||||||
GCS_BUCKET_NAME = var.storage_bucket_name
|
GCS_BUCKET_NAME = var.storage_bucket_name
|
||||||
|
|
||||||
# Google Cloud Vision API
|
# Vertex AI configuration
|
||||||
VISION_API_ENABLED = "true"
|
GOOGLE_CLOUD_PROJECT = var.project_id
|
||||||
|
VERTEX_AI_LOCATION = var.region
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
LOG_LEVEL = "INFO"
|
LOG_LEVEL = "INFO"
|
||||||
@ -97,9 +98,9 @@ resource "google_project_iam_member" "function_storage" {
|
|||||||
member = "serviceAccount:${local.cloud_function_service_account}"
|
member = "serviceAccount:${local.cloud_function_service_account}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "google_project_iam_member" "function_vision" {
|
resource "google_project_iam_member" "function_vertex_ai" {
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
role = "roles/ml.developer"
|
role = "roles/aiplatform.user"
|
||||||
member = "serviceAccount:${local.cloud_function_service_account}"
|
member = "serviceAccount:${local.cloud_function_service_account}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,8 @@ resource "google_project_service" "services" {
|
|||||||
"cloudfunctions.googleapis.com",
|
"cloudfunctions.googleapis.com",
|
||||||
"cloudbuild.googleapis.com",
|
"cloudbuild.googleapis.com",
|
||||||
"eventarc.googleapis.com",
|
"eventarc.googleapis.com",
|
||||||
"pubsub.googleapis.com"
|
"pubsub.googleapis.com",
|
||||||
|
"aiplatform.googleapis.com"
|
||||||
])
|
])
|
||||||
|
|
||||||
project = var.project_id
|
project = var.project_id
|
||||||
@ -63,10 +64,20 @@ resource "google_cloud_run_service" "sereact" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template {
|
template {
|
||||||
|
metadata {
|
||||||
|
annotations = {
|
||||||
|
"autoscaling.knative.dev/maxScale" = "10"
|
||||||
|
# Force Cloud Run to always pull the latest image
|
||||||
|
"run.googleapis.com/execution-environment" = "gen2"
|
||||||
|
# Disable CPU throttling for better performance
|
||||||
|
"run.googleapis.com/cpu-throttling" = "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spec {
|
spec {
|
||||||
containers {
|
containers {
|
||||||
# Use our optimized image
|
# Use our optimized image
|
||||||
image = "gcr.io/${var.project_id}/sereact-api:latest"
|
image = "gcr.io/${var.project_id}/sereact-api:${var.image_tag}"
|
||||||
|
|
||||||
ports {
|
ports {
|
||||||
container_port = 8000
|
container_port = 8000
|
||||||
@ -133,38 +144,6 @@ resource "google_cloud_run_service" "sereact" {
|
|||||||
name = "LOG_LEVEL"
|
name = "LOG_LEVEL"
|
||||||
value = "INFO"
|
value = "INFO"
|
||||||
}
|
}
|
||||||
|
|
||||||
# # CORS Configuration - These were missing!
|
|
||||||
# env {
|
|
||||||
# name = "CORS_ORIGINS"
|
|
||||||
# value = "[\"*\"]"
|
|
||||||
# }
|
|
||||||
|
|
||||||
# env {
|
|
||||||
# name = "CORS_METHODS"
|
|
||||||
# value = "GET,POST,PUT,DELETE,OPTIONS"
|
|
||||||
# }
|
|
||||||
|
|
||||||
# env {
|
|
||||||
# name = "CORS_HEADERS"
|
|
||||||
# value = "Content-Type,Authorization,X-Requested-With"
|
|
||||||
# }
|
|
||||||
|
|
||||||
# env {
|
|
||||||
# name = "CORS_EXPOSE_HEADERS"
|
|
||||||
# value = "Content-Length,Content-Range"
|
|
||||||
# }
|
|
||||||
|
|
||||||
# env {
|
|
||||||
# name = "CORS_MAX_AGE"
|
|
||||||
# value = "3600"
|
|
||||||
# }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata {
|
|
||||||
annotations = {
|
|
||||||
"autoscaling.knative.dev/maxScale" = "10"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"terraform_version": "1.10.1",
|
"terraform_version": "1.10.1",
|
||||||
"serial": 399,
|
"serial": 410,
|
||||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
"outputs": {
|
"outputs": {
|
||||||
"cloud_function_name": {
|
"cloud_function_name": {
|
||||||
@ -98,16 +98,16 @@
|
|||||||
"attributes": {
|
"attributes": {
|
||||||
"exclude_symlink_directories": null,
|
"exclude_symlink_directories": null,
|
||||||
"excludes": null,
|
"excludes": null,
|
||||||
"id": "045029ac803155784c12f8d587fee56b85b1fbe9",
|
"id": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||||
"output_base64sha256": "b/FgNMMT30JSXfrLRXNkWeNc6i22YAmT3YwQRTw1+A4=",
|
"output_base64sha256": "0wAfDV7tH41jEspQ3LBLvIEnrQ6XU2aEtK2GWsMdyCA=",
|
||||||
"output_base64sha512": "7GDDTkHwwQVAlwSxe7yzgtGccMNIRCQ7t72ZRk7bcfDI1tzpruhJ5G/0AbrUMXWQO6LffnWtwumQ7XdFHAIzBA==",
|
"output_base64sha512": "glsNAiHzSTOy9mGDckkSyDJhBVFDtLh8Xr6+hSxtCT8nok9qNGO+61iTRLU42OPxaPS/BrbDAXJeT86F3riefA==",
|
||||||
"output_file_mode": null,
|
"output_file_mode": null,
|
||||||
"output_md5": "34d81725abbd4f423de71ecd4215d116",
|
"output_md5": "a5d3a7fe131c972bf8d0edf309545042",
|
||||||
"output_path": "./function-source.zip",
|
"output_path": "./function-source.zip",
|
||||||
"output_sha": "045029ac803155784c12f8d587fee56b85b1fbe9",
|
"output_sha": "7a7a706b5bba3a12744f2dd109eb18de7112f351",
|
||||||
"output_sha256": "6ff16034c313df42525dfacb45736459e35cea2db6600993dd8c10453c35f80e",
|
"output_sha256": "d3001f0d5eed1f8d6312ca50dcb04bbc8127ad0e97536684b4ad865ac31dc820",
|
||||||
"output_sha512": "ec60c34e41f0c105409704b17bbcb382d19c70c34844243bb7bd99464edb71f0c8d6dce9aee849e46ff401bad43175903ba2df7e75adc2e990ed77451c023304",
|
"output_sha512": "825b0d0221f34933b2f66183724912c83261055143b4b87c5ebebe852c6d093f27a24f6a3463beeb589344b538d8e3f168f4bf06b6c301725e4fce85deb89e7c",
|
||||||
"output_size": 5014,
|
"output_size": 4487,
|
||||||
"source": [],
|
"source": [],
|
||||||
"source_content": null,
|
"source_content": null,
|
||||||
"source_content_filename": null,
|
"source_content_filename": null,
|
||||||
@ -170,11 +170,9 @@
|
|||||||
"run.googleapis.com/ingress": "all"
|
"run.googleapis.com/ingress": "all"
|
||||||
},
|
},
|
||||||
"effective_annotations": {
|
"effective_annotations": {
|
||||||
"run.googleapis.com/client-name": "gcloud",
|
|
||||||
"run.googleapis.com/client-version": "431.0.0",
|
|
||||||
"run.googleapis.com/ingress": "all",
|
"run.googleapis.com/ingress": "all",
|
||||||
"run.googleapis.com/ingress-status": "all",
|
"run.googleapis.com/ingress-status": "all",
|
||||||
"run.googleapis.com/operation-id": "e4d7484f-39e4-4dde-8105-28d285eb927b",
|
"run.googleapis.com/operation-id": "7869f742-fe94-42d0-8d82-a1462681980d",
|
||||||
"run.googleapis.com/urls": "[\"https://sereact-761163285547.us-central1.run.app\",\"https://sereact-p64zpdtkta-uc.a.run.app\"]",
|
"run.googleapis.com/urls": "[\"https://sereact-761163285547.us-central1.run.app\",\"https://sereact-p64zpdtkta-uc.a.run.app\"]",
|
||||||
"serving.knative.dev/creator": "johnpccd3@gmail.com",
|
"serving.knative.dev/creator": "johnpccd3@gmail.com",
|
||||||
"serving.knative.dev/lastModifier": "johnpccd3@gmail.com"
|
"serving.knative.dev/lastModifier": "johnpccd3@gmail.com"
|
||||||
@ -183,15 +181,15 @@
|
|||||||
"cloud.googleapis.com/location": "us-central1",
|
"cloud.googleapis.com/location": "us-central1",
|
||||||
"goog-terraform-provisioned": "true"
|
"goog-terraform-provisioned": "true"
|
||||||
},
|
},
|
||||||
"generation": 2,
|
"generation": 1,
|
||||||
"labels": {},
|
"labels": null,
|
||||||
"namespace": "gen-lang-client-0424120530",
|
"namespace": "gen-lang-client-0424120530",
|
||||||
"resource_version": "AAY16Gy+yWQ",
|
"resource_version": "AAY16UbSm4k",
|
||||||
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
"self_link": "/apis/serving.knative.dev/v1/namespaces/761163285547/services/sereact",
|
||||||
"terraform_labels": {
|
"terraform_labels": {
|
||||||
"goog-terraform-provisioned": "true"
|
"goog-terraform-provisioned": "true"
|
||||||
},
|
},
|
||||||
"uid": "c67276c9-0c25-4a6c-8f39-4ea942599769"
|
"uid": "d5532269-ab10-4b77-b90f-698306bf0919"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "sereact",
|
"name": "sereact",
|
||||||
@ -218,14 +216,14 @@
|
|||||||
"type": "RoutesReady"
|
"type": "RoutesReady"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"latest_created_revision_name": "sereact-00002-cew",
|
"latest_created_revision_name": "sereact-00001-9rv",
|
||||||
"latest_ready_revision_name": "sereact-00002-cew",
|
"latest_ready_revision_name": "sereact-00001-9rv",
|
||||||
"observed_generation": 2,
|
"observed_generation": 1,
|
||||||
"traffic": [
|
"traffic": [
|
||||||
{
|
{
|
||||||
"latest_revision": true,
|
"latest_revision": true,
|
||||||
"percent": 100,
|
"percent": 100,
|
||||||
"revision_name": "sereact-00002-cew",
|
"revision_name": "sereact-00001-9rv",
|
||||||
"tag": "",
|
"tag": "",
|
||||||
"url": ""
|
"url": ""
|
||||||
}
|
}
|
||||||
@ -239,14 +237,14 @@
|
|||||||
{
|
{
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"autoscaling.knative.dev/maxScale": "10",
|
"autoscaling.knative.dev/maxScale": "10",
|
||||||
"run.googleapis.com/client-name": "gcloud",
|
"run.googleapis.com/cpu-throttling": "false",
|
||||||
"run.googleapis.com/client-version": "431.0.0"
|
"run.googleapis.com/execution-environment": "gen2"
|
||||||
},
|
},
|
||||||
"generation": 0,
|
"generation": 0,
|
||||||
"labels": {
|
"labels": {
|
||||||
"run.googleapis.com/startupProbeType": "Default"
|
"run.googleapis.com/startupProbeType": "Default"
|
||||||
},
|
},
|
||||||
"name": "sereact-00002-cew",
|
"name": "",
|
||||||
"namespace": "",
|
"namespace": "",
|
||||||
"resource_version": "",
|
"resource_version": "",
|
||||||
"self_link": "",
|
"self_link": "",
|
||||||
@ -258,8 +256,8 @@
|
|||||||
"container_concurrency": 80,
|
"container_concurrency": 80,
|
||||||
"containers": [
|
"containers": [
|
||||||
{
|
{
|
||||||
"args": [],
|
"args": null,
|
||||||
"command": [],
|
"command": null,
|
||||||
"env": [
|
"env": [
|
||||||
{
|
{
|
||||||
"name": "FIRESTORE_DATABASE_NAME",
|
"name": "FIRESTORE_DATABASE_NAME",
|
||||||
@ -334,7 +332,7 @@
|
|||||||
"cpu": "1",
|
"cpu": "1",
|
||||||
"memory": "1Gi"
|
"memory": "1Gi"
|
||||||
},
|
},
|
||||||
"requests": {}
|
"requests": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"startup_probe": [
|
"startup_probe": [
|
||||||
@ -356,7 +354,7 @@
|
|||||||
"working_dir": ""
|
"working_dir": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"node_selector": {},
|
"node_selector": null,
|
||||||
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
"service_account_name": "761163285547-compute@developer.gserviceaccount.com",
|
||||||
"serving_state": "",
|
"serving_state": "",
|
||||||
"timeout_seconds": 300,
|
"timeout_seconds": 300,
|
||||||
@ -437,7 +435,7 @@
|
|||||||
"schema_version": 0,
|
"schema_version": 0,
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"condition": [],
|
"condition": [],
|
||||||
"etag": "BwY16Etxb+g=",
|
"etag": "BwY16UdHJ00=",
|
||||||
"id": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact/roles/run.invoker/allUsers",
|
"id": "v1/projects/gen-lang-client-0424120530/locations/us-central1/services/sereact/roles/run.invoker/allUsers",
|
||||||
"location": "us-central1",
|
"location": "us-central1",
|
||||||
"member": "allUsers",
|
"member": "allUsers",
|
||||||
@ -471,7 +469,7 @@
|
|||||||
"automatic_update_policy": [
|
"automatic_update_policy": [
|
||||||
{}
|
{}
|
||||||
],
|
],
|
||||||
"build": "projects/761163285547/locations/us-central1/builds/1b8e28d1-ee4d-4d2f-acf2-47e2b03aa421",
|
"build": "projects/761163285547/locations/us-central1/builds/b2b7e513-e00e-462a-8ac8-94abdfb4a0b9",
|
||||||
"docker_repository": "projects/gen-lang-client-0424120530/locations/us-central1/repositories/gcf-artifacts",
|
"docker_repository": "projects/gen-lang-client-0424120530/locations/us-central1/repositories/gcf-artifacts",
|
||||||
"entry_point": "process_image_embedding",
|
"entry_point": "process_image_embedding",
|
||||||
"environment_variables": {},
|
"environment_variables": {},
|
||||||
@ -485,7 +483,7 @@
|
|||||||
{
|
{
|
||||||
"bucket": "gen-lang-client-0424120530-cloud-function-source",
|
"bucket": "gen-lang-client-0424120530-cloud-function-source",
|
||||||
"generation": 1748123369545880,
|
"generation": 1748123369545880,
|
||||||
"object": "function-source-34d81725abbd4f423de71ecd4215d116.zip"
|
"object": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -554,7 +552,7 @@
|
|||||||
"goog-terraform-provisioned": "true"
|
"goog-terraform-provisioned": "true"
|
||||||
},
|
},
|
||||||
"timeouts": null,
|
"timeouts": null,
|
||||||
"update_time": "2025-05-24T22:08:16.899711009Z",
|
"update_time": "2025-05-24T22:31:52.525335119Z",
|
||||||
"url": "https://us-central1-gen-lang-client-0424120530.cloudfunctions.net/process-image-embedding"
|
"url": "https://us-central1-gen-lang-client-0424120530.cloudfunctions.net/process-image-embedding"
|
||||||
},
|
},
|
||||||
"sensitive_attributes": [
|
"sensitive_attributes": [
|
||||||
@ -870,8 +868,8 @@
|
|||||||
"database_edition": "STANDARD",
|
"database_edition": "STANDARD",
|
||||||
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
||||||
"deletion_policy": "ABANDON",
|
"deletion_policy": "ABANDON",
|
||||||
"earliest_version_time": "2025-05-24T21:16:19.051906Z",
|
"earliest_version_time": "2025-05-24T21:29:52.924798Z",
|
||||||
"etag": "INn0mIORvY0DMKrW4vCEvY0D",
|
"etag": "IPHgo4eUvY0DMKrW4vCEvY0D",
|
||||||
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
||||||
"key_prefix": "",
|
"key_prefix": "",
|
||||||
"location_id": "us-central1",
|
"location_id": "us-central1",
|
||||||
@ -1495,21 +1493,21 @@
|
|||||||
"content_encoding": "",
|
"content_encoding": "",
|
||||||
"content_language": "",
|
"content_language": "",
|
||||||
"content_type": "application/zip",
|
"content_type": "application/zip",
|
||||||
"crc32c": "YXAlNA==",
|
"crc32c": "Y4Q5hw==",
|
||||||
"customer_encryption": [],
|
"customer_encryption": [],
|
||||||
"detect_md5hash": "NNgXJau9T0I95x7NQhXRFg==",
|
"detect_md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||||
"event_based_hold": false,
|
"event_based_hold": false,
|
||||||
"generation": 1748124439573408,
|
"generation": 1748125796837241,
|
||||||
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
"id": "gen-lang-client-0424120530-cloud-function-source-function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||||
"kms_key_name": "",
|
"kms_key_name": "",
|
||||||
"md5hash": "NNgXJau9T0I95x7NQhXRFg==",
|
"md5hash": "pdOn/hMclyv40O3zCVRQQg==",
|
||||||
"md5hexhash": "34d81725abbd4f423de71ecd4215d116",
|
"md5hexhash": "a5d3a7fe131c972bf8d0edf309545042",
|
||||||
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-34d81725abbd4f423de71ecd4215d116.zip?generation=1748124439573408\u0026alt=media",
|
"media_link": "https://storage.googleapis.com/download/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip?generation=1748125796837241\u0026alt=media",
|
||||||
"metadata": {},
|
"metadata": null,
|
||||||
"name": "function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
"name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||||
"output_name": "function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
"output_name": "function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||||
"retention": [],
|
"retention": [],
|
||||||
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-34d81725abbd4f423de71ecd4215d116.zip",
|
"self_link": "https://www.googleapis.com/storage/v1/b/gen-lang-client-0424120530-cloud-function-source/o/function-source-a5d3a7fe131c972bf8d0edf309545042.zip",
|
||||||
"source": "./function-source.zip",
|
"source": "./function-source.zip",
|
||||||
"storage_class": "STANDARD",
|
"storage_class": "STANDARD",
|
||||||
"temporary_hold": false,
|
"temporary_hold": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"terraform_version": "1.10.1",
|
"terraform_version": "1.10.1",
|
||||||
"serial": 397,
|
"serial": 404,
|
||||||
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
"lineage": "a183cd95-f987-8698-c6dd-84e933c394a5",
|
||||||
"outputs": {
|
"outputs": {
|
||||||
"cloud_function_name": {
|
"cloud_function_name": {
|
||||||
@ -239,8 +239,8 @@
|
|||||||
{
|
{
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"autoscaling.knative.dev/maxScale": "10",
|
"autoscaling.knative.dev/maxScale": "10",
|
||||||
"run.googleapis.com/client-name": "gcloud",
|
"run.googleapis.com/cpu-throttling": "false",
|
||||||
"run.googleapis.com/client-version": "431.0.0"
|
"run.googleapis.com/execution-environment": "gen2"
|
||||||
},
|
},
|
||||||
"generation": 0,
|
"generation": 0,
|
||||||
"labels": {
|
"labels": {
|
||||||
@ -598,6 +598,13 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mode": "managed",
|
||||||
|
"type": "google_compute_address",
|
||||||
|
"name": "vector_db_static_ip",
|
||||||
|
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mode": "managed",
|
"mode": "managed",
|
||||||
"type": "google_compute_firewall",
|
"type": "google_compute_firewall",
|
||||||
@ -804,6 +811,12 @@
|
|||||||
"zone": "us-central1-a"
|
"zone": "us-central1-a"
|
||||||
},
|
},
|
||||||
"sensitive_attributes": [
|
"sensitive_attributes": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "get_attr",
|
||||||
|
"value": "metadata_startup_script"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"type": "get_attr",
|
"type": "get_attr",
|
||||||
@ -837,12 +850,6 @@
|
|||||||
"type": "get_attr",
|
"type": "get_attr",
|
||||||
"value": "disk_encryption_key_raw"
|
"value": "disk_encryption_key_raw"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"type": "get_attr",
|
|
||||||
"value": "metadata_startup_script"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiNiJ9",
|
"private": "eyJlMmJmYjczMC1lY2FhLTExZTYtOGY4OC0zNDM2M2JjN2M0YzAiOnsiY3JlYXRlIjoxMjAwMDAwMDAwMDAwLCJkZWxldGUiOjEyMDAwMDAwMDAwMDAsInVwZGF0ZSI6MTIwMDAwMDAwMDAwMH0sInNjaGVtYV92ZXJzaW9uIjoiNiJ9",
|
||||||
@ -870,8 +877,8 @@
|
|||||||
"database_edition": "STANDARD",
|
"database_edition": "STANDARD",
|
||||||
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
"delete_protection_state": "DELETE_PROTECTION_DISABLED",
|
||||||
"deletion_policy": "ABANDON",
|
"deletion_policy": "ABANDON",
|
||||||
"earliest_version_time": "2025-05-24T21:15:22.382696Z",
|
"earliest_version_time": "2025-05-24T21:26:23.088753Z",
|
||||||
"etag": "IPeLluiQvY0DMKrW4vCEvY0D",
|
"etag": "IOqynKOTvY0DMKrW4vCEvY0D",
|
||||||
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
"id": "projects/gen-lang-client-0424120530/databases/sereact-imagedb",
|
||||||
"key_prefix": "",
|
"key_prefix": "",
|
||||||
"location_id": "us-central1",
|
"location_id": "us-central1",
|
||||||
|
|||||||
@ -80,4 +80,10 @@ variable "use_static_ip" {
|
|||||||
description = "Whether to use a static IP for the vector database VM"
|
description = "Whether to use a static IP for the vector database VM"
|
||||||
type = bool
|
type = bool
|
||||||
default = false
|
default = false
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "image_tag" {
|
||||||
|
description = "The Docker image tag for the Cloud Run service"
|
||||||
|
type = string
|
||||||
|
default = "latest"
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user