cloud-functions/rideshare-plus-rest-api/main.py (167 lines of code) (raw):

# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # https://cloud.google.com/bigquery/docs/remote-function-tutorial # import urllib.request import flask import functions_framework from google.cloud import bigquery from google.cloud import storage import json import os @functions_framework.http def entrypoint(request: flask.Request) -> flask.Response: print("BEGIN: entrypoint") try: # Set CORS headers for the preflight request if request.method == 'OPTIONS': # Allows all requests from any origin with any header # header and caches preflight response for an 3600s headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*', 'Access-Control-Allow-Headers': '*', 'Access-Control-Max-Age': '3600' } print("END: entrypoint request.method == OPTIONS") return ('', 204, headers) request_json = request.get_json() print("request_json: ", request_json) mode = request_json['mode'] print("mode: ", mode) print("END: entrypoint") if mode == "predict": return generate_predictions(request) elif mode == "streaming_data": return get_streaming_data(request) elif mode == "save_configuration": return save_configuration(request) elif mode == "get_configuration": return get_configuration(request) else: flask_response = flask.make_response(flask.jsonify({'Usage: mode not specified: predict or streaming_data'}), 200) flask_response.headers['Access-Control-Allow-Origin'] = '*' return flask_response except Exception as e: print ("Exception (entrypoint): " + str(e)) flask_response_error = flask.make_response(flask.jsonify({'errorMessage': str(e)}), 400) flask_response_error.headers['Access-Control-Allow-Origin'] = '*' return flask_response_error def generate_predictions(request: flask.Request) -> flask.Response: try: print("BEGIN: generate_predictions") # {'mode': 'predict', 'ride_distance': 'short', 'is_raining': False, 'is_snowing': False} request_json = request.get_json() print("request_json: ", request_json) ride_distance = str(request_json['ride_distance']).lower() is_raining = str(request_json['is_raining']).upper() is_snowing = str(request_json['is_snowing']).upper() print("ride_distance: ", ride_distance) print("is_raining: ", is_raining) print("is_snowing: ", is_snowing) project_id = os.environ['PROJECT_ID'] print("project_id: ", project_id) client = bigquery.Client() sql = "CALL `" + project_id + ".rideshare_lakehouse_curated.sp_website_score_data`('" + \ ride_distance + "', " + is_raining + ", " + is_snowing + ", 0, 0);" print("sql: ", sql) query_job = client.query(sql); results = query_job.result() replies = [] row_dict = { "success" : True} replies.append(row_dict) flask_response = flask.make_response(flask.jsonify({'data': replies}), 200) flask_response.headers['Access-Control-Allow-Origin'] = '*' print("END: generate_predictions") return flask_response except Exception as e: print ("Exception (generate_predictions): " + str(e)) flask_response_error = flask.make_response(flask.jsonify({'errorMessage': str(e)}), 400) flask_response_error.headers['Access-Control-Allow-Origin'] = '*' return flask_response_error def get_streaming_data(request: flask.Request) -> flask.Response: try: print("BEGIN: get_streaming_data") project_id = os.environ['PROJECT_ID'] print("project_id: ", project_id) client = bigquery.Client() sql = "SELECT * FROM `" + project_id + ".rideshare_lakehouse_curated.website_realtime_dashboard`" query_job = client.query(sql); results = query_job.result() replies = [] for row in results: row_dict = { "ride_count": row.ride_count, "average_ride_duration_minutes": row.average_ride_duration_minutes, "average_total_amount": row.average_total_amount, "average_ride_distance": row.average_ride_distance, "max_pickup_location_zone": row.max_pickup_location_zone, "max_pickup_ride_count": row.max_pickup_ride_count, "max_dropoff_location_zone": row.max_dropoff_location_zone, "max_dropoff_ride_count": row.max_dropoff_ride_count } replies.append(row_dict) # print("{} : {} ".format(row.urride_countl, row.average_ride_duration_minutes)) flask_response = flask.make_response(flask.jsonify({'data': replies}), 200) flask_response.headers['Access-Control-Allow-Origin'] = '*' print("END: get_streaming_data") return flask_response except Exception as e: print ("Exception (get_streaming_data): " + str(e)) flask_response_error = flask.make_response(flask.jsonify({'errorMessage': str(e)}), 400) flask_response_error.headers['Access-Control-Allow-Origin'] = '*' return flask_response_error def save_configuration(request: flask.Request) -> flask.Response: try: print("BEGIN: save_configuration") # {'mode': 'predict', 'ride_distance': 'short', 'is_raining': False, 'is_snowing': False} request_json = request.get_json() print("request_json: ", request_json) looker_url = str(request_json['looker_url']).lower() print("looker_url: ", looker_url) project_id = os.environ['PROJECT_ID'] print("project_id: ", project_id) code_bucket = os.environ['ENV_CODE_BUCKET'] print("code_bucket: ", code_bucket) filename = "website/rideshareplusconfig.json"; config_value = { "looker_url" : looker_url } default_json = json.dumps(config_value) storage_client = storage.Client() bucket = storage_client.get_bucket(code_bucket) blob = bucket.blob(filename) blob.upload_from_string(default_json, content_type='application/json', num_retries=3) replies = [] row_dict = { "success" : True} replies.append(row_dict) flask_response = flask.make_response(flask.jsonify({'data': replies}), 200) flask_response.headers['Access-Control-Allow-Origin'] = '*' print("END: save_configuration") return flask_response except Exception as e: print ("Exception (save_configuration): " + str(e)) flask_response_error = flask.make_response(flask.jsonify({'errorMessage': str(e)}), 400) flask_response_error.headers['Access-Control-Allow-Origin'] = '*' return flask_response_error def get_configuration(request: flask.Request) -> flask.Response: try: print("BEGIN: get_configuration") filename = "website/rideshareplusconfig.json"; default_config = { "looker_url" : "https://REPLACE-ME" } default_json = json.dumps(default_config) project_id = os.environ['PROJECT_ID'] print("project_id: ", project_id) code_bucket = os.environ['ENV_CODE_BUCKET'] print("code_bucket: ", code_bucket) storage_client = storage.Client() bucket = storage_client.get_bucket(code_bucket) blob = bucket.blob(filename) if blob.exists() == False: print("Creating default configuration file.") blob.upload_from_string(default_json, content_type='application/json', num_retries=3) contents = blob.download_as_text() config_dict = json.loads(contents) print(config_dict['looker_url']) replies = [] row_dict = { "looker_url" : config_dict['looker_url']} replies.append(row_dict) flask_response = flask.make_response(flask.jsonify({'data': replies}), 200) flask_response.headers['Access-Control-Allow-Origin'] = '*' print("END: get_configuration") return flask_response except Exception as e: print ("Exception (get_configuration): " + str(e)) flask_response_error = flask.make_response(flask.jsonify({'errorMessage': str(e)}), 400) flask_response_error.headers['Access-Control-Allow-Origin'] = '*' return flask_response_error