In recent years, mobile and web development have undergone a significant evolution. Modern applications not only possess powerful features but also require a more comprehensive infrastructure beyond traditional hosting services. At this point, major companies like Amazon and Google offer extensive solutions to meet all these requirements. When transitioning between platforms like AWS and Firebase, it's crucial to meticulously plan each step and manage this complex integration process correctly, ensuring projects successfully adapt to serverless architectures. In this article, I will explain the process of transferring my primary AWS flow to the Firebase platform using Firebase services. In doing so, we will discover how similar the structures of Firebase and AWS platforms actually are. Additionally, we will examine how to send notifications to users using the Firebase Cloud Messaging service.
Definition of AWS Flow
In Figure 1's AWS workflow, user input and connection ID information are received. These collected data are sent to the Replicate service, which runs machine learning models in the cloud environment, through an AWS Lambda function. Replicate provides users with machine learning models in Application Programming Interface (API) or Docker formats. In our article, we will use the models in API format. Replicate's APIs allow the use of a webhook service structure. With the help of the webhook service, the response from the Replicate API is redirected to a different URL. The response received through the webhook service is saved into an AWS S3 bucket using AWS Lambda. The saved response is then returned to the user with the assistance of Websocket.
The AWS workflow described in Figure 1 has been translated into the following steps within a Firebase structure:
- Setting Up the Flask Application:
- Begins with creating a basic Flask project.
- Integration of Firebase Cloud Messaging:
- In the Flask project, FCM token information is obtained with Firebase Cloud Messaging configurations.
- Transformation of AWS Replicate Function:
- The 'Send to AWS Replicate' Lambda function is converted into a cloud function using Firebase Cloud Functions.
- Within the function, configurations for the API used in Replicate are set up. In addition, FCM token information and the webhook service URL are also sent via the API.
- Processing the Webhook Service URL:
- The webhook service URL sent to Replicate is directed to the function equivalent to the 'Save to AWS S3' Lambda function in Figure 1, which saves the image received from the UPA to Google Cloud Storage.
- Transformation of the 'Save to AWS S3' Function:
- Within the Firebase Cloud Function:
- The image received from Replicate is saved in Google Cloud Storage.
- The image URL and FCM token information are extracted.
- Within the application, a POST request containing the image URL and FCM token information is sent to the Firebase Function that sends notifications.
- Within the Firebase Cloud Function:
- Firebase Bildirim Gönderme Fonksiyonu:
- Bu fonksiyon, FBM aracılığıyla bir bildirim göndermeyi sağlar. İsteğin JSON verisi içindeki image_url ve jeton bilgilerini alır, ardından bu bilgileri kullanarak belirtilen cihaza bir bildirim gönderir.
Flask Application
To send notifications to the user, a structure on the user side is required, hence a simple Flask application is created. Within the Flask application, user input is received as depicted in Figure 2, to transmit the input information from the user to a Replicate API. The text input received and the FCM token information generated when the page is first opened are sent to the function equivalent to the 'Send to AWS Replicate' Lambda function on the Flask server side.
Integration of Firebase Cloud Messaging
Creation of Firebase Software Development Kit (SDK)
First, we log into the Firebase console and then create a new Firebase project as shown in Figure 3.
We go to the project settings section within the project we created. In the project settings, under the service accounts tab, we select 'Create new private key'. In the Admin SDK configuration section, it is shown how to use the downloaded private key file according to the language structure we use in the project.
An example of the contents inside a private key file is as follows.
{
"type": "service_account",
"project_id": "your_project_id",
"private_key_id": "your_private_key_id",
"private_key": "your_private_key",
"client_email": "your_client_email.com",
"client_id": "your_client_id",
"auth_uri": "your_auth_uri",
"token_uri": "your_token_uri",
"auth_provider_x509_cert_url": "auth_provider_x509_cert_url",
"client_x509_cert_url": "client_x509_cert_url",
"universe_domain": "universe_domain"
}
On the same settings page, under the General tab, how to install the Firebase SDK into your application is shown as in Figure 4. To set up the SDK connection, we need to create a firebase-messaging-sw.js configuration file with the information shown in Figure 4. This file should be located in the root folder location of the project.
Adding the SDK File to the Flask Application
In our Flask application, we need to write a JavaScript function to obtain the FCM token information. The 'Firebase FCM Token Generation' code below performs the necessary actions to receive instant notifications in the browser using FCM.Firstly,we initialize Firebase with firebaseConfig
and then create a messaging
instance to facilitate interaction with notifications. The registerServiceWorker
function registers a Service Worker in the browser. Service Workers are typically used to enable features like offline access and notifications. When the Service Worker is successfully registered, it prints the scope information to the console; in case of an error, an error message is printed to the console. This code ensures safe operation by handling potential error situations while enabling the capability to send instant notifications to the user. Firstly, we create a service worker with Firebase and register our device with the Firebase Cloud Messaging service. Firebase Cloud Messaging service returns a unique token specific to the device. This token allows us to send notifications to the device. Then, we send this FCM token information to a server-side Python function. The Python function, in turn, sends this token information and the user input to the Firebase cloud function.
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
function registerServiceWorker() {
return navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then((registration) => {
console.log('Service Worker registered with scope:', registration.scope);
return registration;
})
.catch((error) => {
console.error('Service Worker registration failed:', error);
throw error;
});
}
function requestAndSendFCMToken() {
return messaging.requestPermission()
.then(async () => {
const token = await messaging.getToken();
console.log('FCM token:', token);
return token;
})
.catch((error) => {
console.error('Error requesting permission or getting FCM token:', error);
throw error;
});
}
Transformation of AWS Replicate Function
Creating a Cloud Function with Google Cloud Functions
We log into the Google Cloud Console.After logging in, we select our project created via Firebase from the upper left section and then navigate to the Google Cloud Functions service by typing 'Google Cloud Functions' in the search bar.
In the Cloud Functions service, we click on the 'create function' button to create a new function. We configure the sections shown in Figure 5 according to the structure of our function.
As shown in Figure 6, Google Cloud Functions can be written in multiple languages. In the section named 'entry point', we specify the name of the main function that will operate within the function we have written.
Function to Send Queries to Replicate API with Google Cloud Functions
Bu projede oluşturulan tüm fonksiyonlar Python dilinde yazılmış olup Python 3.10 versiyonu kullanılmıştır. Fonksiyon için kullanacağımız dili seçtikten sonra python diline özel bir requirements.txt dosyası oluşturuyoruz. Fonksiyonumuzun bulunacağı .py dosyasına aşağıdaki örnekteki gibi bir Replicate sorgusu yazıyoruz. "Firebase Cloud Function - Sending Query to Replicate" function, the token information received from Flask and the user input are used to query the stable diffusion model on the Replicate site. The function completes without waiting for a response from the query. When a response is received, it is sent to the address specified in the webhook service link. To do this, a connection is established with the Replicate service using the API token information generated by Replicate
import os
import threading
import requests
import replicate
os.environ["REPLICATE_API_TOKEN"] = "YOUR_API_TOKEN"
def replicate_request(request):
request_json = request.get_json()
prompt = request_json.get('prompt', 'default_prompt')
user_id = request_json.get('user_id', 'default_user_id')
model = replicate.models.get("stability-ai/stable-diffusion")
version = model.versions.get("27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478")
prediction = replicate.predictions.create(
version=version,
input={"prompt": prompt, "user_id": user_id},
webhook="https://example.com/your-webhook",
webhook_events_filter=["completed"])
return {"message": "Input sended to replicate."}
Transformation of the 'Save to AWS S3' Function
We first create a bucket using Google Cloud Storage. The images we save will be stored in this bucket. For these operations, we create the 'Firebase Cloud Storage - Saving Received Image Information as PNG' function as shown below.Firstly, a specific Google Cloud Storage bucket name, BUCKET_NAME
, is defined. Then, the download_image function
downloads an image from a given URL and converts it into an image object using the Pillow (PIL) library. The convert_image_to_array
function converts an image object into a NumPy array using the Pillow library. The upload_to_gcs
function uploads this NumPy array to Google Cloud Storage. For this process, a temporary file is created, the image is saved to this file, then it is uploaded to Google Cloud Storage, and the temporary file is deleted. Finally, the process_replicate_webhook
function receives an input request, processes this request by downloading and processing the image, and uploads it to Google Cloud Storage. The image URL and token information from the Replicate API query are sent to the new cloud function we will create for sending notifications.
import os
import tempfile
from google.cloud import storage
from PIL import Image
import numpy as np
from io import BytesIO
import requests
import json
BUCKET_NAME = 'your_bucket_name'
def download_image(image_url):
print("url:",image_url)
response = requests.get(image_url)
print("url:",image_url)
image = Image.open(BytesIO(response.content))
return image
def convert_image_to_array(image):
return np.array(image)
def upload_to_gcs(bucket_name, user_id, image_array):
client = storage.Client()
bucket = client.bucket(bucket_name)
_, temp_filename = tempfile.mkstemp()
Image.fromarray(image_array).save(temp_filename, format='PNG')
destination_blob_name = f"{user_id}/image.png"
blob = bucket.blob(destination_blob_name)
blob.upload_from_filename(temp_filename)
os.remove(temp_filename)
return f"gs://{bucket_name}/{destination_blob_name}"
def process_replicate_webhook(request):
request_json = request.get_json()
print("request:",request_json)
if not request_json:
return {"error": "Invalid JSON payload"}
user_id = request_json['input']['user_id']
status = request_json['status']
image_url = request_json['output'][0]
if not image_url or not user_id:
return {"error": "Missing image_url or user_id"}
image = download_image(image_url)
image_array = convert_image_to_array(image)
gcs_url = upload_to_gcs(BUCKET_NAME, user_id, image_array)
print("Received Replicate webhook:", user_id, status, image_url)
headers = {
"Content-Type": "application/json",
}
push_notificaiton_payload = {
"token": user_id,
"image_url": image_url
}
response_push_notification = requests.post("your_notification_function_url", data=json.dumps(push_notificaiton_payload), headers=headers)
return {"message": f"Image saved to {gcs_url}"}
Firebase Notification Sending Function
"Firebase Cloud Notification - Sending Result Image with Notification" code, performs the process of sending a notification using Firebase Cloud Messaging and the Flask web application framework. Firstly, a Firebase application is initialized using the credentials obtained from a firebase_key.json
file to access the Firebase project. send_notification
function processes the incoming HTTP request and retrieves the FCM token of the requesting device and an image URL from the request. If the FCM token is missing, it returns a 400 Bad Request status with an error message. Then, a messaging.Message
object is created, which includes the FCM token, notification content, and the image URL. This notification is customized with a title, body, and a click action. Finally, the notification sending process is performed with messaging.send(message)
.In case of a successful send, it returns a success message and an HTTP status of 200. In case of any error, it returns a message containing the error and an HTTP status of 500.
import json
import firebase_admin
from firebase_admin import credentials, messaging
from flask import request
cred = credentials.Certificate('firebase_key.json')
firebase_admin.initialize_app(cred, options={'senderId': 'your_sender_id'})
def send_notification(request):
request_json = request.get_json()
image_url = request_json.get('image_url', '')
registration_token = request_json.get('token', '')
if not registration_token:
return 'Missing FCM token in the request', 400
message = messaging.Message(
token=registration_token,
data={'click_action': image_url,
'title':'Resminiz Hazır',
'body':'Resminiz Hazır Indirmek Için Tıklayın!'},
)
try:
response = messaging.send(message)
return f'Successfully sent message: {response}', 200
except Exception as e:
return f'Error sending message: {str(e)}', 500
In order to display the sent notification to the user on the user's side, we need to add the following 'JavaScript Notification Reception and Display to the User' code block to the firebase-messaging-sw.js file. This code represents a background service running in a web browser.The messaging.onBackgroundMessage
function listens for incoming notification messages while the browser is in the background and processes the data within the payloadpayload
. Among these data are the notification title (notificationTitle
) and the click action (click_action
). self.registration.showNotification
function displays a notification in the browser. The title of the displayed notification is set as notificationTitle
, and the click action is defined as click_action
. self.addEventListener('notificationclick', function(event) { ... });
part defines the actions to be taken when a user clicks on a notification. The clicked notification is closed, and if the previously clicked URL (lastClickedURL
) is different from the currently clicked URL, a new window is opened and directed to the payload.data.click_action
URL. Additionally, the clicked URL is assigned to the lastClickedURL
variable as the last clicked URL. This code listens to FCM notifications received through a background service, displays notifications, and redirects the user to a specific URL when clicked.
let lastClickedURL = '';
messaging.onBackgroundMessage(function(payload) {
console.log('Received background message ', payload);
const notificationTitle = payload.data.title;
const notificationOptions = {
click_action: payload.data.click_action,
notificationTitle: notificationTitle,
};
self.registration.showNotification(notificationTitle, notificationOptions);
console.log('test2', payload.data.click_action);
self.addEventListener('notificationclick', function(event) {
const clickedNotification = event.notification;
clickedNotification.close();
if (payload.data.click_action !== lastClickedURL) {
event.waitUntil(
clients.openWindow(payload.data.click_action)
);
lastClickedURL = payload.data.click_action;
}
});
});
Demo
Conclusion
In this article, I explained the process of transitioning a web application developed using Flask between Firebase and AWS. I provided a detailed explanation of how an AWS flow was adapted using Firebase services. During the transition to Firebase, I first added Firebase Cloud Messaging integration to the Flask application. A user structure was created on the user side to send notifications, and the FCM token was obtained and passed to the Flask application. Then, the process of sending queries to the Replicate API's using Google Cloud Functions instead of AWS Lambda functions was performed on Firebase. The incoming responses were saved to Google Cloud Storage, and this process was managed using Firebase Cloud Functions. Finally, a notification was sent to the user using Firebase Cloud Messaging with the image URL and FCM token. These steps were explained in detail, and example code snippets were provided to guide through the transition process step by step.