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

1. Cele

Celem tych warsztatów jest zapewnienie użytkownikom i praktykom praktycznego doświadczenia dotyczącego Duet AI.

Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak:

  1. Aktywuj Duet AI w projekcie GCP i skonfiguruj ją do użycia w IDE oraz konsoli Cloud.
  2. Używaj Duet AI do generowania, uzupełniania i wyjaśniania informacji.
  3. Użyj Duet AI, aby wyjaśnić i rozwiązać problem z aplikacją.
  4. Funkcje Duet AI, takie jak czat w IDE i czat wieloetapowy, generowanie kodu na czacie lub w tekście oraz inteligentne działania, takie jak objaśnianie kodu i potwierdzenie recytacji.

Narrative

Aby pokazać autentyczne wykorzystanie Duet AI dla programistów w codziennym rozwoju aplikacji, ćwiczenia mają miejsce w kontekście narracyjnym.

Do firmy e-commerce dołącza nowy deweloper. Mają oni dodać nową usługę do istniejącej aplikacji e-commerce (która składa się z wielu usług). Nowa usługa dostarcza dodatkowych informacji (o wymiarach, wadze itp.) na temat produktów w katalogu. Ta usługa umożliwia uzyskanie lepszych lub tańszych kosztów dostawy na podstawie wymiarów i wagi produktów.

Ponieważ deweloper dopiero zaczyna korzystać z firmy, będzie używać Duet AI do generowania kodu, wyjaśnień i dokumentacji.

Po zakodowaniu usługi administrator platformy użyje Duet AI (czatu), aby pomóc utworzyć artefakt (kontener Dockera) i zasoby potrzebne do wdrożenia artefaktu w GCP (np.Artifact Registry, uprawnienia uprawnień, repozytorium kodu, infrastruktura obliczeniowa, np. GKE lub CloudRun).

Po wdrożeniu aplikacji w GCP operator aplikacji/środowisko SRE będzie korzystać z Duet AI (i Cloud Ops) do rozwiązania problemów z błędami w nowej usłudze.

Profil klienta

Warsztaty obejmują następujące profile:

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

Ta odmiana warsztatów Duet AI jest przeznaczona tylko dla deweloperów. Nie wymaga znajomości zasobów chmury GCP. Skrypty pokazujące, jak skompilować zasoby GCP wymagane do uruchomienia tej aplikacji, znajdziesz tutaj. Aby wdrożyć wymagane zasoby GCP, postępuj zgodnie z instrukcjami w tym przewodniku.

2. Przygotowywanie środowiska

Aktywuję Duet AI

Możesz aktywować Duet AI w projekcie GCP za pomocą interfejsu API (gcloud lub narzędzi IaC, takich jak Terraform) albo za pomocą interfejsu użytkownika konsoli Cloud.

Aby aktywować Duet AI w projekcie Google Cloud, włącz interfejs Cloud AI Companion API i przypisz do użytkowników role uprawnień Użytkownik usługi Cloud AI Companion oraz Wyświetlający wykorzystanie usług.

Przez gcloud

Aktywuj Cloud Shell:

Skonfiguruj PROJECT_ID i USER oraz 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.

Przypisz do konta USER role Użytkownik usługi Cloud AI Companion oraz Wyświetlający wykorzystanie usług. Interfejs Cloud Companion API znajduje się w tyle za funkcjami dostępnymi w IDE i konsoli, których będziemy używać. Uprawnienie Wyświetlający wykorzystanie usług służy do szybkiego sprawdzenia przed włączeniem interfejsu użytkownika w konsoli (dzięki czemu interfejs Duet AI jest widoczny tylko w projektach, w których interfejs API jest włączony).

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ć ten 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 się stan Włączona. Usługa Duet AI jest teraz dostępna w wybranym projekcie Google Cloud dla wszystkich użytkowników, którzy mają przypisane wymagane role uprawnień.

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

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

W panelu dostępu Edytowanie kliknij dodaj Dodaj kolejną rolę.

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

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

Kliknij Zapisz.

Konfigurowanie IDE

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

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

W tym warsztatach używany jest edytor Cloud Shell.

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

Aby od razu z niej skorzystać, użyj edytora Cloud Shell.

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

Interfejs użytkownika i UX edytora Cloud Shell jest bardzo podobny do interfejsu VSCode.

d6a6565f83576063.png

Kliknij CTRL (Windows)/CMD (Mac) + , (przecinek), aby otworzyć okienko Ustawienia.

Na pasku wyszukiwania wpisz „duet ai”.

Sprawdź lub włącz Cloudcode › Duet AI: Włącz i Cloudcode › Duet AI › Wbudowane sugestie: włącz automatyczne

111b8d587330ec74.png

Na pasku stanu u dołu kliknij Cloud Code – Sign In (Cloud Code – logowanie) i postępuj zgodnie z instrukcjami logowania.

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

Kliknij Cloud Code – Brak projektu. U góry pojawi się okienko akcji. Kliknij Wybierz projekt Google Cloud.

3241a59811e3c84a.png

Zacznij wpisywać identyfikator PROJEKTU, a Twój projekt powinien pojawić się na liście.

c5358fc837588fe.png

Z listy projektów wybierz swój PROJECT_ID.

Pasek stanu u dołu zmieni się i będzie wyświetlał identyfikator projektu. Jeśli tak się nie stanie, być może trzeba będzie odświeżyć kartę edytora Cloud Shell.

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

Zobaczysz teraz okno czatu z 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 uruchomienia skonteneryzowanej usługi.
  3. Artifact Registry do przechowywania obrazu Dockera.
  4. Cloud Source Repositories dla kodu.

W terminalu Cloud Shell skopiuj poniższe repozytorium i uruchom następujące 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. Opracowywanie usługi Python Flask

9745ba5c70782e76.png

Ostatecznie utworzona usługa będzie się składać z poniższych plików. Nie musisz tworzyć tych plików teraz. Możesz tworzyć je pojedynczo, postępując zgodnie z poniższymi instrukcjami:

  1. package-service.yaml – specyfikacja interfejsu Open API w usłudze pakietu z danymi, takimi jak wysokość, szerokość, waga i specjalne instrukcje obsługi.
  2. data_model.py – model danych na potrzeby specyfikacji interfejsu API usługi pakietów. Tworzy też tabelę packages w bazie danych product_details.
  3. connect_connector.py – połączenie z Cloud SQL (definicja silnika, sesji i podstawowego ORM)
  4. db_init.py – generuje przykładowe dane w tabeli packages.
  5. main.py – usługa Python Flask z punktem końcowym GET do pobierania szczegółów pakietu z danych packages na podstawie elementu product_id.
  6. test.py – test jednostkowy
  7. requirement.txt – wymagania Pythona
  8. Dockerfile – aby skonteneryzować tę aplikację

Jeśli podczas ćwiczeń napotkasz jakieś problemy, wszystkie gotowe pliki znajdziesz w DODATEK do tego ćwiczenia z programowania.

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

W terminalu Cloud Shell uruchom poniższe polecenie, aby sklonować repozytorium.

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

Otwórz pasek boczny czatu Duet AI w menu po lewej stronie edytora Cloud Shell. Wygląd ikony: 8b135a000b259175.png. Aby uzyskać pomoc w kodowaniu, możesz teraz używać Duet AI.

package-service.yaml

Jeśli nie masz otwartych plików, poproś Duet o wygenerowanie specyfikacji Open API dla usługi dostawy.

Prompt 1. Wygeneruj specyfikację yaml OpenAPI dla usługi, która dostarcza informacje o dostawie i przesyłce na podstawie liczbowego identyfikatora produktu. Usługa powinna zawierać informacje o wysokości, szerokości, głębokości i wadze paczki oraz specjalne instrukcje obsługi.

ba12626f491a1204.png

W prawym górnym rogu wygenerowanego okna kodu dostępne są 3 opcje.

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

Możesz ADD df645de8c65607a.png kod do obecnie 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 zapisz go w folderze aplikacji pod nazwą package-service.yaml. Kliknij przycisk OK.

f6ebd5b836949366.png

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. 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 w Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

data_model.py

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

Po otwarciu pliku package-service.yaml wpisz ten prompt.

Prompt 1. Wygeneruj model danych dla tej usługi interfejsu API przy użyciu języka sqlalchemy ORM w języku Python. Dołącz też oddzielną 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 nadal asystent i choć może szybko pomóc w tworzeniu kodu, warto jednak sprawdzać wygenerowane treści i rozumieć je na bieżąco.

Pierwszy z nich to Class o nazwie Package rodzajuBase, która określa model danych dla bazy danych packages 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 tworzy tabelę w bazie danych w podobny sposób:

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

Aby utworzyć tabelę w bazie danych Cloud SQL, potrzebujesz głównej funkcji, która uruchamia funkcję create_tables, na przykład:

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 z użyciem lokalnej bazy danych sqlite. Aby używać Cloud SQL, musisz go zmienić. Zrobisz to później.

Użyj kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie data_model.py (zwróć uwagę na podkreślenie w nazwie, a nie znak myślnika).

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

connect-connector.py

Utwórz oprogramowanie sprzęgające Cloud SQL.

Po otwarciu pliku data_model.py wpisz te prompty.

Prompt 1. Wygeneruj funkcję inicjującą pulę połączeń dla instancji Postgres w Cloud SQL przy użyciu biblioteki cloud-sql-python-connector.

ed05cb6ff85d34c5.png

Pamiętaj, że odpowiedź nie korzysta z biblioteki cloud-sql-python-connector. Możesz doprecyzować prompty, dodając konkretne informacje do tego samego wątku czatu, aby dać usłudze Duet ponaglenia.

Użyjmy innego promptu.

Prompt 2. Musi używać biblioteki cloud-sql-python-connector.

d09095b44dde35bf.png

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

Użyj kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie connect_conector.py. Może być konieczne ręczne zaimportowanie biblioteki pg8000. Zapoznaj się z plikiem poniżej.

Wyczyść historię czatu z Duet AI. W otwartym pliku connect_connector.py wygeneruj ORM DB engine, sessionmaker i base, którego będziesz używać w aplikacji.

Prompt 1. Utwórz silnik, klasę Sessionmaker i Base ORM przy użyciu metody connect_with_connector

6e4214b72ab13a63.png

Odpowiedź może dołączać engine, Session i Base do pliku connect_connector.py.

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

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

Zresetuj historię czatu w 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 wyświetlić się odpowiedź importująca plik engine z serwera connect_connector (dla Cloud SQL). create_table używa tego silnika (zamiast domyślnej lokalnej bazy danych sqlite).

Zaktualizuj plik data_model.py.

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. 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 w 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 plik connect_connector.py, jak i plik data_model.py, a następnie wprowadź następujący prompt.

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

Prompt 2. Wygeneruj plik wymagań dotyczących pip dla tego modelu danych i usługi przy użyciu najnowszych wersji

69fae373bc5c6a18.png

Sprawdź, czy nazwy i wersje są prawidłowe. Na przykład w powyższej odpowiedzi nazwa i wersja elementu google-cloud-sql-connecter są nieprawidłowe. Napraw ręcznie błędy wersji i utwórz plik requirements.txt podobny do tego:

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 w 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 oprogramowania sprzęgającego 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

Wyniki są podobne do poniższych (sprawdź w kodzie, co rzeczywiście jest oczekiwane):

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ż ewolucji) wyświetl 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ć szczegóły modelu danych i 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 wyjść z Cloud SQL.

db_init.py

Teraz dodajmy kilka przykładowych danych do tabeli packages.

Wyczyść historię czatu Duet AI. Po otwarciu pliku data_model.py postępuj zgodnie z tymi instrukcjami.

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

Prompt 2. Przy użyciu sesji z connect_connector wygeneruj funkcję, która tworzy 10 przykładowych wierszy pakietów i zatwierdza je w tabeli pakietów

34a9afc5f04ba5.png

Użyj kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie db_init.py.

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. 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 w Duet AI, klikając ikonę kosza f574ca2c1e114856.png u góry paska bocznego Duet AI.

Tworzę dane przykładowych pakietów

Uruchom db_init.py z poziomu 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 pakietów.

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ż ewolucji) pobierz wszystkie dane z tabeli pakietów.

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 wyjść z Cloud SQL.

main.py

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

Prompt 1. Przy użyciu biblioteki kolby w Pythonie – utwórz implementację, która w tej usłudze korzysta z punktów końcowych HTTP odpoczynku

Prompt 2. Przy użyciu biblioteki kolby w Pythonie – utwórz implementację, która w tej usłudze wykorzystuje punkty końcowe HTTP. w celu zaimportowania danych pakietów i zaimportowania elementów SessionMaker (z connect_conector.py do).

Prompt 3. Przy użyciu biblioteki kolby w Pythonie – utwórz implementację, która w tej usłudze korzysta z punktów końcowych protokołu HTTP. W przypadku danych pakietów zaimportuj pakiet z pliku data_model.py oraz użyj kreatora sesji (z connect_conector.py do) i użyj go.

Prompt 4. Przy użyciu biblioteki kolby w Pythonie – utwórz implementację, która w tej usłudze korzysta z punktów końcowych protokołu HTTP. zaimportuj pakiet z pliku data_model.py i użyj kreatora sesji z pliku connect_conector.py do, aby uzyskać dane pakietów. Użyj adresu IP hosta 0.0.0.0 na potrzeby app.run

6d794fc52a90e6ae.png

Zaktualizuj wymagania dotyczące funkcji main.py.

Prompt: utwórz plik wymagań dla pliku main.py

1cc0b318d2d4ca2f.png

Dołącz do pliku requirements.txt. Pamiętaj, aby używać Flask w wersji 3.0.0.

Użyj kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie main.py.

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Zresetuj historię czatu w 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

Przetestuj punkt końcowy /packages/<product_id> z drugiego terminala.

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ć pozostałe identyfikatory produktu w przykładowych danych.

Wpisz CTRL_C, aby wyjść z działającego kontenera Dockera w terminalu.

Generuję testy jednostkowe

Po otwarciu pliku main.py wygeneruj testy jednostkowe.

Prompt 1. Wygeneruj testy jednostkowe.

e861e5b63e1b2657.png

Użyj kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie test.py.

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

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

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

Przeprowadzanie 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 pasku stanu u góry.

Dockerfile

Utwórz Dockerfile dla tej aplikacji.

Otwórz aplikację main.py i skorzystaj z podanych niżej promptów.

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ż skonfigurować ENVARS dla usług INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS i DB_NAME. Możesz to zrobić ręcznie. Twój 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 kodu OPEN a4c7ed6d845df343.png w nowym przepływie pracy związanym z plikiem, tak jak poprzednio. Zapisz kod w pliku o nazwie Dockerfile.

Ostateczny plik znajdziesz w sekcji DODATEK tego ćwiczenia z programowania. Jeśli tak nie jest, ręcznie wprowadź odpowiednie zmiany.

Lokalne uruchamianie aplikacji

Po otwarciu aplikacji Dockerfile wykonaj te czynności.

Prompt 1. Jak lokalnie uruchomić kontener za pomocą tego pliku 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

Z drugiego okna terminala przejdź 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}

Skonteneryzowana aplikacja działa.

Wpisz CTRL_C, aby wyjść z działającego kontenera Dockera w terminalu.

Kompiluję obraz kontenera w Artifact Registry

Utwórz obraz kontenera i wypchnij 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, którą można wdrożyć w GKE.

6. Wdrażam aplikację w klastrze GKE

Klaster z Autopilotem w GKE został utworzony podczas tworzenia zasobów GCP na potrzeby tego warsztatu. Połącz się z klastrem GKE.

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

Dodaj do domyślnego konta usługi Kubernetes adnotację z kontem 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 zostaną uruchomione, a do usługi zostanie przypisany adres IP zewnętrznego 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 z Autopilotem w GKE poczekaj chwilę, aż zasoby będą gotowe.

Uzyskaj dostęp do usługi za pomocą adresu 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 środki: rozwiązywanie problemów ze zgłoszeniem

Usuń rolę uprawnień klienta Cloud SQL z konta usługi cloudsqlsa. Powoduje to błąd podczas łą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 kapsułę dostawy.

kubectl rollout restart deployment shipping

Po ponownym uruchomieniu poda 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, przechodząc do Kubernetes Engine > Zadania

d225b1916c829167.png

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

1d0459141483d6a7.png

Po prawej stronie paska stanu kliknij ikonę Wyświetl w Eksploratorze logów df8b9d19a9fe4c73.png. Otworzy się nowe okno Eksplorator logów.

e86d1c265e176bc4.png

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

d6af045cf03008bc.png

Przeczytaj opis błędu.

Teraz wypróbujmy Duet AI, które pomogą Ci rozwiązać problem.

Wypróbuj ten prompt.

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

9288dd6045369167.png

Wpisz w komunikacie o błędzie komunikat o błędzie.

Prompt 2. Dostęp zabroniony: wygląda na to, że uwierzytelniony podmiot zabezpieczeń uprawnień nie może wysłać żądania do interfejsu API. Weryfikacja interfejsu Cloud SQL Admin API jest włączona w projekcie GCP i w „Klientie Cloud SQL” rola została przypisana do podmiotu zabezpieczeń Uprawnień

f1e64fbdc435d31c.png

A potem.

Prompt 3. Jak za pomocą gcloud przypisać rolę klienta Cloud SQL do konta usługi Google?

bb8926b995a8875c.png

Przypisz rolę klienta 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 uzyskać dostęp do aplikacji.

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ą funkcji Duet AI w Cloud Logging, Eksploratorze logów i funkcji Wyjaśnienie logów.

8. Podsumowanie

Gratulacje! Udało Ci się ukończyć to ćwiczenia z programowania.

Dzięki temu ćwiczeniu z programowania omówiliśmy te kwestie:

  1. Aktywuj Duet AI w projekcie GCP i skonfiguruj ją do użycia w IDE oraz konsoli Cloud.
  2. Używaj Duet AI do generowania, uzupełniania i wyjaśniania informacji.
  3. Użyj Duet AI, aby wyjaśnić i rozwiązać problem z aplikacją.
  4. Funkcje Duet AI, takie jak czat w IDE i czat wieloetapowy, generowanie kodu na czacie lub w tekście oraz inteligentne działania, takie jak objaśnianie kodu i potwierdzenie recytacji.

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