À propos de cet atelier de programmation
1. Présentation
Dans le premier atelier de programmation, vous importerez des images dans un bucket. Cette opération génère un événement de création de fichier qui sera géré par une fonction. La fonction appellera l'API Vision pour analyser des images et enregistrer les résultats dans un datastore.
Points abordés
- Cloud Storage
- Cloud Functions
- API Cloud Vision
- Cloud Firestore
2. Préparation
Configuration de l'environnement au rythme de chacun
- Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)
- Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères non utilisée par les API Google. Vous pouvez le modifier à tout moment.
- L'ID du projet doit être unique sur l'ensemble des projets Google Cloud et doit être immuable (vous ne pouvez pas le modifier une fois que vous l'avez défini). La console Cloud génère automatiquement une chaîne unique. généralement, vous ne vous souciez
pas de ce que c’est. Dans la plupart des ateliers de programmation, vous devrez référencer l'ID du projet (il est généralement identifié comme
PROJECT_ID
). Si l'ID généré ne vous convient pas, vous pouvez en générer un autre au hasard. Vous pouvez également essayer la vôtre pour voir si elle est disponible. Il ne peut pas être modifié après cette étape et restera actif pendant toute la durée du projet. - Pour votre information, il existe une troisième valeur, le numéro de projet, utilisé par certaines API. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
- Vous devez ensuite activer la facturation dans la console Cloud pour utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour arrêter les ressources afin d'éviter que des frais ne vous soient facturés au-delà de ce tutoriel, vous pouvez supprimer les ressources que vous avez créées ou l'ensemble du projet. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai gratuit pour bénéficier d'un crédit de 300 $.
Démarrer Cloud Shell
Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Google Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.
Dans la console Google Cloud, cliquez sur l'icône Cloud Shell dans la barre d'outils supérieure :
Le provisionnement et la connexion à l'environnement prennent quelques instants seulement. Une fois l'opération terminée, le résultat devrait ressembler à ceci :
Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez effectuer toutes les tâches de cet atelier de programmation dans un navigateur. Vous n'avez rien à installer.
3. Activer les API
Dans cet atelier, vous allez utiliser Cloud Functions et l'API Vision, mais vous devez d'abord les activer dans la console Cloud ou avec gcloud
.
Pour activer l'API Vision dans la console Cloud, recherchez Cloud Vision API
dans la barre de recherche:
Vous arrivez sur la page de l'API Cloud Vision:
Cliquez sur le bouton ENABLE
.
Vous pouvez également l'activer dans Cloud Shell à l'aide de l'outil de ligne de commande gcloud.
Dans Cloud Shell, exécutez la commande suivante:
gcloud services enable vision.googleapis.com
L'opération doit s'afficher pour se terminer correctement:
Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.
Activez également Cloud Functions:
gcloud services enable cloudfunctions.googleapis.com
4. Créer le bucket (console)
Créez un bucket de stockage pour les photos. Vous pouvez le faire depuis la console Google Cloud Platform ( console.cloud.google.com) ou à l'aide de l'outil de ligne de commande gsutil depuis Cloud Shell ou votre environnement de développement local.
Accéder à Storage
Du "hamburger", (Twilio), accédez à la page Storage
.
Attribuer un nom au bucket
Cliquez sur le bouton CREATE BUCKET
.
Cliquez sur CONTINUE
.
Choisir un emplacement
Créez un bucket multirégional dans la région de votre choix (ici Europe
).
Cliquez sur CONTINUE
.
Choisir la classe de stockage par défaut
Choisissez la classe de stockage Standard
pour vos données.
Cliquez sur CONTINUE
.
Configurer le contrôle des accès
Comme vous allez travailler avec des images accessibles publiquement, vous souhaitez que toutes les images stockées dans ce bucket aient le même contrôle d'accès uniforme.
Choisissez l'option de contrôle d'accès Uniform
.
Cliquez sur CONTINUE
.
Définir la protection/le chiffrement
Conservez la valeur par défaut (Google-managed key)
, car vous n'utiliserez pas vos propres clés de chiffrement.
Cliquez sur CREATE
pour finaliser la création du bucket.
Ajouter allUsers en tant que lecteur de l'espace de stockage
Accédez à l'onglet Permissions
:
Ajoutez un membre allUsers
au bucket, avec le rôle Storage > Storage Object Viewer
, comme suit:
Cliquez sur SAVE
.
5. Créer le bucket (gsutil)
Vous pouvez également créer des buckets à l'aide de l'outil de ligne de commande gsutil
dans Cloud Shell.
Dans Cloud Shell, définissez une variable pour le nom unique du bucket. GOOGLE_CLOUD_PROJECT
est déjà défini sur votre ID de projet unique dans Cloud Shell. Vous pouvez l'ajouter au nom du bucket.
Exemple :
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
Créez une zone multirégionale standard en Europe:
gsutil mb -l EU gs://${BUCKET_PICTURES}
Assurez-vous que l'accès est uniforme au niveau du bucket:
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
Rendez le bucket public :
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}
Si vous accédez à la section Cloud Storage
de la console, vous devriez disposer d'un bucket uploaded-pictures
public:
Vérifiez que vous pouvez importer des photos dans le bucket et qu'elles sont accessibles au public, comme expliqué à l'étape précédente.
6. Tester l'accès public au bucket
Dans le navigateur de stockage, votre bucket apparaît dans la liste, avec la mention "Public". y compris un panneau d'avertissement vous rappelant que n'importe qui a accès au contenu de ce bucket.
Votre bucket est maintenant prêt à recevoir des photos.
Si vous cliquez sur le nom du bucket, ses informations s'affichent.
Appuyez sur le bouton Upload files
pour tester l'ajout d'une image au bucket. Un pop-up de sélection de fichier vous invite à sélectionner un fichier. Une fois sélectionné, il sera importé dans votre bucket, et vous verrez de nouveau l'accès public
attribué automatiquement à ce nouveau fichier.
Une petite icône de lien apparaît également le long du libellé d'accès Public
. Lorsque vous cliquez dessus, votre navigateur accédera à l'URL publique de cette image, qui se présentera sous la forme suivante:
https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png
BUCKET_NAME
étant le nom unique que vous avez choisi pour votre bucket, suivi du nom de fichier de votre image.
Cliquez sur la case à cocher à côté du nom de l'image pour activer le bouton DELETE
et supprimer cette première image.
7. Créer la fonction
Au cours de cette étape, vous allez créer une fonction qui réagit aux événements d'importation d'images.
Accédez à la section Cloud Functions
de la console Google Cloud. En accédant à cet emplacement, le service Cloud Functions sera automatiquement activé.
Cliquez sur Create function
.
Choisissez un nom (par exemple, picture-uploaded
) et la région (veillez à rester cohérent avec la région choisie pour le bucket):
Il existe deux types de fonctions:
- Des fonctions HTTP pouvant être appelées via une URL (une API Web, par exemple)
- Fonctions d'arrière-plan pouvant être déclenchées par un événement.
Vous souhaitez créer une fonction d'arrière-plan qui se déclenche lorsqu'un nouveau fichier est importé dans notre bucket Cloud Storage
:
Vous êtes intéressé par le type d'événement Finalize/Create
, qui est l'événement déclenché lorsqu'un fichier est créé ou mis à jour dans le bucket:
Sélectionnez le bucket créé précédemment pour indiquer à Cloud Functions d'être averti lorsqu'un fichier est créé ou mis à jour dans ce bucket:
Cliquez sur Select
pour choisir le bucket que vous avez créé précédemment, puis sur Save
.
Avant de cliquer sur "Suivant", vous pouvez développer et modifier les valeurs par défaut (256 Mo de mémoire) sous Paramètres d'exécution, de compilation, de connexion et de sécurité, puis les mettre à jour et les définir sur 1 Go.
Après avoir cliqué sur Next
, vous pouvez ajuster l'environnement d'exécution, le code source et le point d'entrée.
Conservez le Inline editor
pour cette fonction:
Sélectionnez l'un des environnements d'exécution Node.js:
Le code source se compose d'un fichier JavaScript index.js
et d'un fichier package.json
qui fournit diverses métadonnées et dépendances.
Conservez l'extrait de code par défaut, qui consigne le nom de fichier de l'image importée :
Pour l'instant, conservez le nom de la fonction à exécuter dans helloGCS
, à des fins de test.
Cliquez sur Deploy
pour créer et déployer la fonction. Une fois le déploiement réussi, une coche entourée d'un cercle vert doit s'afficher dans la liste des fonctions:
8. Tester la fonction
Au cours de cette étape, vous allez vérifier que la fonction répond aux événements de stockage.
Du "hamburger", (Twilio), revenez à la page Storage
.
Cliquez sur le bucket d'images, puis sur Upload files
pour importer une image.
Revenez à la console Cloud pour accéder à la page Logging > Logs Explorer
.
Dans le sélecteur Log Fields
, sélectionnez Cloud Function
pour afficher les journaux dédiés à vos fonctions. Faites défiler les champs de journal vers le bas. Vous pouvez même sélectionner une fonction spécifique pour obtenir une vue plus détaillée des journaux associés aux fonctions. Sélectionnez la fonction picture-uploaded
.
Vous devriez voir les éléments de journal mentionnant la création de la fonction, les heures de début et de fin de la fonction et notre instruction de journalisation réelle:
Notre instruction de journalisation indique: Processing file: pic-a-daily-architecture-events.png
, ce qui signifie que l'événement lié à la création et au stockage de cette image a bien été déclenché comme prévu.
9. Préparer la base de données
Vous allez stocker des informations sur l'image fournie par l'API Vision dans la base de données Cloud Firestore, une base de données de documents NoSQL sans serveur, cloud native, entièrement gérée et rapide. Préparez votre base de données en accédant à la section Firestore
de Cloud Console:
Deux options sont proposées: Native mode
ou Datastore mode
. Utilisez le mode natif, qui offre des fonctionnalités supplémentaires telles que le fonctionnement hors connexion et la synchronisation en temps réel.
Cliquez sur SELECT NATIVE MODE
.
Choisissez un emplacement multirégional (ici en Europe, mais idéalement au moins la même région que votre fonction et votre bucket de stockage).
Cliquez sur le bouton CREATE DATABASE
.
Une fois la base de données créée, la page suivante doit s'afficher:
Créez une collection en cliquant sur le bouton + START COLLECTION
.
Nom de la collection pictures
.
Vous n'avez pas besoin de créer de document. Vous allez les ajouter par programmation, car de nouvelles images sont stockées dans Cloud Storage et analysées par l'API Vision.
Cliquez sur Save
.
Firestore crée un premier document par défaut dans la collection que vous venez de créer. Vous pouvez supprimer ce document en toute sécurité, car il ne contient aucune information utile:
Les documents qui seront créés par programmation dans notre collection contiendront quatre champs:
- name (chaîne): nom de fichier de l'image importée, qui est également la clé du document.
- labels (tableau de chaînes): étiquettes des éléments reconnus par l'API Vision
- color (chaîne): code hexadécimal de la couleur dominante (par exemple, #ab12ef)
- créé (date): horodatage correspondant au moment où les métadonnées de cette image ont été stockées
- thumbnail (valeur booléenne): champ facultatif qui est présent et a la valeur "true" si une vignette a été générée pour cette image.
Comme nous allons rechercher dans Firestore des images pour lesquelles des vignettes sont disponibles, et trier les dates de création, nous devons créer un index de recherche.
Vous pouvez créer l'index à l'aide de la commande suivante dans Cloud Shell:
gcloud firestore indexes composite create \
--collection-group=pictures \
--field-config field-path=thumbnail,order=descending \
--field-config field-path=created,order=descending
Vous pouvez également le faire depuis la console Cloud. Pour ce faire, cliquez sur Indexes
dans la colonne de navigation à gauche, puis créez un index composite comme indiqué ci-dessous:
Cliquez sur Create
. La création de l'index peut prendre quelques minutes.
10. Mettre à jour la fonction
Revenez à la page Functions
pour mettre à jour la fonction afin d'appeler l'API Vision afin d'analyser les images et de stocker les métadonnées dans Firestore.
Du "hamburger", (Twilio), accédez à la section Cloud Functions
, cliquez sur le nom de la fonction, sélectionnez l'onglet Source
, puis cliquez sur le bouton EDIT
.
Commencez par modifier le fichier package.json
qui répertorie les dépendances de notre fonction Node.JS. Mettez à jour le code pour ajouter la dépendance NPM de l'API Cloud Vision:
{
"name": "picture-analysis-function",
"version": "0.0.1",
"dependencies": {
"@google-cloud/storage": "^1.6.0",
"@google-cloud/vision": "^1.8.0",
"@google-cloud/firestore": "^3.4.1"
}
}
Maintenant que les dépendances sont à jour, vous allez travailler sur le code de notre fonction en mettant à jour le fichier index.js
.
Remplacez le code dans index.js
par le code ci-dessous. Nous y reviendrons à l'étape suivante.
const vision = require('@google-cloud/vision');
const Storage = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const client = new vision.ImageAnnotatorClient();
exports.vision_analysis = async (event, context) => {
console.log(`Event: ${JSON.stringify(event)}`);
const filename = event.name;
const filebucket = event.bucket;
console.log(`New picture uploaded ${filename} in ${filebucket}`);
const request = {
image: { source: { imageUri: `gs://${filebucket}/${filename}` } },
features: [
{ type: 'LABEL_DETECTION' },
{ type: 'IMAGE_PROPERTIES' },
{ type: 'SAFE_SEARCH_DETECTION' }
]
};
// invoking the Vision API
const [response] = await client.annotateImage(request);
console.log(`Raw vision output for: ${filename}: ${JSON.stringify(response)}`);
if (response.error === null) {
// listing the labels found in the picture
const labels = response.labelAnnotations
.sort((ann1, ann2) => ann2.score - ann1.score)
.map(ann => ann.description)
console.log(`Labels: ${labels.join(', ')}`);
// retrieving the dominant color of the picture
const color = response.imagePropertiesAnnotation.dominantColors.colors
.sort((c1, c2) => c2.score - c1.score)[0].color;
const colorHex = decColorToHex(color.red, color.green, color.blue);
console.log(`Colors: ${colorHex}`);
// determining if the picture is safe to show
const safeSearch = response.safeSearchAnnotation;
const isSafe = ["adult", "spoof", "medical", "violence", "racy"].every(k =>
!['LIKELY', 'VERY_LIKELY'].includes(safeSearch[k]));
console.log(`Safe? ${isSafe}`);
// if the picture is safe to display, store it in Firestore
if (isSafe) {
const pictureStore = new Firestore().collection('pictures');
const doc = pictureStore.doc(filename);
await doc.set({
labels: labels,
color: colorHex,
created: Firestore.Timestamp.now()
}, {merge: true});
console.log("Stored metadata in Firestore");
}
} else {
throw new Error(`Vision API error: code ${response.error.code}, message: "${response.error.message}"`);
}
};
function decColorToHex(r, g, b) {
return '#' + Number(r).toString(16).padStart(2, '0') +
Number(g).toString(16).padStart(2, '0') +
Number(b).toString(16).padStart(2, '0');
}
11. Explorer la fonction
Examinons de plus près les différentes parties intéressantes.
Tout d'abord, nous exigeons les modules nécessaires pour Vision, Storage et Firestore:
const vision = require('@google-cloud/vision');
const Storage = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
Ensuite, nous préparons un client pour l'API Vision:
const client = new vision.ImageAnnotatorClient();
Vient maintenant la structure de notre fonction. Nous en faisons une fonction asynchrone, car nous utilisons les fonctionnalités async / await introduites dans Node.js 8:
exports.vision_analysis = async (event, context) => {
...
const filename = event.name;
const filebucket = event.bucket;
...
}
Notez la signature, mais aussi la façon dont nous récupérons le nom du fichier et du bucket qui ont déclenché la fonction Cloud.
Pour référence, voici à quoi ressemble la charge utile de l'événement:
{
"bucket":"uploaded-pictures",
"contentType":"image/png",
"crc32c":"efhgyA==",
"etag":"CKqB956MmucCEAE=",
"generation":"1579795336773802",
"id":"uploaded-pictures/Screenshot.png/1579795336773802",
"kind":"storage#object",
"md5Hash":"PN8Hukfrt6C7IyhZ8d3gfQ==",
"mediaLink":"https://www.googleapis.com/download/storage/v1/b/uploaded-pictures/o/Screenshot.png?generation=1579795336773802&alt=media",
"metageneration":"1",
"name":"Screenshot.png",
"selfLink":"https://www.googleapis.com/storage/v1/b/uploaded-pictures/o/Screenshot.png",
"size":"173557",
"storageClass":"STANDARD",
"timeCreated":"2020-01-23T16:02:16.773Z",
"timeStorageClassUpdated":"2020-01-23T16:02:16.773Z",
"updated":"2020-01-23T16:02:16.773Z"
}
Nous préparons une requête à envoyer via le client Vision:
const request = {
image: { source: { imageUri: `gs://${filebucket}/${filename}` } },
features: [
{ type: 'LABEL_DETECTION' },
{ type: 'IMAGE_PROPERTIES' },
{ type: 'SAFE_SEARCH_DETECTION' }
]
};
Nous avons besoin de trois fonctionnalités clés de l'API Vision:
- Détection de thèmes: pour comprendre le contenu de ces images
- Propriétés de l'image: pour fournir des attributs intéressants de l'image (nous nous intéressons à la couleur dominante de l'image)
- SafeSearch: permet de savoir si l'image peut être affichée sans risque (elle ne doit pas contenir de contenu réservé aux adultes, médical, pour adultes ou violent)
À ce stade, nous pouvons appeler l'API Vision:
const [response] = await client.annotateImage(request);
Pour référence, voici à quoi ressemble la réponse de l'API Vision:
{
"faceAnnotations": [],
"landmarkAnnotations": [],
"logoAnnotations": [],
"labelAnnotations": [
{
"locations": [],
"properties": [],
"mid": "/m/01yrx",
"locale": "",
"description": "Cat",
"score": 0.9959855675697327,
"confidence": 0,
"topicality": 0.9959855675697327,
"boundingPoly": null
},
✄ - - - ✄
],
"textAnnotations": [],
"localizedObjectAnnotations": [],
"safeSearchAnnotation": {
"adult": "VERY_UNLIKELY",
"spoof": "UNLIKELY",
"medical": "VERY_UNLIKELY",
"violence": "VERY_UNLIKELY",
"racy": "VERY_UNLIKELY",
"adultConfidence": 0,
"spoofConfidence": 0,
"medicalConfidence": 0,
"violenceConfidence": 0,
"racyConfidence": 0,
"nsfwConfidence": 0
},
"imagePropertiesAnnotation": {
"dominantColors": {
"colors": [
{
"color": {
"red": 203,
"green": 201,
"blue": 201,
"alpha": null
},
"score": 0.4175916016101837,
"pixelFraction": 0.44456374645233154
},
✄ - - - ✄
]
}
},
"error": null,
"cropHintsAnnotation": {
"cropHints": [
{
"boundingPoly": {
"vertices": [
{ "x": 0, "y": 118 },
{ "x": 1177, "y": 118 },
{ "x": 1177, "y": 783 },
{ "x": 0, "y": 783 }
],
"normalizedVertices": []
},
"confidence": 0.41695669293403625,
"importanceFraction": 1
}
]
},
"fullTextAnnotation": null,
"webDetection": null,
"productSearchResults": null,
"context": null
}
Si aucune erreur ne s'affiche, nous pouvons passer à autre chose. C'est pourquoi nous avons ce bloc "if" :
if (response.error === null) {
...
} else {
throw new Error(`Vision API error: code ${response.error.code},
message: "${response.error.message}"`);
}
Nous allons faire reconnaître les étiquettes des choses, des catégories ou des thèmes sur l'image:
const labels = response.labelAnnotations
.sort((ann1, ann2) => ann2.score - ann1.score)
.map(ann => ann.description)
Nous trions d'abord les étiquettes par score le plus élevé.
Nous souhaitons connaître la couleur dominante de l'image:
const color = response.imagePropertiesAnnotation.dominantColors.colors
.sort((c1, c2) => c2.score - c1.score)[0].color;
const colorHex = decColorToHex(color.red, color.green, color.blue);
Nous trions à nouveau les couleurs par score et prenons la première.
Nous utilisons également une fonction utilitaire pour transformer les valeurs rouge / vert / bleu en un code couleur hexadécimal que nous pouvons utiliser dans les feuilles de style CSS.
Vérifions que l'image peut être affichée sans risque:
const safeSearch = response.safeSearchAnnotation;
const isSafe = ["adult", "spoof", "medical", "violence", "racy"]
.every(k => !['LIKELY', 'VERY_LIKELY'].includes(safeSearch[k]));
Nous vérifions les attributs pour adultes, parodies, médecine, violence ou pour adultes afin de déterminer s'ils sont probables ou très probables.
Si le résultat de la recherche sécurisée est correct, nous pouvons stocker des métadonnées dans Firestore:
if (isSafe) {
const pictureStore = new Firestore().collection('pictures');
const doc = pictureStore.doc(filename);
await doc.set({
labels: labels,
color: colorHex,
created: Firestore.Timestamp.now()
}, {merge: true});
}
12. Déployer la fonction
Il est temps de déployer la fonction.
Appuyez sur le bouton DEPLOY
pour déployer la nouvelle version. Vous pouvez voir la progression:
13. Tester à nouveau la fonction
Une fois la fonction déployée, vous publierez une image dans Cloud Storage, puis vérifiez si la fonction est appelée, ce que renvoie l'API Vision et si les métadonnées sont stockées dans Firestore.
Revenez à Cloud Storage
et cliquez sur le bucket que nous avons créé au début de l'atelier:
Une fois sur la page d'informations du bucket, cliquez sur le bouton Upload files
pour importer une photo.
Du "hamburger", (Twilio), accédez à l'explorateur Logging > Logs
.
Dans le sélecteur Log Fields
, sélectionnez Cloud Function
pour afficher les journaux dédiés à vos fonctions. Faites défiler les champs de journal vers le bas. Vous pouvez même sélectionner une fonction spécifique pour obtenir une vue plus détaillée des journaux associés aux fonctions. Sélectionnez la fonction picture-uploaded
.
En effet, dans la liste des journaux, je peux voir que notre fonction a été appelée:
Les journaux indiquent le début et la fin de l'exécution de la fonction. Entre les deux, nous pouvons voir les journaux que nous avons placés dans notre fonction avec les instructions console.log(). Voici ce que nous voyons:
- Les détails de l'événement qui déclenche notre fonction,
- Les résultats bruts de l'appel de l'API Vision
- Les étiquettes qui ont été trouvées dans l'image que nous avons importée,
- Les informations sur les couleurs dominantes,
- Si l'image peut être affichée en toute sécurité,
- Et finalement, ces métadonnées sur l'image ont été stockées dans Firestore.
Encore une fois,
pour le « hamburger », (Twilio), accédez à la section Firestore
. Dans la sous-section Data
(affichée par défaut), vous devriez voir la collection pictures
avec un nouveau document ajouté, correspondant à l'image que vous venez d'importer:
14. Nettoyer (facultatif)
Si vous n'avez pas l'intention de suivre les autres ateliers de la série, vous pouvez nettoyer les ressources pour réduire les coûts et utiliser globalement le cloud comme il se doit. Vous pouvez nettoyer les ressources individuellement comme suit.
Supprimez le bucket :
gsutil rb gs://${BUCKET_PICTURES}
Supprimez la fonction:
gcloud functions delete picture-uploaded --region europe-west1 -q
Supprimez la collection Firestore en sélectionnant "Supprimer la collection de la collection" :
Vous pouvez également supprimer l'intégralité du projet:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
15. Félicitations !
Félicitations ! Vous avez réussi à mettre en œuvre le premier service de clés du projet.
Points abordés
- Cloud Storage
- Cloud Functions
- API Cloud Vision
- Cloud Firestore