Guida al workshop pratico su Duet AI per sviluppatori codelab

1. Obiettivi

Lo scopo di questo workshop è fornire agli utenti e ai professionisti una formazione pratica su Duet AI.

In questo codelab imparerai a:

  1. Attiva Duet AI nel tuo progetto GCP e configuralo per l'utilizzo in un IDE e nella console Cloud.
  2. Utilizza Duet AI per la generazione, il completamento e la spiegazione del codice.
  3. Utilizza Duet AI per spiegare e risolvere un problema dell'applicazione.
  4. Funzionalità di Duet AI come chat IDE e chat multigiro, chat e generazione di codice in linea, azioni intelligenti come spiegazione del codice e riconoscimento della recitazione e altro ancora.

Presentazione narrativa

Per mostrare come Duet AI per gli sviluppatori viene utilizzato in modo autentico nello sviluppo quotidiano, le attività di questo workshop si svolgono in un contesto narrativo.

Un nuovo sviluppatore entra a far parte di un'azienda di e-commerce. Il loro compito è aggiungere un nuovo servizio all'applicazione e-commerce esistente (che è composta da più servizi). Il nuovo servizio fornisce informazioni aggiuntive (dimensioni, peso e così via) sui prodotti nel catalogo prodotti. Questo servizio consentirà costi di spedizione migliori/più economici in base a dimensioni e peso del prodotto.

Poiché lo sviluppatore è nuovo in azienda, utilizzerà Duet AI per la generazione, la spiegazione e la documentazione del codice.

Una volta codificato il servizio, un amministratore della piattaforma utilizzerà Duet AI (chat) per creare l'artefatto (container Docker) e le risorse necessarie per il deployment dell'artefatto su GCP (ad esempio Artifact Registry, autorizzazioni IAM, un repository di codice, infrastruttura di calcolo, ad es. GKE o Cloud Run e così via).

Una volta che l'applicazione viene implementata su GCP, un operatore dell'applicazione/SRE utilizzerà Duet AI (e Cloud Ops) per risolvere un errore nel nuovo servizio.

Utente tipo

Il workshop tratta il seguente personaggio:

  1. Sviluppatore di applicazioni: sono richieste alcune conoscenze di programmazione e sviluppo software.

Questa variante del workshop su Duet AI è riservata agli sviluppatori. Non è richiesta alcuna conoscenza delle risorse cloud Google Cloud. Gli script per creare le risorse GCP necessarie per eseguire questa applicazione sono disponibili qui. Per eseguire il deployment delle risorse GCP richieste, puoi seguire le istruzioni riportate in questa guida.

2. Preparazione dell'ambiente

Attivare Duet AI

Puoi attivare Duet AI in un progetto GCP tramite API (gcloud o strumenti IaC come Terraform) o tramite la UI della console Cloud.

Per attivare Duet AI in un progetto Google Cloud, devi abilitare l'API Cloud AI Companion e concedere i ruoli Identity and Access Management (IAM) Cloud AI Companion User e Service Usage Viewer agli utenti.

Tramite gcloud

Attiva Cloud Shell:

Configura PROJECT_ID, USER e abilita 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}

L'output è simile al seguente:

Updated property [core/project].
Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.

Concedi i ruoli Identity and Access Management (IAM) Cloud AI Companion User e Service Usage Viewer all'account UTENTE. L'API Cloud Companion si trova dietro le funzionalità dell'IDE e della console che utilizzeremo. L'autorizzazione Visualizzatore utilizzo servizio viene utilizzata come controllo rapido prima di attivare la UI nella console (in modo che la UI di Duet venga visualizzata solo nei progetti in cui l'API è abilitata).

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

L'output è simile al seguente:

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/cloudaicompanion.user

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/serviceusage.serviceUsageViewer

Tramite la console Cloud

Per abilitare l'API, vai alla pagina dell'API Cloud AI Companion nella console Google Cloud.

Nel selettore dei progetti, seleziona un progetto.

Fai clic su Abilita.

La pagina si aggiorna e mostra lo stato Attivato. Duet AI è ora disponibile nel progetto Google Cloud selezionato per tutti gli utenti che dispongono dei ruoli IAM richiesti.

Per concedere i ruoli IAM necessari per utilizzare Duet AI, vai alla pagina IAM.

Nella colonna Entità, trova l'UTENTE per cui vuoi attivare l'accesso a Duet AI, quindi fai clic sull'icona a forma di matita ✏️ Modifica entità in quella riga.

Nel riquadro di accesso Modifica, fai clic su Aggiungi Aggiungi un altro ruolo.

In Seleziona un ruolo, seleziona Utente Cloud AI Companion.

Fai clic su Aggiungi un altro ruolo e seleziona Visualizzatore utilizzo servizio.

Fai clic su Salva.

Configurazione dell'IDE

Gli sviluppatori possono scegliere tra una serie di IDE più adatti alle loro esigenze. L'assistenza per il codice di Duet AI è disponibile in più IDE come Visual Studio Code, IDE JetBrains (IntelliJ, PyCharm, GoLand, WebStorm e altri), Cloud Workstations e Cloud Shell Editor.

In questo lab puoi utilizzare Cloud Workstations o Cloud Shell Editor.

Questo workshop utilizza l'editor di Cloud Shell.

Tieni presente che la configurazione di Cloud Workstations può richiedere 20-30 minuti.

Per utilizzarlo immediatamente, usa l'editor di Cloud Shell.

Apri l'editor di Cloud Shell facendo clic sull'icona a forma di matita ✏️ nella barra dei menu in alto di Cloud Shell.

L'editor di Cloud Shell ha un'interfaccia utente e un'esperienza utente molto simili a VSCode.

d6a6565f83576063.png

Fai clic su CTRL (in Windows)/CMD (in Mac) + , (virgola) per accedere al riquadro Impostazioni.

Nella barra di ricerca, digita "Duet AI".

Assicurati di attivare Cloudcode › Duet AI: Enable e Cloudcode › Duet AI › Inline Suggestions: Enable Auto

111b8d587330ec74.png

Nella barra di stato in basso, fai clic su Cloud Code - Sign In (Cloud Code - Accedi) e segui il flusso di lavoro di accesso.

Se hai già eseguito l'accesso, la barra di stato mostra Cloud Code - No project.

Fai clic su Cloud Code - No project (Cloud Code - Nessun progetto) e nella parte superiore verrà visualizzato un riquadro a discesa delle azioni. Fai clic su Seleziona un progetto Google Cloud.

3241a59811e3c84a.png

Inizia a digitare l'ID PROGETTO e il progetto dovrebbe essere visualizzato nell'elenco.

c5358fc837588fe.png

Seleziona PROJECT_ID dall'elenco dei progetti.

La barra di stato inferiore si aggiorna per mostrare l'ID progetto. In caso contrario, potrebbe essere necessario aggiornare la scheda dell'editor di Cloud Shell.

Fai clic sull'icona di Duet AI d97fc4e7b594c3af.png nella barra dei menu a sinistra e verrà visualizzata la finestra di chat di Duet AI. Se ricevi un messaggio che ti chiede di selezionare un progetto Google Cloud. Fai clic e seleziona di nuovo il progetto.

Ora vedi la finestra della chat di Duet AI

781f888360229ca6.png

3. Configurazione dell'infrastruttura

d3234d237f00fdbb.png

Per eseguire il nuovo servizio di spedizione in Google Cloud, hai bisogno delle seguenti risorse Google Cloud:

  1. Un'istanza Cloud SQL con un database.
  2. Un cluster GKE per eseguire il servizio containerizzato.
  3. Un Artifact Registry per archiviare l'immagine Docker.
  4. Un repository Cloud Source per il codice.

Nel terminale Cloud Shell, clona il seguente repository ed esegui questi comandi per configurare l'infrastruttura nel tuo progetto 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. Sviluppo di un servizio Flask Python

9745ba5c70782e76.png

Il servizio che creeremo sarà composto dai seguenti file. Non devi creare questi file ora, ma li creerai uno alla volta seguendo le istruzioni riportate di seguito:

  1. package-service.yaml: una specifica API aperta per il servizio di pacchi che contiene dati come altezza, larghezza, peso e istruzioni speciali di gestione.
  2. data_model.py: modello di dati per la specifica dell'API package-service. Crea anche la tabella packages nel database product_details.
  3. connect_connector.py - Connessione CloudSQL (definisce il motore, la sessione e l'ORM di base)
  4. db_init.py: genera dati di esempio nella tabella packages.
  5. main.py: un servizio Python Flask con un endpoint GET per recuperare i dettagli del pacchetto dai dati packages in base a product_id.
  6. test.py - Test delle unità
  7. requirement.txt - Requisiti Python
  8. Dockerfile: per containerizzare questa applicazione

Se riscontri problemi durante gli esercizi, i file finali si trovano tutti nell'APPENDICE di questo codelab come riferimento.

Nel passaggio precedente, hai creato un repository Cloud Source. Clona il repository. Creerai i file dell'applicazione nella cartella del repository clonato.

Nel terminale Cloud Shell, esegui questo comando per clonare il repository.

cd ~
gcloud source repos clone shipping shipping
cd ~/shipping 

Apri la barra laterale della chat di Duet AI dal menu a sinistra dell'editor di Cloud Shell. L'icona ha l'aspetto di 8b135a000b259175.png. Ora puoi utilizzare Duet AI per l'assistenza per il codice.

package-service.yaml

Senza file aperti, chiedi a Duet di generare una specifica OpenAPI per il servizio di spedizione.

Prompt 1: genera una specifica OpenAPI yaml per un servizio che fornisce informazioni su spedizione e pacco dato un ID prodotto numerico. Il servizio deve includere informazioni su altezza, larghezza, profondità, peso e istruzioni speciali per la gestione dei pacchi.

ba12626f491a1204.png

Nella parte superiore destra della finestra del codice generato sono elencate tre opzioni.

Puoi COPY 71194556d8061dae.pngil codice e INCOLLARLO in un file.

Puoi ADD df645de8c65607a.png il codice nel file attualmente aperto nell'editor.

In alternativa, puoi OPEN a4c7ed6d845df343.png il codice in un nuovo file.

Fai clic su OPEN a4c7ed6d845df343.png il codice in un nuovo file.

Fai clic su CTRL/CMD + s per salvare il file e archiviarlo nella cartella dell'applicazione con il nome package-service.yaml. Fai clic su OK.

f6ebd5b836949366.png

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Puoi anche provare vari prompt per vedere le risposte di Duet AI.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

data_model.py

Il passaggio successivo consiste nella creazione del file Python del modello di dati per il servizio in base alla specifica OpenAPI.

Con il file package-service.yaml aperto, inserisci il seguente prompt.

Prompt 1: utilizzando l'ORM sqlalchemy di Python, genera un modello di dati per questo servizio API. Includi anche una funzione separata e un punto di ingresso principale che crea le tabelle del database.

b873a6a28bd28ca1.png

Diamo un'occhiata a ogni parte generata. Duet AI è ancora un assistente e, sebbene possa aiutarti a scrivere rapidamente il codice, devi comunque rivedere e comprendere i contenuti generati man mano che procedi.

Innanzitutto, esiste una classe denominata Package di tipo Base che definisce il modello dei dati per il database packages come segue:

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))

Successivamente, devi creare una funzione che crei la tabella nel database, come la seguente:

def create_tables(engine):
    Base.metadata.create_all(engine)

Infine, devi creare una funzione principale che esegua la funzione create_tables per creare effettivamente la tabella nel database CloudSQL, come segue:

if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine('sqlite:///shipping.db')
    create_tables(engine)

    print('Tables created successfully.')

Tieni presente che la funzione main crea un motore utilizzando un database sqlite locale. Per utilizzare CloudSQL, dovrai modificarlo. Lo farai un po' più tardi.

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato data_model.py (nota il carattere di sottolineatura nel nome e non il trattino).

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

connect-connector.py

Crea il connettore Cloud SQL.

Con il file data_model.py aperto, inserisci i seguenti prompt.

Prompt 1: utilizzando la libreria cloud-sql-python-connector, genera una funzione che inizializza un pool di connessioni per un'istanza Cloud SQL di Postgres.

ed05cb6ff85d34c5.png

Tieni presente che la risposta non utilizza la libreria cloud-sql-python-connector. Puoi perfezionare i prompt, per dare un piccolo suggerimento a Duet, aggiungendo dettagli alla stessa chat.

Usiamo un altro prompt.

Prompt 2: deve utilizzare la libreria cloud-sql-python-connector.

d09095b44dde35bf.png

Assicurati che utilizzi la libreria cloud-sql-python-connector.

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato connect_conector.py. Potresti dover importare manualmente la libreria pg8000. Consulta il file riportato di seguito.

Cancella la cronologia della chat di Duet AI e, con il file connect_connector.py aperto, genera l'ORM DB engine, sessionmaker e base da utilizzare nell'applicazione.

Prompt 1: crea un motore, una classe sessionmaker e Base ORM utilizzando il metodo connect_with_connector

6e4214b72ab13a63.png

La risposta potrebbe aggiungere engine, Session e Base al file connect_connector.py.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Puoi anche provare vari prompt per vedere la potenziale variazione delle risposte di Duet AI.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

Aggiornamento di data_model.py

Per creare una tabella nel database Cloud SQL, devi utilizzare il motore creato nel passaggio precedente (nel file connect_connector.py).

Cancella la cronologia della chat Duet AI. Apri il file data_model.py. Prova il seguente prompt.

Prompt 1: nella funzione principale, importa e utilizza il motore da connect_connector.py

2e768c9b6c523b9a.png

Dovresti vedere la risposta che importa engine da connect_connector (per Cloud SQL). create_table utilizza questo motore (anziché il database locale sqlite predefinito).

Aggiorna il file data_model.py.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Puoi anche provare vari prompt per vedere le diverse risposte di Duet AI.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

requirements.txt

Crea un file requirements.txt per l'applicazione.

Apri sia connect_connector.py sia il file data_model.py e inserisci il seguente prompt.

Prompt 1: genera un file dei requisiti pip per questo modello di dati e servizio

Prompt 2: genera un file dei requisiti pip per questo modello di dati e servizio utilizzando le versioni più recenti

69fae373bc5c6a18.png

Verifica che i nomi e le versioni siano corretti. Ad esempio, nella risposta riportata sopra, il nome e la versione di google-cloud-sql-connecter non sono corretti. Correggi manualmente le versioni e crea un file requirements.txt simile a questo:

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0

Nel terminale dei comandi, esegui questo comando:

pip3 install -r requirements.txt

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

Creazione della tabella dei pacchetti in Cloud SQL

Imposta le variabili di ambiente per il connettore del database Cloud SQL.

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

Ora esegui data_model.py.

python data_model.py

L'output è simile al seguente (controlla il codice per vedere cosa è effettivamente previsto):

Tables created successfully.

Connettiti all'istanza Cloud SQL e verifica che il database sia stato creato.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Dopo aver inserito la password (anche evolution), recupera le tabelle.

product_details=> \dt

L'output è simile al seguente:

           List of relations
 Schema |   Name   | Type  |   Owner   
--------+----------+-------+-----------
 public | packages | table | evolution
(1 row)

Puoi anche controllare il modello di dati e i dettagli della tabella.

product_details=> \d+ packages

L'output è simile al seguente:

                                                                        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

Digita \q per uscire da Cloud SQL.

db_init.py

A questo punto, aggiungiamo alcuni dati di esempio alla tabella packages.

Cancella la cronologia della chat Duet AI. Con il file data_model.py aperto, prova i seguenti prompt.

Prompt 1: genera una funzione che crea 10 righe di pacchetti di esempio e le inserisce nella tabella dei pacchetti

Prompt 2: utilizzando la sessione di connect_connector, genera una funzione che crea 10 righe di pacchetti di esempio e le inserisce nella tabella dei pacchetti

34a9afc5f04ba5.png

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato db_init.py.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Puoi anche provare vari prompt per vedere le diverse risposte di Duet AI.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

Creazione di dati di esempio sui pacchetti

Esegui db_init.py dalla riga di comando.

python db_init.py

L'output è simile al seguente:

Packages created successfully.

Connettiti di nuovo all'istanza Cloud SQL e verifica che i dati di esempio siano stati aggiunti alla tabella dei pacchetti.

Connettiti all'istanza Cloud SQL e verifica che il database sia stato creato.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Dopo aver inserito la password (anche evolution), recupera tutti i dati dalla tabella dei pacchetti.

product_details=> SELECT * FROM packages;

L'output è simile al seguente:

 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)

Digita \q per uscire da Cloud SQL.

main.py

Con i file data_model.py, package-service.yaml e connect_connector.py aperti, crea un main.py per l'applicazione.

Prompt 1: Using the python flask library - create an implementation that uses http rest endpoints for this service

Prompt 2: utilizzando la libreria Flask di Python, crea un'implementazione che utilizzi endpoint REST HTTP per questo servizio. Importa e utilizza SessionMaker da connect_conector.py per i dati dei pacchetti.

Prompt 3: utilizzando la libreria Python Flask, crea un'implementazione che utilizzi endpoint REST HTTP per questo servizio. Importa e utilizza Package da data_model.py e SessionMaker da connect_conector.py per i dati dei pacchetti.

Prompt 4: Using the python flask library - create an implementation that uses http rest endpoints for this service. import and use Package from the data_model.py and the SessionMaker from connect_conector.py to for packages data. Utilizza l'IP host 0.0.0.0 per app.run

6d794fc52a90e6ae.png

Aggiorna i requisiti per main.py.

Prompt: crea il file requirements per main.py

1cc0b318d2d4ca2f.png

Aggiungi questo al file requirements.txt. Assicurati di utilizzare Flask versione 3.0.0.

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato main.py.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

5. Testare ed eseguire l'applicazione

Installa i requisiti.

pip3 install -r requirements.txt

Esegui main.py.

python main.py

L'output è simile al seguente:

 * 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

Da un secondo terminale, testa l'endpoint /packages/<product_id>.

curl localhost:5000/packages/1

L'output è simile al seguente:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Puoi anche testare qualsiasi altro ID prodotto nei dati di esempio.

Inserisci CTRL_C per uscire dal container Docker in esecuzione nel terminale.

Generazione di test delle unità

Con il file main.py aperto, genera i test delle unità.

Prompt 1: genera test delle unità.

e861e5b63e1b2657.png

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato test.py.

Nella funzione test_get_package, è necessario definire un product_id. Puoi aggiungerlo manualmente.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Reimposta la cronologia della chat di Duet AI facendo clic sull'icona del cestino f574ca2c1e114856.png nella parte superiore della barra laterale di Duet AI.

Esecuzione dei test delle unità

Esegui il test delle unità.

python test.py

L'output è simile al seguente:

.
----------------------------------------------------------------------
Ran 1 test in 1.061s

OK

Chiudi tutti i file nell'editor di Cloud Shell e cancella la cronologia della chat facendo clic sull'icona del cestino 1ecccfe10d6c540.png nella barra di stato in alto.

Dockerfile

Crea un Dockerfile per questa applicazione.

Apri main.py e prova i seguenti prompt.

Prompt 1: genera un Dockerfile per questa applicazione.

Prompt 2: genera un Dockerfile per questa applicazione. Copia tutti i file nel container.

9c473caea437a5c3.png

Devi anche impostare ENVARS per INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS e DB_NAME. Puoi farlo manualmente. Il Dockerfile dovrebbe avere il seguente aspetto:

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"]

Utilizza OPEN a4c7ed6d845df343.png il codice in un nuovo flusso di lavoro dei file come prima. Salva il codice in un file denominato Dockerfile.

Il file finale si trova nella sezione APPENDICE di questo codelab. In caso contrario, apporta manualmente le modifiche necessarie.

Esecuzione locale dell'applicazione

Con Dockerfile aperto, prova il seguente prompt.

Prompt 1: come faccio a eseguire localmente un container utilizzando questo Dockerfile?

570fd5c296ca8c83.png

Segui le istruzioni.

# Build
docker build -t shipping .
# And run
docker run -p 5000:5000 -it shipping

L'output è simile al seguente:

 * 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

Da una seconda finestra del terminale, accedi al container.

curl localhost:5000/packages/1

L'output è simile al seguente:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

L'applicazione containerizzata funziona.

Inserisci CTRL_C per uscire dal container Docker in esecuzione nel terminale.

Creazione dell'immagine container in Artifact Registry

Crea l'immagine container ed eseguine il push in 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

Il container dell'applicazione ora si trova in us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping, che può essere sottoposto a deployment in GKE.

6. Deployment dell'applicazione nel cluster GKE

Quando hai creato le risorse GCP per questo workshop, è stato creato un cluster GKE Autopilot. Connettiti al cluster GKE.

gcloud container clusters get-credentials gke1 \
    --region=us-central1

Annota il service account Kubernetes predefinito con il service account Google.

kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com

L'output è simile al seguente:

serviceaccount/default annotated

Prepara e applica il file 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

L'output è simile al seguente:

deployment.apps/shipping created
service/shipping created

Attendi che i pod siano in esecuzione e che al servizio sia assegnato un indirizzo IP del bilanciatore del carico esterno.

kubectl get pods
kubectl get service shipping

L'output è simile al seguente:

# 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

Per i cluster GKE Autopilot, attendi qualche istante finché le risorse non sono pronte.

Accedi al servizio tramite l'indirizzo EXTERNAL-IP.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

L'output è simile al seguente:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

7. Crediti extra: risoluzione dei problemi dell'applicazione

Rimuovi il ruolo IAM Client Cloud SQL dal service account cloudsqlsa. Ciò causa un errore di connessione al database Cloud SQL.

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Riavvia il pod di spedizione.

kubectl rollout restart deployment shipping

Dopo il riavvio del pod, prova ad accedere di nuovo al servizio shipping.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1 

L'output è simile al seguente:

...
<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>

Esamina i log andando a Kubernetes Engine > Workload.

d225b1916c829167.png

Fai clic sul deployment shipping e poi sulla scheda Log.

1d0459141483d6a7.png

Fai clic sull'icona Visualizza in Esplora log df8b9d19a9fe4c73.pngsul lato destro della barra di stato. Si apre una nuova finestra di Esplora log.

e86d1c265e176bc4.png

Fai clic su una delle voci di errore Traceback, quindi fai clic su Spiega questa voce di log.

d6af045cf03008bc.png

Puoi leggere la spiegazione dell'errore.

Ora chiediamo a Duet AI di aiutarci a risolvere l'errore.

Prova il seguente prompt.

Prompt 1: Aiutami a risolvere questo errore

9288dd6045369167.png

Inserisci il messaggio di errore nel prompt.

Prompt 2: Forbidden: Authenticated IAM principal does not seem authorized to make API request. Verifica che l'API Cloud SQL Admin sia abilitata nel tuo progetto GCP e che il ruolo "Client Cloud SQL" sia stato concesso all'entità IAM

f1e64fbdc435d31c.png

E poi

Prompt 3: come faccio ad assegnare il ruolo Client Cloud SQL a un service account Google utilizzando gcloud?

bb8926b995a8875c.png

Assegna il ruolo Client Cloud SQL a cloudsqlsa.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Attendi qualche istante e prova ad accedere di nuovo all'applicazione.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

L'output è simile al seguente:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Hai utilizzato correttamente Duet AI in Cloud Logging, Esplora log e nella funzionalità Spiegazione log per risolvere il problema.

8. Conclusione

Complimenti! Hai completato correttamente questo codelab.

In questo codelab hai imparato:

  1. Attiva Duet AI nel tuo progetto GCP e configuralo per l'utilizzo in un IDE e nella console Cloud.
  2. Utilizza Duet AI per la generazione, il completamento e la spiegazione del codice.
  3. Utilizza Duet AI per spiegare e risolvere un problema dell'applicazione.
  4. Funzionalità di Duet AI come chat IDE e chat multigiro, chat e generazione di codice in linea, azioni intelligenti come spiegazione del codice e riconoscimento della recitazione e altro ancora.

9. Appendice

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"]