Usprawnij programowanie dzięki Gemini Code Assist

1. Wprowadzenie

e5b98fd4e417c877.png

W tym samouczku dowiesz się, jak Gemini Code Assist może Ci pomóc na kluczowych etapach cyklu życia oprogramowania (SDLC), takich jak projektowanie, tworzenie i testowanie oraz wdrażanie. Zaprojektujemy i opracujemy całą aplikację, a następnie wdrożymy ją w Google Cloud.

Stworzymy interfejs API i aplikację do wyszukiwania sesji w ramach wydarzenia technicznego. Każda sesja będzie miała tytuł, podsumowanie, czas trwania, kategorie i co najmniej jednego prelegenta.

Co musisz zrobić

  • Projektowanie, tworzenie, testowanie i wdrażanie aplikacji internetowej od podstaw na podstawie specyfikacji OpenAPI

Czego się nauczysz

  • Jak używać Gemini Code Assist do generowania specyfikacji OpenAPI
  • Jak używać funkcji generowania kodu Gemini Code Assist do tworzenia aplikacji Python Flask na potrzeby specyfikacji OpenAPI
  • Jak używać Gemini Code Assist do generowania interfejsu internetowego aplikacji Python Flask
  • Jak korzystać z Gemini Code Assist, aby uzyskać pomoc dotyczącą wdrażania aplikacji w Google Cloud Run
  • Korzystaj z funkcji Gemini Code Assist, takich jak wyjaśnianie kodu i generowanie przypadków testowych, podczas tworzenia i testowania aplikacji.

Czego potrzebujesz

  • przeglądarki Chrome,
  • konto Gmail,
  • Projekt w chmurze z włączonymi płatnościami
  • Usługa Gemini Code Assist jest włączona w Twoim projekcie w Cloud

Ten moduł jest przeznaczony dla deweloperów na wszystkich poziomach zaawansowania, w tym dla początkujących. Chociaż przykładowa aplikacja jest napisana w języku Python, nie musisz znać tego języka, aby zrozumieć, co się dzieje. Skupimy się na zapoznaniu się z możliwościami Gemini Code Assist.

2. Konfigurowanie Gemini Code Assist

W tej sekcji znajdziesz wszystko, co musisz zrobić, aby rozpocząć ten moduł.

Włączanie Gemini Code Assist w środowisku IDE Cloud Shell

W pozostałej części tego samouczka będziemy używać Cloud Shell IDE, w pełni zarządzanego środowiska programistycznego opartego na Code OSS. Musimy włączyć i skonfigurować Code Assist w środowisku IDE Cloud Shell. Poniżej znajdziesz instrukcje:

  1. Otwórz ide.cloud.google.com. Wyświetlenie środowiska IDE może zająć trochę czasu, więc poczekaj i zaakceptuj domyślne ustawienia. Jeśli zobaczysz instrukcje dotyczące konfigurowania środowiska IDE, wykonaj je z ustawieniami domyślnymi.
  2. Na pasku stanu u dołu kliknij przycisk Cloud Code – zaloguj się, jak pokazano na ilustracji. Autoryzuj wtyczkę zgodnie z instrukcjami. Jeśli na pasku stanu widzisz „Cloud Code – brak projektu”, wybierz tę opcję, a następnie wybierz z listy projekt Google Cloud, z którym chcesz pracować.

6f5ce865fc7a3ef5.png

  1. Kliknij przycisk Pomocnik w pisaniu kodu w prawym dolnym rogu, jak pokazano na ilustracji, i jeszcze raz wybierz właściwy projekt w chmurze Google. Jeśli pojawi się prośba o włączenie interfejsu Cloud AI Companion API, zrób to i przejdź dalej.
  2. Po wybraniu projektu Google Cloud sprawdź, czy jest on widoczny w komunikacie o stanie Cloud Code na pasku stanu oraz czy po prawej stronie na pasku stanu masz włączoną funkcję Code Assist, jak pokazano poniżej:

709e6c8248ac7d88.png

Usługa Gemini Code Assist jest gotowa do użycia.

3. Konfigurowanie Firestore

Cloud Firestore to w pełni zarządzana bezserwerowa baza danych dokumentów, której będziemy używać jako backendu do danych aplikacji. Dane w Cloud Firestore są uporządkowane w kolekcjach dokumentów.

Musimy utworzyć kolekcję o nazwie sessions w domyślnej bazie danych Firestore. Będzie ona zawierać przykładowe dane (dokumenty), których będziemy używać w naszej aplikacji.

Otwórz terminal w środowisku IDE Cloud Shell za pomocą menu głównego, jak pokazano poniżej:

f1535e14c9beeec6.png

Musimy utworzyć kolekcję o nazwie sessions. Będzie ona zawierać listę przykładowych dokumentów sesji. Każdy dokument będzie miał te atrybuty:

  1. title: ciąg znaków
  2. categories: tablica ciągów znaków
  3. speakers: tablica ciągów znaków
  4. duration: ciąg znaków
  5. summary: ciąg znaków

Wypełnijmy tę kolekcję przykładowymi danymi, kopiując plik zawierający przykładowe dane do zasobnika w Twoim projekcie, z którego możesz następnie zaimportować kolekcję za pomocą polecenia gcloud firestore import.

Inicjowanie bazy danych Firestore

Otwórz stronę Firestore w konsoli Cloud.

Jeśli w projekcie nie masz jeszcze zainicjowanej bazy danych Firestore, utwórz bazę danych default. Podczas tworzenia bazy danych użyj tych wartości:

  • Tryb Firestore: Native
  • Lokalizacja: wybierz typ lokalizacji Region i region odpowiedni dla Twojej aplikacji. Zanotuj tę lokalizację, ponieważ będzie Ci potrzebna w następnym kroku jako lokalizacja kosza.
  • Utwórz bazę danych.

504cabdb99a222a5.png

Teraz utworzymy kolekcję sessions, wykonując te czynności:

  1. Utwórz zasobnik w projekcie za pomocą podanego poniżej polecenia gsutil. W poniższym poleceniu zastąp zmienną <PROJECT_ID> identyfikatorem projektu Google Cloud. Zastąp <BUCKET_LOCATION> nazwą regionu odpowiadającą obszarowi geograficznemu domyślnej bazy danych Firestore (jak podano w poprzednim kroku). Może to być US-WEST1, EUROPE-WEST1 lub ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. Po utworzeniu zasobnika musimy skopiować do niego przygotowany eksport bazy danych, zanim będziemy mogli go zaimportować do bazy danych Firebase. Użyj polecenia podanego poniżej:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

Teraz, gdy mamy dane do zaimportowania, możemy przejść do ostatniego kroku, czyli zaimportowania danych do utworzonej przez nas bazy danych Firebase (default).

  1. Użyj podanego niżej polecenia gcloud:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

Importowanie potrwa kilka sekund. Po zakończeniu możesz sprawdzić bazę danych Firestore i kolekcję, otwierając stronę https://console.cloud.google.com/firestore/databases, wybierając bazę danych default i kolekcję sessions, jak pokazano poniżej:

d3e294d46ba29cd5.png

W ten sposób utworzysz kolekcję Firestore, której będziemy używać w naszej aplikacji.

4. Tworzenie szablonu aplikacji

Utworzymy przykładową aplikację (aplikację Flask w języku Python), której będziemy używać w dalszej części tych ćwiczeń. Ta aplikacja będzie wyszukiwać sesje oferowane na konferencji technicznej.

Wykonaj te czynności:

  1. Na pasku stanu poniżej kliknij nazwę projektu Google Cloud.

f151759c156c124e.png

  1. Pojawi się lista opcji. Na liście poniżej kliknij Nowa aplikacja.

91ea9836f38b7f74.png

  1. Wybierz Cloud Run application (będzie to środowisko wykonawcze naszej aplikacji).
  2. Wybierz szablon aplikacji Python (Flask): Cloud Run.
  3. Nadaj aplikacji nazwę i zapisz ją w wybranej lokalizacji.
  4. Pojawi się powiadomienie potwierdzające utworzenie aplikacji, a w nowym oknie otworzy się aplikacja, jak pokazano poniżej. Otworzy się plik README.md. Możesz na razie zamknąć ten widok.

aaa3725b17ce27cf.png

5. Interakcja z Gemini Code Assist

Na potrzeby tego modułu użyjemy czatu Gemini Code Assist dostępnego w środowisku IDE Cloud Shell w ramach rozszerzenia Cloud Code w VS Code. Możesz go otworzyć, klikając przycisk Asystent kodu na pasku nawigacyjnym po lewej stronie. Na pasku narzędzi nawigacyjnych po lewej stronie znajdź ikonę Code Assist a489f98a34898727.png i kliknij ją.

Spowoduje to wyświetlenie panelu czatu Code Assist w środowisku IDE Cloud Shell, na którym możesz rozmawiać z Code Assist.

14ad103efaa0ddaa.png

U góry zobaczysz ikonę kosza na śmieci – to sposób na zresetowanie kontekstu historii czatu Code Assist. Pamiętaj też, że ta rozmowa na czacie jest powiązana z plikami, nad którymi pracujesz w IDE.

6. Projekt interfejsu API

Pierwszym krokiem będzie skorzystanie z pomocy Gemini Code Assist na etapie projektowania. W tym kroku wygenerujemy specyfikację OpenAPI dla encji (sesji technicznych w ramach wydarzenia), które chcemy przeszukiwać.

Wpisz ten prompt:

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

Powinno to wygenerować specyfikację OpenAPI do wyszukiwania w sesjach za pomocą różnych parametrów zapytania. Przykładowa specyfikacja:

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

W specyfikacji możesz zauważyć:

  • Schemat zdefiniowany dla typu sesji.
  • Zdefiniowano kilka ścieżek interfejsu API:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

Utwórz w głównym folderze plik o nazwie sessionsapi.yaml i skopiuj do niego zawartość z okna czatu Asystenta kodu, korzystając z opcji „Wstaw do bieżącego pliku” (przycisk +). Pozostaw plik otwarty w IDE Cloud Shell.

W tym momencie możesz zwrócić uwagę na ciekawą funkcję Gemini Code Assist: cytowanie. Te informacje są udostępniane deweloperowi, gdy wygenerowany kod zawiera długie cytaty z innego źródła, np. z istniejącego kodu open source. Zawiera źródło i licencję, dzięki czemu deweloper może zdecydować, co z nim zrobić.

Jeśli wygenerowane treści są odpowiednie, możemy użyć tego dokumentu specyfikacji do wygenerowania aplikacji Python Flask.

7. Generowanie aplikacji

Teraz poprosimy Code Assist o wygenerowanie aplikacji. Wpisz ten prompt, gdy plik sessionsapi.yaml jest otwarty.

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

Powinien on zawierać szkielet aplikacji Python Flask, który jest oparty na funkcjach i ścieżkach określonych w pliku specyfikacji OpenAPI.

Podany kod aplikacji w Pythonie Flask powinien być podobny do tego:

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

Plik app.py został wygenerowany w poprzednim kroku. Wystarczy zastąpić jego zawartość kodem wygenerowanym przez Code Assist i zapisać plik.

Chcemy zmienić wiersz app.run(), aby używać portu 8080, adresu hosta 0.0.0.0, a także uruchamiać go w trybie debugowania podczas lokalnego wykonywania.Oto jak to zrobić. Najpierw zaznaczmy wiersz:

app.run()

Następnie w interfejsie czatu Code Assist wpisz prompt: Explain this.

Powinno się w nim znaleźć szczegółowe wyjaśnienie dotyczące danego wiersza. Przykład znajdziesz poniżej:

58ec896a32a4fb68.png

Teraz użyj tego prompta:

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

Wygenerowany sugerowany kod powinien wyglądać tak:

app.run(host='0.0.0.0', port=8080, debug=True)

Pamiętaj, aby zaktualizować plik app.py za pomocą tego fragmentu kodu.

Lokalne uruchamianie aplikacji

Uruchommy teraz aplikację lokalnie, aby sprawdzić, czy spełnia ona wymagania, które określiliśmy na początku.

Pierwszym krokiem będzie utworzenie wirtualnego środowiska Pythona z zależnościami pakietu Pythona w pliku requirements.txt, które zostaną zainstalowane w środowisku wirtualnym. Aby to zrobić, otwórz paletę poleceń (Ctrl+Shift+P) w IDE Cloud Shell i wpisz Utwórz środowisko Pythona. Wykonaj kilka kolejnych kroków, aby wybrać środowisko wirtualne (venv), interpreter Pythona 3.x i plik requirements.txt.

Po utworzeniu środowiska otwórz nowe okno terminala (Ctrl+Shift+`) i wpisz to polecenie:

python app.py

Przykładowe wykonanie jest pokazane poniżej:

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
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:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

Możesz teraz wyświetlić podgląd interfejsu API pod tymi adresami URL. Zakładamy, że serwer programistyczny działa na porcie 8080. Jeśli nie, zmień go na odpowiedni numer portu.

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

Aby mieć pewność, że za pomocą tych adresów URL możesz pobrać dane JSON zawarte w pliku app.py, wykonaj te czynności:

Otwórz nowe okno terminala i wypróbuj dowolne z tych poleceń:

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

8. Refaktoryzacja kodu

Zamiast umieszczać w app.py zakodowane na stałe przykładowe dane JSON, prawdopodobnie chcielibyśmy je oddzielić lub wyodrębnić do innego modułu, aby zachować wyraźny podział między kodem a danymi. Zróbmy to!

Pozostaw otwarty plik app.py i wpisz ten prompt:

Can I improve this code and separate out the sessions data from this app.py file?

Powinny pojawić się sugestie, jak to zrobić. Przykładowa sugestia, którą otrzymaliśmy (Ty też powinieneś otrzymać podobną), jest pokazana poniżej:

9b9c56cb527dac4c.png

Zgodnie z sugestią Asystenta kodu podzielmy dane na pliki sessions.py.

Utwórz nowy plik o nazwie sessions.py.

, której zawartość jest listą JSON, zgodnie z wygenerowanymi przez nas danymi:

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

Plik app.py został znacznie uproszczony i wygląda teraz tak:

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

Sprawdź, czy nadal możesz uruchamiać aplikację lokalnie i korzystać z interfejsu API po wprowadzeniu tych zmian. Serwer programistyczny Pythona prawdopodobnie nadal działa, więc wystarczy, że przypomnisz sobie polecenia curl z poprzedniego kroku.

9. Integracja z kolekcją Firestore

Następnym krokiem jest odejście od lokalnej listy JSON w pamięci, którą mamy dla naszych sesji, i połączenie aplikacji z kolekcją sessions w bazie danych Firestore, którą utworzyliśmy na początku tego laboratorium.

Pozostaw otwarty plik sessions.py i wpisz ten prompt:

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

Otrzymaliśmy następującą sugestię, aby odczytać wszystkie sesje z kolekcji Firestore:

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

Wprowadź kod w sessions.py.

Jeśli lokalnie działa serwer programistyczny Flask, aplikacja mogła zostać zamknięta z powodu braku modułu Pythona.

Możesz na przykład zapytać Code Assist, który moduł Pythona należy dodać do pliku requirements.txt:

Which Python package needs to be installed to make the firestore code work?

Otrzymasz nazwę modułu Pythona (np. google-cloud-firestore). Dodaj ją do pliku requirements.txt.

Musisz ponownie utworzyć środowisko Pythona z nowo dodanym modułem (google-cloud-firestore). Aby to zrobić, wpisz w istniejącym oknie terminala to polecenie:

pip install -r requirements.txt

Uruchom ponownie aplikację (zrestartuj ją, klikając python app.py) i otwórz adres URL /sessions. Powinny się teraz wyświetlić przykładowe dokumenty, które dodaliśmy do kolekcji sessions.

975d05e6518f1a6a.png

Możesz wysyłać zapytania dotyczące innych identyfikatorów URI, aby pobrać konkretne sesje lub wszystkie sesje w danej kategorii, zgodnie z opisem w poprzednich krokach.

10. Wyjaśnienie kodu

Teraz jest dobry moment, aby użyć funkcji "Explain this" Gemini Code Assist i lepiej zrozumieć kod. Możesz otworzyć dowolny plik lub wybrać konkretne fragmenty kodu i zadać pytanie Code Assist, używając tego promptu: Explain this.

Aby poćwiczyć, otwórz plik sessions.py i zaznacz kod dotyczący Firestore, a następnie uzyskaj jego wyjaśnienie. Wypróbuj tę funkcję także w przypadku innych plików w projekcie, nie tylko kodu w języku Python.

11. Generowanie aplikacji internetowej

Po wygenerowaniu interfejsu API i zintegrowaniu go z aktywną kolekcją Firestore wygenerujmy frontend aplikacji oparty na internecie. Nasza platforma internetowa będzie obecnie miała minimalną funkcjonalność, tzn. będzie umożliwiać wyszukiwanie sesji należących do określonej kategorii. Pamiętaj, że mamy ścieżkę interfejsu API, czyli /sessions/categories/{category}, więc nasza aplikacja internetowa powinna ją wywołać i pobrać wyniki.

Zaczynajmy. Wpisz w Code Assist ten prompt:

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

Spowoduje to wygenerowanie kodu HTML aplikacji internetowej z osadzonymi w nim kodami JavaScript i CSS. Poprosi Cię też o dodanie nowej trasy do pliku app.py, aby każdy użytkownik odwiedzający poziom główny lub podstawowy adres URL mógł zobaczyć stronę główną. Jeśli nie ma w nim tych informacji, zapytaj o nie lub użyj poniższego fragmentu:

@app.route('/')
def index():
   return render_template('index.html')

Możesz zapisać ten plik jako index.html, ale możesz mieć pytanie, gdzie go zapisać (tzn. w którym folderze). Możemy zadać Asystentowi kodu dodatkowe pytanie.

Given that I am using the flask framework, where should I put the index.html file?

Powinny one zawierać jasne informacje o tym, że używa on platformy render_template, a w związku z tym plik index.html musi znajdować się w folderze templates. Ten folder będzie dostępny, ponieważ na początku tego ćwiczenia wygenerowaliśmy aplikację na podstawie szablonu Flask. W rezultacie istnieje już plik index.html, więc wystarczy zastąpić jego zawartość nową, wygenerowaną tutaj. Code Assist wspomina też o zaimportowaniu render_template w pliku app.py.

Zapisz kod aplikacji internetowej w pliku index.html i pamiętaj, aby umieścić go w folderze templates.

Lokalne uruchamianie aplikacji

Uruchommy teraz aplikację lokalnie, aby sprawdzić, czy spełnia ona wymagania, które określiliśmy na początku.

Sprawdź, czy lokalny serwer Flask nadal działa i nie wyświetla żadnych błędów. Jeśli wystąpią błędy, rozwiąż je i uruchom serwer.

Po uruchomieniu aplikacji otwórz jej adres URL. Powinien wyświetlić się plik index.html, jak pokazano poniżej:

8ca586acc4536879.png

Podaj jedną z kategorii z danych jako dane wejściowe (np. AI) i kliknij przycisk Search. Powinny się wyświetlić sesje otagowane kategorią AI.

165faded790a6c.png

Opcjonalnym ćwiczeniem jest wyświetlenie dodatkowych metadanych, takich jak czas trwania, kategorie, prelegenci i podsumowanie każdej sesji.

12. Generowanie przypadków testowych

Wygenerowaliśmy interfejs API sesji i możemy teraz użyć Gemini Code Assist, aby wygenerować przypadki testów jednostkowych dla różnych ścieżek interfejsu API.

Pozostaw otwarty plik app.py i wpisz ten prompt:

Generate unit test cases for app routes. Use unittest module.

Otrzymaliśmy następującą odpowiedź:

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

Utwórz plik o nazwie tests.py z powyższym kodem.

Uwaga na temat generowania przypadków testowych

Może się zdarzyć, że zobaczysz inną listę kodów niż powyższa, co może powodować problemy z uruchamianiem przypadków testowych. Na przykład w niektórych naszych testach pominięto te kluczowe fragmenty kodu:

from app import app

Powyższy kod jest wymagany do zaimportowania istniejącej aplikacji Flask, w której będziemy wywoływać przypadki testowe.

if __name__ == '__main__':

`unittest.main()`

Powyższy kod jest potrzebny do uruchomienia przypadków testowych.

Zalecamy sprawdzenie każdego przypadku testowego, assertEqual i innych warunków w wygenerowanym kodzie, aby upewnić się, że będzie on działać. Ponieważ dane są zewnętrzne w kolekcji Firestore, może nie mieć do nich dostępu i w rezultacie używać danych testowych, co może powodować niepowodzenie testów. Dostosuj odpowiednio przypadki testowe lub zakomentuj niektóre z nich, jeśli nie są Ci od razu potrzebne.

Na potrzeby demonstracji uruchomiliśmy przypadki testowe za pomocą tego polecenia (pamiętaj, aby uruchomić lokalny serwer deweloperski, ponieważ wywołania będą kierowane do lokalnych punktów końcowych interfejsu API):

python tests.py

Otrzymaliśmy to podsumowanie:

Ran 4 tests in 0.274s

FAILED (failures=2)

To prawda, ponieważ w 3 teście identyfikator sesji był nieprawidłowy, a nie ma kategorii o nazwie category1.

.

Dostosuj odpowiednio elementy testowania i przeprowadź test.

13. Test Driven Development

Przyjrzyjmy się teraz dodawaniu nowej metody wyszukiwania w naszym interfejsie API sesji zgodnie z metodologią programowania opartego na testach (TDD), która polega na pisaniu najpierw przypadków testowych, powodowaniu ich niepowodzenia z powodu braku implementacji i używaniu Gemini Code Assist do generowania brakującej implementacji, aby test zakończył się powodzeniem.

Otwórz plik tests.py (zakładając, że plik tests.py zawiera wszystkie testy, które przechodzą). Zadaj Asystentowi kodu ten prompt:

Generate a new test case to search for sessions by speaker

Dzięki temu uzyskaliśmy implementację testu, którą wstawiliśmy do pliku tests.py.

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

Jeśli uruchomisz testy, powinien pojawić się ten błąd:

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

Dzieje się tak, ponieważ przypadek testowy wywołał ścieżkę (/sessions/speakers/), która nie jest zaimplementowana w app.py.

Poprośmy Code Assist o podanie implementacji. Otwórz plik app.py i wpisz w Code Assist ten prompt:

Add a new route to search for sessions by a specific speaker

Asystent kodu zaproponował nam tę implementację, którą dodaliśmy do pliku app.py:

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

Ponownie sprawdziliśmy plik tests.py i zmodyfikowaliśmy nasz przypadek testowy w ten sposób, aby szybko sprawdzić:

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

Test został przeprowadzony prawidłowo. Pozostawiamy Ci sprawdzenie wygenerowanych elementów testowania, zmodyfikowanie ich w zależności od danych, które możesz mieć w Firestore, oraz zastosowanie odpowiednich metod assert* w elementach testowania jednostki Pythona.

14. Wdrażanie w Google Cloud Run

Teraz, gdy mamy pewność, że jakość naszego programowania jest odpowiednia, ostatnim krokiem będzie wdrożenie tej aplikacji w Google Cloud Run. Ale na wszelki wypadek zapytajmy Code Assist, czy o czymś nie zapomnieliśmy. Otwórz app.py i wpisz ten prompt :

Is there something here I should change before I deploy to production?

Dobrze, że o to pytasz, bo zapomnieliśmy wyłączyć flagę debugowania :

2f87ed3a811fb218.png

Zgodnie z instrukcjami wyłącz debugowanie i zapytaj Gemini Code Assist o pomoc w wykonaniu polecenia gcloud, które umożliwia wdrożenie aplikacji w Cloud Run bezpośrednio ze źródła (bez konieczności wcześniejszego tworzenia kontenera).

Wpisz ten prompt:

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

Wypróbuj kilka odmian powyższego prompta. Inny przykład, który wypróbowaliśmy:

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

Powinno pojawić się to polecenie gcloud:

gcloud run deploy sessions --source .

Możesz też otrzymać:

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

Uruchom powyższe polecenie w folderze głównym aplikacji. Gdy pojawi się prośba o podanie region, wybierz us-central1, a gdy pojawi się prośba o zezwolenie na unauthenticated invocations, wybierz Y. Może też pojawić się prośba o włączenie interfejsów API Google Cloud, takich jak Artifact Registry, Cloud Build i Cloud Run, oraz o przyznanie uprawnień do tworzenia repozytorium Artifact Registry. W takim przypadku przyznaj te uprawnienia.

Proces wdrażania potrwa około 2 minut, więc zachowaj cierpliwość.

Po pomyślnym wdrożeniu zobaczysz adres URL usługi Cloud Run. Otwórz ten publiczny adres URL. Powinna się wyświetlić ta sama aplikacja internetowa, która została wdrożona i działa prawidłowo.

c5322d0fd3e0f616.png

Gratulacje, świetna robota!

15. (Opcjonalnie) Korzystanie z Cloud Logging

Możemy wprowadzić w aplikacji rejestrowanie, tak aby logi aplikacji były scentralizowane w jednej z usług Google Cloud (Cloud Logging). Możemy też użyć funkcji Obserwacja w Gemini, aby zrozumieć wpisy w logach.

Aby to zrobić, musimy najpierw użyć istniejącej biblioteki Python Cloud Logging z Google Cloud i wykorzystać ją do rejestrowania komunikatów informacyjnych, ostrzegawczych lub o błędach (w zależności od dziennika lub poziomu ważności).

Spróbujmy najpierw zadać to pytanie usłudze Code Assist. Wypróbuj ten prompt:

How do I use the google-cloud-logging package in Python?

Powinna się wyświetlić odpowiedź z informacjami na ten temat, jak poniżej:

2472e1ccaf8a217d.png

Dodajmy instrukcje logowania do funkcji, która wyszukuje sesje według kategorii.

Najpierw dodaj pakiet Pythona google-cloud-logging do pliku requirements.txt.

Poniżej znajdziesz fragment kodu, który pokazuje, jak zintegrowaliśmy kod, aby wdrożyć rejestrowanie:

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

Ponownie wdróż usługę w Cloud Run, używając tego samego polecenia co w poprzedniej sekcji. Po wdrożeniu wykonaj kilka wywołań punktu końcowego /sessions/categories/<category>.

Otwórz stronę Cloud Console → Logs Explorer.

59e297577570695.png

…i powinno być możliwe filtrowanie tych instrukcji logowania, jak pokazano poniżej:

914f1fb6cac30a89.png

Możesz kliknąć dowolny wpis logu, rozwinąć go, a następnie kliknąć Explain this log entry, aby Gemini wyjaśnił wpis. Pamiętaj, że jeśli nie masz włączonej usługi Gemini w Google Cloud, pojawi się prośba o włączenie interfejsu Cloud AI Companion API. Wykonaj te czynności zgodnie z instrukcjami.

Przykładowa odpowiedź jest podana poniżej:

7fc9783910fa92cc.png

16. Gratulacje

Gratulacje! Udało Ci się utworzyć aplikację od podstaw i użyć Gemini Code Assist w wielu aspektach cyklu życia oprogramowania, w tym w projektowaniu, tworzeniu, testowaniu i wdrażaniu.

Co dalej?

Sprawdź te ćwiczenia z programowania:

Dokumentacja