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 za pomocą wyszukiwania wektorowego będzie rekomendować pozycje jogi.

W ramach ćwiczeń z programowania będziesz wykonywać kolejne czynności:

  1. Użyj istniejącego zbioru danych Hugging Face z pozami jogi (w formacie JSON).
  2. Wzbogać zbiór danych o dodatkowy opis pola, który wykorzystuje Gemini do generowania opisów każdej z pozycji.
  3. Użyj Langchain, aby utworzyć dokument, a następnie użyj integracji Firestore Langchain, aby utworzyć kolekcję i osadzenia w Firestore.
  4. Utwórz indeks złożony w Firestore, aby umożliwić wyszukiwanie wektorowe.
  5. Użyj wyszukiwania wektorowego w aplikacji Flask, która łączy wszystkie elementy, jak pokazano poniżej:

84e1cbf29cbaeedc.png

Co musisz zrobić

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

Czego się nauczysz

  • Jak używać Gemini do generowania treści tekstowych, a w kontekście tego laboratorium – opisów pozycji jogi
  • Jak używać programu Langchain Document Loader for Firestore do wczytywania rekordów z ulepszonego zbioru danych z Hugging Face do Firestore wraz z wektorowymi osadzaniami.
  • Jak używać Langchain Vector Store for Firestore do wyszukiwania danych na podstawie zapytania w języku naturalnym
  • Jak używać interfejsu Google Cloud Text-to-Speech API do generowania treści audio

Czego potrzebujesz

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

Ten przewodnik, przeznaczony dla deweloperów na wszystkich poziomach zaawansowania (w tym dla początkujących), wykorzystuje w przykładowej aplikacji język Python. Znajomość Pythona nie jest jednak wymagana do zrozumienia przedstawionych koncepcji.

2. Zanim zaczniesz

Utwórz projekt

  1. W konsoli Google Cloud na stronie wyboru 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. Będziesz używać Cloud Shell, czyli środowiska wiersza poleceń działającego w Google Cloud, które jest wstępnie załadowane narzędziem bq. U góry konsoli Google Cloud kliknij Aktywuj Cloud Shell.

Obraz przycisku aktywowania Cloud Shell

  1. Po połączeniu z Cloud Shell sprawdź, czy uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu, używając tego polecenia:
gcloud auth list
  1. Aby potwierdzić, że 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, aby go ustawić:
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 poniżej:

Operation "operations/..." finished successfully.

Alternatywą dla polecenia gcloud jest wyszukanie poszczególnych usług w konsoli lub skorzystanie z tego linku.

Jeśli pominiesz jakiś interfejs API, możesz go włączyć w trakcie wdrażania.

Informacje o poleceniach gcloud i ich użyciu 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 przewodnika. Zakładając, że jesteś w Cloud Shell, wpisz to polecenie w katalogu głównym:

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. Kliknij pasek menu w lewym górnym rogu i wybierz Plik → Otwórz folder, jak pokazano poniżej:

66221fd0d0e5202f.png

Wybierz folder yoga-poses-recommender-python. Powinien się otworzyć i zawierać te pliki:

44699efc7fb1b911.png

Teraz musimy skonfigurować zmienne środowiskowe, których będziemy używać. Kliknij plik config.template.yaml. Powinna wyświetlić się jego zawartość, jak pokazano 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 tym, co zostało wybrane podczas tworzenia projektu Google Cloud i regionu bazy danych Firestore. Najlepiej, aby wartości location były takie same w przypadku projektu Google Cloud i bazy danych Firestore, np. us-central1.

Na potrzeby tego laboratorium wybierzemy wstępnie skonfigurowane wartości (z wyjątkiem project_idlocation, które musisz ustawić zgodnie z konfiguracją).

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

Ostatnim krokiem jest utworzenie środowiska Pythona, którego będziemy używać lokalnie ze wszystkimi skonfigurowanymi zależnościami Pythona. Zapoznaj się z plikiem pyproject.toml, który zawiera szczegóły dotyczące tego samego. Jego zawartość jest widoczna poniżej:

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 w requirements.txt.. Podsumowując, musimy utworzyć wirtualne środowisko Pythona z zależnościami pakietu Pythona w requirements.txt, które mają zostać zainstalowane w środowisku wirtualnym. Aby to zrobić, w środowisku IDE Cloud Shell kliknij Command Palette (Ctrl+Shift+P) i wpisz Python: Create Environment. Wykonaj kilka kolejnych czynności, aby wybrać pliki Virtual Environment(venv), Python 3.x interpreterrequirements.txt.

Po utworzeniu środowiska musimy je aktywować za pomocą tego polecenia:

source .venv/bin/activate

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

Świetnie! Możemy teraz przejść do konfigurowania bazy danych Firestore.

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.

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, klikając Create Database. Podczas tworzenia bazy danych użyj tych wartości:

  • Tryb Firestore: Native.
  • Wybierz Typ lokalizacji – Region i wybierz lokalizację us-central1 dla regionu.
  • W przypadku reguł zabezpieczeń wybierz Test rules.
  • Utwórz bazę danych.

61d0277510803c8d.png

W następnej sekcji przygotujemy podstawy do utworzenia kolekcji o nazwie poses w domyślnej bazie danych Firestore. Ta kolekcja będzie zawierać przykładowe dane (dokumenty) lub informacje o pozycjach jogi, które następnie wykorzystamy w naszej aplikacji.

To już koniec sekcji dotyczącej konfigurowania bazy danych Firestore.

4. Przygotowywanie zbioru danych z pozami jogi

Naszym pierwszym zadaniem jest przygotowanie zbioru danych Yoga Poses, którego będziemy używać w aplikacji. Zaczniemy od istniejącego zbioru danych Hugging Face, a następnie uzupełnimy go o dodatkowe informacje.

Zapoznaj się z zbiorem danych Hugging Face dotyczącym pozycji jogi. Pamiętaj, że w tym samouczku używamy jednego ze zbiorów danych, ale możesz użyć dowolnego innego zbioru danych i zastosować te same techniki, aby go ulepszyć.

298cfae7f23e4bef.png

W sekcji Files and versions możemy pobrać plik danych JSON ze wszystkimi pozami.

3fe6e55abdc032ec.png

Pobraliśmy plik yoga_poses.json i udostępniliśmy go Tobie. Ten plik ma nazwę yoga_poses_alldata.json i znajduje się w folderze /data.

Otwórz plik data/yoga_poses.json w edytorze Cloud Shell i zapoznaj się z listą obiektów JSON, z których każdy reprezentuje pozycję jogi. Mamy łącznie 3 rekordy. Przykładowy rekord jest pokazany poniżej:

{
   "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 możemy użyć domyślnego modelu do wygenerowania pola description.

W edytorze Cloud Shell otwórz plik generate-descriptions.py. Zawartość tego pliku jest pokazana poniżej:

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 z pozycją jogi. Opis zostanie uzyskany w wyniku wywołania modelu Gemini, któremu przekażemy odpowiedni 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. W funkcji main() zobaczysz, że wywołuje ona funkcję add_descriptions_to_json i podaje oczekiwany plik wejściowy i wyjściowy.
  2. Funkcja add_descriptions_to_json wykonuje te czynności w przypadku każdego rekordu JSON, czyli informacji o poście dotyczącym jogi:
  3. Wyodrębnia pose_name, sanskrit_name, expertise_levelpose_types.
  4. Wywołuje funkcję generate_description, która tworzy prompt, a następnie wywołuje klasę modelu Langchain VertexAI, aby uzyskać tekst odpowiedzi.
  5. Ten tekst odpowiedzi jest następnie dodawany do obiektu JSON.
  6. Zaktualizowana lista obiektów JSON zostanie zapisana w pliku docelowym.

Uruchommy tę aplikację. Otwórz nowe okno terminala (Ctrl+Shift+C) i wpisz to polecenie:

python generate-descriptions.py

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

Aplikacja zacznie działać. Dodaliśmy 30-sekundowe opóźnienie między rekordami, aby uniknąć limitów szybkości, które mogą występować na nowych kontach Google Cloud. Prosimy o cierpliwość.

Poniżej widać przykładowe uruchomienie w trakcie:

8e830d9ea9b6c60.png

Gdy wszystkie 3 rekordy zostaną wzbogacone o informacje z wywołania Gemini, zostanie wygenerowany plik data/yoga_poses_with_description.json. Możesz to sprawdzić.

Mamy już plik danych. Teraz musimy dowiedzieć się, jak wypełnić nim bazę danych Firestore i wygenerować osadzanie.

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

Mamy już plik data/yoga_poses_with_description.json. Musimy teraz wypełnić nim bazę danych Firestore i wygenerować osadzenia wektorowe dla każdego rekordu. Wektory dystrybucyjne przydadzą się później, gdy będziemy musieli przeprowadzić na nich wyszukiwanie podobieństw za pomocą zapytania użytkownika podanego w języku naturalnym.

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

Aby to zrobić:

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

Kod dla import-data.py jest podany poniżej (fragmenty kodu zostały skrócone):

... 

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

Uruchommy tę aplikację. Otwórz nowe okno terminala (Ctrl+Shift+C) i wpisz to polecenie:

python import-data.py

Jeśli wszystko przebiegnie prawidłowo, zobaczysz komunikat podobny do tego poniżej:

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

Aby sprawdzić, czy rekordy zostały wstawione i czy wygenerowano osadzanie, otwórz stronę Firestore w konsoli Cloud.

504cabdb99a222a5.png

Kliknij (domyślną) bazę danych. Powinna się wyświetlić kolekcja test-poses i wiele dokumentów w tej kolekcji. 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ą użytej przez nas klasy Langchain VertexAIEmbeddings, w której podaliśmy model osadzania text-embedding-004 Vertex AI.

d67113e2dc63cd6b.png

Po przesłaniu rekordów do bazy danych Firestore z osadzonymi wektorami możemy przejść do następnego kroku i sprawdzić, jak przeprowadzić wyszukiwanie podobieństwa wektorowego w Firestore.

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

Teraz utworzymy kolekcję poses, która zawiera pełną listę 160 pozycji jogi. Wygenerowaliśmy dla niej plik importu bazy danych, który możesz bezpośrednio zaimportować. Dzięki temu zaoszczędzisz czas w laboratorium. Proces generowania bazy danych zawierającej opis i wektory osadzenia jest taki sam jak w poprzedniej sekcji.

Zaimportuj bazę danych, wykonując czynności opisane poniżej:

  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.
gsutil mb -l us-central1 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://yoga-database-firestore-export-bucket/2025-01-27T05:11:02_62615  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/2025-01-27T05:11:02_62615

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ę poses, jak pokazano poniżej:

a8f5a6ba69bec69b.png

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

7. Wykonywanie wyszukiwania podobieństwa wektorów w Firestore

Aby przeprowadzić wyszukiwanie podobieństwa wektorowego, użyjemy zapytania od użytkownika. Przykładowe zapytanie to "Suggest me some exercises to relieve back pain".

Zapoznaj się z plikiem search-data.py. Najważniejsza funkcja to wyszukiwanie, która jest pokazana poniżej. Na najwyższym poziomie tworzy klasę osadzania, która będzie używana do generowania osadzania dla zapytania użytkownika. Następnie używa klasy FirestoreVectorStore, aby wywołać funkcję 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 zapytanie z kilkoma przykładami, musisz najpierw wygenerować złożony indeks Firestore, który jest potrzebny do prawidłowego działania zapytań. Jeśli uruchomisz aplikację bez utworzenia indeksu, pojawi się błąd wskazujący, że musisz najpierw utworzyć indeks, wraz z poleceniem, które to umożliwi.

Poniżej znajdziesz 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

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

gcloud firestore indexes composite list

Na liście powinien pojawić się utworzony właśnie indeks.

Wypróbuj teraz to polecenie:

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

Powinno pojawić się kilka rekomendacji. Przykładowe uruchomienie pokazano poniżej:

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

Gdy to zrobisz, będziesz wiedzieć, jak korzystać z bazy danych wektorów Firestore, aby przesyłać rekordy, generować wektory dystrybucyjne i przeprowadzać wyszukiwanie podobieństwa wektorów. Możemy teraz utworzyć aplikację internetową, która zintegruje wyszukiwanie wektorowe z interfejsem internetowym.

8. Aplikacja internetowa

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

Zalecamy zapoznanie się z obydwoma plikami. Zacznij od pliku main.py, który zawiera moduł obsługi /search. Moduł ten pobiera prompt przekazany z pliku HTML index.html. Następnie wywołuje to metodę wyszukiwania, która przeprowadza wyszukiwanie podobieństwa wektorowego omówione w poprzedniej sekcji.

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

Lokalne uruchamianie aplikacji

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

python main.py

Przykładowe wykonanie jest pokazane poniżej:

 * 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 jej adres URL, klikając przycisk Podgląd w przeglądarce widoczny poniżej:

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. Powinno to spowodować pobranie z bazy danych niektórych rekomendacji. Zobaczysz też przycisk Play Audio, który wygeneruje strumień audio na podstawie opisu. Możesz go od razu odsłuchać.

789b4277dc40e2be.png

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

Ostatnim krokiem będzie wdrożenie tej aplikacji w Google Cloud Run. Poniżej znajduje się polecenie wdrażania. Zanim je uruchomisz, zastąp wartości zmiennej (<<YOUR_PROJECT_ID>>) wartościami specyficznymi dla Twojego projektu. Są to wartości, które można 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 w folderze głównym aplikacji. Może też pojawić się prośba o włączenie interfejsów Cloud API Google i potwierdzenie różnych uprawnień.

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

3a6d86fd32e4a5e.png

Po pomyślnym wdrożeniu w danych wyjściowych wdrożenia pojawi się adres URL usługi Cloud Run. Będzie on miał postać:

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

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.

84e1cbf29cbaeedc.png

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

f2b34a8c9011be4c.png

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

faaa5e0c02fe0423.png

W ten sposób zakończyliśmy tworzenie i wdrażanie aplikacji internetowej do rekomendowania pozycji 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 przeprowadza wyszukiwanie podobieństwa wektorowego na podstawie zapytania użytkownika.

Dokumentacja