Uproszczone zarządzanie danymi głównymi: dopasowanie & Połącz się z generatywną AI

1. Omówienie

Czym jest zarządzanie danymi głównymi?

Głównym zarządzaniem danymi (MDM) jest stworzenie jednego, niezawodnego źródła wiarygodnych danych organizacji o największym znaczeniu. Wyobraź sobie skrupulatnie uporządkowaną bibliotekę, w której każda książka (punkt danych) jest odpowiednio oznaczona, aktualna i łatwa do znalezienia.

Dane główne reprezentują podstawowe, podstawowe podmioty biznesowe niezbędne dla działalności firmy. Oto najważniejsze elementy danych głównych:

  • Podmioty biznesowe: podmioty, takie jak klienci, produkty, dostawcy, lokalizacje i pracownicy. Są to nazwy, którymi zajmuje się Twoja firma.
  • Identyfikatory: unikalne identyfikatory, dzięki którym każdy element jest inny i możliwy do śledzenia w różnych systemach.
  • Atrybuty: cechy opisujące poszczególne podmioty, np. adres klienta, cena produktu itp.

Aby pomóc Ci lepiej zrozumieć dane główne, porównajmy je z danymi transakcyjnymi. Dane dotyczące transakcji rejestrują poszczególne zdarzenia (zakup, dostawa itp.). Dane główne dostarczają natomiast kontekst tych zdarzeń, definiując powiązane z nimi elementy. Na przykład transakcja sprzedażowa zawiera link do danych głównych klienta, produktu i sprzedawcy.

Wdrożenie niezawodnego MDM jest kluczowe w przypadku strategicznego podejmowania decyzji, ale może być złożone i wymagać dużych ilości zasobów. Dlatego w pełni wykorzystują potencjał generatywnej AI, w szczególności modeli takich jak Gemini 1.0 Pro, Gemini 1.0 Pro Vision czy Gemini 1.5 Pro.

2. Cel

W ramach tego ćwiczenia w programie pokażemy, jak Gemini 1.0 Pro upraszcza główne aplikacje do zarządzania danymi, takie jak wzbogacanie i deduplikacja danych citibike_stations w publicznym zbiorze danych BigQuery.

Czego będziesz używać

  1. Publiczny zbiór danych BigQuery bigquery-public-data.new_york_citibike.
  2. Wywołanie funkcji w Gemini (funkcja w Cloud Functions w Cloud Functions, która pobiera informacje o adresie za pomocą interfejsu reverse Geocoding API na potrzeby współrzędnych dostępnych w danych citibike_stations).
  3. Vertex AI Embeddings API i wyszukiwanie wektorowe w BigQuery w celu identyfikowania duplikatów.

Co utworzysz

  1. Utworzysz zbiór danych BigQuery na potrzeby tego przypadku użycia. W tym zbiorze danych utworzysz tabelę docelową z danymi z publicznej tabeli zbioru danych bigquery-public-data.new_york_citibike.citibike_stations.
  2. Wdrożysz funkcję w Cloud Functions, która obejmuje wywoływanie funkcji Gemini na potrzeby standaryzacji adresów.
  3. Przechowujesz wzbogacone dane adresowe w tabelach docelowych (z 2 źródeł podanych na potrzeby tej demonstracji).
  4. Wywołujesz interfejs Vertex AI Embeddings API z BigQuery na danych adresowych.
  5. Wykorzystasz wyszukiwanie wektorowe BigQuery do identyfikowania zduplikowanych rekordów.

Na diagramie poniżej widać przepływ danych i kroki związane z implementacją.

Ogólny przebieg przypadku użycia

3. Wymagania

  • przeglądarki, na przykład Chrome lub Firefox;
  • Projekt Google Cloud z włączonymi płatnościami.

4. Zanim zaczniesz

  1. W konsoli Google Cloud na stronie selektora projektów 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 – środowiska wiersza poleceń działającego w Google Cloud, które zawiera wstępnie zainstalowane narzędzie bq. Kliknij Aktywuj Cloud Shell u góry konsoli Google Cloud.

Obraz przycisku aktywowania Cloud Shell

  1. Po nawiązaniu połączenia z Cloud Shell możesz użyć tego polecenia, aby sprawdzić, czy użytkownik jest już uwierzytelniony i czy identyfikator projektu jest ustawiony na identyfikator Twojego projektu:
gcloud auth list
  1. Uruchom to polecenie w Cloud Shell, aby sprawdzić, czy polecenie gcloud zna Twój projekt.
gcloud config list project
  1. Jeśli Twój projekt nie jest skonfigurowany, ustaw go za pomocą tego polecenia:
gcloud config set project <YOUR_PROJECT_ID>
  1. Przejdź do Gemini w Google Cloud Marketplace, aby włączyć interfejs API. Możesz też użyć tego polecenia w terminalu Cloud Shell:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
  1. Sprawdź, czy interfejsy BigQuery, BigQuery Connection, Cloud Function, Cloud Run, Vertex AI i Cloud Build API są włączone. Alternatywą dla polecenia gcloud jest korzystanie z konsoli za pomocą tego linku.

Więcej informacji o poleceniach i sposobie korzystania z gcloud znajdziesz w dokumentacji.

5. Tworzenie zbioru danych BigQuery i połączenia zewnętrznego

Zacznijmy od utworzenia zbioru danych i połączenia z zasobami Cloud.

Zbiór danych w BigQuery to kontener na wszystkie tabele i obiekty aplikacji.

Aby utworzyć zbiór danych:

  1. Otwórz stronę BigQuery w konsoli Google Cloud.
  2. W panelu Explorer wybierz projekt, w którym chcesz utworzyć zbiór danych.
  3. Rozwiń opcję Działania (ikonę wielokropka) i kliknij Utwórz zbiór danych.

Obraz menu czynności i opcji Utwórz zbiór danych

  1. W polu Identyfikator zbioru danych wpisz mdm_gemini.
  2. Ustaw typ lokalizacji jako Multi-region i zaakceptuj wartość domyślną, czyli US(multiple regions in United States..
  3. Kliknij Utwórz zbiór danych.
  4. Sprawdź w panelu Explorer, czy zbiór danych został utworzony i wyświetlony pod identyfikatorem projektu.

Do interakcji z funkcją w Cloud Functions wymagane jest połączenie z BigQuery. Aby utworzyć funkcję zdalną, musisz utworzyć połączenie z BigQuery. W tym ćwiczeniu w programowaniu użyjemy połączenia BigLake, aby uzyskać dostęp do modelu z BigQuery za pomocą funkcji w Cloud Functions. Połączenia BigLake pomagają połączyć zewnętrzne źródło danych przy zachowaniu szczegółowej kontroli dostępu i zabezpieczeń BigQuery – w naszym przypadku jest to interfejs Vertex AI Gemini Pro API.

Aby utworzyć połączenie z BigLake, wykonaj te czynności:

  1. W panelu Eksplorator na stronie BigQuery kliknij Dodaj.

Konsola BigQuery z zaznaczonym przyciskiem DODAJ, który umożliwia dodanie połączenia zewnętrznego

  1. Kliknij Połączenia z zewnętrznymi źródłami danych.
  2. Z listy Typ połączenia wybierz Modele zdalne Vertex AI, funkcje zdalne oraz BigLake (zasób Cloud).
  3. W polu Connection ID (Identyfikator połączenia) wpisz nazwę połączenia gemini-bq-conn.
  4. Ustaw typ lokalizacji jako Multi-region i zaakceptuj wartość domyślną, czyli US(multiple regions in United States..
  5. Kliknij Utwórz połączenie.
  6. Kliknij Otwórz połączenie,a następnie skopiuj identyfikator konta usługi w panelu Informacje o połączeniu.

Zrzut ekranu z informacjami o połączeniu

  1. Otwórz Administracja Administracja i kliknij Przyznaj dostęp.
  2. W polu Nowe zasady wklej identyfikator konta usługi.
  3. Z listy ról wybierz rolę Vertex AI user, a następnie kliknij Zapisz.

Przyznaj dostęp do zrzutu ekranu konta usługi

Udało Ci się utworzyć zbiór danych i połączenie z BigQuery.

6. Wdrażanie wywoływania funkcji Gemini (funkcja w Cloud Functions w JavaScripcie)

Wykonaj te czynności, aby wdrożyć funkcję w Cloud Functions w języku Java, która obejmuje wywoływanie funkcji Gemini.

  1. Skopiuj repozytorium GitHub z terminalu Cloud Shell za pomocą tego polecenia:
git clone https://github.com/AbiramiSukumaran/GeminiFunctionCalling
  1. Zastąp zmienne YOUR_API_KEY i YOUR_PROJECT_ID swoimi wartościami.

Jeśli przeczytasz tego bloga, wiesz, że implementacje wywołań funkcji korzystają z interfejsu Reverse Geocoding API. Możesz utworzyć własny klucz API_KEY zgodnie z tymi instrukcjami.

  1. W terminalu Cloud Shell przejdź do nowo sklonowanego katalogu projektu GeminiFunctionCalling i uruchom tę instrukcję, aby skompilować i wdrożyć funkcję w Cloud Functions:
gcloud functions deploy gemini-fn-calling --gen2 --region=us-central1 --runtime=java11 --source=. --entry-point=cloudcode.helloworld.HelloWorld --trigger-http

Powiedz „y” gdy pojawi się komunikat „Zezwalaj na nieuwierzytelnione wywołania”. pytania. Najlepiej skonfigurować uwierzytelnianie dla aplikacji firmowych zgodnie z zaleceniem. Ponieważ jest to aplikacja w wersji demonstracyjnej, nie będzie można uwierzytelniać.

Dane wyjściowe to adres URL typu REST w takim formacie:

https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling

  1. Przetestuj tę funkcję w Cloud Functions, uruchamiając w terminalu to polecenie:
gcloud functions call gemini-fn-calling --region=us-central1 --gen2 --data '{"calls":[["40.714224,-73.961452"]]}'

Odpowiedź na losowy przykładowy prompt:

 '{"replies":["{ \"DOOR_NUMBER\": \"277\", \"STREET_ADDRESS\": \"Bedford Ave\", \"AREA\":
 null, \"CITY\": \"Brooklyn\", \"TOWN\": null, \"COUNTY\": \"Kings County\", \"STATE\":
 \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null}}```"]}'

Parametry żądania i odpowiedzi tej funkcji w Cloud Functions zostały zaimplementowane w sposób zgodny ze zdalnym wywoływaniem funkcji BigQuery. Może być bezpośrednio pobierana z bieżących danych BigQuery. Oznacza to, że jeśli dane wejściowe (ostatnie i długie dane) znajdują się w BigQuery, możesz wywołać funkcję zdalną na danych i otrzymać odpowiedź, którą można zapisać lub przetworzyć w BigQuery bezpośrednio.

  1. Uruchom następujące DDL z BigQuery, aby utworzyć funkcję zdalną, która wywołuje tę wdrożoną funkcję w Cloud Functions:
CREATE OR REPLACE FUNCTION
 `mdm_gemini.MDM_GEMINI` (latlng STRING) RETURNS STRING
 REMOTE WITH CONNECTION `us.gemini-bq-conn`
 OPTIONS (
   endpoint = 'https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling', max_batching_rows = 1
 );

Zapytanie testowe, które pozwala użyć utworzonej nowej funkcji zdalnej:

SELECT mdm_gemini.MDM_GEMINI(latlong) z mdm_gemini.CITIBIKE_STATIONS limitu 1;

Jeśli zapytanie testowe korzystające z nowej funkcji zdalnej utworzonej w BigQuery nie powiedzie się z powodu problemu z uprawnieniami Cloud Functions, otwórz Cloud Functions w konsoli Google Cloud i znajdź wdrożoną funkcję w Cloud Functions o nazwie „gemini-fn-calling. Otwórz kartę uprawnień i dodaj podmiot zabezpieczeń jako „allUsers” i przypiszesz do niego rolę „Wywołujący Cloud Functions” aby upewnić się, że funkcje w Cloud Functions są dostępne dla wszystkich użytkowników (tylko dlatego, że jest to aplikacja w wersji demonstracyjnej).

7. Jak obejść ten problem

Jeśli nie masz klucza API_KEY niezbędnego do wywołania funkcji odwrotnego geokodowania lub z jakiegoś powodu funkcja w Cloud Functions nie jest wdrożona, możesz zamiast tego wykonać te czynności:

  1. Pobierz plik CITIBIKE_STATIONS.csv z repozytorium do folderu projektu Cloud Shell i przejdź do niego.
  2. Wyeksportuj dane z pliku CSV do nowego zbioru danych BigQuery mdm_gemini za pomocą tego polecenia w terminalu Cloud Shell:
bq load --source_format=CSV --skip_leading_rows=1 mdm_gemini.CITIBIKE_STATIONS ./CITIBIKE_STATIONS.csv \ name:string,latlng:string,capacity:numeric,num_bikes_available:numeric,num_docks_available:numeric,last_reported:timestamp,full_address_string:string

8. Utwórz tabelę i wzbogać dane adresowe

Krok 1. Utwórz tabelę

Wyświetlenie: pomiń ten krok, jeśli korzystasz z tego obejścia, ponieważ tabela została już utworzona.

Jeśli nie korzystano z obejścia, uruchom następujące DDL w edytorze BigQuery SQL:

CREATE TABLE mdm_gemini.CITIBIKE_STATIONS as (
select  name, latitude || ',' || longitude as latlong, capacity, num_bikes_available, num_docks_available,last_reported,
'' as full_address_string
from bigquery-public-data.new_york_citibike.citibike_stations) ;

Teraz wzbogać dane adresowe, wywołując funkcję zdalną obsługującą współrzędne szerokości i długości geograficznej, które można znaleźć w tabeli. Ustaw następujące warunki danych:

  • Podana w 2024 r.
  • Liczba dostępnych rowerów > 0
  • Pojemność > 100

Uruchom poniższe zapytanie:

update `mdm_gemini.CITIBIKE_STATIONS`
set full_address_string = `mdm_gemini.MDM_GEMINI`(latlong)
where EXTRACT(YEAR FROM last_reported) = 2024 and num_bikes_available > 0 and capacity > 100;

Krok 2. Utwórz drugie źródło danych o lokalizacji stacji rowerów

Nie pomijaj tego kroku, nawet jeśli do utworzenia tabeli korzystasz z obejścia.

W tym kroku utworzysz drugie źródło danych o lokalizacji stacji rowerów na potrzeby tego ćwiczenia z programowania. To pokazanie, że MDM gromadzi dane z wielu źródeł i identyfikuje złotą prawdę.

Uruchom następujące DDL w edytorze BigQuery SQL, aby utworzyć drugie źródło danych o lokalizacji z 2 rekordami. Nazwijmy tę tabelę mdm_gemini.CITIBIKE_STATIONS_SOURCE2 i wstawmy do niej dwa rekordy.

CREATE TABLE mdm_gemini.CITIBIKE_STATIONS_SOURCE2 (name STRING(55), address STRING(1000), embeddings_src ARRAY<FLOAT64>);

insert into mdm_gemini.CITIBIKE_STATIONS_SOURCE2 VALUES ('Location broadway and 29','{ "DOOR_NUMBER": "1593", "STREET_ADDRESS": "Broadway", "AREA": null, "CITY": "New York", "TOWN": null, "COUNTY": "New York County", "STATE": "NY", "COUNTRY": "USA", "ZIPCODE": "10019", "LANDMARK": null}', null);

insert into mdm_gemini.CITIBIKE_STATIONS_SOURCE2 VALUES ('Allen St & Hester','{ "DOOR_NUMBER": "36", "STREET_ADDRESS": "Allen St", "AREA": null, "CITY": "New York", "TOWN": null, "COUNTY": "New York County", "STATE": "NY", "COUNTRY": "USA", "ZIPCODE": "10002", "LANDMARK": null}', null);

9. Generowanie wektorów dystrybucyjnych danych adresowych

Wektory dystrybucyjne to wysokowymiarowe wektory liczbowe, które reprezentują określoną encję, np. fragment tekstu czy plik audio. Modele systemów uczących się używają reprezentacji właściwościowych do kodowania semantyki takich encji, co ułatwia ich analizowanie i porównywanie. Na przykład typową operacją w modelach grupowania, klasyfikacji i rekomendacji jest pomiar odległości między wektorami w obszarze wektora dystrybucyjnego w celu znalezienia elementów, które są najbardziej podobne pod względem semantycznym. Interfejs Vertex AI text-embeddings API umożliwia tworzenie wektorów dystrybucyjnych tekstu przy użyciu generatywnej AI w Vertex AI. Wektory dystrybucyjne tekstu to liczbowe reprezentacje tekstu, które rejestrują zależności między słowami i wyrażeniami. Więcej informacji o umieszczaniu tekstu w Vertex AI znajdziesz tutaj.

  1. Uruchom poniższy model DDL, aby utworzyć model zdalny dla interfejsu API wektorów dystrybucyjnych tekstu Vertex AI:
CREATE OR REPLACE MODEL `mdm_gemini.CITIBIKE_STATIONS_ADDRESS_EMB`
REMOTE WITH CONNECTION `us.gemini-bq-conn`
OPTIONS (ENDPOINT = 'textembedding-gecko@latest');
  1. Teraz, gdy zdalny model wektorów dystrybucyjnych jest już gotowy, wygeneruj wektory dystrybucyjne dla pierwszego źródła i zapiszmy go w tabeli za pomocą tego zapytania:
CREATE TABLE `mdm_gemini.CITIBIKE_STATIONS_SOURCE1` AS (
SELECT *
FROM ML.GENERATE_EMBEDDING(
 MODEL `mdm_gemini.CITIBIKE_STATIONS_ADDRESS_EMB`,
 ( select name, full_address_string as content from `mdm_gemini.CITIBIKE_STATIONS`
 where full_address_string is not null )
  )
);

Zamiast tworzyć nową tabelę, możesz też zapisać pole wyniku wektorów dystrybucyjnych w utworzonej wcześniej tabeli mdm_gemini.CITIBIKE_STATIONS.

  1. Aby wygenerować wektory dystrybucyjne dla danych adresowych w tabeli CITIBIKE_STATIONS_SOURCE2,uruchom to zapytanie:
update `mdm_gemini.CITIBIKE_STATIONS_SOURCE2` a set embeddings_src =
(
SELECT  ml_generate_embedding_result
FROM ML.GENERATE_EMBEDDING(
 MODEL `mdm_gemini.CITIBIKE_STATIONS_ADDRESS_EMB`,
 ( select name, address as content from `mdm_gemini.CITIBIKE_STATIONS_SOURCE2` ))
where name = a.name) where name is not null;

Powinno to spowodować utworzenie wektorów dystrybucyjnych dla drugiego źródła. Zwróć uwagę, że utworzyliśmy w tej samej tabeli CITIBIKE_STATIONS_SOURCE2 pole wektorów dystrybucyjnych.

  1. Aby zwizualizować wektory dystrybucyjne wygenerowane na potrzeby tabel danych źródłowych 1 i 2, uruchom to zapytanie:
select name,address,embeddings_src from `mdm_gemini.CITIBIKE_STATIONS_SOURCE2`;
select name,content,ml_generate_embedding_result from `mdm_gemini.CITIBIKE_STATIONS_SOURCE1`;

Przeprowadźmy teraz wyszukiwanie wektorowe, aby zidentyfikować duplikaty.

10. Przeprowadzanie wyszukiwania wektorowego w celu zgłaszania zduplikowanych adresów

W tym kroku wyszukasz w kolumnie ml_generate_embedding_result tabeli mdm_gemini.CITIBIKE_STATIONS_SOURCE1 2 pierwsze wektory dystrybucyjne, które pasują do każdego wiersza danych w kolumnie embeddings_src tabeli mdm_gemini.CITIBIKE_STATIONS_SOURCE2.

Aby to zrobić, uruchom to zapytanie:

select query.name name1,base.name name2,
/* (select address from mdm_gemini.CITIBIKE_STATIONS_SOURCE2 where name = query.name) content1, base.content content2, */
distance
from VECTOR_SEARCH(
 TABLE mdm_gemini.CITIBIKE_STATIONS_SOURCE1,
 'ml_generate_embedding_result',
 (SELECT * FROM mdm_gemini.CITIBIKE_STATIONS_SOURCE2),
 'embeddings_src',
 top_k => 2
) where query.name <> base.name
order by distance desc;

Tabela, której dotyczy zapytanie: mdm_gemini.CITIBIKE_STATIONS_SOURCE1 w polu ml_generate_embedding_result

Tabela, której używamy jako podstawy: mdm_gemini.CITIBIKE_STATIONS_SOURCE2 w polu embeddings_src

top_k: określa liczbę najbliższych sąsiadów do zwrócenia. Wartością domyślną jest 10. Wartość ujemna jest traktowana jako nieskończoność, co oznacza, że wszystkie wartości są zliczane jako sąsiedzi i zwracani.

distance_type::określa typ danych, które mają być używane do obliczania odległości między dwoma wektorami. Obsługiwane typy odległości to euklidesowa i Cosinus. Wartość domyślna to euklidesowa.

Wynik zapytania jest taki:

Zestaw wyników

Jak widać, dla 2 wierszy w komórce CITIBIKE_STATIONS_SOURCE2 ze zbioru CITIBIKE_STATIONS_SOURCE1 wskazano 2 najbliższych sąsiadów (czyli najbliższe duplikaty). Parametr distance_type nie jest określony, dlatego zakładamy, że jest euklidesowa, a odległość jest odczytywana jako odległości między dwoma źródłami w wartościach TEXT, przy czym najniższa wartość to najbardziej podobne teksty adresowe.

Ustawmy distance_type na Cosinus za pomocą tego zapytania:

select query.name name1,base.name name2,
/* (select address from mdm_gemini.CITIBIKE_STATIONS_SOURCE2 where name = query.name) content1, base.content content2, */
distance
from VECTOR_SEARCH(
 TABLE mdm_gemini.CITIBIKE_STATIONS_SOURCE1,
 'ml_generate_embedding_result',
 (SELECT * FROM mdm_gemini.CITIBIKE_STATIONS_SOURCE2),
 'embeddings_src',
 top_k => 2,distance_type => 'COSINE'
) where query.name <> base.name
order by distance desc;

Wynik zapytania jest taki:

Zestaw wyników 2

Oba zapytania (w obu rodzajach odległości) są uporządkowane według odległości DESCENDING, co oznacza, że wyniki należy wyświetlić w kolejności malejącej odległości. Zauważysz jednak, że kolejność odległości w drugim zapytaniu jest odwrócona. Czy potrafisz zrozumieć, dlaczego?

Tak. Masz rację! W podobieństwie cosinusowym większa liczba oznacza większe podobieństwo i mniejszą odległość. W odległości euklidesowej większa liczba oznacza większą odległość między wartościami.

Więcej informacji o MDM oraz wskazówki dotyczące różnicy i zastosowań metod Euklidesowa i Cosinus znajdziesz na blogu.

11. Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud opłatami za zasoby zużyte w tym poście, wykonaj te czynności:

  1. W konsoli Google Cloud otwórz stronę Zarządzanie zasobami.
  2. Na liście projektów wybierz projekt do usunięcia, a potem kliknij Usuń.
  3. W oknie wpisz identyfikator projektu i kliknij Wyłącz, aby usunąć projekt.
  4. Jeśli chcesz zachować projekt, pomiń powyższe kroki i usuń funkcję w Cloud Functions, przechodząc do Cloud Functions i z listy funkcji zaznacz tę, którą chcesz usunąć, i kliknij Usuń.

12. Gratulacje

Gratulacje! Udało Ci się udowodnić, jak skutecznie można wykorzystać Gemini 1.0 Pro i wywoływanie funkcji w ramach przekształcania kilku działań MDM w uproszczone, a zarazem zaawansowane, deterministyczne i niezawodne funkcje generatywnej AI. Teraz, gdy już wiesz, możesz podzielić się innymi sposobami wdrożenia tego samego przypadku użycia lub innych funkcji MDM. Czy istnieją zbiory danych, które da się zweryfikować, luki informacyjne możesz uzupełnić, lub zadania, które można zautomatyzować za pomocą uporządkowanych wywołań umieszczonych w odpowiedziach generatywnej AI? Szczegółowe informacje znajdziesz w dokumentacji usług Vertex AI, funkcji zdalnych BigQuery, Cloud Functions, Umieszczanie i Wyszukiwania wektorowego. Oto repozytorium GitHub dla tego projektu. Powiedz nam, co udało Ci się osiągnąć dzięki tym szkoleniom.