Mikroserwisowa aplikacja chmurowa, która automatycznie analizuje wgrane zdjęcia przy użyciu Azure AI Vision (generowanie opisów, tagów, wykrywanie obiektów, OCR), indeksuje je wektorowo (Azure OpenAI) i udostępnia w nowoczesnej galerii z wyszukiwaniem semantycznym.
Projekt demonstruje w pełni rozproszoną architekturę opartą na asynchronicznej komunikacji (Azure Service Bus) oraz wykorzystaniu wielu języków programowania.
- Inteligentna analiza obrazu - automatyczne generowanie opisów, wyciąganie tagów oraz odczytywanie tekstu ze zdjęć (OCR) za pomocą Azure AI Vision.
- Asynchroniczne przetwarzanie: - zdjęcia po wgraniu od razu trafiają do galerii ze statusem
pending. Analiza dzieje się w tle, zapobiegając blokowaniu interfejsu użytkownika. - Wyszukiwanie semantyczne - możliwość wyszukania zdjęć używając naturalnego języka np. "pies na plaży". Tekst z obrazów i opisy są zamieniane na wektory (model
text-embedding-3-small), a serwis catalog-cs oblicza podobieństwo kosinusowe, by zwrócić najtrafniejsze wyniki. - Reaktywny interfejs (UI) - interfejs napisany w Streamlit oferuje dynamiczne auto-odświeżanie galerii (co 5 sekund), dzięki czemu statusy (
pending->done/failed) zmieniają się na oczach użytkownika.
- Użytkownik wgrywa plik przez Frontend.
- Ingestion API ładuje plik do Blob Storage, zapisuje metadane w bazie i wysyła wiadomość do kolejki.
- Frontend natychmiast pokazuje zdjęcie w galerii ze statusem oczekiwania.
- Worker odbiera wiadomość, analizuje zdjęcie w zewnętrznych usługach AI i uaktualnia bazę danych o wektory i tagi.
- Użytkownik wpisuje frazę w wyszukiwarce. Catalog API zamienia frazę na wektor za pomocą OpenAI, porównuje z wektorami w Cosmos DB i zwraca posortowane wyniki.
- Azure Storage Account (Blob) - fizyczne przechowywanie plików
.jpg,.pngitp. - Azure Cosmos DB (NoSQL) - szybka i bez-schematowa baza danych przechowująca metadane zdjęć, tagi oraz embeddingi wektorowe.
- Azure Service Bus - kolejka komunikatów rozprzęgająca proces wgrywania od procesu analizy AI.
- Azure AI Vision - usługa kognitywna do ekstrakcji informacji z obrazów.
- Azure OpenAI - dostawca modelu LLM (
text-embedding-3-small) do generowania wielowymiarowych wektorów semantycznych.
Aplikacja składa się z 4 niezależnych komponentów:
| Komponent | Język / Framework | Rola |
|---|---|---|
frontend |
Python (Streamlit) | Interfejs użytkownika. Obsługuje wgrywanie plików (upload), wyświetla galerię z auto-odświeżaniem i obsługuje wyszukiwarkę. |
services/ingestion-js |
JavaScript (Node.js + Express) | Brama wejściowa. Zapisuje fizyczny plik w Azure Blob Storage, tworzy nowy dokument ze statusem pending w bazie Cosmos DB i publikuje zdarzenie (job) na kolejkę Service Bus. |
services/worker-py |
Python | Konsument kolejki pracujący w tle. Pobiera zadanie, wywołuje Azure AI Vision, buduje tekstowy profil zdjęcia, zamienia go na embedding przez Azure OpenAI i aktualizuje dokument w Cosmos DB na status done. |
services/catalog-cs |
C# (.NET 8 Minimal API) | REST API dla galerii. Udostępnia endpoint /photos (pobranie wszystkich zdjęć) oraz /search (wyszukiwanie wektorowe przy użyciu lokalnego obliczania Cosine Similarity). |
Wymagania: Docker, Docker Compose, konto Azure z postawioną infrastrukturą (Cosmos DB, Storage, Service Bus, AI Vision, OpenAI - patrz infra/).
Jeśli masz już wdrożoną infrastrukturę Terraformem, najprościej wyciągnąć dane przez skrypt pomocniczy:
RG=$(cd infra && terraform output -raw resource_group)
./local/gen-env.sh $RGSkrypt zapyta az o connection stringi/klucze i zapisze je do .env w głównym katalogu repo.
Jeśli nie masz skryptu albo wolisz zrobić to ręcznie, skopiuj szablon:
cp .env.example .envi uzupełnij wartości w .env.
Wartości wyciągniesz komendami:
RG=$(cd infra && terraform output -raw resource_group)
az storage account show-connection-string -g $RG -n $(cd infra && terraform output -raw storage_account) --query connectionString -o tsv
az cosmosdb keys list -g $RG -n $(cd infra && terraform output -raw cosmos_account) --query primaryMasterKey -o tsv
az servicebus namespace authorization-rule keys list -g $RG --namespace-name $(cd infra && terraform output -raw servicebus_namespace) --name RootManageSharedAccessKey --query primaryConnectionString -o tsv
az cognitiveservices account keys list -g $RG -n $(cd infra && terraform output -raw vision_account) --query key1 -o tsvdocker compose up --buildTo zbuduje i uruchomi 4 kontenery: ingestion (:3000), worker, catalog (:8080), frontend (:8501).
- Frontend: http://localhost:8501
- Katalog (API): http://localhost:8080/photos
- Ingestion (zdrowie): http://localhost:3000/health
W przeglądarce wgraj zdjęcie w zakładce Upload, przejdź do Galeria - status powinien przejść z przetwarzanie na gotowe.
docker compose downŻeby zrestartować po zmianie kodu (bez cache):
docker compose up --build --force-recreatePipeline (.github/workflows/ci-cd.yml) sam buduje obrazy i wdraża je na Azure Container Apps po każdym wypchnięciu na branch main. Żeby to zadziałało, jednorazowo skonfiguruj poniższe.
az group create -n rg-tfstate -l germanywestcentral
SA_TF="sttf$RANDOM$RANDOM"
az storage account create -n $SA_TF -g rg-tfstate -l germanywestcentral --sku Standard_LRS
az storage container create -n tfstate --account-name $SA_TF
echo "Nazwa konta: $SA_TF"SUB_ID=$(az account show --query id -o tsv)
az ad sp create-for-rbac --name smartphoto-ci --role Contributor --scopes /subscriptions/$SUB_ID --sdk-authZapisz cały wypisany JSON - będzie potrzebny w następnym kroku.
W repo: Settings -> Secrets and variables -> Actions -> New repository secret. Dodaj:
| Nazwa sekretu | Wartość |
|---|---|
AZURE_CREDENTIALS |
cały JSON z az ad sp create-for-rbac --sdk-auth |
ARM_CLIENT_ID |
pole clientId z tego JSON-a |
ARM_CLIENT_SECRET |
pole clientSecret z tego JSON-a |
ARM_SUBSCRIPTION_ID |
pole subscriptionId z tego JSON-a |
ARM_TENANT_ID |
pole tenantId z tego JSON-a |
TFSTATE_RG |
rg-tfstate |
TFSTATE_STORAGE_ACCOUNT |
nazwa konta z kroku 1 (np. sttf189423) |
TFSTATE_CONTAINER |
tfstate |
git add .
git commit -m "Trigger CI/CD"
git push origin mainW zakładce Actions w repo zobaczysz dwa joby:
infra- Terraform stawia/aktualizuje infrastrukturę na Azure,deploy- buduje 4 obrazy Docker, wypycha je do ACR i aktualizuje Container Apps.
Po zielonym przebiegu każdy kolejny git push na main automatycznie zbuduje i wdroży nową wersję aplikacji - bez żadnej ręcznej interwencji.
cd infra
terraform output -raw frontend_urlAby usunąć całą utworzoną infrastrukturę w Azure:
cd infra
terraform destroyPotwierdź operację wpisując:
yes
Po zakończeniu można dodatkowo usunąć zasoby utworzone poza Terraformem:
# usunięcie grupy zasobów przechowującej stan Terraform
az group delete -n rg-tfstate --yes --no-wait
# usunięcie Service Principal używanego do wdrożenia
az ad sp delete --id <CLIENT_ID>Sprawdzenie, czy zasoby zostały usunięte:
az resource list --output tablelub dla konkretnej grupy:
az group list --output table



