import os
import json
import pandas as pd
import hana_ml.dataframe as dataframe
from hana_ml.model_storage import ModelStorage
from flask import Flask
from flask import request as call_request
import uuid
# Print external IP address
from requests import get
ip = get('https://api.ipify.org').text
print(f'My public IP address is: {ip}')
# Variable for connection to SAP HANA
conn = None
# Function to establish connection to SAP HANA
def get_hanaconnection():
global conn
conn = dataframe.ConnectionContext(address=os.getenv('HANA_ADDRESS'),
port=int(os.getenv('HANA_PORT')),
user=os.getenv('HANA_USER'),
password=os.getenv('HANA_PASSWORD'))
print('Connection to SAP HANA established: ' + str(conn.connection.isconnected()))
# Creates Flask serving engine
app = Flask(__name__)
# You may customize the endpoint, but must have the prefix `/v<number>`
@app.route("/v1/predict", methods=["POST"])
def predict():
print("start serving ...")
# Convert incoming payload to Pandas DataFrame
payload = call_request.get_json()
payloadString = json.dumps(payload)
parsedPayload = json.loads(payloadString)
df_data = pd.json_normalize(parsedPayload)
# Ensure that the connection to SAP HANA is active
if (conn.connection.isconnected() == False):
get_hanaconnection()
# Load the saved model
model_storage = ModelStorage(connection_context=conn)
ur_hgbt = model_storage.load_model('Car price regression')
# Save received data as temporary table in SAP HANA
temp_table_name = '#' + str(uuid.uuid1()).upper()
df_remote_topredict = dataframe.create_dataframe_from_pandas(
connection_context=conn,
pandas_df=df_data,
table_name=temp_table_name,
force=True,
drop_exist_tab=True,
replace=False)
# Create prediction based on the data in the temporary table
df_predicted = ur_hgbt.predict(data=df_remote_topredict,
key='CAR_ID').collect()
prediction = df_predicted['SCORE'][0]
# Delete the temporary table
dbapi_cursor = conn.connection.cursor()
dbapi_cursor.execute('DROP TABLE "' + temp_table_name + '"')
# Send the prediction as response
output = json.dumps({'price_estimate': round(prediction, 1)})
return output
if __name__ == "__main__":
# Establish initial connection to SAP HANA
get_hanaconnection()
print("Serving Started")
app.run(host="0.0.0.0", debug=False, port=9001)
Flask==2.0.1
hana_ml==2.17.23071400
shapely==1.8.0
jinja2==3.1.2
urllib3==1.26.16
requests==2.29.0
cryptography==39.0.1
IPython==8.14.0
# Specify which base layers (default dependencies) to use
# You may find more base layers at https://hub.docker.com/
FROM python:3.9
#
# Creates directory within your Docker image
RUN mkdir -p /app/src/
#
# Copies file from your Local system TO path in Docker image
COPY main.py /app/src/
COPY requirements.txt /app/src/
#
# Installs dependencies within you Docker image
RUN pip3 install -r /app/src/requirements.txt
#
# Enable permission to execute anything inside the folder app
RUN chgrp -R 65534 /app && \
chmod -R 777 /app
docker build -t YOURUSERHERE/hana-ml-car-price-restapi-inference:01 .
docker push YOURUSERHERE/hana-ml-car-price-restapi-inference:01
apiVersion: ai.sap.com/v1alpha1
kind: ServingTemplate
metadata:
name: i056450-hana-ml-car-price-inference-rest-api # Executable ID (max length 64 lowercase-hyphen-separated), please modify this to any value if you are not the only user of your SAP AI Core instance. Example: `first-pipeline-1234`
annotations:
scenarios.ai.sap.com/name: "HANA ML Car Price"
scenarios.ai.sap.com/description: "Estimate the price of a use car with SAP HANA Machine Learning"
executables.ai.sap.com/name: "HANAMLCarPriceInferenceRESTAPI" # No spaces allowed in the name here
executables.ai.sap.com/description: "Create estimate"
labels:
scenarios.ai.sap.com/id: "hana-ml-car-price" # The scenario ID to which the serving template belongs
ai.sap.com/version: "0.0.1"
spec:
template:
apiVersion: "serving.kserve.io/v1beta1"
metadata:
annotations: |
autoscaling.knative.dev/metric: concurrency # condition when to scale
autoscaling.knative.dev/target: 1
autoscaling.knative.dev/targetBurstCapacity: 0
labels: |
ai.sap.com/resourcePlan: starter # computing power
spec: |
predictor:
imagePullSecrets:
- name: docker-registry-secret-XYZ # your docker registry secret
minReplicas: 1
maxReplicas: 2 # how much to scale
containers:
- name: kserve-container
image: docker.io/YOURUSERHERE/hana-ml-car-price-restapi-inference:01 # Your docker image name
ports:
- containerPort: 9001 # customizable port
protocol: TCP
command: ["/bin/sh", "-c"]
args:
- "python /app/src/main.py"
env:
- name: HANA_ADDRESS # Name of the environment variable that will be available in the image
valueFrom:
secretKeyRef:
name: hanacred # Name of the generic secret created in SAP AI Core for the Resource Group
key: address # Name of the key from the JSON string that is saved as generic secret
- name: HANA_PORT
valueFrom:
secretKeyRef:
name: hanacred
key: port
- name: HANA_USER
valueFrom:
secretKeyRef:
name: hanacred
key: user
- name: HANA_PASSWORD
valueFrom:
secretKeyRef:
name: hanacred
key: password
import json
service_key_location = "AICoreServiceKey.json"
file_read = open(service_key_location, "r")
config = json.loads(file_read.read())
uua_url = config['url']
clientid = config["clientid"]
clientsecret = config["clientsecret"]
import requests
params = {"grant_type": "client_credentials" }
resp = requests.post(f"{uua_url}/oauth/token",
auth=(clientid, clientsecret),
params=params)
token = resp.json()["access_token"]
inference_url = 'YOURDEPLOYMENTURLHERE' + '/v1/predict'
headers = {'Content-Type' : 'application/json',
'AI-Resource-Group': 'YOURRESOURCEGROUPHERE',
'Authorization': f'Bearer {token}'}
payload = json.dumps({
"CAR_ID": 1,
"BRAND": "audi",
"MODEL": "a5",
"VEHICLETYPE": "coupe",
"YEAROFREGISTRATION": 2016,
"HP": 120,
"FUELTYPE": "benzin",
"GEARBOX": "manuell",
"KILOMETER": 100000
})
response = requests.request("POST", inference_url, headers=headers, data=payload)
if response.status_code == 200:
print(response.text)
else:
print('Error. Status code: ' + str(response.status_code))
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
20 | |
13 | |
12 | |
10 | |
7 | |
6 | |
6 | |
6 | |
5 | |
5 |