diff --git a/auth/index.py b/auth/index.py new file mode 100644 index 0000000..87c3d55 --- /dev/null +++ b/auth/index.py @@ -0,0 +1,115 @@ +import sys +sys.path.append("lib") + +# [START import_sdk] +import firebase_admin +# [END import_sdk] +from firebase_admin import credentials +from firebase_admin import auth + +def initialize_sdk_with_service_account(): + # [START initialize_sdk_with_service_account] + import firebase_admin + from firebase_admin import credentials + + cred = credentials.Certificate('path/to/serviceAccountKey.json') + default_app = firebase_admin.initialize_app(cred) + # [END initialize_sdk_with_service_account] + firebase_admin.delete_app(default_app) + +def initialize_sdk_with_application_default(): + # [START initialize_sdk_with_application_default] + default_app = firebase_admin.initialize_app() + # [END initialize_sdk_with_application_default] + firebase_admin.delete_app(default_app) + +def initialize_sdk_with_refresh_token(): + # [START initialize_sdk_with_refresh_token] + cred = credentials.RefreshToken('path/to/refreshToken.json') + default_app = firebase_admin.initialize_app(cred) + # [END initialize_sdk_with_refresh_token] + firebase_admin.delete_app(default_app) + +def access_services_default(): + cred = credentials.Certificate('path/to/service.json') + # [START access_services_default] + # Import the Firebase service + from firebase_admin import auth + + # Initialize the default app + default_app = firebase_admin.initialize_app(cred) + print(default_app.name); # "[DEFAULT]" + + # Retrieve services via the auth package... + # auth.create_custom_token(...) + # [END access_services_default] + firebase_admin.delete_app(default_app) + +def access_services_nondefault(): + cred = credentials.Certificate('path/to/service.json') + otherCred = credentials.Certificate('path/to/service.json') + + # [START access_services_nondefault] + # Initialize the default app + default_app = firebase_admin.initialize_app(cred) + + # Initialize another app with a different config + other_app = firebase_admin.initialize_app(cred, name='other') + + print(default_app.name); # "[DEFAULT]" + print(other_app.name); # "other" + + # Retrieve default services via the auth package... + # auth.create_custom_token(...) + + # Use the `app` argument to retrieve the other app's services + # auth.create_custom_token(..., app=other_app) + # [END access_services_nondefault] + firebase_admin.delete_app(default_app) + firebase_admin.delete_app(other_app) + +def create_token_uid(): + cred = credentials.Certificate('path/to/service.json') + default_app = firebase_admin.initialize_app(cred) + # [START create_token_uid] + uid = 'some-uid' + + custom_token = auth.create_custom_token(uid) + # [END create_token_uid] + firebase_admin.delete_app(default_app) + return custom_token + +def create_token_with_claims(): + cred = credentials.Certificate('path/to/service.json') + default_app = firebase_admin.initialize_app(cred) + # [START create_token_with_claims] + uid = 'some-uid' + additional_claims = { + 'premiumAccount': True + } + + custom_token = auth.create_custom_token(uid, additional_claims) + # [END create_token_with_claims] + firebase_admin.delete_app(default_app) + return custom_token + +def verify_token_uid(id_token): + cred = credentials.Certificate('path/to/service.json') + default_app = firebase_admin.initialize_app(cred) + # [START verify_token_uid] + # id_token comes from the client app (shown above) + + decoded_token = auth.verify_id_token(id_token) + uid = decoded_token['uid'] + # [END verify_token_uid] + print(uid) + firebase_admin.delete_app(default_app) + +initialize_sdk_with_service_account() +initialize_sdk_with_application_default() +#initialize_sdk_with_refresh_token() +access_services_default() +access_services_nondefault() +create_token_uid() +token_with_claims = create_token_with_claims() +#verify_token_uid() diff --git a/config/.gitignore b/config/.gitignore deleted file mode 100644 index 4813827..0000000 --- a/config/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -config.json -service-account.json -.idea \ No newline at end of file diff --git a/config/README.md b/config/README.md deleted file mode 100644 index b307eb1..0000000 --- a/config/README.md +++ /dev/null @@ -1,108 +0,0 @@ -Firebase Remote Config REST API Python Quickstart -=============================================== - -The [Firebase Remote Config](https://firebase.google.com/docs/remote-config/) Python quickstart -app demonstrates retrieving and updating the Firebase Remote Config template. - -Introduction ------------- - -This is a simple example of using the Firebase Remote Config REST API to update -the Remote Config template being used by clients apps. - -Getting started ---------------- - -1. [Add Firebase to your Android Project](https://firebase.google.com/docs/android/setup). -2. Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. - - Copy the private key JSON file to this folder and rename it to `service-account.json`. -3. Change the `PROJECT_ID` variable in `configure.py` to your project ID. - -Run ---- - -- Get active template - - From the `config` directory run `python configure.py --action=get` to retrieve the template. - - The returned template is stored in a file named `config.json`. - - Note the Etag printed to the console you will need to use it when publishing template updates. -- Update the template - - If your template already has parameters, adjust one or more of the values. - - If your template is empty, update it to look like this: - - { - "conditions": [ - { - "name": "AndroidUsers", - "expression": "device.os == 'android'", - "tagColor": "PURPLE" - }, - { - "name": "iOSUsers", - "expression": "device.os == 'ios'", - "tagColor": "GREEN" - } - ], - "parameters": { - "welcome_message": { - "defaultValue": { - "value": "Welcome" - }, - "conditionalValues": { - "AndroidUsers": { - "value": "Welcome Android User" - }, - "iOSUsers": { - "value": "Welcome iOS User" - } - } - } - } - } - - - From the `config` directory run `python configure.py --action=publish --etag=` to update the template. - - Be sure to set the etag to the one that was last printed in the console. - - Confirm in the console that the template has been updated. - - At this point mobile clients can fetch the updated values. -- View existing versions - - From the `config` directory run `python configure.py --action=versions` to print the - last 5 template versions. -- Roll back to an existing template - - From the `config` directory run `python configure.py --action=rollback --version=` to - activate the template with the matching version number. - -Best practices --------------- - -This section provides some additional information about how the Remote Config -REST API should be used when retrieving and updating templates. - -### [Versions](https://firebase.google.com/docs/remote-config/templates) ### - -Each time you update parameters, {{remote_config}} creates a -new versioned {{remote_config}} template and stores the previous template as -a version that you can retrieve or roll back to as needed. - -All non-active versions expire and are removed if they are older than 90 days or if -there are more than 300 newer template versions. Since template versions expire, any -versions that need to be retrieved later on should be persisted externally. - -Use the `listVersions` [query parameters](https://firebase.google.com/docs/reference/remote-config/rest/v1/projects.remoteConfig/listVersions#query-parameters) -to filter the versions that are returned. - -### ETags ### - -Each time the Remote Config template it retrieved an ETag is included. This ETag is a -unique identifier of the current template on the server. When submitting updates -to the template you must include the latest ETag to ensure that your updates are consistent. - -In the event that you want to completely overwrite the server's template use -an ETag of "\*". Use this with caution since this operation cannot be undone. - -**NOTE:** To get the ETag your request must accept the gzip encoding. Add the header -`Accept-Encoding: gzip` to receive the ETag in the response header `ETag`. - -Support -------- - -- [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase-remote-config) -- [Firebase Support](https://firebase.google.com/support/) diff --git a/config/configure.py b/config/configure.py deleted file mode 100644 index 8a56f87..0000000 --- a/config/configure.py +++ /dev/null @@ -1,131 +0,0 @@ -import argparse -import requests -import io - -from oauth2client.service_account import ServiceAccountCredentials - - -PROJECT_ID = 'PROJECT_ID' -BASE_URL = 'https://firebaseremoteconfig.googleapis.com' -REMOTE_CONFIG_ENDPOINT = 'v1/projects/' + PROJECT_ID + '/remoteConfig' -REMOTE_CONFIG_URL = BASE_URL + '/' + REMOTE_CONFIG_ENDPOINT -SCOPES = ['https://www.googleapis.com/auth/firebase.remoteconfig'] - -# [START retrieve_access_token] -def _get_access_token(): - """Retrieve a valid access token that can be used to authorize requests. - - :return: Access token. - """ - credentials = ServiceAccountCredentials.from_json_keyfile_name( - 'service-account.json', SCOPES) - access_token_info = credentials.get_access_token() - return access_token_info.access_token -# [END retrieve_access_token] - -def _get(): - """Retrieve the current Firebase Remote Config template from server. - - Retrieve the current Firebase Remote Config template from server and store it - locally. - """ - headers = { - 'Authorization': 'Bearer ' + _get_access_token() - } - resp = requests.get(REMOTE_CONFIG_URL, headers=headers) - - if resp.status_code == 200: - with io.open('config.json', 'wb') as f: - f.write(resp.text.encode('utf-8')) - - print('Retrieved template has been written to config.json') - print('ETag from server: {}'.format(resp.headers['ETag'])) - else: - print('Unable to get template') - print(resp.text) - -def _listVersions(): - """Print the last 5 Remote Config version's metadata.""" - headers = { - 'Authorization': 'Bearer ' + _get_access_token() - } - resp = requests.get(REMOTE_CONFIG_URL + ':listVersions?pageSize=5', headers=headers) - - if resp.status_code == 200: - print('Versions:') - print(resp.text) - else: - print('Request to print template versions failed.') - print(resp.text) - -def _rollback(version): - """Roll back to an available version of Firebase Remote Config template. - - :param version: The version of the template to roll back to. - """ - headers = { - 'Authorization': 'Bearer ' + _get_access_token() - } - - json = { - "version_number": version - } - resp = requests.post(REMOTE_CONFIG_URL + ':rollback', headers=headers, json=json) - - if resp.status_code == 200: - print('Rolled back to version: ' + version) - print(resp.text) - print('ETag from server: {}'.format(resp.headers['ETag'])) - else: - print('Request to roll back to version ' + version + ' failed.') - print(resp.text) - -def _publish(etag): - """Publish local template to Firebase server. - - Args: - etag: ETag for safe (avoid race conditions) template updates. - * can be used to force template replacement. - """ - with open('config.json', 'r', encoding='utf-8') as f: - content = f.read() - headers = { - 'Authorization': 'Bearer ' + _get_access_token(), - 'Content-Type': 'application/json; UTF-8', - 'If-Match': etag - } - resp = requests.put(REMOTE_CONFIG_URL, data=content.encode('utf-8'), headers=headers) - if resp.status_code == 200: - print('Template has been published.') - print('ETag from server: {}'.format(resp.headers['ETag'])) - else: - print('Unable to publish template.') - print(resp.text) - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--action') - parser.add_argument('--etag') - parser.add_argument('--version') - args = parser.parse_args() - - if args.action and args.action == 'get': - _get() - elif args.action and args.action == 'publish' and args.etag: - _publish(args.etag) - elif args.action and args.action == 'versions': - _listVersions() - elif args.action and args.action == 'rollback' and args.version: - _rollback(args.version) - else: - print('''Invalid command. Please use one of the following commands: -python configure.py --action=get -python configure.py --action=publish --etag= -python configure.py --action=versions -python configure.py --action=rollback --version=''') - - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/machine-learning/Firebase_ML_API_Tutorial.ipynb b/machine-learning/Firebase_ML_API_Tutorial.ipynb deleted file mode 100644 index f49057f..0000000 --- a/machine-learning/Firebase_ML_API_Tutorial.ipynb +++ /dev/null @@ -1,1029 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Firebase ML API Tutorial", - "provenance": [], - "collapsed_sections": [], - "toc_visible": true - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.7" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ZRvF80bJ1imr" - }, - "source": [ - "```\n", - "# Copyright 2020 Google LLC\n", - "#\n", - "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", - "# you may not use this file except in compliance with the License.\n", - "# You may obtain a copy of the License at\n", - "#\n", - "#     https://www.apache.org/licenses/LICENSE-2.0\n", - "#\n", - "# Unless required by applicable law or agreed to in writing, software\n", - "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", - "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", - "# See the License for the specific language governing permissions and\n", - "# limitations under the License.\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "XK1TC6JmaSo5" - }, - "source": [ - "This Colab demonstrates how you can use the Firebase Admin Python SDK from a Jupyter notebook to manage your Firebase-hosted ML models." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ThfwN5km4l7X" - }, - "source": [ - "# **1. Install the Admin SDK and TensorFlow** " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "x4qsJu_y4onY" - }, - "source": [ - "Install the Firebase Admin SDK and TensorFlow. If you're running this notebook in a Google Colab environment, you can skip this step." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "1sTVOhJC20Ce", - "colab": {} - }, - "source": [ - "%pip install 'firebase_admin>=4.1.0'\n", - "%pip install 'tensorflow>=2.1.0'" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "xTklrznZYR_F" - }, - "source": [ - "# **2. Set up a Firebase project**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "CHjogYcnYcgb" - }, - "source": [ - "Before you can continue, you need to set up a Firebase project:\n", - "\n", - "1. If you don't already have a Firebase project, create a new project in the [Firebase console](https://console.firebase.google.com/). Then, open your project and do the following:\n", - "\n", - " 1. On the [Settings](https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk) page, create a service account and download the service account key file. Keep this file safe, since it grants administrator access to your project.\n", - "\n", - " 1. On the [Storage](https://console.firebase.google.com/project/_/storage) page, enable Cloud Storage. Take note of your bucket name.\n", - "\n", - " You need a Storage bucket to temporarily store model files while adding them to your Firebase project. If you are on the Blaze plan, you can create and use a bucket other than the default for this purpose.\n", - "\n", - " 1. On the [ML Kit](https://console.firebase.google.com/project/_/ml) page, click **Get started** if you haven't yet enabled ML Kit.\n", - "\n", - "1. In the [Google APIs console](https://console.developers.google.com/apis/library/firebaseml.googleapis.com?project=_), open your Firebase project and enable the Firebase ML API.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "qJ07z89GsNqh" - }, - "source": [ - "# **3. Upload the json service account key file for your project to the runtime**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "A9w5FJ0cXia2" - }, - "source": [ - "Then, upload the service account key file you got in the previous step:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "8OeMQU9az4gh", - "colab": {} - }, - "source": [ - "import ipywidgets\n", - "\n", - "uploader = ipywidgets.FileUpload(\n", - " accept='.json',\n", - " multiple=False\n", - ")\n", - "service_acct_file = {}\n", - "def handle_upload(change):\n", - " service_acct_file['name'] = next(iter(change['owner'].value))\n", - " service_acct_file['data'] = change['owner'].value[service_acct_file['name']]['content']\n", - " with open(service_acct_file['name'], 'wb') as f:\n", - " f.write(service_acct_file['data'])\n", - " print('Uploaded {}'.format(service_acct_file['name']))\n", - "uploader.observe(handle_upload, names='data')\n", - "display(uploader)\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "HEVNf2rxwgfo" - }, - "source": [ - "# **4. Set your Google Application Credentials location**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "39qaiVVqeA51" - }, - "source": [ - "Set the `GOOGLE_APPLICATION_CREDENTIALS` environmental variable to the location of the key file:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "fdGKEWCH1SsT", - "colab": {} - }, - "source": [ - "import os\n", - "os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = os.path.realpath(service_acct_file['name'])" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ma-McTrY0cGE" - }, - "source": [ - "# **5. Initialize Firebase Admin**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "X9xyubP_ekA5" - }, - "source": [ - "Import the `firebase_admin` module and initialize the SDK with the name of your Storage bucket. Be sure the Storage bucket is in the same Firebase project as your service account. Your project's default bucket looks like `your-project-id.appspot.com`." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "2sLO335O7IIF", - "colab": {} - }, - "source": [ - "storage_bucket = input('Storage bucket (no \"gs://\"): ')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "YxYkdFBs0oS1", - "colab": {} - }, - "source": [ - "import firebase_admin\n", - "from firebase_admin import ml\n", - "\n", - "firebase_admin.initialize_app(options={'storageBucket': storage_bucket})" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "DLOmPtM77wMI" - }, - "source": [ - "# **6. Train your model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "oNEyKOO_ivrO" - }, - "source": [ - "Next, train your model.\n", - "\n", - "In a real notebook, you'd use a model architecture designed for your use case and provide your own training data. For this demo, just train a trivial model:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "6lrYxa4Z70Xp", - "colab": {} - }, - "source": [ - "import tensorflow as tf\n", - "\n", - "# Create a simple Keras model.\n", - "x = [-1, 0, 1, 2, 3, 4]\n", - "y = [-3, -1, 1, 3, 5, 7]\n", - "\n", - "model_binary = tf.keras.models.Sequential(\n", - " [tf.keras.layers.Dense(units=1, input_shape=[1])])\n", - "model_binary.compile(optimizer='sgd', loss='mean_squared_error')\n", - "model_binary.fit(x, y, epochs=3)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "1LK9d37xYDet" - }, - "source": [ - "# **7. Convert & upload your model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "mGe3os8Xkf7F" - }, - "source": [ - "Now that you have a trained model, you can upload it to Firebase and make it available to your iOS and Android apps.\n", - "\n", - "First, convert the model to TensorFlow Lite and upload it to Cloud Storage. With the Admin SDK, this is a single call:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "SLZvUStHa7T3", - "colab": {} - }, - "source": [ - "# This takes the Keras model, converts it to a TFLite model, and uploads it to\n", - "# your bucket as my_model.tflite\n", - "source = ml.TFLiteGCSModelSource.from_keras_model(model_binary, 'my_model.tflite')\n", - "print(source.gcs_tflite_uri)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "NpZMyCUzGTbU", - "colab_type": "text" - }, - "source": [ - "If you get a `toco_from_protos: command not found` error, make sure the Python binary directory is in your `PATH`, then try again." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "qR3s7s5BGTbU", - "colab_type": "code", - "colab": {} - }, - "source": [ - "import os\n", - "import sys\n", - "py_bin_dir = os.path.dirname(sys.executable)\n", - "os.environ['PATH'] = '{}:{}'.format(os.environ['PATH'], py_bin_dir)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "RRA56_U9o2P9" - }, - "source": [ - "# **8. Create a Model object**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "HzB_CV5yo9Ms" - }, - "source": [ - "Next, create a `Model` object, specifying the model's Cloud Storage source and the name of your model. (You will use the name you specify here to download the model in your iOS and Android apps.)" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "rljlmVwgo1dk", - "colab": {} - }, - "source": [ - "model_format = ml.TFLiteFormat(model_source=source)\n", - "sdk_model_1 = ml.Model(display_name=\"my_model_1\", model_format=model_format)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "0Hd7aZrpdOqm" - }, - "source": [ - "# **9. Add the model to your Firebase project**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ZEMJ-B2LqhPt" - }, - "source": [ - "Add the model to your Firebase project by calling `create_model()`. When you do so, the model gets copied from Cloud Storage.\n", - "\n", - "Note that this step will fail if your project already has a model named `my_model_1`. If this happens, [delete the model with the Firebase console](https://console.firebase.google.com/project/_/ml/custom) and try again." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "AOjQVSU2eG8v", - "colab": {} - }, - "source": [ - "firebase_model_1 = ml.create_model(sdk_model_1)\n", - "if firebase_model_1.validation_error:\n", - " raise Exception(firebase_model_1.validation_error)\n", - "print(firebase_model_1.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "lMthadQ4qU32" - }, - "source": [ - "# **10. Publish the model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "oNTN-XEFvd7g" - }, - "source": [ - "Finally, publish your model:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "qK2S0KD7qbIB", - "colab": {} - }, - "source": [ - "model_id = firebase_model_1.model_id\n", - "firebase_model_1 = ml.publish_model(model_id)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "IpxBS8HzvvWm" - }, - "source": [ - "Now that you've published the model, you can [use it in your apps](https://firebase.google.com/docs/ml-kit/use-custom-models)." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ZHSN6vM7b_pH" - }, - "source": [ - "# **11. Create a second model (so we can update)**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "lhuuTNtHwduW" - }, - "source": [ - "You can update a published model with a new model file. When you do so, client apps automatically download and use the new model.\n", - "\n", - "For demonstration purposes, first save one of Keras's prepackaged models to a saved model directory:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "1pLVpHi4cF6e", - "colab": {} - }, - "source": [ - "tf.saved_model.save(tf.keras.applications.MobileNet(), '/tmp/saved_model/1')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "veOOV0ZxjMf-" - }, - "source": [ - "# **12. Create a second model source and model format from the new model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "XIyAhNEFGNIN" - }, - "source": [ - "Now, convert the saved model to TensorFlow Lite and upload it to Cloud Storage. This time, you're converting a TensorFlow saved model to TensorFlow Lite, but you could also convert a Keras model like you did earlier, or convert a Keras model saved as an HDF5 (`.h5`) file." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "hn5IgonpjWmy", - "colab": {} - }, - "source": [ - "# This takes the saved model directory, converts it to TFLite and writes it to your bucket as my_model_2.tflite\n", - "source2 = ml.TFLiteGCSModelSource.from_saved_model('/tmp/saved_model/1', 'my_model_2.tflite')" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "wtXV_x7ko1Dz" - }, - "source": [ - "# **13. Modify the local model and then call the API Update**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "m2WyUn4SJWEC" - }, - "source": [ - "Change the original `Model` object's model source and (optionally) metadata, then call `update_model()`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "MiRQi2Iqo8PK", - "colab": {} - }, - "source": [ - "model_format2 = ml.TFLiteFormat(model_source=source2)\n", - "firebase_model_1.model_format = model_format2\n", - "firebase_model_1.tags = ['tag1', 'tag2'] # replaces any existing tags with these tags.\n", - "\n", - "firebase_model_2 = ml.update_model(firebase_model_1)\n", - "if firebase_model_2.validation_error:\n", - " raise Exception(firebase_model_2.validation_error)\n", - "print(firebase_model_2.as_dict())\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "uZzu3k5EXMma" - }, - "source": [ - "# **14. Publish the model_format2 model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "XaiWqq4EkWBU" - }, - "source": [ - "After you update the model, re-publish it:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "iGsNmx2oXUFS", - "colab": {} - }, - "source": [ - "firebase_model_2 = ml.publish_model(model_id)\n", - "print(firebase_model_2.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "m2YmhA4Ab1DH" - }, - "source": [ - "# **15. Get the model**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "_01adxyEk0JN" - }, - "source": [ - "If you need to get a `Model` object from one of your project's models, use `get_model()`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "9Q1jQXYJb4qx", - "colab": {} - }, - "source": [ - "firebase_model_get = ml.get_model(model_id)\n", - "print(firebase_model_get.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "OphmZAVdcqxO" - }, - "source": [ - "# **16. List the models**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "kOIjFLyGlpyq" - }, - "source": [ - "To list your project's models, iterate over the result of `list_models()`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "ebJBI9NVcwjp", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models()\n", - "iterator = firebase_models_list.iterate_all()\n", - "for m in iterator:\n", - " print(m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "p_4yAHeFg7BA" - }, - "source": [ - "# **17. Make more models so we can show lists better**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "9vOkbq1lmA2B" - }, - "source": [ - "The Admin SDK can help you manage projects with many models.\n", - "\n", - "To demonstrate this, create some more models:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "ce3zB3HLhCTf", - "colab": {} - }, - "source": [ - "list_model_1 = ml.create_model(ml.Model(display_name='my_model_2', tags=['tag2', 'tag3'], model_format=model_format))\n", - "list_model_2 = ml.create_model(ml.Model(display_name='my_model_3', tags=['tag3'], model_format=model_format))\n", - "list_model_3 = ml.create_model(ml.Model(display_name='cat_model_1', tags=['cat'], model_format=model_format))\n", - "list_model_4 = ml.create_model(ml.Model(display_name='cat_model_2', tags=['cat'], model_format=model_format))\n", - "list_model_5 = ml.create_model(ml.Model(display_name='new_cat_model_007', tags=['cat'], model_format=model_format))" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "QmxpYBsQnua4" - }, - "source": [ - "# **18. Publish some of them**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "OvYY0orEmtsT" - }, - "source": [ - "And publish some of them:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "x6kzkhWjnyXr", - "colab": {} - }, - "source": [ - "list_model_2 = ml.publish_model(list_model_2.model_id)\n", - "list_model_4 = ml.publish_model(list_model_4.model_id)" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "aAIAexOTpkVu" - }, - "source": [ - "# **19. Listing with page size**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "BZC1dbfnm43F" - }, - "source": [ - "You can specify how many results to return at a time:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "kf3rUxE0pqzJ", - "colab": {} - }, - "source": [ - "firebase_models_list_2 = ml.list_models(page_size=3)\n", - "for m in firebase_models_list_2.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "V0WpL3UarTlA" - }, - "source": [ - "# **20. Listing the next page**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "iPh886g2nNm9" - }, - "source": [ - "Get the next page of results:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "iodXtP_XrYGT", - "colab": {} - }, - "source": [ - "firebase_models_list_3 = firebase_models_list_2.get_next_page()\n", - "for m in firebase_models_list_3.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "LJwxO53KnYHA" - }, - "source": [ - "When you retrieve the final page, `get_next_page()` returns `None`." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "Xbv-NAm5tT_5" - }, - "source": [ - "# **21. Filtering lists**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "-aNfitPHoF9P" - }, - "source": [ - "You can also filter the results.\n", - "\n", - "Filter by display name:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "9eS1kVSwtgwJ", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models(list_filter='display_name=cat_model_1')\n", - "for m in firebase_models_list.models:\n", - " print (m.as_dict())\n" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "mLNhAGtjuxqF" - }, - "source": [ - "Filter by display name prefix (note that only prefix matching is supported; you can't do general wildcard matching):" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "YpihoJvnu1PU", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models(list_filter='display_name:cat_*')\n", - "for m in firebase_models_list.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "e54EB4ngwBM6" - }, - "source": [ - "Filter by tag:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "woK9u8P0wJ0a", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models(list_filter='tags: cat')\n", - "for m in firebase_models_list.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "ZrSJImzSyRoI" - }, - "source": [ - "Filter by publish state:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "G2xmcFuMyXRX", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models(list_filter='state.published = true')\n", - "for m in firebase_models_list.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "-EagFFnwzyI5" - }, - "source": [ - "Combine filters:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "3U40mUaQz9KE", - "colab": {} - }, - "source": [ - "firebase_models_list = ml.list_models(list_filter='(display_name: cat_* OR tags: tag3) AND NOT state.published = true')\n", - "for m in firebase_models_list.models:\n", - " print (m.as_dict())" - ], - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "sYur7GCQBVas" - }, - "source": [ - "# **22. Clean up**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "v1BKMU30Blnr" - }, - "source": [ - "That's it!\n", - "\n", - "Clean up by deleting the example models:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab_type": "code", - "id": "wGRXAfFiCHOF", - "colab": {} - }, - "source": [ - "ml.delete_model(model_id)\n", - "ml.delete_model(list_model_1.model_id)\n", - "ml.delete_model(list_model_2.model_id)\n", - "ml.delete_model(list_model_3.model_id)\n", - "ml.delete_model(list_model_4.model_id)\n", - "ml.delete_model(list_model_5.model_id)" - ], - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/machine-learning/README.md b/machine-learning/README.md deleted file mode 100644 index a89284b..0000000 --- a/machine-learning/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# Firebase Admin Python SDK ML quickstart - -This sample script shows how you can use the Firebase Admin SDK to manage your -Firebase-hosted ML models. - -Also see the [Firebase ML API Tutorial Colab/Jupyter notebook][colab]. - -[colab]: https://colab.research.google.com/github/firebase/quickstart-python/blob/master/machine-learning/Firebase_ML_API_Tutorial.ipynb - -## Setup - -1. Install the Admin SDK and other dependencies (probably in a virtual - environment): - - ``` - $ pip install -U pip setuptools - $ pip install -r requirements.txt - ``` - -2. Clone the quickstart repository and change to the `machine-learning` -   directory: - - ``` - $ git clone https://github.com/firebase/quickstart-python.git - $ cd quickstart-python/machine-learning - $ chmod u+x manage-ml.py # Optional - ``` - -3. If you don't already have a Firebase project, create a new project in the - [Firebase console](https://console.firebase.google.com/). Then, open your - project in the Firebase console and do the following: - - 1. On the [Settings][service-account] page, create a service account and - download the service account key file. Keep this file safe, since it - grants administrator access to your project. - 2. On the Storage page, enable Cloud Storage. Take note of your default - bucket name (or create a new bucket for ML models.) - 3. On the ML Kit page, click **Get started** if you haven't yet enabled ML - Kit. - -4. In the [Google APIs console][enable-api], open your Firebase project and - enable the Firebase ML API. - -[enable-api]: https://console.developers.google.com/apis/library/firebaseml.googleapis.com?project=_ - -5. At the top of `manage-ml.py`, set the `SERVICE_ACCOUNT_KEY` and - `STORAGE_BUCKET`: - - ``` - SERVICE_ACCOUNT_KEY = '/path/to/your/service_account_key.json' - STORAGE_BUCKET = 'your-storage-bucket' - ``` - -[service-account]: https://firebase.google.com/project/_/settings/serviceaccounts/adminsdk - -## Example session - -``` -$ ./manage-ml.py list - Name ID Tags ----------------------- ---------- ------------------ - fish_recognizer 12990533 vision - barcode_scanner 12990544 vision -$ ./manage-ml.py new yak_detector -f model.tflite -t vision,experimental -Uploading to Cloud Storage... -Model uploaded and published: - yak_detector 12990577 experimental, vision -$ ./manage-ml.py new flower_classifier -a projects/12345/locations/us-central1/models/ICN12345 -Model uploaded and published: - flower_classifier 12990597 -$ ./manage-ml.py list - Name ID Tags ----------------------- ---------- ---------------------- - fish_recognizer 12990533 vision - barcode_scanner 12990544 vision - yak_detector 12990577 experimental, vision - flower_classifier 12990597 -$ ./manage-ml.py update 12990577 --remove_tags experimental -$ ./manage-ml.py delete 12990544 -$ ./manage-ml.py list - Name ID Tags ----------------------- ---------- ------------------ - fish_recognizer 12990533 vision - yak_detector 12990577 vision - flower_classifier 12990597 -$ -``` diff --git a/machine-learning/manage-ml.py b/machine-learning/manage-ml.py deleted file mode 100755 index e18ea26..0000000 --- a/machine-learning/manage-ml.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python3 -"""Firebase Admin SDK ML quickstart example.""" - -import argparse -from datetime import datetime -from datetime import timezone - -from beautifultable import BeautifulTable -import firebase_admin -from firebase_admin import ml - - -# TODO(user): Configure for your project. (See README.md.) -SERVICE_ACCOUNT_KEY = '/path/to/your/service_account_key.json' -STORAGE_BUCKET = 'your-storage-bucket' - -credentials = firebase_admin.credentials.Certificate(SERVICE_ACCOUNT_KEY) -firebase_admin.initialize_app(credentials, options={ - 'storageBucket': STORAGE_BUCKET -}) - - -def upload_model(model_file, name, tags=None): - """Upload a tflite model file to the project and publish it.""" - # Load a tflite file and upload it to Cloud Storage - print('Uploading to Cloud Storage...') - model_source = ml.TFLiteGCSModelSource.from_tflite_model_file(model_file) - - # Create the model object - tflite_format = ml.TFLiteFormat(model_source=model_source) - model = ml.Model( - display_name=name, - model_format=tflite_format) - if tags is not None: - model.tags = tags - - # Add the model to your Firebase project and publish it - new_model = ml.create_model(model) - ml.publish_model(new_model.model_id) - - print('Model uploaded and published:') - print_models([new_model], headers=False) - - -def add_automl_model(model_ref, name, tags=None): - """Add an AutoML tflite model file to the project and publish it.""" - # Create the model object - model_source = ml.TFLiteAutoMlSource(model_ref) - model = ml.Model( - display_name=name, - model_format=ml.TFLiteFormat(model_source=model_source)) - if tags is not None: - model.tags = tags - - # Add the model to your Firebase project and publish it - new_model = ml.create_model(model) - new_model.wait_for_unlocked() - ml.publish_model(new_model.model_id) - - print('Model uploaded and published:') - print_models([new_model], headers=False) - - -def list_models(filter_exp=''): - """List the models in the project.""" - models = ml.list_models(list_filter=filter_exp).iterate_all() - print_models(models) - - -def print_models(models, headers=True): - """Prettyprint a list of models.""" - table = BeautifulTable() - if headers: - table.columns.header = ['Name', 'ID', 'Tags'] - for model in models: - tags = ', '.join(model.tags) if model.tags is not None else '' - table.rows.append([model.display_name, model.model_id, tags]) - table.set_style(BeautifulTable.STYLE_COMPACT) - table.columns.header.alignment = BeautifulTable.ALIGN_CENTER - table.columns.alignment = BeautifulTable.ALIGN_LEFT - print(table) - - -def get_model_info(model_id): - """Get model details.""" - model = ml.get_model(model_id) - created = datetime.fromtimestamp(model.create_time / 1000, timezone.utc) - updated = datetime.fromtimestamp(model.update_time / 1000, timezone.utc) - table = BeautifulTable() - table.columns.append(['Name:', 'ID:', 'Tags:', 'Published:', 'ETag:', - 'SHA256:', 'Created:', 'Updated:']) - table.columns.append([model.display_name, - model.model_id, - ', '.join(model.tags) if model.tags else '', - 'Yes' if model.published else 'No', - model.etag, - model.model_hash, - created.isoformat(' ', timespec='seconds'), - updated.isoformat(' ', timespec='seconds')]) - table.set_style(BeautifulTable.STYLE_COMPACT) - table.columns.alignment = BeautifulTable.ALIGN_LEFT - print(table) - - -def update_model(model_id, model_file=None, name=None, - new_tags=None, remove_tags=None): - """Update one of the project's models.""" - model = ml.get_model(model_id) - - if model_file is not None: - # Load a tflite file and upload it to Cloud Storage - print('Uploading to Cloud Storage...') - model_source = ml.TFLiteGCSModelSource.from_tflite_model_file(model_file) - tflite_format = ml.TFLiteFormat(model_source=model_source) - model.model_format = tflite_format - - if name is not None: - model.display_name = name - - if new_tags is not None: - model.tags = new_tags if model.tags is None else model.tags + new_tags - - if remove_tags is not None and model.tags is not None: - model.tags = list(set(model.tags).difference(set(remove_tags))) - - updated_model = ml.update_model(model) - ml.publish_model(updated_model.model_id) - - -def delete_model(model_id): - """Delete a model from the project.""" - ml.delete_model(model_id) - - -# The rest of the file just parses the command line and dispatches one of the -# functions above. - - -def main(): - main_parser = argparse.ArgumentParser() - subparsers = main_parser.add_subparsers( - dest='command', required=True, metavar='command') - - new_parser = subparsers.add_parser( - 'new', help='upload a tflite model file or AutoML model reference to' - ' your project') - new_parser.add_argument( - 'name', type=str, help='display name for the new model') - new_source_group = new_parser.add_mutually_exclusive_group(required=True) - new_source_group.add_argument( - '-f', '--file', type=str, help='path to the tflite file') - new_source_group.add_argument( - '-a', '--automl', type=str, help='AutoML model reference (e.g. projects/' - '12345678/locations/us-central1/models/' - 'ICN1234567890)') - new_parser.add_argument( - '-t', '--tags', type=str, help='comma-separated list of tags') - - list_parser = subparsers.add_parser( - 'list', help='list your project\'s models') - list_parser.add_argument( - '-f', '--filter', type=str, default='', - help='''filter expression to limit results (see: - https://firebase.google.com/docs/ml-kit/manage-hosted-models#list_your_projects_models)''') - - info_parser = subparsers.add_parser( - 'info', help='') - info_parser.add_argument( - 'model_id', type=valid_id, help='the ID of the model you want to view') - - update_parser = subparsers.add_parser( - 'update', help='update one of your project\'s models') - update_parser.add_argument( - 'model_id', type=valid_id, help='the ID of the model you want to update') - update_parser.add_argument( - '-m', '--model_file', type=str, help='path to a new tflite file') - update_parser.add_argument( - '-n', '--name', type=str, help='display name for the model') - update_parser.add_argument( - '-t', '--new_tags', type=str, - help='comma-separated list of tags to add') - update_parser.add_argument( - '-d', '--remove_tags', type=str, - help='comma-separated list of tags to remove') - - delete_parser = subparsers.add_parser( - 'delete', help='delete a model from your project') - delete_parser.add_argument( - 'model_id', type=valid_id, help='the ID of the model you want to delete') - - args = main_parser.parse_args() - try: - if args.command == 'new' and args.file is not None: - tags = args.tags.split(',') if args.tags is not None else None - upload_model(args.file.strip(), args.name.strip(), tags) - if args.command == 'new' and args.automl is not None: - tags = args.tags.split(',') if args.tags is not None else None - add_automl_model(args.automl.strip(), args.name.strip(), tags) - elif args.command == 'list': - list_models(args.filter) - elif args.command == 'info': - get_model_info(args.model_id) - elif args.command == 'update': - new_tags = args.new_tags.split(',') if args.new_tags is not None else None - remove_tags = ( - args.remove_tags.split(',') if args.remove_tags is not None else None) - update_model(args.model_id, args.model_file, args.name, - new_tags, remove_tags) - elif args.command == 'delete': - delete_model(args.model_id) - except firebase_admin.exceptions.NotFoundError: - print('ERROR: Model not found. Make sure you\'re specifying a valid' - ' numerical model ID.') - - -def valid_id(model_id): - try: - val = int(model_id) - return str(val) - except ValueError: - raise argparse.ArgumentTypeError('must be a numerical model ID.') - - -if __name__ == '__main__': - main() diff --git a/machine-learning/requirements.txt b/machine-learning/requirements.txt deleted file mode 100644 index 9a1b22c..0000000 --- a/machine-learning/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -beautifultable~=1.0.0 -firebase-admin~=4.4.0 diff --git a/messaging/.gitignore b/messaging/.gitignore deleted file mode 100644 index fe6109d..0000000 --- a/messaging/.gitignore +++ /dev/null @@ -1 +0,0 @@ -service-account.json \ No newline at end of file diff --git a/messaging/README.md b/messaging/README.md deleted file mode 100644 index c6c705e..0000000 --- a/messaging/README.md +++ /dev/null @@ -1,103 +0,0 @@ -Firebase Cloud Messaging Python Quickstart -========================================== - -The Firebase Cloud Messaging Python quickstart app demonstrates sending -notification messages to a topic. All clients subscribed to the topic -will receive the message. - -Introduction ------------- - -This is a simple example of using Firebase Cloud Messaging REST API to send -the same message to different platforms. To learn more about how you can use -Firebase Cloud Messaging REST API in your app, see [About Cloud Messaging Server](https://firebase.google.com/docs/cloud-messaging/server/). - -Getting started ---------------- - -1. Create a service account as described in [Adding Firebase to your Server](https://firebase.google.com/docs/admin/setup) and download the JSON file. - - Copy the json file to this folder and rename it to `service-account.json`. -2. Change the `PROJECT_ID` variable in `messaging.py` to your project ID. -3. Ensure you install `requests` and `google-api-python-client` - - easy_install --upgrade requests - easy_install --upgrade google-api-python-client - -Run ---- -- This sample allows you to send two types of messages: - - 1. A message that uses the common `notification` object of the API. It is used to define - the `title` and `body` of a notification message (display message). To send this message, from the - `messaging` directory run: - - python messaging.py --message=common-message - - 2. A message that uses the common `notification` object of the API as well as tha `android` and - `apns` objects to customize the messages received on the corresponding platforms. To send this - message, from the `messaging` directory run: - - python messaging.py --message=override-message - -- Any client devices that you have subscribed to the news topic should receive - a notification message. - - 1. When you use the `common-message` option, clients receive a simple notification message - with only title and body defined. - - 2. When you use the `override-message` option, clients receive a simple notification message - with title and body defined. In addition: - - iOS devices would receive high priority messages and if the app is in the background then a - badge will be applied to the app's icon. - - - Android devices would receive a message with a `click_action`. In this case it is set - to the default intent, but this could be customized to any intent available in your app. - -Best practices --------------- -This section provides some additional information about how the FCM payloads can -be used to target different platforms. - -### Common payloads ### - -In many cases you may want to send the same message to multiple platforms. If -this is a notification message (display notification) then you can use the -common payloads. These are payloads that are automatically translated to their -platform equivalent payloads. - -### Platform customizations ### - -In cases where you would like to customize the message for the different platforms -that will receive the message, use the platform specific objects to add or override -anything set by the common fields. - -For example, if you want to send a notification message (display notification) to all platforms -but you would like to include accompanying data to Android clients receiving the -message, then you can use the `android` object to define a `data` payload that will -be appended to the notification message when sent to Android clients. - -Support -------- - -- [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase-cloud-messaging) -- [Firebase Support](https://firebase.google.com/support/) - -License -------- - -Copyright 2016 Google, Inc. - -Licensed to the Apache Software Foundation (ASF) under one or more contributor -license agreements. See the NOTICE file distributed with this work for -additional information regarding copyright ownership. The ASF licenses this -file to you 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. diff --git a/messaging/messaging.py b/messaging/messaging.py deleted file mode 100644 index 7e9b235..0000000 --- a/messaging/messaging.py +++ /dev/null @@ -1,126 +0,0 @@ -"""Server Side FCM sample. - -Firebase Cloud Messaging (FCM) can be used to send messages to clients on iOS, -Android and Web. - -This sample uses FCM to send two types of messages to clients that are subscribed -to the `news` topic. One type of message is a simple notification message (display message). -The other is a notification message (display notification) with platform specific -customizations. For example, a badge is added to messages that are sent to iOS devices. -""" - -import argparse -import json -import requests -import google.auth.transport.requests - -from google.oauth2 import service_account - -PROJECT_ID = '' -BASE_URL = 'https://fcm.googleapis.com' -FCM_ENDPOINT = 'v1/projects/' + PROJECT_ID + '/messages:send' -FCM_URL = BASE_URL + '/' + FCM_ENDPOINT -SCOPES = ['https://www.googleapis.com/auth/firebase.messaging'] - -# [START retrieve_access_token] -def _get_access_token(): - """Retrieve a valid access token that can be used to authorize requests. - - :return: Access token. - """ - credentials = service_account.Credentials.from_service_account_file( - 'service-account.json', scopes=SCOPES) - request = google.auth.transport.requests.Request() - credentials.refresh(request) - return credentials.token -# [END retrieve_access_token] - -def _send_fcm_message(fcm_message): - """Send HTTP request to FCM with given message. - - Args: - fcm_message: JSON object that will make up the body of the request. - """ - # [START use_access_token] - headers = { - 'Authorization': 'Bearer ' + _get_access_token(), - 'Content-Type': 'application/json; UTF-8', - } - # [END use_access_token] - resp = requests.post(FCM_URL, data=json.dumps(fcm_message), headers=headers) - - if resp.status_code == 200: - print('Message sent to Firebase for delivery, response:') - print(resp.text) - else: - print('Unable to send message to Firebase') - print(resp.text) - -def _build_common_message(): - """Construct common notifiation message. - - Construct a JSON object that will be used to define the - common parts of a notification message that will be sent - to any app instance subscribed to the news topic. - """ - return { - 'message': { - 'topic': 'news', - 'notification': { - 'title': 'FCM Notification', - 'body': 'Notification from FCM' - } - } - } - -def _build_override_message(): - """Construct common notification message with overrides. - - Constructs a JSON object that will be used to customize - the messages that are sent to iOS and Android devices. - """ - fcm_message = _build_common_message() - - apns_override = { - 'payload': { - 'aps': { - 'badge': 1 - } - }, - 'headers': { - 'apns-priority': '10' - } - } - - android_override = { - 'notification': { - 'click_action': 'android.intent.action.MAIN' - } - } - - fcm_message['message']['android'] = android_override - fcm_message['message']['apns'] = apns_override - - return fcm_message - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('--message') - args = parser.parse_args() - if args.message and args.message == 'common-message': - common_message = _build_common_message() - print('FCM request body for message using common notification object:') - print(json.dumps(common_message, indent=2)) - _send_fcm_message(common_message) - elif args.message and args.message == 'override-message': - override_message = _build_override_message() - print('FCM request body for override message:') - print(json.dumps(override_message, indent=2)) - _send_fcm_message(override_message) - else: - print('''Invalid command. Please use one of the following commands: -python messaging.py --message=common-message -python messaging.py --message=override-message''') - -if __name__ == '__main__': - main()