Codelab – tworzenie kontekstowej aplikacji do rekomendowania asan jogi za pomocą Firestore, wyszukiwania wektorowego, Langchain i Gemini (wersja w Pythonie)

1. Wprowadzenie

W tym ćwiczeniu w Codelabs utworzysz aplikację, która korzysta z wyszukiwania wektorowego, aby rekomendować pozycje jogi.

W ramach tego ćwiczenia będziesz wykonywać czynności krok po kroku:

  1. Użyj istniejącego zbioru danych Hugging Face zawierającego pozycje jogi (format JSON).
  2. Ulepszyć zbiór danych, dodając dodatkowy opis pola, który wykorzystuje Gemini do generowania opisów każdej z poz.
  3. Użyj Langchain do utworzenia dokumentu, a potem użyj integracji Langchain z Firestore, aby utworzyć w Firestore kolekcję i wstawki.
  4. Utwórz indeks złożony w Firestore, aby umożliwić wyszukiwanie wektorów.
  5. Użyj wyszukiwarki wektorowej w aplikacji Flask, która łączy wszystko w jedną całość, jak pokazano poniżej:

84e1cbf29cbaeedc.png

Co musisz zrobić

  • Zaprojektuj, zbuduj i wdróż aplikację internetową, która wykorzystuje wyszukiwanie wektorowe do rekomendowania pozycji jogi.

Czego się nauczysz

  • Jak za pomocą Gemini wygenerować treść tekstową, a w kontekście tego CodeLab – jak wygenerować opisy asan jogi
  • Jak za pomocą narzędzia Langchain Document Loader for Firestore załadować do Firestore rekordy z rozszerzonego zbioru danych z Hugging Face wraz z wektorowymi reprezentacjami dokumentów
  • Jak używać Langchain Vector Store for Firestore do wyszukiwania danych na podstawie zapytania w języku naturalnym
  • Jak użyć interfejsu Google Cloud Text-to-Speech API do generowania treści audio

Czego potrzebujesz

  • przeglądarka Chrome,
  • konto Gmail,
  • projekt w chmurze z włączonymi płatnościami,

Ten warsztat programistyczny przeznaczony dla deweloperów na wszystkich poziomach zaawansowania (w tym dla początkujących) używa Pythona w próbnej aplikacji. Jednak znajomość Pythona nie jest wymagana do zrozumienia omawianych zagadnień.

2. Zanim zaczniesz

Utwórz projekt

  1. W konsoli Google Cloud na stronie selektora projektu wybierz lub utwórz projekt Google Cloud.
  2. Sprawdź, czy w projekcie Cloud włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności .
  3. Użyjesz Cloud Shell, czyli środowiska wiersza poleceń działającego w Google Cloud, które jest wstępnie wczytane w bq. Kliknij Aktywuj Cloud Shell u góry konsoli Google Cloud.

Obraz przycisku aktywowania Cloud Shell

  1. Po połączeniu z Cloud Shell sprawdź, czy jesteś już uwierzytelniony i czy projekt jest ustawiony na identyfikator Twojego projektu, używając tego polecenia:
gcloud auth list
  1. Aby sprawdzić, czy polecenie gcloud zna Twój projekt, uruchom w Cloud Shell to polecenie:
gcloud config list project
  1. Jeśli projekt nie jest ustawiony, użyj tego polecenia:
gcloud config set project <YOUR_PROJECT_ID>
  1. Włącz wymagane interfejsy API za pomocą polecenia pokazanego poniżej. Może to potrwać kilka minut, więc zachowaj cierpliwość.
gcloud services enable firestore.googleapis.com \
                       compute.googleapis.com \
                       cloudresourcemanager.googleapis.com \
                       servicenetworking.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       cloudfunctions.googleapis.com \
                       aiplatform.googleapis.com \
                       texttospeech.googleapis.com

Po pomyślnym wykonaniu polecenia powinien wyświetlić się komunikat podobny do tego:

Operation "operations/..." finished successfully.

Alternatywą dla polecenia gcloud jest konsola, w której możesz wyszukać poszczególne usługi lub skorzystać z tego linku.

Jeśli pominiesz któryś interfejs API, możesz go włączyć w trakcie implementacji.

Więcej informacji o poleceniach i użytkowaniu gcloud znajdziesz w dokumentacji.

Klonowanie repozytorium i konfigurowanie ustawień środowiska

Następnym krokiem jest sklonowanie przykładowego repozytorium, do którego będziemy się odwoływać w dalszej części tego samouczka. Zakładając, że jesteś w Cloud Shell, uruchom to polecenie w katalogu domowym:

git clone https://github.com/rominirani/yoga-poses-recommender-python

Aby uruchomić edytor, na pasku narzędzi w oknie Cloud Shell kliknij Otwórz edytor. W lewym górnym rogu kliknij pasek menu i wybierz Plik → Otwórz folder, jak pokazano na ilustracji:

66221fd0d0e5202f.png

Wybierz folder yoga-poses-recommender-python. Powinien otworzyć się folder z tymi plikami:

44699efc7fb1b911.png

Teraz musimy skonfigurować zmienne środowiskowe, których będziemy używać. Kliknij plik config.template.yaml. Powinieneś zobaczyć zawartość pokazaną poniżej:

project_id: your-project-id
location: us-central1
gemini_model_name: gemini-1.5-flash-002
embedding_model_name: text-embedding-004
image_generation_model_name: imagen-3.0-fast-generate-002
database: (default)
collection: poses
test_collection: test-poses
top_k: "3"

Zaktualizuj wartości project_idlocation zgodnie z ustawieniami wybranymi podczas tworzenia projektu Google Cloud i bazy danych Firestore. W idealnej sytuacji wartości parametru location powinny być takie same w przypadku projektu Google Cloud i bazy danych Firestore, np. us-central1.

W tym ćwiczeniu użyjemy wartości wstępnie skonfigurowanych (z wyjątkiem oczywiście wartości project_idlocation, które musisz ustawić zgodnie ze swoją konfiguracją.

Zapisz ten plik jako config.yaml w tym samym folderze co plik config.template.yaml.

Ostatnim krokiem jest utworzenie środowiska Pythona, które będziemy używać lokalnie ze wszystkimi zależnościami Pythona skonfigurowanymi dla nas. Zapoznaj się z pliku pyproject.toml, który zawiera szczegółowe informacje. Poniżej znajdziesz jego zawartość:

dependencies = [
    "datasets>=3.2.0",
    "flask>=3.1.0",
    "google-cloud-aiplatform>=1.78.0",
    "google-cloud-texttospeech>=2.24.0",
    "langchain-community>=0.3.15",
    "langchain-core>=0.3.31",
    "langchain-google-community>=2.0.4",
    "langchain-google-firestore>=0.5.0",
    "langchain-google-vertexai>=2.0.7",
    "pydantic-settings>=2.7.1",
    "pyyaml>=6.0.2",
    "tenacity>=9.0.0",
]

Te zależności są już zablokowane pod względem wersji w requirements.txt.. Podsumowując, musimy utworzyć wirtualne środowisko Pythona z zależностями pakietu Pythona w requirements.txt, które mają zostać zainstalowane w środowisku wirtualnym. Aby to zrobić, w Cloud Shell IDE kliknij Command Palette (Ctrl+Shift+P) i wpisz Python: Create Environment. Aby wybrać plik Virtual Environment(venv), Python 3.x interpreterrequirements.txt, wykonaj kilka kolejnych czynności.

Po utworzeniu środowiska należy je aktywować za pomocą tego polecenia

source .venv/bin/activate

W konsoli powinien pojawić się plik (.venv). np. -> (.venv) yourusername@cloudshell:

Świetnie! Wszystko jest już gotowe do skonfigurowania bazy danych Firestore.

3. Konfigurowanie Firestore

Cloud Firestore to w pełni zarządzana bezserwerowa baza danych dokumentów, której użyjemy jako backendu dla danych aplikacji. Dane w Cloud Firestore są ustrukturyzowane w kolekcjach dokumentów.

Inicjowanie bazy danych Firestore

Otwórz stronę Firestore w konsoli Cloud.

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

  • Tryb Firestore: Native.
  • Lokalizacja: użyj domyślnych ustawień lokalizacji.
  • W przypadku reguł zabezpieczeń wybierz Test rules.
  • Utwórz bazę danych.

504cabdb99a222a5.png

W następnej sekcji przygotujemy się do utworzenia kolekcji o nazwie poses w domyślnej bazie danych Firestore. Ta kolekcja będzie zawierać przykładowe dane (dokumenty) lub informacje o pozach jogi, których użyjemy w naszej aplikacji.

To koniec sekcji poświęconej konfigurowaniu bazy danych Firestore.

4. Przygotowanie zbioru danych o pozach jogi

Naszym pierwszym zadaniem jest przygotowanie zbioru danych o pozycjach jogi, którego użyjemy w aplikacji. Zaczniemy od istniejącego zbioru danych Hugging Face, a potem wzbogacimy go o dodatkowe informacje.

Zapoznaj się ze zbiorem danych Hugging Face do rozpoznawania pozycji jogi. Pamiętaj, że chociaż w tym laboratorium kodów używamy jednego zbioru danych, możesz użyć dowolnego innego zbioru danych i zastosować te same techniki, aby go wzbogacić.

298cfae7f23e4bef.png

Jeśli przejdziesz do sekcji Files and versions, możesz pobrać plik danych JSON ze wszystkimi pozami.

3fe6e55abdc032ec.png

Pobrany plik yoga_poses.json został Ci przesłany. Plik o nazwie yoga_poses_alldata.json znajduje się w folderze /data.

Otwórz plik data/yoga_poses.json w edytorze Cloud Shell i sprawdź listę obiektów JSON, z których każdy reprezentuje jedną pozycję jogi. Mamy łącznie 3 rekordy, a przykładowy rekord wygląda tak:

{
   "name": "Big Toe Pose",
   "sanskrit_name": "Padangusthasana",
   "photo_url": "https://pocketyoga.com/assets/images/full/ForwardBendBigToe.png",
   "expertise_level": "Beginner",
   "pose_type": ["Standing", "Forward Bend"]
 }

To świetna okazja, aby przedstawić Gemini i pokazać, jak za pomocą modelu domyślnego wygenerować dla niego pole description.

W edytorze Cloud Shell otwórz plik generate-descriptions.py. Poniżej znajduje się zawartość tego pliku:

import json
import time
import logging
import vertexai
from langchain_google_vertexai import VertexAI
from tenacity import retry, stop_after_attempt, wait_exponential
from settings import get_settings

settings = get_settings()
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
# Initialize Vertex AI SDK
vertexai.init(project=settings.project_id, location=settings.location)
logging.info("Done Initializing Vertex AI SDK")


@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=4, max=10),
)
def generate_description(pose_name, sanskrit_name, expertise_level, pose_types):
    """Generates a description for a yoga pose using the Gemini API."""

    prompt = f"""
    Generate a concise description (max 50 words) for the yoga pose: {pose_name}
    Also known as: {sanskrit_name}
    Expertise Level: {expertise_level}
    Pose Type: {", ".join(pose_types)}

    Include key benefits and any important alignment cues.
    """
    try:
        model = VertexAI(model_name=settings.gemini_model_name, verbose=True)
        response = model.invoke(prompt)
        return response
    except Exception as e:
        logging.info(f"Error generating description for {pose_name}: {e}")
        return ""


def add_descriptions_to_json(input_file, output_file):
    """Loads JSON data, adds descriptions, and saves the updated data."""

    with open(input_file, "r") as f:
        yoga_poses = json.load(f)

    total_poses = len(yoga_poses)
    processed_count = 0

    for pose in yoga_poses:
        if pose["name"] != " Pose":
            start_time = time.time()  # Record start time
            pose["description"] = generate_description(
                pose["name"],
                pose["sanskrit_name"],
                pose["expertise_level"],
                pose["pose_type"],
            )
            end_time = time.time()  # Record end time

            processed_count += 1
            end_time = time.time()  # Record end time
            time_taken = end_time - start_time
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )

        else:
            pose["description"] = ""
            processed_count += 1
            logging.info(
                f"Processed: {processed_count}/{total_poses} - {pose['name']} ({time_taken:.2f} seconds)"
            )
        # Adding a delay to avoid rate limit
        time.sleep(30)

    with open(output_file, "w") as f:
        json.dump(yoga_poses, f, indent=2)


def main():
    # File paths
    input_file = "./data/yoga_poses.json"
    output_file = "./data/yoga_poses_with_descriptions.json"

    # Add descriptions and save the updated JSON
    add_descriptions_to_json(input_file, output_file)


if __name__ == "__main__":
    main()

Ta aplikacja doda nowe pole description do każdego rekordu JSON dotyczącego pozycji jogi. Otrzyma opis za pomocą wywołania modelu Gemini, w którym przekażemy niezbędny prompt. Pole zostanie dodane do pliku JSON, a nowy plik zostanie zapisany w pliku data/yoga_poses_with_descriptions.json.

Oto główne kroki:

  1. Funkcja main() wywołuje funkcję add_descriptions_to_json i przekazuje oczekiwany plik wejściowy i wyjściowy.
  2. Funkcja add_descriptions_to_json wykonuje te czynności w przypadku każdego rekordu JSON, np. informacji o poście na temat jogi:
  3. Wyodrębnia pose_name, sanskrit_name, expertise_level i pose_types.
  4. Wywołuje funkcję generate_description, która tworzy prompt, a potem wywołuje klasę modelu Langchain VertexAI, aby uzyskać tekst odpowiedzi.
  5. Następnie tekst odpowiedzi jest dodawany do obiektu JSON.
  6. Następnie zaktualizowana lista obiektów JSON jest zapisywana w pliku docelowym.

Pozwól nam uruchomić tę aplikację. Uruchom nowe okno terminala (Ctrl+Shift+C) i wpisz to polecenie:

python generate-descriptions.py

Jeśli pojawi się prośba o autoryzację, potwierdź ją.

Aplikacja zacznie się wykonywać. Dodaliśmy 30-sekundową przerwę między rekordami, aby uniknąć limitów szybkości, które mogłyby wystąpić na nowych kontach Google Cloud. Prosimy o cierpliwość.

Poniżej widać przykładowy proces wykonywania:

8e830d9ea9b6c60.png

Po ulepszeniu wszystkich 3 rekordów za pomocą wywołania Gemini zostanie wygenerowany plik data/yoga_poses_with_description.json. Możesz to sprawdzić.

Mamy już plik danych, więc następnym krokiem jest zapełnienie nim bazy danych Firestore oraz wygenerowanie zaszyfrowanych danych.

5. Importowanie danych do Firestore i generowanie wektorów dystrybucyjnych

Mamy plik data/yoga_poses_with_description.json i teraz musimy wypełnić nim bazę danych Firestore oraz, co ważne, wygenerować wektory zanurzeniowe dla każdego rekordu. Wektory zanurzone będą przydatne później, gdy będziemy musieli przeprowadzić wyszukiwanie podobieństw z użyciem zapytania użytkownika podanego w języku naturalnym.

Do wdrożenia tego procesu użyjemy komponentów Langchain Firestore.

Aby to zrobić:

  1. Lista obiektów JSON zostanie przekonwertowana na listę obiektów Langchain Document. Każdy dokument będzie mieć 2 atrybuty: page_content i metadata. Obiekt metadanych zawiera cały obiekt JSON z atrybutami takimi jak name, description, sanskrit_name itp. Element page_content będzie ciągiem tekstowym, który będzie zawierał konkatenację kilku pól.
  2. Gdy mamy listę obiektów Document, używamy klasy Langchain FirestoreVectorStore, a w szczególności metody from_documents z tą listą dokumentów, nazwą zbioru (korzystamy z zmiennej TEST_COLLECTION, która wskazuje na test-poses), klasy Vertex AI Embedding i danymi połączenia Firestore (PROJECT_IDDATABASE nazwa). Spowoduje to utworzenie kolekcji oraz wygenerowanie pola embedding dla każdego atrybutu.

Poniżej znajduje się kod import-data.py (część kodu została skrócona ze względu na zwiężenie):

... 

def create_langchain_documents(poses):
   """Creates a list of Langchain Documents from a list of poses."""
   documents = []
   for pose in poses:
       # Convert the pose to a string representation for page_content
       page_content = (
           f"name: {pose.get('name', '')}\n"
           f"description: {pose.get('description', '')}\n"
           f"sanskrit_name: {pose.get('sanskrit_name', '')}\n"
           f"expertise_level: {pose.get('expertise_level', 'N/A')}\n"
           f"pose_type: {pose.get('pose_type', 'N/A')}\n"
       ).strip()
       # The metadata will be the whole pose
       metadata = pose

       document = Document(page_content=page_content, metadata=metadata)
       documents.append(document)
   logging.info(f"Created {len(documents)} Langchain documents.")
   return documents

def main():
    all_poses = load_yoga_poses_data_from_local_file(
        "./data/yoga_poses_with_descriptions.json"
    )
    documents = create_langchain_documents(all_poses)
    logging.info(
        f"Successfully created langchain documents. Total documents: {len(documents)}"
    )

    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore.from_documents(
        client=client,
        collection=settings.test_collection,
        documents=documents,
        embedding=embedding,
    )
    logging.info("Added documents to the vector store.")


if __name__ == "__main__":
    main()

Pozwól nam uruchomić tę aplikację. Uruchom nowe okno terminala (Ctrl+Shift+C) i wpisz to polecenie:

python import-data.py

Jeśli wszystko pójdzie dobrze, powinien wyświetlić się komunikat podobny do tego:

2025-01-21 14:50:06,479 - INFO - Added documents to the vector store.

Aby sprawdzić, czy rekordy zostały wstawione i czy zostały wygenerowane elementy embeddingu, otwórz stronę Firestore w konsoli Google Cloud.

504cabdb99a222a5.png

Kliknij bazę danych (domyślną). Powinna się wyświetlić kolekcja test-poses i kilka dokumentów w niej. Każdy dokument to jedna pozycja jogi.

d0708499e403aebc.png

Kliknij dowolny dokument, aby sprawdzić pola. Oprócz zaimportowanych pól znajdziesz też pole embedding, które jest polem wektorowym wygenerowanym automatycznie za pomocą klasy Langchain VertexAIEmbeddings, w której udostępniliśmy model osadzania Vertex AI text-embedding-004.

d67113e2dc63cd6b.png

Teraz, gdy rekordy zostały przesłane do bazy danych Firestore z umieszczonymi w niej wektorami dystrybucyjnymi, możemy przejść do następnego kroku i zobaczyć, jak wykonać wyszukiwanie wektorowe w Firestore.

6. Importowanie pełnych pozycji jogi do kolekcji bazy danych Firestore

Utworzymy teraz kolekcję poses, która zawiera pełną listę 160 pozycji jogi. Wygenerowaliśmy plik do importu bazy danych, który możesz zaimportować bezpośrednio. Robimy to, aby zaoszczędzić czas w laboratorium. Proces generowania bazy danych zawierającej opis i wbudowane modele jest taki sam jak w poprzedniej sekcji.

Aby zaimportować bazę danych, wykonaj te czynności:

  1. Utwórz zasobnik w projekcie za pomocą podanego niżej polecenia gsutil. W poniższym poleceniu zastąp zmienną <PROJECT_ID> identyfikatorem projektu Google Cloud.
gsutil mb -l us-central1 gs://<PROJECT_ID>-my-bucket
  1. Teraz, gdy zasób został utworzony, musimy skopiować przygotowany wcześniej eksport bazy danych do tego zasobu, zanim będziemy mogli go zaimportować do bazy danych Firebase. Użyj podanego niżej polecenia:
gsutil cp -r gs://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615  gs://<PROJECT_ID>-my-bucket

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

  1. Użyj polecenia gcloud podanego poniżej:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2025-01-27T05:11:02_62615

Importowanie zajmie kilka sekund. Gdy zakończy się ono, możesz zweryfikować bazę danych Firestore i kolekcję, klikając https://console.cloud.google.com/firestore/databases i wybierając bazę danych default oraz kolekcję poses, jak pokazano poniżej:

a8f5a6ba69bec69b.png

To kończy tworzenie kolekcji Firestore, której będziemy używać w naszej aplikacji.

7. Przeprowadzanie wyszukiwania według podobieństwa wektora w Firestore

Aby przeprowadzić wyszukiwanie według podobieństwa wektorowego, pobieramy zapytanie od użytkownika. Przykładem takiego zapytania może być "Suggest me some exercises to relieve back pain".

Zapoznaj się z plikiem search-data.py. Najważniejsza funkcja to wyszukiwarka, którą możesz zobaczyć poniżej. Ogólnie rzecz biorąc, tworzy klasę embeddingu, która służy do generowania embeddingu zapytania użytkownika. Następnie używa klasy FirestoreVectorStore do wywołania funkcji similarity_search.

def search(query: str):
    """Executes Firestore Vector Similarity Search"""
    embedding = VertexAIEmbeddings(
        model_name=settings.embedding_model_name,
        project=settings.project_id,
        location=settings.location,
    )

    client = firestore.Client(project=settings.project_id, database=settings.database)

    vector_store = FirestoreVectorStore(
        client=client, collection=settings.collection, embedding_service=embedding
    )

    logging.info(f"Now executing query: {query}")
    results: list[Document] = vector_store.similarity_search(
        query=query, k=int(settings.top_k), include_metadata=True
    )
    for result in results:
        print(result.page_content)

Zanim uruchomisz to narzędzie z kilkoma przykładami zapytań, musisz najpierw wygenerować złożony indeks Firehose, który jest potrzebny do wykonania zapytań. Jeśli uruchomisz aplikację bez utworzenia indeksu, wyświetli się błąd z komendą, która poinformuje Cię, że musisz najpierw utworzyć indeks.

Poniżej przedstawiono polecenie gcloud służące do tworzenia indeksu złożonego:

gcloud firestore indexes composite create --project=<YOUR_PROJECT_ID> --collection-group=poses --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding

Utworzenie indeksu może potrwać kilka minut, ponieważ w bazie danych jest ponad 150 rekordów. Po zakończeniu indeksowania możesz wyświetlić indeks za pomocą polecenia widocznego poniżej:

gcloud firestore indexes composite list

Na liście powinien pojawić się utworzony przez Ciebie indeks.

Wypróbuj teraz to polecenie:

python search-data.py --prompt "Recommend me some exercises for back pain relief"

Powinieneś/powinnaś otrzymać kilka rekomendacji. Poniżej przedstawiono przykładowy przebieg:

2025-01-21 15:48:51,282 - INFO - Now executing query: Recommend me some exercises for back pain relief
name: Supine Spinal Twist Pose
description: A gentle supine twist (Supta Matsyendrasana), great for beginners.  Releases spinal tension, improves digestion, and calms the nervous system.  Keep shoulders flat on the floor and lengthen the spine.

sanskrit_name: Supta Matsyendrasana
expertise_level: Beginner
pose_type: ['Supine', 'Twist']
name: Cow Pose
description: Cow Pose (Bitilasana) is a gentle backbend, stretching the chest, shoulders, and abdomen.  Maintain a neutral spine, lengthen the tailbone, and avoid hyperextension.  Benefits include improved posture and stress relief.

sanskrit_name: Bitilasana
expertise_level: Beginner
pose_type: ['Arm Leg Support', 'Back Bend']
name: Locust I Pose
description: Locust Pose I (Shalabhasana A) strengthens the back, glutes, and shoulders.  Lie prone, lift chest and legs simultaneously, engaging back muscles.  Keep hips grounded and gaze slightly forward.

sanskrit_name: Shalabhasana A
expertise_level: Intermediate
pose_type: ['Prone', 'Back Bend']

Teraz, gdy już wiesz, jak korzystać z bazy danych wektorów Firestore do przesyłania rekordów, generowania wektorów dystrybucyjnych i wyszukiwania podobieństwa wektorów, Możemy teraz utworzyć aplikację internetową, która zintegruje wyszukiwanie wektorów z interfejsem internetowym.

8. Aplikacja internetowa

Aplikacja internetowa Python Flask jest dostępna w pliku main.py, a plik HTML front-endu znajduje się w pliku templates/index.html..

Zalecamy zapoznanie się z obu plikami. Zacznij od pliku main.py, który zawiera moduł obsługi /search. Ten moduł obsługuje prompt przekazany z pliku HTML index.html na froncie. Następnie wywołuje metodę wyszukiwania, która przeprowadza wyszukiwanie według podobieństwa wektorowego, omówione w poprzedniej sekcji.

Odpowiedź jest następnie wysyłana z listą rekomendacji do index.html. Następnie index.html wyświetla rekomendacje w postaci różnych kart.

Uruchamianie aplikacji lokalnie

Uruchom nowe okno terminala (Ctrl+Shift+C) lub dowolne istniejące okno terminala i wpisz to polecenie:

python main.py

Poniżej przedstawiamy przykład wykonania:

 * Serving Flask app 'main'
 * Debug mode: on
2025-01-21 16:02:37,473 - INFO - 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.4:8080
2025-01-21 16:02:37,473 - INFO - Press CTRL+C to quit
2025-01-21 16:02:37,474 - INFO -  * Restarting with stat
2025-01-21 16:02:41,462 - WARNING -  * Debugger is active!
2025-01-21 16:02:41,484 - INFO -  * Debugger PIN: 440-653-555

Po uruchomieniu aplikacji otwórz URL strony głównej aplikacji, klikając przycisk Podgląd w przeglądarce:

de297d4cee10e0bf.png

Powinien wyświetlić się plik index.html, jak pokazano poniżej:

20240a0e885ac17b.png

Podaj przykładowe zapytanie (np. Provide me some exercises for back pain relief) i kliknij przycisk Search. Powinien on pobrać z bazy danych kilka rekomendacji. Zobaczysz też przycisk Play Audio, który wygeneruje strumień audio na podstawie opisu.

789b4277dc40e2be.png

9. (Opcjonalnie) Wdrażanie w Google Cloud Run

Ostatnim krokiem będzie wdrożenie tej aplikacji w Google Cloud Run. Polecenie wdrażania jest widoczne poniżej. Przed wdrożeniem upewnij się, że wartości zmiennej (<<YOUR_PROJECT_ID>>) zostały zastąpione wartościami właściwymi dla Twojego projektu. Te wartości możesz pobrać z pliku config.yaml.

gcloud run deploy yogaposes --source . \
  --port=8080 \
  --allow-unauthenticated \
  --region=us-central1 \
  --platform=managed  \
  --project=<<YOUR_PROJECT_ID>> \
  --env-vars-file=config.yaml

Uruchom powyższe polecenie z folderu głównego aplikacji. Możesz też zostać poproszony(-a) o włączenie interfejsów Google Cloud API i potwierdzenie różnych uprawnień.

Proces wdrażania może potrwać 5–7 minut, więc zachowaj cierpliwość.

3a6d86fd32e4a5e.png

Po udanym wdrożeniu w wyniku wdrożonego procesu znajdziesz adres URL usługi Cloud Run. Ma ono następującą formę:

Service URL: https://yogaposes-<<UNIQUEID>.us-central1.run.app

Otwórz ten publiczny adres URL, aby sprawdzić, czy aplikacja internetowa została wdrożona i działa prawidłowo.

84e1cbf29cbaeedc.png

W konsoli Google Cloud możesz też otworzyć Cloud Run, aby wyświetlić listę usług w Cloud Run. Usługa yogaposes powinna być jedną z wymienionych usług (jeśli nie jedyną).

f2b34a8c9011be4c.png

Aby wyświetlić szczegóły usługi, takie jak adres URL, konfiguracje, dzienniki itp., kliknij nazwę konkretnej usługi (w naszym przypadku jest to yogaposes).

faaa5e0c02fe0423.png

To kończy rozwój i wdrażanie aplikacji internetowej polecającej pozycje jogi w Cloud Run.

10. Gratulacje

Gratulacje! Udało Ci się utworzyć aplikację, która przesyła zbiór danych do Firestore, generuje wektory dystrybucyjne i wykonuje wyszukiwanie według podobieństwa wektorów na podstawie zapytania użytkownika.

Dokumenty referencyjne