This commit is contained in:
johnpccd 2025-05-25 00:32:06 +02:00
parent c00f0e641f
commit 38d5cb8d98
9 changed files with 358 additions and 175 deletions

View File

@ -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}")

View File

@ -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

View 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)

View 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

View File

@ -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}"
} }

View File

@ -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"
} }
} }
} }

View File

@ -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,

View File

@ -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",

View File

@ -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"
} }