Przewodnik techniczny dotyczący Duet AI z ćwiczeń z programowania dla programistów

1. Cele

Celem tych warsztatów jest praktyczne zapoznanie użytkowników i specjalistów z Duet AI.

Z tego przewodnika dowiesz się:

  1. Aktywuj Duet AI w projekcie GCP i skonfiguruj go do używania w IDE i konsoli Cloud.
  2. Używaj Duet AI do generowania, uzupełniania i wyjaśniania kodu.
  3. Używaj Duet AI do wyjaśniania i rozwiązywania problemów z aplikacjami.
  4. Funkcje Duet AI, takie jak czat w środowisku IDE i czat wieloetapowy, generowanie kodu w czacie i w tekście, inteligentne działania, takie jak wyjaśnianie kodu i potwierdzanie recytacji, i inne.

Opis

Aby pokazać, jak Duet AI dla deweloperów jest autentycznie wykorzystywany w codziennej pracy, działania w ramach tych warsztatów są osadzone w kontekście narracyjnym.

Nowy deweloper dołącza do firmy e-commerce. Ich zadaniem jest dodanie nowej usługi do istniejącej aplikacji e-commerce (składającej się z wielu usług). Nowa usługa dostarcza dodatkowe informacje (wymiary, waga itp.) o produktach w katalogu produktów. Ta usługa pozwoli na obniżenie kosztów dostawy na podstawie wymiarów i wagi produktu.

Deweloper jest nowy w firmie, więc będzie korzystać z Duet AI do generowania, wyjaśniania i dokumentowania kodu.

Po zakodowaniu usługi administrator platformy użyje Duet AI (czatu), aby utworzyć artefakt (kontener Dockera) i zasoby potrzebne do wdrożenia go w GCP (np. Artifact Registry, uprawnienia IAM, repozytorium kodu, infrastrukturę obliczeniową, np. GKE lub CloudRun itp.).

Po wdrożeniu aplikacji w GCP operator aplikacji lub inżynier ds. niezawodności witryny użyje Duet AI (i Cloud Ops), aby rozwiązać problem z nową usługą.

Osobowość

Warsztaty obejmują następującą personę:

  1. Programista aplikacji – wymagana jest pewna wiedza z zakresu programowania i tworzenia oprogramowania.

Ta wersja warsztatów Duet AI jest przeznaczona tylko dla programistów. Nie musisz znać zasobów Google Cloud. Skrypty dotyczące tworzenia zasobów GCP wymaganych do uruchomienia tej aplikacji znajdziesz tutaj. Aby wdrożyć wymagane zasoby GCP, postępuj zgodnie z instrukcjami w tym przewodniku.

2. Przygotowywanie środowiska

Aktywowanie Duet AI

Aktywować Duet AI w projekcie GCP możesz za pomocą interfejsu API (gcloud lub narzędzia IaC, takie jak Terraform) albo interfejsu konsoli Google Cloud.

Aby aktywować Duet AI w projekcie Google Cloud, włącz interfejs Cloud AI Companion API i przyznaj użytkownikom role Identity and Access Management (IAM) użytkownika usługi Cloud AI Companion oraz wyświetlającego wykorzystanie usług.

Za pomocą gcloud

Aktywuj Cloud Shell:

Skonfiguruj PROJECT_ID, USER i włącz interfejs Cloud AI Companion API.

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}

Dane wyjściowe wyglądają tak:

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

Przyznaj kontu UŻYTKOWNIKA role Identity and Access Management (IAM) użytkownika usługi Cloud AI Companion oraz wyświetlającego wykorzystanie usług. Interfejs Cloud Companion API jest podstawą funkcji, z których będziemy korzystać w IDE i konsoli. Uprawnienie przeglądającego wykorzystanie usługi jest używane do szybkiego sprawdzania przed włączeniem interfejsu w konsoli (aby interfejs Duet AI pojawiał się tylko w projektach, w których włączony jest interfejs API).

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

Dane wyjściowe wyglądają tak:

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

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

W konsoli Cloud

Aby włączyć interfejs API, otwórz stronę Cloud AI Companion API w konsoli Google Cloud.

W selektorze projektów wybierz projekt.

Kliknij Włącz.

Strona zostanie zaktualizowana i wyświetli stan Włączony. Duet AI jest teraz dostępny w wybranym projekcie Google Cloud dla wszystkich użytkowników, którzy mają wymagane role IAM.

Aby przypisać role uprawnień wymagane do korzystania z Duet AI, otwórz stronę Uprawnienia.

W kolumnie Podmiot zabezpieczeń znajdź UŻYTKOWNIKA, któremu chcesz włączyć dostęp do Duet AI, a następnie kliknij ikonę ołówka ✏️ Edytuj podmiot zabezpieczeń w tym wierszu.

W panelu dostępu Edytuj kliknij Dodaj kolejną rolę.

W sekcji Wybierz rolę kliknij Użytkownik usługi Cloud AI Companion.

Kliknij Dodaj kolejną rolę i wybierz Wyświetlający wykorzystanie usługi.

Kliknij Zapisz.

Konfigurowanie środowiska IDE

Deweloperzy mogą wybierać spośród różnych środowisk IDE, które najlepiej odpowiadają ich potrzebom. Pomoc w kodowaniu Duet AI jest dostępna w wielu środowiskach IDE, takich jak Visual Studio Code, IDE JetBrains (IntelliJ, PyCharm, GoLand, WebStorm i inne), Cloud Workstations i edytor Cloud Shell.

W tym module możesz użyć Cloud Workstations lub edytora Cloud Shell.

W tych warsztatach używamy edytora Cloud Shell.

Pamiętaj, że skonfigurowanie Cloud Workstations może potrwać 20–30 minut.

Aby od razu zacząć korzystać z tego narzędzia, użyj edytora Cloud Shell.

Otwórz edytor Cloud Shell, klikając ikonę ołówka ✏️ na górnym pasku menu Cloud Shell.

Edytor Cloud Shell ma interfejs użytkownika bardzo podobny do VSCode.

d6a6565f83576063.png

Naciśnij CTRL (w systemie Windows) lub CMD (na komputerze Mac) + , (przecinek), aby otworzyć panel Ustawienia.

Na pasku wyszukiwania wpisz „duet ai”.

Sprawdź, czy opcje Cloudcode › Duet AI: Włącz i Cloudcode › Duet AI › Sugestie w tekście: Włącz automatycznie są włączone.

111b8d587330ec74.png

Na pasku stanu u dołu kliknij Cloud Code – zaloguj się i postępuj zgodnie z instrukcjami logowania.

Jeśli jesteś już zalogowany(-a), na pasku stanu wyświetli się komunikat Cloud Code – No project (Cloud Code – brak projektu).

Kliknij Cloud Code – brak projektu. U góry pojawi się panel z menu czynności. Kliknij Wybierz projekt w chmurze Google Cloud.

3241a59811e3c84a.png

Zacznij wpisywać IDENTYFIKATOR PROJEKTU, a projekt powinien pojawić się na liście.

c5358fc837588fe.png

Na liście projektów wybierz PROJECT_ID.

Pasek stanu u dołu ekranu zaktualizuje się i wyświetli identyfikator projektu. Jeśli tak się nie stanie, może być konieczne odświeżenie karty edytora Cloud Shell.

Kliknij ikonę Duet AI d97fc4e7b594c3af.png na pasku menu po lewej stronie. Pojawi się okno czatu Duet AI. Jeśli pojawi się komunikat Wybierz projekt GCP. Kliknij projekt i wybierz go ponownie.

Wyświetli się okno czatu Duet AI.

781f888360229ca6.png

3. Konfigurowanie infrastruktury

d3234d237f00fdbb.png

Aby uruchomić nową usługę dostawy w GCP, potrzebujesz tych zasobów GCP:

  1. Instancja Cloud SQL z bazą danych.
  2. klaster GKE do uruchamiania skonteneryzowanej usługi;
  3. Artifact Registry do przechowywania obrazu Dockera.
  4. Repozytorium Cloud Source na potrzeby kodu.

W terminalu Cloud Shell sklonuj to repozytorium i uruchom te polecenia, aby skonfigurować infrastrukturę w projekcie 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. Tworzenie usługi Flask w Pythonie

9745ba5c70782e76.png

Usługa, którą utworzymy, będzie ostatecznie składać się z tych plików. Nie musisz teraz tworzyć tych plików. Zrobisz to po kolei, postępując zgodnie z instrukcjami poniżej:

  1. package-service.yaml – otwarta specyfikacja interfejsu API usługi dostawy paczek, która zawiera dane takie jak wysokość, szerokość, waga i instrukcje specjalnego postępowania.
  2. data_model.py – model danych dla specyfikacji interfejsu API usługi pakietowej. Tworzy też tabelę packages w bazie danych product_details.
  3. connect_connector.py – połączenie Cloud SQL (określa silnik, sesję i podstawowy ORM)
  4. db_init.py – generuje przykładowe dane w tabeli packages.
  5. main.py – usługa Python Flask z punktem końcowym GET, który pobiera szczegóły pakietu z danych packages na podstawie identyfikatora produktu.
  6. test.py – test jednostkowy
  7. requirement.txt – wymagania dotyczące Pythona
  8. Dockerfile – aby umieścić tę aplikację w kontenerze.

Jeśli podczas ćwiczeń napotkasz jakieś trudności, w DODATKU do tego laboratorium znajdziesz pliki końcowe, które mogą Ci pomóc.

W poprzednim kroku utworzyliśmy repozytorium Cloud Source Repositories. Sklonuj repozytorium. Pliki aplikacji utworzysz w folderze sklonowanego repozytorium.

Aby sklonować repozytorium, w terminalu Cloud Shell uruchom to polecenie:

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

Otwórz panel czatu Duet AI w menu po lewej stronie edytora Cloud Shell. Ikona wygląda tak: 8b135a000b259175.png. Możesz teraz korzystać z Duet AI, aby uzyskać pomoc dotyczącą kodu.

package-service.yaml

Nie otwierając żadnych plików, poproś Duet o wygenerowanie specyfikacji Open API dla usługi dostawy.

Prompt 1: Wygeneruj specyfikację OpenAPI w formacie YAML dla usługi, która na podstawie numerycznego identyfikatora produktu podaje informacje o dostawie i przesyłce. Usługa powinna zawierać informacje o wysokości, szerokości, głębokości i wadze paczki oraz wszelkie specjalne instrukcje dotyczące obsługi.

ba12626f491a1204.png

W prawym górnym rogu okna wygenerowanego kodu znajdziesz 3 opcje.

Możesz COPY 71194556d8061dae.pngkod i WKLEIĆ go do pliku.

Możesz ADD df645de8c65607a.png kod do aktualnie otwartego pliku w edytorze.

Możesz też OPEN a4c7ed6d845df343.png kod w nowym pliku.

Kliknij OPEN a4c7ed6d845df343.png kod w nowym pliku.

Kliknij CTRL/CMD + s, aby zapisać plik, i przechowuj go w folderze aplikacji pod nazwą package-service.yaml. Kliknij przycisk OK.

f6ebd5b836949366.png

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Możesz też wypróbować różne prompty, aby zobaczyć odpowiedzi Duet AI.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

data_model.py

Następnie na podstawie specyfikacji OpenAPI utwórz plik Python modelu danych dla usługi.

Otwórz plik package-service.yaml i wpisz ten prompt.

Prompt 1: Using the python sqlalchemy ORM, generate a data model for this API service. Dodaj też osobną funkcję i główny punkt wejścia, który tworzy tabele bazy danych.

b873a6a28bd28ca1.png

Przyjrzyjmy się każdej wygenerowanej części. Duet AI to wciąż asystent, który może pomóc w szybkim tworzeniu kodu, ale nadal należy sprawdzać wygenerowane treści i je rozumieć.

Najpierw jest klasa o nazwie Package rodzajuBase, która definiuje model danych dla bazy danych packages, np. w ten sposób:

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

Następnie potrzebujesz funkcji, która utworzy tabelę w bazie danych, np. takiej:

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

Na koniec potrzebujesz funkcji głównej, która uruchamia funkcję create_tables, aby utworzyć tabelę w bazie danych Cloud SQL, np. taką jak ta:

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

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

    print('Tables created successfully.')

Pamiętaj, że funkcja main tworzy silnik przy użyciu lokalnej bazy danych sqlite. Aby używać Cloud SQL, musisz ją zmienić. Zrobisz to nieco później.

Użyj OPEN a4c7ed6d845df343.png kodu w nowym pliku, tak jak wcześniej. Zapisz kod w pliku o nazwie data_model.py (zwróć uwagę na podkreślenie w nazwie, a nie myślnik).

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

connect-connector.py

Utwórz oprogramowanie sprzęgające CloudSQL.

Otwórz plik data_model.py i wpisz te prompty.

Prompt 1: Using the cloud-sql-python-connector library, Generate a function that Initializes a connection pool for a Cloud SQL instance of Postgres.

ed05cb6ff85d34c5.png

Pamiętaj, że odpowiedź nie korzysta z biblioteki cloud-sql-python-connector. Możesz doprecyzować prompty, aby nieco ukierunkować Duet, dodając szczegóły w tym samym wątku czatu.

Użyjmy innego prompta.

Prompt 2: Musisz użyć biblioteki cloud-sql-python-connector.

d09095b44dde35bf.png

Upewnij się, że korzysta z biblioteki cloud-sql-python-connector.

Użyj OPEN a4c7ed6d845df343.png kodu w nowym pliku, tak jak wcześniej. Zapisz kod w pliku o nazwie connect_conector.py. Może być konieczne ręczne zaimportowanie biblioteki pg8000. Więcej informacji znajdziesz w pliku poniżej.

Wyczyść historię czatu Duet AI i przy otwartym pliku connect_connector.py wygeneruj ORM DB engine, sessionmakerbase do użycia w aplikacji.

Prompt 1. Utwórz klasę silnika, sessionmaker i podstawowy ORM za pomocą metody connect_with_connector

6e4214b72ab13a63.png

Odpowiedź może dołączyć znaki engine, SessionBase do pliku connect_connector.py.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Możesz też wypróbować różne prompty, aby zobaczyć potencjalne różnice w odpowiedziach Duet AI.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

Aktualizowanie pliku data_model.py

Aby utworzyć tabelę w bazie danych Cloud SQL, musisz użyć silnika utworzonego w poprzednim kroku (w pliku connect_connector.py).

Wyczyść historię czatu Duet AI. Otwórz plik data_model.py. Wypróbuj ten prompt.

Prompt 1: W funkcji głównej zaimportuj i użyj silnika z pliku connect_connector.py

2e768c9b6c523b9a.png

Powinna pojawić się odpowiedź informująca o importowaniu engineconnect_connector (w przypadku Cloud SQL). create_table korzysta z tego silnika (zamiast domyślnej lokalnej bazy danych sqlite).

Zaktualizuj plik data_model.py.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Możesz też wypróbować różne prompty, aby zobaczyć różne odpowiedzi Duet AI.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

requirements.txt

Utwórz plik requirements.txt dla aplikacji.

Otwórz zarówno connect_connector.py, jak i plik data_model.py, a następnie wpisz ten prompt.

Prompt 1. Wygeneruj plik wymagań pip dla tego modelu danych i usługi

Prompt 2: Generate a pip requirements file for this data model and service using latest versions

69fae373bc5c6a18.png

Sprawdź, czy nazwy i wersje są prawidłowe. Na przykład w odpowiedzi powyżej nazwa i wersja google-cloud-sql-connecter są nieprawidłowe. Ręcznie popraw wersje i utwórz plik requirements.txt, który będzie wyglądać tak:

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

W terminalu poleceń uruchom to polecenie:

pip3 install -r requirements.txt

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

Tworzenie tabeli pakietów w Cloud SQL

Ustaw zmienne środowiskowe dla łącznika bazy danych 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

Teraz uruchom plik data_model.py.

python data_model.py

Dane wyjściowe są podobne do tych (sprawdź kod, aby zobaczyć, czego się spodziewasz):

Tables created successfully.

Połącz się z instancją Cloud SQL i sprawdź, czy baza danych została utworzona.

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

Po wpisaniu hasła (również evolution) pobierz tabele.

product_details=> \dt

Dane wyjściowe są podobne do tych:

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

Możesz też sprawdzić model danych i szczegóły tabeli.

product_details=> \d+ packages

Dane wyjściowe są podobne do tych:

                                                                        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

Wpisz \q, aby zamknąć Cloud SQL.

db_init.py

Teraz dodajmy do tabeli packages przykładowe dane.

Wyczyść historię czatu Duet AI. Po otwarciu pliku data_model.py wypróbuj te prompty:

Prompt 1. Wygeneruj funkcję, która utworzy 10 przykładowych wierszy pakietów i zapisze je w tabeli packages.

Prompt 2. Korzystając z sesji z connect_connector, wygeneruj funkcję, która tworzy 10 przykładowych wierszy pakietów i zatwierdza je w tabeli packages.

34a9afc5f04ba5.png

Użyj OPEN a4c7ed6d845df343.png kodu w nowym pliku, tak jak wcześniej. Zapisz kod w pliku o nazwie db_init.py.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Możesz też wypróbować różne prompty, aby zobaczyć różne odpowiedzi Duet AI.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

Tworzenie przykładowych danych pakietów

Uruchom db_init.py z wiersza poleceń.

python db_init.py

Dane wyjściowe są podobne do tych:

Packages created successfully.

Ponownie połącz się z instancją Cloud SQL i sprawdź, czy przykładowe dane zostały dodane do tabeli packages.

Połącz się z instancją Cloud SQL i sprawdź, czy baza danych została utworzona.

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

Po wpisaniu hasła (evolution) pobierz wszystkie dane z tabeli packages.

product_details=> SELECT * FROM packages;

Dane wyjściowe są podobne do tych:

 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)

Wpisz \q, aby zamknąć Cloud SQL.

main.py

Po otwarciu plików data_model.py, package-service.yamlconnect_connector.py utwórz main.py dla aplikacji.

Prompt 1. Korzystając z biblioteki Python Flask, utwórz implementację, która używa punktów końcowych HTTP REST dla tej usługi.

Prompt 2. Korzystając z biblioteki Python Flask, utwórz implementację, która używa punktów końcowych HTTP REST dla tej usługi. Zaimportuj i użyj SessionMaker z pliku connect_conector.py do danych pakietów.

Prompt 3. Korzystając z biblioteki python flask, utwórz implementację, która używa punktów końcowych HTTP REST dla tej usługi. Zaimportuj i użyj pakietu z pliku data_model.py oraz SessionMaker z pliku connect_conector.py do danych pakietów.

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. Użyj adresu IP hosta 0.0.0.0 dla app.run

6d794fc52a90e6ae.png

Zaktualizuj wymagania dotyczące main.py.

Prompt: Create requirements file for main.py

1cc0b318d2d4ca2f.png

Dodaj to do pliku requirements.txt. Upewnij się, że używasz Flaska w wersji 3.0.0.

Użyj OPEN a4c7ed6d845df343.png kodu w nowym przepływie pracy z plikiem, tak jak wcześniej. Zapisz kod w pliku o nazwie main.py.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

5. Testowanie i uruchamianie aplikacji

Zainstaluj wymagania.

pip3 install -r requirements.txt

Uruchom main.py.

python main.py

Dane wyjściowe są podobne do tych:

 * 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

Na drugim terminalu przetestuj punkt końcowy /packages/<product_id>.

curl localhost:5000/packages/1

Dane wyjściowe są podobne do tych:

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

Możesz też przetestować dowolny inny identyfikator produktu w danych przykładowych.

Wpisz CTRL_C, aby zamknąć działający kontener Dockera w terminalu.

Generowanie testów jednostkowych

Po otwarciu pliku main.py wygeneruj testy jednostkowe.

Prompt 1. Wygeneruj testy jednostkowe.

e861e5b63e1b2657.png

Użyj OPEN a4c7ed6d845df343.png kodu w nowym pliku, tak jak wcześniej. Zapisz kod w pliku o nazwie test.py.

W funkcji test_get_package musi być zdefiniowana wartość product_id. Możesz dodać go ręcznie.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Zresetuj historię czatu Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

Uruchamianie testów jednostkowych

Uruchom test jednostkowy.

python test.py

Dane wyjściowe są podobne do tych:

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

OK

Zamknij wszystkie pliki w edytorze Cloud Shell i wyczyść historię czatu, klikając ikonę kosza 1ecccfe10d6c540.png na górnym pasku stanu.

Dockerfile

Utwórz Dockerfile dla tej aplikacji.

Otwórz main.py i wypróbuj te prompty.

Prompt 1. Wygeneruj plik Dockerfile dla tej aplikacji.

Prompt 2. Wygeneruj plik Dockerfile dla tej aplikacji. Skopiuj wszystkie pliki do kontenera.

9c473caea437a5c3.png

Musisz też ustawić ENVARS dla INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS i DB_NAME. Możesz to zrobić ręcznie. Plik Dockerfile powinien wyglądać tak:

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

Użyj OPEN a4c7ed6d845df343.png kodu w nowym pliku, tak jak wcześniej. Zapisz kod w pliku o nazwie Dockerfile.

Ostateczny plik znajdziesz w sekcji DODATEK w tym ćwiczeniu. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Lokalne uruchamianie aplikacji

Gdy Dockerfile jest otwarty, wypróbuj ten prompt.

Prompt 1: How do I locally run a container using this Dockerfile

570fd5c296ca8c83.png

Postępuj zgodnie z instrukcjami.

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

Dane wyjściowe są podobne do tych:

 * 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

W drugim oknie terminala uzyskaj dostęp do kontenera.

curl localhost:5000/packages/1

Dane wyjściowe są podobne do tych:

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

Aplikacja skonteneryzowana działa.

Wpisz CTRL_C, aby zamknąć działający kontener Dockera w terminalu.

Tworzenie obrazu kontenera w Artifact Registry

Utwórz obraz kontenera i przenieś go do 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

Kontener aplikacji znajduje się teraz w lokalizacji us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping, z której można go wdrożyć w GKE.

6. Wdrażanie aplikacji w klastrze GKE

Podczas tworzenia zasobów GCP na potrzeby tych warsztatów został utworzony klaster GKE z Autopilotem. połączyć się z klastrem GKE;

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

Dodaj do domyślnego konta usługi Kubernetes adnotację konta usługi Google.

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

Dane wyjściowe są podobne do tych:

serviceaccount/default annotated

Przygotuj i zastosuj plik 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

Dane wyjściowe są podobne do tych:

deployment.apps/shipping created
service/shipping created

Poczekaj, aż pody zaczną działać, a usługa otrzyma zewnętrzny adres IP systemu równoważenia obciążenia.

kubectl get pods
kubectl get service shipping

Dane wyjściowe są podobne do tych:

# 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

W przypadku klastrów GKE z Autopilotem poczekaj kilka minut, aż zasoby będą gotowe.

Uzyskaj dostęp do usługi pod adresem EXTERNAL-IP.

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

Dane wyjściowe są podobne do tych:

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

7. Dodatkowe informacje: rozwiązywanie problemów z aplikacją

Usuń z konta usługi cloudsqlsa rolę uprawnień Klient Cloud SQL. Powoduje to błąd połączenia z bazą danych Cloud SQL.

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

Ponownie uruchom moduł dostawy.

kubectl rollout restart deployment shipping

Po ponownym uruchomieniu urządzenia Pod spróbuj ponownie uzyskać dostęp do usługi shipping.

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

Dane wyjściowe są podobne do tych:

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

Sprawdź logi, otwierając Kubernetes Engine > Zadania.

d225b1916c829167.png

Kliknij wdrożenie shipping, a następnie kartę Logi.

1d0459141483d6a7.png

Kliknij ikonę Wyświetl w Eksploratorze logów df8b9d19a9fe4c73.png po prawej stronie paska stanu. Otworzy się nowe okno Eksploratora logów.

e86d1c265e176bc4.png

Kliknij jeden z wpisów o błędach Traceback, a następnie kliknij Wyjaśnij ten wpis w logu.

d6af045cf03008bc.png

Możesz przeczytać wyjaśnienie błędu.

Teraz poprośmy Duet AI o pomoc w rozwiązaniu problemu.

Wypróbuj ten prompt.

Prompt 1. Pomóż mi rozwiązać ten problem

9288dd6045369167.png

Wpisz komunikat o błędzie w prompcie.

Prompt 2. Zabronione: Uwierzytelniony podmiot zabezpieczeń Uprawnień nie wydaje się upoważniony do wykonania żądania do interfejsu API. Sprawdź, czy w projekcie GCP jest włączony interfejs „Cloud SQL Admin API” i czy podmiotowi zabezpieczeń IAM została przyznana rola „Klient Cloud SQL”.

f1e64fbdc435d31c.png

Allons-y?

Prompt 3: How do I assign the Cloud SQL Client role to a google service account using gcloud?

bb8926b995a8875c.png

Przypisz rolę Klient Cloud SQL do cloudsqlsa.

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

Zaczekaj chwilę i spróbuj ponownie otworzyć aplikację.

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

Dane wyjściowe są podobne do tych:

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

Udało Ci się rozwiązać problem za pomocą Duet AI w Cloud Logging, eksploratorze logów i funkcji wyjaśniania logów.

8. Podsumowanie

Gratulacje! Udało Ci się ukończyć to ćwiczenie w Codelabs.

Z tego modułu dowiedzieliśmy się, że:

  1. Aktywuj Duet AI w projekcie GCP i skonfiguruj go do używania w IDE i konsoli Cloud.
  2. Używaj Duet AI do generowania, uzupełniania i wyjaśniania kodu.
  3. Używaj Duet AI do wyjaśniania i rozwiązywania problemów z aplikacjami.
  4. Funkcje Duet AI, takie jak czat w środowisku IDE i czat wieloetapowy, generowanie kodu w czacie i w tekście, inteligentne działania, takie jak wyjaśnianie kodu i potwierdzanie recytacji, i inne.

9. Dodatek

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