Skip to content

Commit 8a3ddbd

Browse files
committed
fix versions
1 parent 2d58802 commit 8a3ddbd

4 files changed

Lines changed: 642 additions & 40 deletions

File tree

pipeline.yaml

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ deploymentSpec:
255255
\ '--no-deps' 'typing-extensions>=3.7.4,<5; python_version<\"3.9\"' &&\
256256
\ python3 -m pip install --quiet --no-warn-script-location 'google-cloud-aiplatform>=1.59.0'\
257257
\ 'google-cloud-run>=0.10.0' 'google-cloud-storage>=2.10.0' 'requests>=2.31.0'\
258-
\ 'joblib>=1.4.2' && \"$0\" \"$@\"\n"
258+
\ 'joblib>=1.4.2' 'scikit-learn>=1.3.0' 'pandas>=2.0.0' 'numpy>=1.24.0'\
259+
\ && \"$0\" \"$@\"\n"
259260
- sh
260261
- -ec
261262
- 'program_path=$(mktemp -d)
@@ -270,30 +271,46 @@ deploymentSpec:
270271
\ *\n\ndef deploy_blessed_model_to_fastapi(\n project_id: str,\n location:\
271272
\ str,\n model_name: str,\n service_name: str,\n service_endpoint:\
272273
\ Output[Artifact]\n):\n from google.cloud import aiplatform, aiplatform_v1,\
273-
\ run_v2, storage\n import joblib\n import tempfile\n import os\n\
274-
\ import requests\n import time\n\n print(f\"Starting FastAPI deployment\
275-
\ for blessed model: {model_name}\")\n print(f\"Service name: {service_name}\"\
276-
)\n\n # 1. Initialize Vertex AI and find blessed model\n aiplatform.init(project=project_id,\
277-
\ location=location)\n\n client = aiplatform_v1.ModelServiceClient(\n\
278-
\ client_options={\"api_endpoint\": f\"{location}-aiplatform.googleapis.com\"\
279-
}\n )\n request = {\n \"parent\": f\"projects/{project_id}/locations/{location}\"\
280-
,\n \"filter\": f\"display_name={model_name}\"\n }\n\n models\
281-
\ = list(client.list_models(request=request))\n blessed_model = None\n\
282-
\n print(f\"Found {len(models)} models with name {model_name}\")\n\n\
283-
\ for model in models:\n print(f\"Model: {model.name}, Aliases:\
284-
\ {list(model.version_aliases)}\")\n if \"blessed\" in model.version_aliases:\n\
285-
\ blessed_model = model\n break\n\n if not blessed_model:\n\
286-
\ raise ValueError(f\"No blessed version found for model {model_name}.\
287-
\ Available models: {[(m.name, list(m.version_aliases)) for m in models]}\"\
288-
)\n\n print(f\"Found blessed model: {blessed_model.name}\")\n print(f\"\
289-
Model URI: {blessed_model.artifact_uri}\")\n\n # 2. Download joblib model\
290-
\ from blessed version\n gcs_uri = blessed_model.artifact_uri\n if\
291-
\ not gcs_uri.startswith('gs://'):\n raise ValueError(f\"Expected\
292-
\ GCS URI, got: {gcs_uri}\")\n\n bucket_name = gcs_uri.replace('gs://',\
293-
\ '').split('/')[0]\n model_path = '/'.join(gcs_uri.replace('gs://',\
294-
\ '').split('/')[1:])\n\n print(f\"Downloading model from gs://{bucket_name}/{model_path}\"\
295-
)\n\n storage_client = storage.Client()\n bucket = storage_client.bucket(bucket_name)\n\
296-
\n # Download and validate the model\n model_blob_path = f\"{model_path}/model.joblib\"\
274+
\ run_v2, storage\n from google.auth import default\n import joblib\n\
275+
\ import tempfile\n import os\n import requests\n import time\n\
276+
\n print(f\"Starting FastAPI deployment for blessed model: {model_name}\"\
277+
)\n print(f\"Service name: {service_name}\")\n\n # 1. Initialize Vertex\
278+
\ AI and get credentials\n aiplatform.init(project=project_id, location=location)\n\
279+
\n # Get default credentials\n credentials, _ = default()\n print(credentials)\n\
280+
\n # Create client with explicit credentials\n client = aiplatform_v1.ModelServiceClient(\n\
281+
\ credentials=credentials,\n client_options={\"api_endpoint\"\
282+
: f\"{location}-aiplatform.googleapis.com\"}\n )\n\n print(f\"Searching\
283+
\ for blessed model with name: {model_name}\")\n\n # Use the high-level\
284+
\ aiplatform library to list all model versions\n # models = aiplatform.Model.list(filter=f\"\
285+
display_name={model_name}\")\n # blessed_model = None\n\n request\
286+
\ = {\n \"parent\": f\"projects/{project_id}/locations/{location}\"\
287+
,\n \"filter\": f\"display_name={model_name}\"\n }\n\n\
288+
\ models = list(client.list_models(request=request))\n blessed_model\
289+
\ = None\n\n print(f\"Found {len(models)} model versions with name {model_name}\"\
290+
)\n\n # Search through all model versions (each item in models is already\
291+
\ a version)\n for parent_model in models:\n print(f\"Checking\
292+
\ parent model: {parent_model.name}\")\n\n # List all versions of\
293+
\ this model\n versions_request = {\"name\": parent_model.name}\n\
294+
\ versions = list(client.list_model_versions(request=versions_request))\n\
295+
\n print(f\"Found {len(versions)} versions for this model\")\n\n\
296+
\ for version in versions:\n print(f\"Version {version.version_id}:\
297+
\ Aliases = {list(version.version_aliases)}\")\n if \"blessed\"\
298+
\ in version.version_aliases:\n blessed_model = version\n\
299+
\ print(f\"Found blessed version: {version.version_id}\"\
300+
)\n break\n\n if blessed_model:\n break\n\
301+
\n if not blessed_model:\n available_versions = [(m.resource_name,\
302+
\ m.version_id, list(m.version_aliases)) for m in models]\n raise\
303+
\ ValueError(f\"No blessed version found for model {model_name}. Available\
304+
\ versions: {available_versions}\")\n\n print(f\"Found blessed model:\
305+
\ {blessed_model.name}\")\n print(f\"Model URI: {blessed_model.artifact_uri}\"\
306+
)\n\n # 2. Download joblib model from blessed version\n gcs_uri =\
307+
\ blessed_model.artifact_uri\n if not gcs_uri.startswith('gs://'):\n\
308+
\ raise ValueError(f\"Expected GCS URI, got: {gcs_uri}\")\n\n \
309+
\ bucket_name = gcs_uri.replace('gs://', '').split('/')[0]\n model_path\
310+
\ = '/'.join(gcs_uri.replace('gs://', '').split('/')[1:])\n\n print(f\"\
311+
Downloading model from gs://{bucket_name}/{model_path}\")\n\n storage_client\
312+
\ = storage.Client()\n bucket = storage_client.bucket(bucket_name)\n\n\
313+
\ # Download and validate the model\n model_blob_path = f\"{model_path}/model.joblib\"\
297314
\n blob = bucket.blob(model_blob_path)\n\n if not blob.exists():\n\
298315
\ raise ValueError(f\"Model file not found at gs://{bucket_name}/{model_blob_path}\"\
299316
)\n\n with tempfile.NamedTemporaryFile(suffix='.joblib', delete=False)\

src/ml_pipelines_kfp/iris_xgboost/pipelines/components/deploy.py

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from kfp.dsl import Input, Model, component, Artifact, Output
2-
from ml_pipelines_kfp.iris_xgboost.constants import IMAGE_NAME, FASTAPI_IMAGE_NAME, BUCKET, PROJECT_ID
2+
from ml_pipelines_kfp.iris_xgboost.constants import IMAGE_NAME
33

44
@component(
55
base_image=IMAGE_NAME,
@@ -8,17 +8,22 @@
88
"google-cloud-run>=0.10.0",
99
"google-cloud-storage>=2.10.0",
1010
"requests>=2.31.0",
11-
"joblib>=1.4.2"
11+
"joblib>=1.4.2",
12+
"scikit-learn>=1.3.0",
13+
"pandas>=2.0.0",
14+
"numpy>=1.24.0"
1215
]
1316
)
1417
def deploy_blessed_model_to_fastapi(
1518
project_id: str,
1619
location: str,
1720
model_name: str,
1821
service_name: str,
22+
fastapi_image_name: str,
1923
service_endpoint: Output[Artifact]
2024
):
2125
from google.cloud import aiplatform, aiplatform_v1, run_v2, storage
26+
from google.auth import default
2227
import joblib
2328
import tempfile
2429
import os
@@ -28,30 +33,58 @@ def deploy_blessed_model_to_fastapi(
2833
print(f"Starting FastAPI deployment for blessed model: {model_name}")
2934
print(f"Service name: {service_name}")
3035

31-
# 1. Initialize Vertex AI and find blessed model
36+
# 1. Initialize Vertex AI and get credentials
3237
aiplatform.init(project=project_id, location=location)
3338

39+
# Get default credentials
40+
credentials, _ = default()
41+
print(credentials)
42+
43+
# Create client with explicit credentials
3444
client = aiplatform_v1.ModelServiceClient(
45+
credentials=credentials,
3546
client_options={"api_endpoint": f"{location}-aiplatform.googleapis.com"}
3647
)
48+
49+
print(f"Searching for blessed model with name: {model_name}")
50+
51+
# Use the high-level aiplatform library to list all model versions
52+
# models = aiplatform.Model.list(filter=f"display_name={model_name}")
53+
# blessed_model = None
54+
3755
request = {
38-
"parent": f"projects/{project_id}/locations/{location}",
39-
"filter": f"display_name={model_name}"
40-
}
56+
"parent": f"projects/{project_id}/locations/{location}",
57+
"filter": f"display_name={model_name}"
58+
}
4159

4260
models = list(client.list_models(request=request))
4361
blessed_model = None
4462

45-
print(f"Found {len(models)} models with name {model_name}")
63+
print(f"Found {len(models)} model versions with name {model_name}")
4664

47-
for model in models:
48-
print(f"Model: {model.name}, Aliases: {list(model.version_aliases)}")
49-
if "blessed" in model.version_aliases:
50-
blessed_model = model
65+
# Search through all model versions (each item in models is already a version)
66+
for parent_model in models:
67+
print(f"Checking parent model: {parent_model.name}")
68+
69+
# List all versions of this model
70+
versions_request = {"name": parent_model.name}
71+
versions = list(client.list_model_versions(request=versions_request))
72+
73+
print(f"Found {len(versions)} versions for this model")
74+
75+
for version in versions:
76+
print(f"Version {version.version_id}: Aliases = {list(version.version_aliases)}")
77+
if "blessed" in version.version_aliases:
78+
blessed_model = version
79+
print(f"Found blessed version: {version.version_id}")
80+
break
81+
82+
if blessed_model:
5183
break
5284

5385
if not blessed_model:
54-
raise ValueError(f"No blessed version found for model {model_name}. Available models: {[(m.name, list(m.version_aliases)) for m in models]}")
86+
available_versions = [(m.resource_name, m.version_id, list(m.version_aliases)) for m in models]
87+
raise ValueError(f"No blessed version found for model {model_name}. Available versions: {available_versions}")
5588

5689
print(f"Found blessed model: {blessed_model.name}")
5790
print(f"Model URI: {blessed_model.artifact_uri}")
@@ -107,7 +140,7 @@ def deploy_blessed_model_to_fastapi(
107140
run_client = run_v2.ServicesClient()
108141

109142
# Use pre-built generic FastAPI image from CI/CD
110-
generic_image = FASTAPI_IMAGE_NAME
143+
generic_image = fastapi_image_name
111144

112145
service_config = {
113146
"parent": f"projects/{project_id}/locations/{location}",

src/ml_pipelines_kfp/iris_xgboost/pipelines/iris_pipeline_training.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from google.oauth2 import service_account
66
from ml_pipelines_kfp.iris_xgboost.constants import (
77
PIPELINE_NAME, REPO_ROOT, PIPELINE_ROOT, MODEL_NAME, IMAGE_NAME, SERVICE_ACCOUNT_PATH,
8-
PROJECT_ID, REGION, SERVICE_ACCOUNT, ENDPOINT_NAME, BQ_DATASET, BQ_TABLE)
8+
PROJECT_ID, REGION, SERVICE_ACCOUNT, ENDPOINT_NAME, BQ_DATASET, BQ_TABLE, FASTAPI_IMAGE_NAME)
99

1010
@kfp.dsl.pipeline(name=PIPELINE_NAME, pipeline_root=PIPELINE_ROOT)
1111
def pipeline(project_id: str, location: str, bq_dataset: str, bq_table: str):
@@ -52,7 +52,8 @@ def pipeline(project_id: str, location: str, bq_dataset: str, bq_table: str):
5252
project_id=project_id,
5353
location=location,
5454
model_name=MODEL_NAME,
55-
service_name=f"{MODEL_NAME.lower().replace('_', '-')}-service"
55+
service_name=f"{MODEL_NAME.lower().replace('_', '-')}-service",
56+
fastapi_image_name=FASTAPI_IMAGE_NAME
5657
).set_display_name("Deploy Blessed Model to FastAPI").after(upload_model_op)
5758

5859

0 commit comments

Comments
 (0)