1. Objectifs
L'objectif de cet atelier est de fournir une formation pratique sur Duet AI aux utilisateurs et aux professionnels.
Dans cet atelier de programmation, vous allez apprendre les points suivants :
- Activez Duet AI dans votre projet GCP et configurez-le pour l'utiliser dans un IDE et la console Cloud.
- Utiliser Duet AI pour générer, compléter et expliquer du code
- Utiliser Duet AI pour expliquer et résoudre un problème d'application
- Fonctionnalités de Duet AI, comme le chat IDE et le chat multitour, la génération de code par chat ou intégrée, les actions intelligentes comme l'explication du code et la confirmation de la récitation, et plus encore.
Présentation
Pour montrer comment Duet AI pour les développeurs est utilisé de manière authentique dans le développement quotidien, les activités de cet atelier se déroulent dans un contexte narratif.
Un nouveau développeur rejoint une entreprise d'e-commerce. Ils doivent ajouter un service à l'application d'e-commerce existante (qui est composée de plusieurs services). Le nouveau service fournit des informations supplémentaires (dimensions, poids, etc.) sur les produits du catalogue. Ce service vous permettra de bénéficier de frais de port plus avantageux en fonction des dimensions et du poids des produits.
Comme le développeur est nouveau dans l'entreprise, il utilisera Duet AI pour générer, expliquer et documenter le code.
Une fois le service codé, un administrateur de plate-forme utilisera Duet AI (chat) pour créer l'artefact (conteneur Docker) et les ressources nécessaires pour déployer l'artefact sur GCP (par exemple, Artifact Registry, les autorisations IAM, un dépôt de code, une infrastructure de calcul, c'est-à-dire GKE ou Cloud Run, etc.).
Une fois l'application déployée sur GCP, un opérateur d'application/SRE utilisera Duet AI (et Cloud Ops) pour résoudre un problème lié au nouveau service.
Persona
L'atelier couvre la persona suivante :
- Développeur d'applications : des connaissances en programmation et en développement de logiciels sont requises.
Cette variante de l'atelier Duet AI est réservée aux développeurs. Aucune connaissance des ressources cloud GCP n'est requise. Les scripts permettant de créer les ressources GCP requises pour exécuter cette application sont disponibles sur cette page. Vous pouvez suivre les instructions de ce guide pour déployer les ressources GCP requises.
2. Préparer l'environnement
Activer Duet AI
Vous pouvez activer Duet AI dans un projet GCP via l'API (gcloud ou outils d'IaC comme Terraform) ou l'interface utilisateur de la console Cloud.
Pour activer Duet AI dans un projet Google Cloud, vous devez activer l'API Cloud AI Companion et attribuer les rôles IAM (Identity and Access Management) "Utilisateur de Cloud AI Companion" et "Lecteur Service Usage" aux utilisateurs.
Via gcloud
Activez Cloud Shell :
Configurez vos PROJECT_ID et USER, puis activez l'API Cloud AI Companion.
export PROJECT_ID=<YOUR PROJECT ID>
export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com
gcloud config set project ${PROJECT_ID}
gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}
Le résultat ressemble à ce qui suit :
Updated property [core/project]. Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.
Attribuez les rôles Identity and Access Management (IAM) "Utilisateur de Cloud AI Companion" et "Lecteur Service Usage" au compte UTILISATEUR. L'API Cloud Companion est à la base des fonctionnalités que nous allons utiliser dans l'IDE et la console. L'autorisation "Lecteur de l'utilisation du service" est utilisée pour une vérification rapide avant d'activer l'UI dans la console (afin que l'UI Duet n'apparaisse que dans les projets dans lesquels l'API est activée).
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member=user:${USER} --role=roles/cloudaicompanion.user
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member=user:${USER} --role=roles/serviceusage.serviceUsageViewer
Le résultat ressemble à ce qui suit :
... - members: - user:<YOUR USER ACCOUNT> role: roles/cloudaicompanion.user ... - members: - user:<YOUR USER ACCOUNT> role: roles/serviceusage.serviceUsageViewer
Via la console Cloud
Pour activer l'API, accédez à la page de l'API Cloud AI Companion dans la console Google Cloud.
Dans le sélecteur de projets, choisissez un projet.
Cliquez sur Activer.
La page s'actualise et affiche l'état Activé. Duet AI est désormais disponible dans le projet Google Cloud sélectionné pour tous les utilisateurs disposant des rôles IAM requis.
Pour attribuer les rôles IAM requis pour utiliser Duet AI, accédez à la page IAM.
Dans la colonne Compte principal, recherchez l'UTILISATEUR pour lequel vous souhaitez activer l'accès à Duet AI, puis cliquez sur l'icône en forme de crayon ✏️ Modifier le compte principal sur cette ligne.
Dans le volet Modifier l'accès, cliquez sur Ajouter un autre rôle.
Dans "Sélectionner un rôle", sélectionnez Utilisateur Cloud AI Companion.
Cliquez sur Ajouter un autre rôle, puis sélectionnez Lecteur Service Usage.
Cliquez sur Enregistrer.
Configurer l'IDE
Les développeurs peuvent choisir parmi différents IDE celui qui répond le mieux à leurs besoins. L'assistance au code Duet AI est disponible dans plusieurs IDE, tels que Visual Studio Code, JetBrains IDEs (IntelliJ, PyCharm, GoLand, WebStorm, etc.), Cloud Workstations et l'éditeur Cloud Shell.
Dans cet atelier, vous pouvez utiliser Cloud Workstations ou l'éditeur Cloud Shell.
Cet atelier utilise l'éditeur Cloud Shell.
Notez que la configuration de Cloud Workstations peut prendre entre 20 et 30 minutes.
Pour l'utiliser immédiatement, utilisez l'éditeur Cloud Shell.
Ouvrez l'éditeur Cloud Shell en cliquant sur l'icône en forme de crayon ✏️ dans la barre de menu supérieure de Cloud Shell.
L'interface utilisateur et l'expérience utilisateur de l'éditeur Cloud Shell sont très similaires à celles de VSCode.

Cliquez sur CTRL (sous Windows)/CMD (sous Mac) + , (virgule) pour accéder au volet "Paramètres".
Dans la barre de recherche, saisissez "Duet AI".
Assurez-vous que les options Cloudcode › Duet AI : Activer et Cloudcode › Duet AI › Suggestions intégrées : Activer automatiquement sont activées.

Dans la barre d'état en bas de l'écran, cliquez sur Cloud Code - Se connecter et suivez la procédure de connexion.
Si vous êtes déjà connecté, la barre d'état affiche Cloud Code - Aucun projet.
Cliquez sur "Cloud Code - Aucun projet". Un volet déroulant d'actions s'affiche en haut de l'écran. Cliquez sur Sélectionner un projet Google Cloud.

Commencez à saisir l'ID de votre projet. Il devrait apparaître dans la liste.

Sélectionnez votre PROJECT_ID dans la liste des projets.
La barre d'état en bas de l'écran affiche l'ID de votre projet. Si ce n'est pas le cas, vous devrez peut-être actualiser l'onglet de l'éditeur Cloud Shell.
Cliquez sur l'icône Duet AI
dans la barre de menu de gauche pour afficher la fenêtre de chat Duet AI. Si le message "Sélectionner un projet GCP" s'affiche, Cliquez sur le projet, puis sélectionnez-le à nouveau.
La fenêtre de chat Duet AI s'affiche.

3. Configurer l'infrastructure

Pour exécuter le nouveau service de livraison dans GCP, vous avez besoin des ressources GCP suivantes :
- Une instance Cloud SQL avec une base de données.
- Un cluster GKE pour exécuter le service conteneurisé.
- Un dépôt Artifact Registry pour stocker l'image Docker.
- Un dépôt Cloud Source Repositories pour le code.
Dans le terminal Cloud Shell, clonez le dépôt suivant et exécutez les commandes suivantes pour configurer l'infrastructure dans votre projet GCP.
# Set your project
export PROJECT_ID=<INSERT_YOUR_PROJECT_ID>
gcloud config set core/project ${PROJECT_ID}
# Enable Cloudbuild and grant Cloudbuild SA owner role
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
gcloud services enable cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner
# Clone the repo
git clone https://github.com/duetailabs/dev.git ~/duetaidev
cd ~/duetaidev
# Run Cloudbuild to create the necessary resources
gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID}
# To destroy all GCP resources, run the following
# gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml
4. Développer un service Python Flask

Le service que nous allons créer se composera des fichiers suivants. Vous n'avez pas besoin de créer ces fichiers maintenant. Vous les créerez un par un en suivant les instructions ci-dessous :
package-service.yaml: spécification OpenAPI pour le service de colis, qui contient des données telles que la hauteur, la largeur, le poids et les instructions de manutention spéciales.data_model.py: modèle de données pour la spécification de l'API package-service. Crée également la tablepackagesdans la base de données product_details.connect_connector.py: connexion CloudSQL (définit le moteur, la session et l'ORM de base)db_init.py: génère des exemples de données dans la tablepackages.main.py: service Python Flask avec un point de terminaisonGETpermettant de récupérer les détails du package à partir des donnéespackagesen fonction de product_id.test.py: test unitairerequirement.txt: exigences PythonDockerfile: pour conteneuriser cette application
Si vous rencontrez des problèmes lors des exercices, vous trouverez tous les fichiers finaux dans l'ANNEXE de cet atelier de programmation, à titre de référence.
À l'étape précédente, vous avez créé un dépôt Cloud Source Repositories. Clonez le dépôt. Vous allez créer les fichiers d'application dans le dossier du dépôt cloné.
Dans le terminal Cloud Shell, exécutez la commande suivante pour cloner le dépôt.
cd ~ gcloud source repos clone shipping shipping cd ~/shipping
Ouvrez la barre latérale de chat Duet AI dans le menu de gauche de l'éditeur Cloud Shell. L'icône ressemble à
. Vous pouvez désormais utiliser Duet AI pour obtenir de l'aide au codage.
package-service.yaml
Sans aucun fichier ouvert, demandez à Duet de générer une spécification OpenAPI pour le service de livraison.
Requête 1 : génère une spécification OpenAPI YAML pour un service qui fournit des informations sur la livraison et les colis à partir d'un ID de produit numérique. Le service doit inclure des informations sur la hauteur, la largeur, la profondeur et le poids des colis, ainsi que des instructions de manutention spécifiques.

Trois options sont listées en haut à droite de la fenêtre de code généré.
Vous pouvez COPY
le code et le COLLER dans un fichier.
Vous pouvez ADD
le code dans le fichier actuellement ouvert dans l'éditeur.
Vous pouvez également OPEN
le code dans un nouveau fichier.
Cliquez sur OPEN
le code dans un nouveau fichier.
Cliquez sur CTRL/CMD + s pour enregistrer le fichier, puis stockez-le dans le dossier de l'application sous le nom package-service.yaml. Cliquez sur OK.

Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Vous pouvez également essayer différentes requêtes pour voir les réponses de Duet AI.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
data_model.py
Ensuite, vous allez créer le fichier Python du modèle de données pour le service en fonction de la spécification OpenAPI.
Ouvrez le fichier package-service.yaml et saisissez le prompt suivant.
Requête 1 : à l'aide de l'ORM SQLAlchemy Python, génère un modèle de données pour ce service d'API. Incluez également une fonction distincte et un point d'entrée principal qui crée les tables de base de données.

Examinons chaque partie générée. Duet AI reste un assistant. Bien qu'il puisse vous aider à rédiger du code rapidement, vous devez toujours examiner le contenu généré et le comprendre au fur et à mesure.
Tout d'abord, il existe une classe appelée Package de typeBase qui définit le modèle de données pour la base de données packages comme suit :
class Package(Base):
__tablename__ = 'packages'
id = Column(Integer, primary_key=True)
product_id = Column(String(255))
height = Column(Float)
width = Column(Float)
depth = Column(Float)
weight = Column(Float)
special_handling_instructions = Column(String(255))
Ensuite, vous avez besoin d'une fonction qui crée la table dans la base de données, comme suit :
def create_tables(engine):
Base.metadata.create_all(engine)
Enfin, vous avez besoin d'une fonction principale qui exécute la fonction create_tables pour créer la table dans la base de données Cloud SQL, comme suit :
if __name__ == '__main__':
from sqlalchemy import create_engine
engine = create_engine('sqlite:///shipping.db')
create_tables(engine)
print('Tables created successfully.')
Notez que la fonction main crée un moteur à l'aide d'une base de données sqlite locale. Pour utiliser Cloud SQL, vous devrez le modifier. Vous le ferez un peu plus tard.
Utilisez le workflow OPEN
le code dans un nouveau fichier comme précédemment. Enregistrez le code dans un fichier nommé data_model.py (notez le trait de soulignement dans le nom, et non le tiret).
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
connect-connector.py
Créez le connecteur Cloud SQL.
Ouvrez le fichier data_model.py, puis saisissez les prompts suivants.
Requête 1 : à l'aide de la bibliothèque cloud-sql-python-connector, génère une fonction qui initialise un pool de connexions pour une instance Postgres de Cloud SQL.

Notez que la réponse n'utilise pas la bibliothèque cloud-sql-python-connector. Vous pouvez affiner les requêtes pour donner un coup de pouce à Duet en ajoutant des détails dans le même fil de discussion.
Utilisons un autre prompt.
Requête 2 : Doit utiliser la bibliothèque cloud-sql-python-connector.

Assurez-vous qu'il utilise la bibliothèque cloud-sql-python-connector.
Utilisez le workflow OPEN
le code dans un nouveau fichier comme précédemment. Enregistrez le code dans un fichier nommé connect_conector.py. Vous devrez peut-être importer manuellement la bibliothèque pg8000. Veuillez consulter le fichier ci-dessous.
Effacez l'historique du chat Duet AI, puis, avec le fichier connect_connector.py ouvert, générez les ORM DB engine, sessionmaker et base à utiliser dans l'application.
Requête 1 : Créez une classe engine, sessionmaker et un ORM de base à l'aide de la méthode connect_with_connector

La réponse peut ajouter les engine, Session et Base au fichier connect_connector.py.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Vous pouvez également essayer différentes requêtes pour voir la variation potentielle des réponses de Duet AI.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
Mettre à jour data_model.py
Vous devez utiliser le moteur que vous avez créé à l'étape précédente (dans le fichier connect_connector.py) pour créer une table dans la base de données CloudSQL.
Effacez l'historique des discussions Duet AI. Ouvrez le fichier data_model.py. Essayez le prompt suivant.
Requête 1 : Dans la fonction principale, importez et utilisez le moteur depuis connect_connector.py.

La réponse devrait indiquer que engine a été importé depuis connect_connector (pour Cloud SQL). create_table utilise ce moteur (au lieu de la base de données locale sqlite par défaut).
Mettez à jour le fichier data_model.py.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Vous pouvez également essayer différentes requêtes pour voir les différentes réponses de Duet AI.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
requirements.txt
Créez un fichier requirements.txt pour l'application.
Ouvrez les fichiers connect_connector.py et data_model.py, puis saisissez la requête suivante.
Requête 1 : Génère un fichier de requirements pip pour ce modèle de données et ce service
Requête 2 : Génère un fichier de requirements pip pour ce modèle de données et ce service en utilisant les dernières versions.

Vérifiez que les noms et les versions sont corrects. Par exemple, dans la réponse ci-dessus, le nom et la version de google-cloud-sql-connecter sont incorrects. Corrigez manuellement les versions et créez un fichier requirements.txt qui ressemble à ceci :
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Dans le terminal de commande, exécutez la commande suivante :
pip3 install -r requirements.txt
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
Créer une table de packages dans Cloud SQL
Définissez les variables d'environnement pour le connecteur de base de données CloudSQL.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export DB_USER=evolution
export DB_PASS=evolution
export DB_NAME=product_details
Exécutez maintenant data_model.py.
python data_model.py
Le résultat ressemble à ce qui suit (vérifiez le code pour voir ce qui est réellement attendu) :
Tables created successfully.
Connectez-vous à l'instance Cloud SQL et vérifiez que la base de données a été créée.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Après avoir saisi le mot de passe (evolution), récupérez les tables.
product_details=> \dt
Le résultat ressemble à ce qui suit :
List of relations Schema | Name | Type | Owner --------+----------+-------+----------- public | packages | table | evolution (1 row)
Vous pouvez également consulter le modèle de données et les détails des tableaux.
product_details=> \d+ packages
Le résultat ressemble à ce qui suit :
Table "public.packages"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
-------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+-------------
id | integer | | not null | nextval('packages_id_seq'::regclass) | plain | | |
product_id | integer | | not null | | plain | | |
height | double precision | | not null | | plain | | |
width | double precision | | not null | | plain | | |
depth | double precision | | not null | | plain | | |
weight | double precision | | not null | | plain | | |
special_handling_instructions | character varying | | | | extended | | |
Indexes:
"packages_pkey" PRIMARY KEY, btree (id)
Access method: heap
Saisissez \q pour quitter Cloud SQL.
db_init.py
Ajoutons ensuite des exemples de données à la table packages.
Effacez l'historique des discussions Duet AI. Une fois le fichier data_model.py ouvert, essayez les requêtes suivantes.
Requête 1 : Génère une fonction qui crée 10 lignes d'échantillons de packages et les enregistre dans la table des packages
Requête 2 : À l'aide de la session de connect_connector, générez une fonction qui crée 10 lignes d'échantillons de packages et les valide dans la table des packages.

Utilisez le workflow OPEN
le code dans un nouveau fichier comme précédemment. Enregistrez le code dans un fichier nommé db_init.py.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Vous pouvez également essayer différentes requêtes pour voir les différentes réponses de Duet AI.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
Créer des exemples de données de packages
Exécutez db_init.py à partir de la ligne de commande.
python db_init.py
Le résultat ressemble à ce qui suit :
Packages created successfully.
Reconnectez-vous à l'instance Cloud SQL et vérifiez que les exemples de données ont été ajoutés à la table "packages".
Connectez-vous à l'instance Cloud SQL et vérifiez que la base de données a été créée.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
Après avoir saisi le mot de passe (evolution), récupérez toutes les données de la table "packages".
product_details=> SELECT * FROM packages;
Le résultat ressemble à ce qui suit :
id | product_id | height | width | depth | weight | special_handling_instructions ----+------------+--------+-------+-------+--------+----------------------------------- 1 | 0 | 10 | 10 | 10 | 10 | No special handling instructions. 2 | 1 | 10 | 10 | 10 | 10 | No special handling instructions. 3 | 2 | 10 | 10 | 10 | 10 | No special handling instructions. 4 | 3 | 10 | 10 | 10 | 10 | No special handling instructions. 5 | 4 | 10 | 10 | 10 | 10 | No special handling instructions. 6 | 5 | 10 | 10 | 10 | 10 | No special handling instructions. 7 | 6 | 10 | 10 | 10 | 10 | No special handling instructions. 8 | 7 | 10 | 10 | 10 | 10 | No special handling instructions. 9 | 8 | 10 | 10 | 10 | 10 | No special handling instructions. 10 | 9 | 10 | 10 | 10 | 10 | No special handling instructions. (10 rows)
Saisissez \q pour quitter Cloud SQL.
main.py
Avec les fichiers data_model.py, package-service.yaml et connect_connector.py ouverts, créez un main.py pour l'application.
Requête 1 : En utilisant la bibliothèque Python Flask, crée une implémentation qui utilise des points de terminaison REST HTTP pour ce service.
Requête 2 : À l'aide de la bibliothèque Python Flask, créez une implémentation qui utilise des points de terminaison REST HTTP pour ce service. Importez et utilisez SessionMaker à partir de connect_conector.py pour les données de packages.
Requête 3 : À l'aide de la bibliothèque Python Flask, créez une implémentation qui utilise des points de terminaison REST HTTP pour ce service. Importez et utilisez le package à partir de data_model.py et SessionMaker à partir de connect_conector.py pour les données des packages.
Requête 4 : À l'aide de la bibliothèque Python Flask, créez une implémentation qui utilise des points de terminaison REST HTTP pour ce service. Importez et utilisez le package à partir de data_model.py et SessionMaker à partir de connect_conector.py pour les données de packages. Utiliser l'adresse IP de l'hôte 0.0.0.0 pour app.run

Mettez à jour les exigences pour main.py.
Requête : Crée un fichier d'exigences pour main.py

Ajoutez ceci au fichier requirements.txt. Assurez-vous d'utiliser Flask version 3.0.0.
Utilisez OPEN
pour créer le code dans un nouveau fichier, comme précédemment. Enregistrez le code dans un fichier nommé main.py.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
5. Tester et exécuter l'application
Installez les éléments requis.
pip3 install -r requirements.txt
Exécutez main.py.
python main.py
Le résultat ressemble à ce qui suit :
* Serving Flask app 'main' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://10.88.0.3:5000 Press CTRL+C to quit
À partir d'un deuxième terminal, testez le point de terminaison /packages/<product_id>.
curl localhost:5000/packages/1
Le résultat ressemble à ce qui suit :
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Vous pouvez également tester n'importe quel autre ID de produit dans vos exemples de données.
Saisissez CTRL_C pour quitter le conteneur Docker en cours d'exécution dans le terminal.
Générer des tests unitaires
Ouvrez le fichier main.py et générez des tests unitaires.
Requête 1 : Génère des tests unitaires.

Utilisez le workflow OPEN
le code dans un nouveau fichier comme précédemment. Enregistrez le code dans un fichier nommé test.py.
Dans la fonction test_get_package, un product_id doit être défini. Vous pouvez l'ajouter manuellement.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Réinitialisez l'historique du chat Duet AI en cliquant sur l'icône Corbeille
en haut de la barre latérale Duet AI.
L'exécution des tests unitaires
Exécutez le test unitaire.
python test.py
Le résultat ressemble à ce qui suit :
. ---------------------------------------------------------------------- Ran 1 test in 1.061s OK
Fermez tous les fichiers dans l'éditeur Cloud Shell et effacez l'historique du chat en cliquant sur l'icône Corbeille
dans la barre d'état supérieure.
Dockerfile
Créez un Dockerfile pour cette application.
Ouvrez main.py et essayez les requêtes suivantes.
Requête 1 : Génère un Dockerfile pour cette application.
Requête 2 : Génère un Dockerfile pour cette application. Copiez tous les fichiers dans le conteneur.

Vous devez également définir ENVARS pour INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS et DB_NAME. Vous pouvez le faire manuellement. Votre fichier Dockerfile doit ressembler à ce qui suit :
FROM python:3.10-slim
WORKDIR /app
COPY . ./
RUN pip install -r requirements.txt
# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details
CMD ["python", "main.py"]
Utilisez le workflow OPEN
le code dans un nouveau fichier comme précédemment. Enregistrez le code dans un fichier nommé Dockerfile.
Le fichier final se trouve dans la section "ANNEXE" de cet atelier de programmation. Si ce n'est pas le cas, apportez manuellement les modifications nécessaires.
Exécuter l'application en local
Une fois le Dockerfile ouvert, essayez le prompt suivant.
Requête 1 : Comment exécuter un conteneur localement à l'aide de ce Dockerfile ?

Suivez les instructions.
# Build docker build -t shipping . # And run docker run -p 5000:5000 -it shipping
Le résultat ressemble à ce qui suit :
* Serving Flask app 'main' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000 * Running on http://172.17.0.2:5000 Press CTRL+C to quit
Dans une deuxième fenêtre de terminal, accédez au conteneur.
curl localhost:5000/packages/1
Le résultat ressemble à ce qui suit :
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
L'application conteneurisée fonctionne.
Saisissez CTRL_C pour quitter le conteneur Docker en cours d'exécution dans le terminal.
Créer une image de conteneur dans Artifact Registry
Créez l'image de conteneur et transmettez-la à Artifact Registry.
cd ~/shipping
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping .
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
Le conteneur d'application se trouve maintenant à l'emplacement us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping, qui peut être déployé sur GKE.
6. Déployer l'application sur le cluster GKE
Un cluster GKE Autopilot a été créé lorsque vous avez créé les ressources GCP pour cet atelier. Connectez-vous au cluster GKE.
gcloud container clusters get-credentials gke1 \
--region=us-central1
annoter le compte de service Kubernetes par défaut avec le compte de service Google ;
kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com
Le résultat ressemble à ce qui suit :
serviceaccount/default annotated
Préparez et appliquez le fichier k8s.yaml.
cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml
kubectl apply -f k8s.yaml
Le résultat ressemble à ce qui suit :
deployment.apps/shipping created service/shipping created
Attendez que les pods soient en cours d'exécution et qu'une adresse IP d'équilibreur de charge externe soit attribuée au service.
kubectl get pods kubectl get service shipping
Le résultat ressemble à ce qui suit :
# kubectl get pods NAME READY STATUS RESTARTS AGE shipping-f5d6f8d5-56cvk 1/1 Running 0 4m47s shipping-f5d6f8d5-cj4vv 1/1 Running 0 4m48s shipping-f5d6f8d5-rrdj2 1/1 Running 0 4m47s # kubectl get service shipping NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE shipping LoadBalancer 34.118.225.125 34.16.39.182 80:30076/TCP 5m41s
Pour les clusters GKE Autopilot, attendez quelques instants que les ressources soient prêtes.
Accédez au service via l'adresse EXTERNAL-IP.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Le résultat ressemble à ce qui suit :
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
7. Points en plus : Résoudre les problèmes liés à l'application
Supprimez le rôle IAM "Client Cloud SQL" du compte de service cloudsqlsa. Cela entraîne une erreur de connexion à la base de données CloudSQL.
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Redémarrez le pod de livraison.
kubectl rollout restart deployment shipping
Une fois le pod redémarré, essayez à nouveau d'accéder au service shipping.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Le résultat ressemble à ce qui suit :
... <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
Inspectez les journaux en accédant à Kubernetes Engine > Charges de travail.

Cliquez sur le déploiement shipping, puis sur l'onglet Journaux.

Cliquez sur l'icône Afficher dans l'explorateur de journaux
sur le côté droit de la barre d'état. Une nouvelle fenêtre Explorateur de journaux s'ouvre.

Cliquez sur l'une des entrées d'erreur Traceback, puis sur Expliquer cette entrée de journal.

Vous pouvez lire l'explication de l'erreur.
Ensuite, demandons à Duet AI de nous aider à résoudre l'erreur.
Essayez le prompt suivant.
Requête 1 : Aide-moi à résoudre cette erreur

Saisissez le message d'erreur dans la requête.
Requête 2 : Interdit : le compte principal IAM authentifié ne semble pas autorisé à effectuer la requête API. Vérifiez que l'API Cloud SQL Admin est activée dans votre projet GCP et que le rôle "Client Cloud SQL" a été attribué au principal IAM.

[Musique]
Requête 3 : Comment attribuer le rôle Client Cloud SQL à un compte de service Google à l'aide de gcloud ?

Attribuez le rôle Client Cloud SQL à cloudsqlsa.
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Patientez quelques instants, puis réessayez d'accéder à l'application.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Le résultat ressemble à ce qui suit :
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Vous avez utilisé Duet AI dans Cloud Logging, l'explorateur de journaux et la fonctionnalité Explication des journaux pour résoudre le problème.
8. Conclusion
Félicitations ! Vous avez terminé cet atelier de programmation.
Dans cet atelier de programmation, vous avez appris les points suivants :
- Activez Duet AI dans votre projet GCP et configurez-le pour l'utiliser dans un IDE et la console Cloud.
- Utiliser Duet AI pour générer, compléter et expliquer du code
- Utiliser Duet AI pour expliquer et résoudre un problème d'application
- Fonctionnalités de Duet AI, comme le chat IDE et le chat multitour, la génération de code par chat ou intégrée, les actions intelligentes comme l'explication du code et la confirmation de la récitation, et plus encore.
9. Annexe
package-service.yaml
swagger: "2.0"
info:
title: Shipping and Package Information API
description: This API provides information about shipping and packages.
version: 1.0.0
host: shipping.googleapis.com
schemes:
- https
produces:
- application/json
paths:
/packages/{product_id}:
get:
summary: Get information about a package
description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
parameters:
- name: product_id
in: path
required: true
type: integer
format: int64
responses:
"200":
description: A successful response
schema:
type: object
properties:
height:
type: integer
format: int64
width:
type: integer
format: int64
depth:
type: integer
format: int64
weight:
type: integer
format: int64
special_handling_instructions:
type: string
"404":
description: The product_id was not found
data_model.py
from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base
from connect_connector import engine
Base = declarative_base()
class Package(Base):
__tablename__ = 'packages'
id = Column(Integer, primary_key=True)
product_id = Column(Integer, nullable=False)
height = Column(Float, nullable=False)
width = Column(Float, nullable=False)
depth = Column(Float, nullable=False)
weight = Column(Float, nullable=False)
special_handling_instructions = Column(String, nullable=True)
def create_tables():
Base.metadata.create_all(engine)
if __name__ == '__main__':
create_tables()
print('Tables created successfully.')
connect_connector.py
import os
from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy
# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base
def connect_with_connector() -> sqlalchemy.engine.base.Engine:
"""Initializes a connection pool for a Cloud SQL instance of Postgres."""
# Note: Saving credentials in environment variables is convenient, but not
# secure - consider a more secure solution such as
# Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
# keep secrets safe.
instance_connection_name = os.environ[
"INSTANCE_CONNECTION_NAME"
] # e.g. 'project:region:instance'
db_user = os.environ["DB_USER"] # e.g. 'my-database-user'
db_pass = os.environ["DB_PASS"] # e.g. 'my-database-password'
db_name = os.environ["DB_NAME"] # e.g. 'my-database'
ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC
connector = Connector()
def getconn() -> sqlalchemy.engine.base.Engine:
conn: sqlalchemy.engine.base.Engine = connector.connect(
instance_connection_name,
"pg8000",
user=db_user,
password=db_pass,
db=db_name,
ip_type=ip_type,
)
return conn
pool = sqlalchemy.create_engine(
"postgresql+pg8000://",
creator=getconn,
# ...
)
return pool
# Create a connection pool
engine = connect_with_connector()
# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)
# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()
db_init.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine
from data_model import Package
def create_packages():
# Create a session
session = sessionmaker(bind=engine)()
# Create 10 sample packages
for i in range(10):
package = Package(
product_id=i,
height=10.0,
width=10.0,
depth=10.0,
weight=10.0,
special_handling_instructions="No special handling instructions."
)
# Add the package to the session
session.add(package)
# Commit the changes
session.commit()
if __name__ == '__main__':
create_packages()
print('Packages created successfully.')
main.py
from flask import Flask, request, jsonify
from data_model import Package
from connect_connector import SessionMaker
app = Flask(__name__)
session_maker = SessionMaker()
@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
"""Get information about a package."""
session = session_maker
package = session.query(Package).filter(Package.product_id == product_id).first()
if package is None:
return jsonify({"message": "Package not found."}), 404
return jsonify(
{
"height": package.height,
"width": package.width,
"depth": package.depth,
"weight": package.weight,
"special_handling_instructions": package.special_handling_instructions,
}
), 200
if __name__ == "__main__":
app.run(host="0.0.0.0")
test.py
import unittest
from data_model import Package
from connect_connector import SessionMaker
from main import app
class TestPackage(unittest.TestCase):
def setUp(self):
self.session_maker = SessionMaker()
def tearDown(self):
self.session_maker.close()
def test_get_package(self):
"""Test the `get_package()` function."""
package = Package(
product_id=11, # Ensure that the product_id different from the sample data
height=10,
width=10,
depth=10,
weight=10,
special_handling_instructions="Fragile",
)
session = self.session_maker
session.add(package)
session.commit()
response = app.test_client().get("/packages/11")
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.json,
{
"height": 10,
"width": 10,
"depth": 10,
"weight": 10,
"special_handling_instructions": "Fragile",
},
)
if __name__ == "__main__":
unittest.main()
requirements.txt
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3
Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY . ./
RUN pip install -r requirements.txt
# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details
CMD ["python", "main.py"]