<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <table align="left">
  <td>
    <a href="https
Step1:  Restart the kernel
After you install the additional packages, you need to restart the notebook kernel so it can find the packages.
Step2:  Before you begin
Set up your Google Cloud project
The following steps are required, regardless of your notebook environment.
Select or create a Google Cloud project. When you first create an account, you get a $300 free credit towards your compute/storage costs.
Make sure that billing is enabled for your project.
Enable the Vertex API.
Enable the Compute Engine API.
If you are running this notebook locally, you will need to install the Cloud SDK.
Enter your project ID in the cell below. Then run the cell to make sure the
Cloud SDK uses the right project for all the commands in this notebook.
Note
Step3:  Otherwise, set your project ID here.
Step4:  Authenticate your Google Cloud account
If you are using Vertex AI Workbench notebooks, your environment is already
authenticated. Skip this step.
If you are using Colab, run the cell below and follow the instructions
when prompted to authenticate your account via oAuth.
Otherwise, follow these steps
Step5:  Create a Cloud Storage bucket
The following steps are required, regardless of your notebook environment.
To update your model artifacts without re-building the container, you must upload your model
artifacts and any custom code to Cloud Storage.
Set the name of your Cloud Storage bucket below. It must be unique across all
Cloud Storage buckets.
Step6:  Only if your bucket doesn't already exist
Step7:  Finally, validate access to your Cloud Storage bucket by examining its contents
Step8:  Create a directory for all your model artifacts
Step9:  Configure model, repository, and artifact names
Step10:  MODEL_ARTIFACT_DIR - Folder directory path to your model artifacts within a Cloud Storage bucket, for example
Step12:  Train and store the model locally
Next, we define a function to train time series models using fbprophet for a few sales categories. 
We're also adding a regressor to allow 2 different types of forecasts. One that only uses sales, and another that takes the weather as an additional regressor (https
Step15:  Train additional models that use the weather as a regressor
The query for the regressor retrieves 2 years of weather data, and uses a moving average to generate 100 future weather data points
Step16:  Train a model for two sample categories (Canadian Whiskies and American Vodkas)
This model uses only the Iowa liquor sales data as input
Step17:  Train a model for the same sample categories (Canadian Whiskies and American Vodkas)
This model uses only the Iowa liquor sales data, and an additional regressor to account for the impact of weather. As mentioned before, the regressor must be known for both the history and future dates. In the query for the regressor data, a moving average was used to calculate the future weather data
More info on regressors can be found here
Step18:  Upload model artifacts and custom code to Cloud Storage
Before you can deploy your model for serving, Vertex needs access to the following files in Cloud Storage
Step19:  Local model testing
Review the trained FB Prophet models with and without the regressor in the sections below
Step20:  Test model with regressor
Step21:  Build a FastAPI server
Step22:  Add pre-start script
FastAPI will execute this script before starting up the server. The PORT environment variable is set to equal AIP_HTTP_PORT in order to run FastAPI on same the port expected by Vertex AI Prediction.
Step23:  Store test instances to use later
To learn more about formatting input instances in JSON, read the documentation.
Step24:  Build and push container to Artifact Registry
Write the Dockerfile, using tiangolo/uvicorn-gunicorn-fastapi as a base image. This will automatically run FastAPI for you using Gunicorn and Uvicorn. Visit the FastAPI docs to read more about deploying FastAPI with Docker.
Step25:  Build the image and tag the Artifact Registry path that you will push to.
Initial FB prophet install will fail, but eventually will install. This is a known bug
Step26:  Run and test the container locally (optional)
Run the container locally in detached mode and provide the environment variables that the container requires. These env vars will be provided to the container by Vertex AI Prediction once deployed. Test the /health and /predict routes, then stop the running image.
Step27:  Test without regressor
Step28:  Push the container to artifact registry
Configure Docker to access Artifact Registry. Then push your container image to your Artifact Registry repository.
Make sure to enable the Artifact Registry API here if you haven't already
Step29:  Run this once to create the artifact repository
Step30:  Deploy to Vertex AI
Use the Python SDK to upload and deploy your model.
Step31:  Deploy the model endpoint
After this step completes, the model is deployed and ready for online prediction.
Step32:  Send predictions
Using Python SDK
Step33:  Using REST
Step34:  Using gcloud CLI
Step35:  Cleaning up
To clean up all Google Cloud resources used in this project, you can delete the Google Cloud
project you used for the tutorial.
Otherwise, you can delete the individual resources you created in this tutorial
<ASSISTANT_TASK:>
Python Code:
import os
# The Google Cloud Notebook product has specific requirements
IS_GOOGLE_CLOUD_NOTEBOOK = os.path.exists("/opt/deeplearning/metadata/env_version")
# Google Cloud Notebook requires dependencies to be installed with '--user'
USER_FLAG = ""
if IS_GOOGLE_CLOUD_NOTEBOOK:
    USER_FLAG = "--user"
%%writefile requirements.txt
joblib~=1.0
numpy~=1.20
google-cloud-storage>=1.26.0,<2.0.0dev
#new files for this example
pystan==2.19.1.1
pandas==1.0.5
plotly==4.8.2
# Required in Docker serving container
%pip install {USER_FLAG} --upgrade pip
%pip install {USER_FLAG} -r requirements.txt
# fbprophet requires a second install
%pip install {USER_FLAG} fbprophet==0.6
# For local FastAPI development and running
%pip install -U {USER_FLAG} "uvicorn[standard]>=0.12.0,<0.14.0" fastapi~=0.63
# Vertex SDK for Python
%pip install -U --user google-cloud-aiplatform
Explanation: <table align="left">
  <td>
    <a href="https://colab.research.google.com/github/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/community/sdk/SDK_FBProphet_Forecasting_Online.ipynb"">
      <img src="https://cloud.google.com/ml-engine/images/colab-logo-32px.png" alt="Colab logo"> Run in Colab
    </a>
  </td>
  <td>
    <a href="https://github.com/GoogleCloudPlatform/vertex-ai-samples/tree/master/notebooks/community/sdk/SDK_FBProphet_Forecasting_Online.ipynb">
      <img src="https://cloud.google.com/ml-engine/images/github-logo-32px.png" alt="GitHub logo">
      View on GitHub
    </a>
  </td>
</table>
Overview
This tutorial walks through building a custom container to serve a facebook prophet model on Vertex Prediction. You will use the FastAPI Python web server framework to create a prediction and health check endpoint. This Notebook is an modified example based on serving a scikit-learn model on Vertex AI Predictions that can be found here: https://github.com/GoogleCloudPlatform/vertex-ai-samples/blob/master/notebooks/community/sdk/SDK_Custom_Container_Prediction.ipynb
The facebook prophet model was taken from an article on testdriven.io (https://testdriven.io/blog/fastapi-machine-learning/)
Dataset
This example uses historical liquor sales data in Iowa from a public dataset in BigQuery: bigquery-public-data:iowa_liquor_sales.sales
Each instance includes 2 features, a datestamp and the adjusted sales for that time period.
Objective
The goal is to:
- Train a model locally that forecasts sales for the number of days passed into the model prediction function
- Train a model that uses both sales and weather data
- Save the models
- Build a FastAPI server to handle predictions and health checks
- Build a custom container with model artifacts
- Upload and deploy the custom container to Vertex Prediction
This example focuses more on deploying this model than on the design of the model itself.
Costs
This tutorial uses billable components of Google Cloud:
Vertex AI
Cloud Storage
Artifact Registry
Learn about Vertex AI
pricing and Cloud Storage
pricing, and use the Pricing
Calculator
to generate a cost estimate based on your projected usage.
Set up your local development environment
If you are using Colab or Google Cloud Notebooks, your environment already meets
all the requirements to run this notebook. You can skip this step.
Otherwise, make sure your environment meets this notebook's requirements.
You need the following:
Docker
Git
Google Cloud SDK (gcloud)
Python 3
virtualenv
Jupyter notebook running in a virtual environment with Python 3
The Google Cloud guide to Setting up a Python development
environment and the Jupyter
installation guide provide detailed instructions
for meeting these requirements. The following steps provide a condensed set of
instructions:
Install and initialize the Cloud SDK.
Install Python 3.
Install
   virtualenv
   and create a virtual environment that uses Python 3. Activate the virtual environment.
To install Jupyter, run pip install jupyter on the
command-line in a terminal shell.
To launch Jupyter, run jupyter notebook on the command-line in a terminal shell.
Open this notebook in the Jupyter Notebook Dashboard.
Install additional packages
Install additional package dependencies not installed in your notebook environment, such as NumPy, pystan, pandas, plotly, yfinance, fbprophet, FastAPI, Uvicorn, and joblib. This example uses a specific version for each libray, but in general the latest major GA version of each package is suggested
End of explanation
# Automatically restart kernel after installs
import os
if not os.getenv("IS_TESTING"):
    # Automatically restart kernel after installs
    import IPython
    app = IPython.Application.instance()
    app.kernel.do_shutdown(True)
Explanation: Restart the kernel
After you install the additional packages, you need to restart the notebook kernel so it can find the packages.
End of explanation
# Get your Google Cloud project ID from gcloud
shell_output=!gcloud config list --format 'value(core.project)' 2>/dev/null
try:
    PROJECT_ID = shell_output[0]
except IndexError:
    PROJECT_ID = None
print("Project ID:", PROJECT_ID)
Explanation: Before you begin
Set up your Google Cloud project
The following steps are required, regardless of your notebook environment.
Select or create a Google Cloud project. When you first create an account, you get a $300 free credit towards your compute/storage costs.
Make sure that billing is enabled for your project.
Enable the Vertex API.
Enable the Compute Engine API.
If you are running this notebook locally, you will need to install the Cloud SDK.
Enter your project ID in the cell below. Then run the cell to make sure the
Cloud SDK uses the right project for all the commands in this notebook.
Note: Jupyter runs lines prefixed with ! or % as shell commands, and it interpolates Python variables with $ or {} into these commands.
Set your project ID
If you don't know your project ID, you may be able to get your project ID using gcloud.
End of explanation
if PROJECT_ID == "" or PROJECT_ID is None:
    PROJECT_ID = "[your-project-id]"  # @param {type:"string"}
Explanation: Otherwise, set your project ID here.
End of explanation
import os
import sys
# If you are running this notebook in Colab, run this cell and follow the
# instructions to authenticate your GCP account. This provides access to your
# Cloud Storage bucket and lets you submit training jobs and prediction
# requests.
# The Google Cloud Notebook product has specific requirements
IS_GOOGLE_CLOUD_NOTEBOOK = os.path.exists("/opt/deeplearning/metadata/env_version")
# If on Google Cloud Notebooks, then don't execute this code
if not IS_GOOGLE_CLOUD_NOTEBOOK:
    if "google.colab" in sys.modules:
        from google.colab import auth as google_auth
        google_auth.authenticate_user()
    # If you are running this notebook locally, replace the string below with the
    # path to your service account key and run this cell to authenticate your GCP
    # account.
    elif not os.getenv("IS_TESTING"):
        %env GOOGLE_APPLICATION_CREDENTIALS 'path/to/your/credentials.json'
Explanation: Authenticate your Google Cloud account
If you are using Vertex AI Workbench notebooks, your environment is already
authenticated. Skip this step.
If you are using Colab, run the cell below and follow the instructions
when prompted to authenticate your account via oAuth.
Otherwise, follow these steps:
In the Cloud Console, go to the Create service account key
   page.
Click Create service account.
In the Service account name field, enter a name, and
   click Create.
In the Grant this service account access to project section, click the Role drop-down list. Type "Vertex AI"
into the filter box, and select
   Vertex AI Administrator. Type "Storage Object Admin" into the filter box, and select Storage Object Admin.
Click Create. A JSON file that contains your key downloads to your
local environment.
Enter the path to your service account key as the
GOOGLE_APPLICATION_CREDENTIALS variable in the cell below and run the cell.
End of explanation
BUCKET_NAME = "gs://[your-bucket-name]"  # @param {type:"string"}
REGION = "[your-region]"  # @param {type:"string"}
Explanation: Create a Cloud Storage bucket
The following steps are required, regardless of your notebook environment.
To update your model artifacts without re-building the container, you must upload your model
artifacts and any custom code to Cloud Storage.
Set the name of your Cloud Storage bucket below. It must be unique across all
Cloud Storage buckets.
End of explanation
! gsutil mb -l $REGION $BUCKET_NAME
Explanation: Only if your bucket doesn't already exist: Run the following cell to create your Cloud Storage bucket.
End of explanation
! gsutil ls -al $BUCKET_NAME
Explanation: Finally, validate access to your Cloud Storage bucket by examining its contents:
End of explanation
%mkdir -p app
Explanation: Create a directory for all your model artifacts
End of explanation
MODEL_ARTIFACT_DIR = "custom-fb-container-prediction-model"  # @param {type:"string"}
REPOSITORY = "custom-fb-container-prediction"  # @param {type:"string"}
IMAGE = "custom-fb-fastapi-server"  # @param {type:"string"}
MODEL_NAME = "fb_custom_container"  # @param {type:"string"}
MODEL_DISPLAY_NAME = "FB Prophet Forecast"  # @param {type:"string"}
Explanation: Configure model, repository, and artifact names
End of explanation
import datetime
import os
# BQ libraries
import google.auth
from fbprophet import Prophet
from google.cloud import bigquery, bigquery_storage
TODAY = datetime.date.today()
credentials, your_project_id = google.auth.default(
    scopes=["https://www.googleapis.com/auth/cloud-platform"]
)
bqclient = bigquery.Client(
    credentials=credentials,
    project=your_project_id,
)
bqstorageclient = bigquery_storage.BigQueryReadClient(credentials=credentials)
Explanation: MODEL_ARTIFACT_DIR - Folder directory path to your model artifacts within a Cloud Storage bucket, for example: "my-models/fraud-detection/trial-4"
REPOSITORY - Name of the Artifact Repository to create or use.
IMAGE - Name of the container image that will be pushed.
MODEL_NAME - Name of Model.
MODEL_DISPLAY_NAME - Display Name of Model.
Import libraries and define constants
End of explanation
import joblib
def train(category="1012100"):
    # Download query results. # change to Data, Adj_Close
    query_string = 
    SELECT date as Date, upper(category_name) as category_name, category, sum(sale_dollars) as sales
    FROM `bigquery-public-data.iowa_liquor_sales.sales`
    where category = '{}'
      and date >= '2020-01-01'
    group by Date, category_name, category
    .format(
        category
    )
    data = (
        bqclient.query(query_string)
        .result()
        .to_dataframe(bqstorage_client=bqstorageclient)
    )
    data.head()
    data.plot(title=f"{category} Daily Sales", x="Date", y="sales")
    # Copy results into a dataframe with two columns ds=Date, y=value
    df_forecast = data.copy()
    df_forecast.reset_index(inplace=True)
    df_forecast["ds"] = df_forecast["Date"]
    df_forecast["y"] = df_forecast[
        "sales"
    ]  # Add underscore as BQ changes this field name
    df_forecast = df_forecast[["ds", "y"]]
    df_forecast
    # Train the Prophet model
    model = Prophet()
    model.fit(df_forecast)
    # Save the model locally
    joblib.dump(model, "{}.sav".format(category))
Explanation: Train and store the model locally
Next, we define a function to train time series models using fbprophet for a few sales categories. 
We're also adding a regressor to allow 2 different types of forecasts. One that only uses sales, and another that takes the weather as an additional regressor (https://facebook.github.io/prophet/docs/seasonality,_holiday_effects,_and_regressors.html)
Weather data comes from a public dataset in BigQuery described here:
https://cloud.google.com/blog/products/gcp/global-historical-daily-weather-data-now-available-in-bigquery
At the end, the function exports your trained model as a joblib (.sav) file and exports your instance as a (.sav) file:
End of explanation
def train_w_regressor(category="1012100"):
    # Download query results. # change to Data, Adj_Close
    query_string = 
    SELECT date as Date, upper(category_name) as category_name, category, sum(sale_dollars) as sales
    FROM `bigquery-public-data.iowa_liquor_sales.sales`
    where category = '{}'
      and date >= '2020-01-01'
    group by Date, category_name, category
    .format(
        category
    )
    query_string_regressor = 
    WITH history as
    (
    SELECT
      wx.date as ds,
      AVG(wx.value/10) AS temp
    FROM
      `bigquery-public-data.ghcn_d.ghcnd_stations` AS stn
    JOIN
      `bigquery-public-data.ghcn_d.ghcnd_2021` AS wx ON wx.id = stn.id
    WHERE
      stn.state = 'IA'
      AND wx.element = 'TMIN'
      AND wx.qflag IS NULL
    GROUP by wx.date
    union all
    SELECT
      wx.date as ds,
      AVG(wx.value/10) AS temp
    FROM
      `bigquery-public-data.ghcn_d.ghcnd_stations` AS stn
    JOIN
      `bigquery-public-data.ghcn_d.ghcnd_2020` AS wx ON wx.id = stn.id
    WHERE
      stn.state = 'IA'
      AND wx.element = 'TMIN'
      AND wx.qflag IS NULL
    GROUP by wx.date
    )
    ,next_100_days as
    (
    SELECT DATE_ADD(max(stn.date) over (order by 1), INTERVAL row_number() over (order by stn.id) DAY) as ds, null as temp
    FROM `bigquery-public-data.ghcn_d.ghcnd_2021` AS stn
    LIMIT 100
    )
    ,combined_data as
    (
    select *
    from history
    union all
    select * from next_100_days
    )
    select c.ds
          ,case when temp is null then AVG(c.temp) OVER (ORDER BY c.ds ASC ROWS 100 PRECEDING)
           else temp end as temp
    from combined_data c;
    
    data = (
        bqclient.query(query_string)
        .result()
        .to_dataframe(bqstorage_client=bqstorageclient)
    )
    data.head()
    data.plot(title=f"{category} Daily Sales", x="Date", y="sales")
    # Copy results into a dataframe with two columns ds=Date, y=value
    df_forecast = data.copy()
    df_forecast.reset_index(inplace=True)
    df_forecast["ds"] = df_forecast["Date"]
    df_forecast["y"] = df_forecast[
        "sales"
    ]  # Add underscore as BQ changes this field name
    df_forecast = df_forecast[["ds", "y"]]
    df_forecast
    # Return the weather data from BQ
    data_regressor = (
        bqclient.query(query_string_regressor)
        .result()
        .to_dataframe(bqstorage_client=bqstorageclient)
    )
    data_regressor.head()
    df_regressor = data_regressor.copy()
    # Deal with any NaN values using fillna
    df_regressor_out = df_regressor.fillna(method="pad")
    df_regressor_out.to_csv(f"{category}_weather.csv", index=False)
    # Add a temp column to the df_forecast dataframe, and populate it from the df_regressor dataframe
    df_forecast["temp"] = df_forecast.ds.map(
        df_regressor.set_index("ds")["temp"].to_dict()
    )
    df_forecast.head()
    df_forecast.fillna(method="pad")  # Address NaN values of temp
    # Train the Prophet model with the regressor
    model = Prophet()
    model.add_regressor("temp")
    model.fit(df_forecast)
    # Save the model locally, with _weather appended to the file name
    joblib.dump(model, f"{category}_weather.sav")
Explanation: Train additional models that use the weather as a regressor
The query for the regressor retrieves 2 years of weather data, and uses a moving average to generate 100 future weather data points
End of explanation
%cd app/
# Choose a few product categories to build forecasts for from the Iowa Liquor sales data in BQ: bigquery-public-data:iowa_liquor_sales.sales
# 1012100 CANADIAN WHISKIES
# 1031100 AMERICAN VODKAS
train("1012100")
train("1031100")
%cd ..
Explanation: Train a model for two sample categories (Canadian Whiskies and American Vodkas)
This model uses only the Iowa liquor sales data as input
End of explanation
%cd app/
# Choose a few product categories to build forecasts for from the Iowa Liquor sales data in BQ: bigquery-public-data:iowa_liquor_sales.sales
# 1012100 CANADIAN WHISKIES
# 1031100 AMERICAN VODKAS
train_w_regressor("1012100")
train_w_regressor("1031100")
%cd ..
Explanation: Train a model for the same sample categories (Canadian Whiskies and American Vodkas)
This model uses only the Iowa liquor sales data, and an additional regressor to account for the impact of weather. As mentioned before, the regressor must be known for both the history and future dates. In the query for the regressor data, a moving average was used to calculate the future weather data
More info on regressors can be found here: https://facebook.github.io/prophet/docs/seasonality,_holiday_effects,_and_regressors.html
End of explanation
%cd app
!gsutil cp *.sav *.csv {BUCKET_NAME}/{MODEL_ARTIFACT_DIR}/
%cd ..
Explanation: Upload model artifacts and custom code to Cloud Storage
Before you can deploy your model for serving, Vertex needs access to the following files in Cloud Storage:
{category}.sav (model artifact) for each sales category you would like to retrieve the forecast for
*.csv - Data for the weather regressor that will be needed at prediction time
Run the following commands to upload your files:
End of explanation
os.environ["AIP_STORAGE_URI"] = f"{BUCKET_NAME}/{MODEL_ARTIFACT_DIR}"
os.environ["AIP_HTTP_PORT"] = "8080"
os.environ["AIP_HEALTH_ROUTE"] = "/health"
os.environ["AIP_PREDICT_ROUTE"] = "/predict"
print(os.environ["AIP_STORAGE_URI"])
print(os.environ["AIP_HTTP_PORT"])
print(os.environ["AIP_HEALTH_ROUTE"])
print(os.environ["AIP_PREDICT_ROUTE"])
os.getcwd()
%cd app
import datetime
import pandas as pd
from google.cloud import storage
gcs_client = storage.Client()
# Set a sample category and number of days to test with
category = "1012100"
days = 7
# Test the loading of the model from GCS
fname = f"{category}.sav"
with open(f"{fname}", "wb") as model_g:
    gcs_client.download_blob_to_file(
        f"{os.environ['AIP_STORAGE_URI']}/{fname}", model_g
    )
model = joblib.load(f"{category}.sav")
# Create a dataframe that ranges from 2020 to Today + the number of days set above
TODAY = datetime.date.today()
future = TODAY + datetime.timedelta(days=days)
dates = pd.date_range(
    start="2020-01-01",
    end=future.strftime("%m/%d/%Y"),
)
df = pd.DataFrame({"ds": dates})
# Run a prediction for these dates and save it to a forecast dataframe
forecast = model.predict(df)
model.plot(forecast).savefig(f"{category}_plot.png")
model.plot_components(forecast).savefig(f"{category}_plot_components.png")
forecast.tail(days).to_dict("records")
%cd ..
Explanation: Local model testing
Review the trained FB Prophet models with and without the regressor in the sections below
End of explanation
%cd app
gcs_client = storage.Client()
# Set a sample category and number of days to test with
category = "1012100_weather"
days = 7
# Test the loading of the model from GCS
fname = f"{category}.sav"
with open(f"{fname}", "wb") as model_g:
    gcs_client.download_blob_to_file(
        f"{os.environ['AIP_STORAGE_URI']}/{fname}", model_g
    )
model = joblib.load(f"{category}.sav")
# Test the loading of the regressor from GCS
fname_csv = f"{category}.csv"
with open(f"{fname_csv}", "wb") as model_csv:
    gcs_client.download_blob_to_file(
        f"{os.environ['AIP_STORAGE_URI']}/{fname_csv}", model_csv
    )
df_regressor = pd.read_csv(fname_csv)
# Return the data from the regressor that ranges from 2020 to Today + the number of days set above
TODAY = datetime.date.today()
future = TODAY + datetime.timedelta(days=days)
start = "2020-01-01"
after_start_date = df_regressor["ds"] >= start
before_end_date = df["ds"] <= future.strftime("%m/%d/%Y")
between_two_dates = after_start_date & before_end_date
df_final = df_regressor.loc[between_two_dates]
df_final.tail()
# Run a prediction for these dates and the regressor
forecast = model.predict(df_final)
model.plot(forecast).savefig(f"{category}_plot.png")
model.plot_components(forecast).savefig(f"{category}_plot_components.png")
%cd ..
Explanation: Test model with regressor
End of explanation
%%writefile app/main.py
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
import joblib
import json
import numpy as np
import os
import datetime
import pandas as pd
import errno
from google.cloud import storage
app = FastAPI()
gcs_client = storage.Client()
@app.exception_handler(Exception)
async def validation_exception_handler(request, err):
    base_error_message = f"Failed to execute: {request.method}: {request.url}"
    # Change here to LOGGER
    return JSONResponse(status_code=400, content={"message": f"{base_error_message}. Detail: {err}"})
    
def download_model(category="1012100", regressor=""): #defaults to "1012100"
    if not category:
        raise HTTPException(status_code=400, detail=f"category not found. category={category}")
    fname = f"{category}{regressor}.sav"
    with open(f"{fname}", 'wb') as model_g:
        gcs_client.download_blob_to_file(
            f"{os.environ['AIP_STORAGE_URI']}/{fname}", model_g
        )
    model = joblib.load (fname)
    return model
    
def predict_in(model, days=7, regressor="", category="1012100"):
    TODAY = datetime.date.today()
    future = TODAY + datetime.timedelta(days=days)
    dates = pd.date_range(start="2020-01-01", end=future.strftime("%m/%d/%Y"),)
    df = pd.DataFrame({"ds": dates})
    if (regressor > ""):
        fname_csv = f"{category}{regressor}.csv"
        with open(f"{fname_csv}", 'wb') as model_csv:
            gcs_client.download_blob_to_file(
                f"{os.environ['AIP_STORAGE_URI']}/{fname_csv}", model_csv
            )
        df_regressor = pd.read_csv(fname_csv)
        start="2020-01-01"
        after_start_date = df_regressor["ds"] >= start
        before_end_date = df["ds"] <= future.strftime("%m/%d/%Y")
        between_two_dates = after_start_date & before_end_date
        df_final = df_regressor.loc[between_two_dates]
        df_final.tail()
        
        forecast = model.predict(df_final)
    
    else:
        forecast = model.predict(df)
    model.plot(forecast).savefig("model_plot.png")
    model.plot_components(forecast).savefig("model_plot_components.png")    
    
    return forecast.tail(days).to_dict("records")
def convert(prediction_list):
    output = {}
    for data in prediction_list:
        date = data["ds"].strftime("%m/%d/%Y")
        output[date] = data["trend"]
    return output
@app.get(os.environ['AIP_HEALTH_ROUTE'], status_code=200)
def health():
    return {}
@app.post(os.environ['AIP_PREDICT_ROUTE'])
async def predict(request: Request):
    body = await request.json()
    try:
        if type(body) is list:
            body = body[0]
    except:
        None #Do Nothing
    print (body)
    instances = body["instances"]
    try:
        if type(instances) is list:
            instances = instances[0]
    except:
        None #Do Nothing
    print(instances)    
    category = instances["category"] 
    days = instances["days"]
    regressor = instances["regressor"]
    
    try:
        if type(category) is list:
            category = category[0]
    except:
        None #Do Nothing
    print(category) 
    try:
        if type(days) is list:
            days = days[0]
    except:
        None #Do Nothing
    print(days) 
    try:
        if type(regressor) is list:
            regressor = regressor[0]
    except:
        None #Do Nothing
    print(regressor) 
    
    model_download = download_model (category, regressor)
    prediction_list = predict_in(model_download, days, regressor, category)  
    
    if not prediction_list:
        raise HTTPException(status_code=400, detail="Model not found.")
    
    prediction_output = convert(prediction_list)
    final_output = [(k, v) for k, v in prediction_output.items()] 
    
    return {"predictions": final_output}
Explanation: Build a FastAPI server
End of explanation
%%writefile app/prestart.sh
export PORT=$AIP_HTTP_PORT
Explanation: Add pre-start script
FastAPI will execute this script before starting up the server. The PORT environment variable is set to equal AIP_HTTP_PORT in order to run FastAPI on same the port expected by Vertex AI Prediction.
End of explanation
%%writefile instances.json
{"instances": [{"category":["1012100"], "days": [30], "regressor": ["_weather"]}]}
Explanation: Store test instances to use later
To learn more about formatting input instances in JSON, read the documentation.
End of explanation
%%writefile Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
COPY ./app /app
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
RUN pip install fbprophet==0.6
!gcloud auth configure-docker {REGION}-docker.pkg.dev --quiet
Explanation: Build and push container to Artifact Registry
Write the Dockerfile, using tiangolo/uvicorn-gunicorn-fastapi as a base image. This will automatically run FastAPI for you using Gunicorn and Uvicorn. Visit the FastAPI docs to read more about deploying FastAPI with Docker.
End of explanation
!sudo docker build \
    --tag="{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}" \
    .
Explanation: Build the image and tag the Artifact Registry path that you will push to.
Initial FB prophet install will fail, but eventually will install. This is a known bug
End of explanation
!sudo docker stop local-ts
!sudo docker rm local-ts
!sudo docker run -d -p 80:8080 \
    --name=local-ts \
    -e AIP_HTTP_PORT=8080 \
    -e AIP_HEALTH_ROUTE=/health \
    -e AIP_PREDICT_ROUTE=/predict \
    -e AIP_STORAGE_URI={BUCKET_NAME}/{MODEL_ARTIFACT_DIR} \
    "{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}"
!curl localhost/health
!curl -X POST \
  -d @instances.json \
  -H "Content-Type: application/json; charset=utf-8" \
  localhost/predict
Explanation: Run and test the container locally (optional)
Run the container locally in detached mode and provide the environment variables that the container requires. These env vars will be provided to the container by Vertex AI Prediction once deployed. Test the /health and /predict routes, then stop the running image.
End of explanation
%%writefile instances.json
{"instances": [{"category":["1012100"], "days": [30], "regressor": [""]}]}
!curl -X POST \
  -d @instances.json \
  -H "Content-Type: application/json; charset=utf-8" \
  localhost/predict
!sudo docker stop local-ts
Explanation: Test without regressor
End of explanation
!gcloud services enable artifactregistry.googleapis.com
Explanation: Push the container to artifact registry
Configure Docker to access Artifact Registry. Then push your container image to your Artifact Registry repository.
Make sure to enable the Artifact Registry API here if you haven't already:
End of explanation
!gcloud beta artifacts repositories create {REPOSITORY} \
 --repository-format=docker \
 --location=$REGION
!docker push {REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}
Explanation: Run this once to create the artifact repository
End of explanation
from google.cloud import aiplatform
aiplatform.init(project=PROJECT_ID, location=REGION)
model = aiplatform.Model.upload(
    display_name=MODEL_DISPLAY_NAME,
    artifact_uri=f"{BUCKET_NAME}/{MODEL_ARTIFACT_DIR}",
    serving_container_image_uri=f"{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}",
)
Explanation: Deploy to Vertex AI
Use the Python SDK to upload and deploy your model.
End of explanation
endpoint = model.deploy(machine_type="n1-standard-4")
Explanation: Deploy the model endpoint
After this step completes, the model is deployed and ready for online prediction.
End of explanation
endpoint.predict(instances=[{"category": ["1012100"], "days": [30], "regressor": [""]}])
endpoint.predict(
    instances=[{"category": ["1012100"], "days": [30], "regressor": ["_weather"]}]
)
Explanation: Send predictions
Using Python SDK
End of explanation
ENDPOINT_ID = endpoint.name
! curl \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d @instances.json \
https://{REGION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{REGION}/endpoints/{ENDPOINT_ID}:predict
Explanation: Using REST
End of explanation
!gcloud beta ai endpoints predict $ENDPOINT_ID \
  --region=$REGION \
  --json-request=instances.json
Explanation: Using gcloud CLI
End of explanation
# Undeploy model and delete endpoint
endpoint.delete(force=True)
# Delete the model resource
model.delete()
# Delete the container image from Artifact Registry
!gcloud artifacts docker images delete \
    --quiet \
    --delete-tags \
    {REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}
Explanation: Cleaning up
To clean up all Google Cloud resources used in this project, you can delete the Google Cloud
project you used for the tutorial.
Otherwise, you can delete the individual resources you created in this tutorial:
End of explanation
<END_TASK>