ā§§. āĻā§āĻŽāĻŋāĻāĻž
āĻāĻĒāύāĻŋ āϝāĻž āϤā§āϰāĻŋ āĻāϰāĻŦā§āύ
āĻāĻ āĻā§āĻĄāϞā§āϝāĻžāĻŦā§, āĻāĻĒāύāĻŋ āĻāĻāĻāύ āĻĄā§āĻā§āϞāĻĒāĻžāϰā§āϰ āĻā§āĻŽāĻŋāĻāĻžāϝāĻŧ āĻ āĻŦāϤā§āϰā§āĻŖ āĻšāϝāĻŧā§ āĻāĻāĻāĻŋ āĻāĻžāϞā§āĻĒāύāĻŋāĻ āϰāĻŋāĻā§āĻāϞ āĻŦā§āϰā§āϝāĻžāύā§āĻĄā§āϰ āĻāύā§āϝ âāĻĢā§āϝāĻžāĻļāύ āĻ ā§āϝāĻžāĻĒâ āύāĻžāĻŽā§āϰ āĻāĻāĻāĻŋ āĻĢā§āϞāĻžāĻāĻžāϰ āĻļāĻĒāĻŋāĻ āĻ ā§āϝāĻžāĻĒ āϤā§āϰāĻŋ āĻāϰāĻŦā§āύāĨ¤ āĻāĻĒāύāĻžāϰ āĻāĻžāĻ āĻšāϞā§: āĻĻā§āĻāĻŋ āĻāĻāĻ-āĻāĻžāϞāĻŋāϤ āĻĢāĻŋāĻāĻžāϰ āϝā§āĻ āĻāϰāĻž, āϝāĻž āĻ āύāϞāĻžāĻāύ āĻļāĻĒāĻŋāĻ-āĻāϰ āĻ āĻāĻŋāĻā§āĻāϤāĻžāĻā§ āĻāĻŽā§āϞ āĻŦāĻĻāϞ⧠āĻĻā§āĻŦā§āĨ¤
- āĻāĻžāϰā§āĻā§āϝāĻŧāĻžāϞ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ â āĻāĻāĻāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āύāĻŋāĻā§āϰ āĻāĻāĻāĻŋ āĻāĻŦāĻŋ āĻāĻĒāϞā§āĻĄ āĻāϰā§āύ, āĻāĻāĻāĻŋ āĻĒā§āĻļāĻžāĻ āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰā§āύ āĻāĻŦāĻ āϏā§āĻ āĻĒā§āĻļāĻžāĻāĻāĻŋ āĻĒāϰāĻž āĻ āĻŦāϏā§āĻĨāĻžāϝāĻŧ āĻāĻāĻ āĻĻā§āĻŦāĻžāϰāĻž āϤā§āϰāĻŋ āύāĻŋāĻā§āϰ āĻāĻāĻāĻŋ āĻāĻŦāĻŋ āĻĻā§āĻāϤ⧠āĻĒāĻžāύāĨ¤
- āĻāĻāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ â āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻ āĻŦāϏā§āĻĨāĻžāύ, āĻāĻĒāϞāĻā§āώ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞā§āϰ āĻĒāĻāύā§āĻĻā§āϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰ⧠āĻāĻāĻāĻŋ āĻāĻāĻ āĻāĻā§āύā§āĻ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻĒā§āĻļāĻžāĻā§āϰ āϏā§āĻĒāĻžāϰāĻŋāĻļ āϤā§āϰāĻŋ āĻāϰ⧠āĻĻā§āϝāĻŧ â āĻāĻŦāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻāĻĨā§āĻĒāĻāĻĨāύā§āϰ āĻŽāĻžāϧā§āϝāĻŽā§ āϏā§āĻā§āϞā§āĻā§ āĻāϰāĻ āĻĒāϰāĻŋāĻŽāĻžāϰā§āĻāύ āĻāϰāϤ⧠āĻĒāĻžāϰā§āύāĨ¤
āĻŽā§āϞ āϧāĻžāϰāĻŖāĻžāĻāĻŋ āĻā§āĻŦāĻ āϏāĻšāĻ: āĻŽāĻžāύā§āώ āϝāĻāύ āĻā§āϰāĻžāϝāĻŧāĻžāϞ āϰā§āĻŽā§ āĻĒā§āĻļāĻžāĻ āĻĒāϰ⧠āĻĻā§āĻā§, āϤāĻāύ āϤāĻžāĻĻā§āϰ āϏā§āĻā§āϞ⧠āĻā§āύāĻžāϰ āϏāĻŽā§āĻāĻžāĻŦāύāĻž āĻ āύā§āĻ āĻŦā§āĻļāĻŋ āĻĨāĻžāĻā§āĨ¤ āĻāĻŋāύā§āϤ⧠āĻ āύāϞāĻžāĻāύā§? āϏā§āĻāĻž āĻā§āĻŦāϞāĻ āĻāύā§āĻĻāĻžāĻ āĻāϰāĻžāĨ¤ āĻāĻ āĻĒā§āϰāĻāϞā§āĻĒāĻāĻŋ āĻā§āϤā§āϰāĻŋāĻŽ āĻŦā§āĻĻā§āϧāĻŋāĻŽāϤā§āϤāĻžāϰ āĻŽāĻžāϧā§āϝāĻŽā§ āϏā§āĻ āĻŦā§āϝāĻŦāϧāĻžāύāĻāĻŋ āĻĒā§āϰāĻŖ āĻāϰā§āĨ¤
āϏā§āĻĨāĻžāĻĒāϤā§āϝā§āϰ āĻāĻ āĻāϞāĻ
Flutter App ââââ HTTP/REST âââââļ ADK Go Backend
â
ââââââââââââŧâââââââââââ
Fitting Room Stylist Catalog
Agent Agent Agent
â
Gemini API + Cloud Storage
āĻŽā§āϞ āĻĒā§āϰāϝā§āĻā§āϤāĻŋ
āĻāĻĒāĻžāĻĻāĻžāύ | āĻĒā§āϰāϝā§āĻā§āϤāĻŋ | āĻāĻĻā§āĻĻā§āĻļā§āϝ |
āĻāĻā§āύā§āĻ āĻĢā§āϰā§āĻŽāĻāϝāĻŧāĻžāϰā§āĻ | Go-āĻāϰ āĻāύā§āϝ ADK (āĻāĻā§āύā§āĻ āĻĄā§āĻā§āϞāĻĒāĻŽā§āύā§āĻ āĻāĻŋāĻ) | āĻŽāĻžāϞā§āĻāĻŋ-āĻāĻā§āύā§āĻ āĻ āϰā§āĻā§āϏā§āĻā§āϰā§āĻļāύ, āϏā§āĻļāύ, āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ |
āĻāĻā§āύā§āĻ āϝā§āĻā§āϤāĻŋ (āĻĒā§āϰā§) | āĻā§āĻŽāĻŋāύāĻŋ ā§Š.ā§§ āĻĒā§āϰ⧠āĻĒā§āϰāĻŋāĻāĻŋāĻ | āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻāĻĻā§āϰ āĻā§āώāĻŽāϤāĻž āĻĻā§āϝāĻŧ |
āĻāĻā§āύā§āĻ āϝā§āĻā§āϤāĻŋ (āĻĢā§āϞā§āϝāĻžāĻļ) | āĻā§āĻŽāĻŋāύāĻŋ ā§Š āĻĢā§āϞā§āϝāĻžāĻļ āĻĒā§āϰāĻŋāĻāĻŋāĻ | āϰā§āĻ āĻāĻŦāĻ āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻāĻĻā§āϰ (āϞāĻžāĻāĻāĻāϝāĻŧā§āĻ āϰāĻžāĻāĻāĻŋāĻ/āϞā§āĻāĻāĻĒ) āĻļāĻā§āϤāĻŋ āϝā§āĻāĻžāϝāĻŧāĨ¤ |
āĻāĻŋāϤā§āϰ āϤā§āϰāĻŋ | āĻā§āĻŽāĻŋāύāĻŋ ⧍.ā§Ģ āĻĢā§āϞā§āϝāĻžāĻļ āĻāĻŽā§āĻ | āĻā§āϰāĻžāĻ-āĻ āύ āĻāĻŦāĻ āĻĒā§āĻļāĻžāĻā§āϰ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰ⧠|
āĻĢā§āϰāύā§āĻāĻāύā§āĻĄ | āĻĢā§āϞāĻžāĻāĻžāϰ (āĻĄāĻžāϰā§āĻ) | āĻā§āϰāϏ-āĻĒā§āϞā§āϝāĻžāĻāĻĢāϰā§āĻŽ āĻ ā§āϝāĻžāĻĒ (āĻāϝāĻŧā§āĻŦ, āĻāĻāĻāĻāϏ, āĻ ā§āϝāĻžāύā§āĻĄā§āϰāϝāĻŧā§āĻĄ) |
āϏā§āĻā§āϰā§āĻ | āĻā§āĻāϞ āĻā§āϞāĻžāĻāĻĄ āϏā§āĻā§āϰā§āĻ | āĻĒāĻŖā§āϝā§āϰ āĻāĻŦāĻŋ āĻāĻŦāĻ āϤā§āϰāĻŋ āĻāϰāĻž āύāĻŋāĻĻāϰā§āĻļāύāĻā§āϞāĻŋ āϏāĻāϰāĻā§āώāĻŖ āĻāϰ⧠|
āĻšā§āϏā§āĻāĻŋāĻ | āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ | āϏāĻžāϰā§āĻāĻžāϰāĻŦāĻŋāĻšā§āύ āĻāύā§āĻā§āĻāύāĻžāϰ āϏā§āĻĨāĻžāĻĒāύ |
⧍. đĻ āĻĒā§āϰā§āĻŦāĻļāϰā§āϤ āĻ āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āϏā§āĻāĻāĻĒ
ā§§. āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āĻāĻĄāĻŋāĻāϰ āĻā§āϞā§āύ
đ āĻāĻĒāύāĻžāϰ āĻŦā§āϰāĻžāĻāĻāĻžāϰ⧠āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āĻāĻĄāĻŋāĻāϰ āĻā§āϞā§āύāĨ¤
āϝāĻĻāĻŋ āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞāĻāĻŋ āϏā§āĻā§āϰāĻŋāύā§āϰ āύā§āĻā§ āĻĒā§āϰāĻĻāϰā§āĻļāĻŋāϤ āύāĻž āĻšāϝāĻŧ:
- āĻāĻŋāĻ â āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ-āĻ āĻā§āϞāĻŋāĻ āĻāϰā§āύ
⧍. āĻĢā§āϞāĻžāĻāĻžāϰ āĻāϏāĻĄāĻŋāĻā§ āϏā§āĻ āĻāĻĒ āĻāϰā§āύ
āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ-āĻāϰ āϏāĻžāĻĨā§ /google/flutter āĻ āĻĢā§āϞāĻžāĻāĻžāϰ āĻāĻā§ āĻĨā§āĻā§āĻ āĻāύāϏā§āĻāϞ āĻāϰāĻž āĻĨāĻžāĻā§āĨ¤ āϝā§āĻšā§āϤ⧠āĻāĻ āĻĄāĻŋāϰā§āĻā§āĻāϰāĻŋāĻāĻŋ āĻ
āύā§āϝ āĻāĻāĻāύ āϏāĻŋāϏā§āĻā§āĻŽ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻŽāĻžāϞāĻŋāĻāĻžāύāĻžāϧā§āύ, āϤāĻžāĻ āĻāĻĒāύāĻŋ āĻĒā§āϰāĻĨāĻŽāĻŦāĻžāϰ flutter āĻāĻžāϞāĻžāύā§āϰ āϏāĻŽāϝāĻŧ āĻāĻāĻāĻŋ fatal: detected dubious ownership āϤā§āϰā§āĻāĻŋ āĻĒāĻžāĻŦā§āύāĨ¤ āĻāĻāĻŋāĻā§ āĻāĻāĻŦāĻžāϰ āĻāĻŋāĻ-āĻāϰ āύāĻŋāϰāĻžāĻĒāĻĻ-āĻĄāĻŋāϰā§āĻā§āĻāϰāĻŋ āϤāĻžāϞāĻŋāĻāĻžāϝāĻŧ āϝā§āĻ āĻāϰā§āύ:
git config --global --add safe.directory /google/flutter
āĻĢā§āϞāĻžāĻāĻžāϰ āĻāĻĒāύāĻžāϰ PATH āĻ āĻāĻā§ āĻāĻŦāĻ āĻāĻžāĻ āĻāϰāĻā§ āĻāĻŋāύāĻž āϤāĻž āϝāĻžāĻāĻžāĻ āĻāϰā§āύ:
flutter --version
āĻĒā§āϰāĻĨāĻŽāĻŦāĻžāϰ āĻāĻžāϞāĻžāϞ⧠āĻĄāĻžāϰā§āĻ āĻāϏāĻĄāĻŋāĻā§ āĻĄāĻžāĻāύāϞā§āĻĄ āĻšāϝāĻŧ āĻāĻŦāĻ āĻĢā§āϞāĻžāĻāĻžāϰ āĻā§āϞāĻāĻŋ āĻŦāĻŋāϞā§āĻĄ āĻšāϝāĻŧ â āĻāĻ āĻŽāĻŋāύāĻŋāĻ āĻ
āĻĒā§āĻā§āώāĻž āĻāϰā§āύāĨ¤ āĻāĻĒāύāĻŋ Flutter 3.x âĸ channel stable . āĻāϰ āĻŽāϤ⧠āĻāĻŋāĻā§ āĻĻā§āĻāϤ⧠āĻĒāĻžāĻŦā§āύāĨ¤
ā§Š. āϰāĻŋāĻĒā§āĻāĻŋāĻāϰāĻŋ āĻā§āϞā§āύ āĻāϰā§āύ
cd ~
git clone https://github.com/gca-americas/fashion-app-demo
cd fashion_app_demo
ā§Ē. āĻĒā§āϰāĻāϞā§āĻĒā§āϰ āĻāĻžāĻ āĻžāĻŽā§ āĻ āύā§āĻŦā§āώāĻŖ āĻāϰā§āύ
fashion_app_demo/
âââ adk_backend/ # Go backend with ADK agents
â âââ main.go # Entry point â wires all agents + REST server
â âââ catalog/ # Catalog Agent â product lookup
â â âââ agent.go
â â âââ catalog.yaml # Product database (YAML)
â â âââ instructions.md # Agent persona prompt
â âââ fittingroom/ # Fitting Room Agent â virtual try-on
â â âââ agent.go
â â âââ instructions.md # Agent persona prompt
â â âââ tool_instructions.md # Image generation prompt
â âââ stylist/ # Stylist Agent â outfit curation
â â âââ agent.go
â â âââ instructions.md # Agent persona + output format
â âââ rootagent/ # Root Agent â routes to the right agent
â â âââ agent.go
â âââ tools/ # Shared tools
â âââ imagetool.go # getProductImage â loads product images
â âââ outfit_gen_tool.go # generate_outfit_image â creates outfit images
â âââ cors_helper.go # CORS middleware + request logging
â
âââ flutter_frontend/ # Flutter cross-platform app
â âââ lib/
â â âââ main.dart # App entry point + Provider setup
â â âââ app_config.dart # Backend URL configuration
â â âââ core_app/ # Pre-built shopping app (browse, cart, etc.)
â â âââ workshop_tasks/ # AI feature code
â â âââ step_1_try_it_on/ # Virtual Try-On flow
â â â âââ providers/ # TryItOnProvider (state management)
â â â âââ services/ # AdkFittingRoomService (HTTP calls)
â â â âââ ui/ # Screens (product detail â try on â fitting room)
â â âââ step_2_style_me/ # Style Me flow
â â âââ models/ # Outfit, StyleRequest data classes
â â âââ providers/ # StylingProvider (state management)
â â âââ services/ # AdkStylingService (HTTP calls)
â â âââ ui/ # Screens (form sheet â outfit carousel)
â âââ assets/images/ # Product catalog images
ā§Š. âī¸ āĻā§āĻāϞ āĻā§āϞāĻžāĻāĻĄ āĻĒā§āϰāĻā§āĻā§āĻ āϏā§āĻāĻāĻĒ
ā§§. āĻāĻāĻāĻŋ āύāϤā§āύ āĻĒā§āϰāĻāϞā§āĻĒ āϤā§āϰāĻŋ āĻāϰā§āύ
gcloud projects create fashion-app-demo --name="Fashion App Demo"
gcloud config set project fashion-app-demo
⧍. āĻāĻāĻāĻŋ āĻŦāĻŋāϞāĻŋāĻ āĻ ā§āϝāĻžāĻāĻžāĻāύā§āĻ āϞāĻŋāĻā§āĻ āĻāϰā§āύ
āĻāĻĒāύāĻžāϰ āĻŦāĻŋāϞāĻŋāĻ āĻ ā§āϝāĻžāĻāĻžāĻāύā§āĻāĻā§āϞāĻŋāϰ āϤāĻžāϞāĻŋāĻāĻž āĻĻāĻŋāύ:
gcloud billing accounts list
āĻĻā§āĻā§āύ
OPEN
āĻāϞāĻžāĻŽāĨ¤ āĻāĻāĻžāύ⧠āĻ
āĻŦāĻļā§āϝāĻ True āϞā§āĻāĻž āĻĨāĻžāĻāϤ⧠āĻšāĻŦā§āĨ¤ āϝāĻĻāĻŋ False āϞā§āĻāĻž āĻĨāĻžāĻā§ (āϝāĻž āĻŽā§āϝāĻŧāĻžāĻĻā§āϤā§āϤā§āϰā§āĻŖ āĻĢā§āϰāĻŋ āĻā§āϰāĻžāϝāĻŧāĻžāϞā§āϰ āĻā§āώā§āϤā§āϰ⧠āϏāĻžāϧāĻžāϰāĻŖ), āϤāĻžāĻšāϞ⧠āĻ
ā§āϝāĻžāĻāĻžāĻāύā§āĻāĻāĻŋ āĻŦāύā§āϧ āĻšāϝāĻŧā§ āĻā§āĻā§ āĻāĻŦāĻ āĻāĻĒāύāĻŋ āĻāϏāϞ⧠āĻā§āύ⧠āĻāĻŋāĻā§āϰ āĻāύā§āϝ āĻ
āϰā§āĻĨ āĻĒā§āϰāĻĻāĻžāύ āĻāϰāĻŦā§āύ āύāĻž â āĻāĻāĻŋāϝāĻŧā§ āϝāĻžāĻāϝāĻŧāĻžāϰ āĻāĻā§ āύāĻŋāĻā§āϰ āĻā§āϰāĻžāĻŦāϞāĻļā§āĻāĻŋāĻ āĻŦā§āϞāĻā§ āĻāϞ⧠āϝāĻžāύāĨ¤
āĻāĻāĻāĻŋ OPEN: True āĻ
ā§āϝāĻžāĻāĻžāĻāύā§āĻā§āϰ ACCOUNT_ID (āϝāĻž 0X0X0X-0X0X0X-0X0X0X āĻāϰ āĻŽāϤ⧠āĻĻā§āĻāϤā§) āĻāĻĒāĻŋ āĻāϰā§āύ āĻāĻŦāĻ āĻāĻĒāύāĻžāϰ āĻĒā§āϰā§āĻā§āĻā§āĻā§āϰ āϏāĻžāĻĨā§ āϞāĻŋāĻā§āĻ āĻāϰā§āύ:
gcloud billing projects link fashion-app-demo \
--billing-account=YOUR_BILLING_ACCOUNT_ID
āϞāĻŋāĻā§āĻāĻāĻŋ āϝāĻžāĻāĻžāĻ āĻāϰā§āύ:
gcloud billing projects describe fashion-app-demo
āĻāĻĒāύāĻžāϰ billingEnabled: true āĻĻā§āĻāĻž āĻāĻāĻŋāϤāĨ¤ āϞāĻŋāĻā§āĻ āĻāϰāĻžāϰ āĻĒāϰā§āĻ āϝāĻĻāĻŋ āĻāĻĒāύāĻŋ billingEnabled: false āĻĻā§āĻā§āύ, āϤāĻžāĻšāϞ⧠āĻ
ā§āϝāĻžāĻāĻžāĻāύā§āĻāĻāĻŋ āĻŦāύā§āϧ āĻāĻā§ ( OPEN: False ) â āύāĻŋāĻā§āϰ āĻā§āϰāĻžāĻŦāϞāĻļā§āĻāĻŋāĻ āĻŦā§āϞāĻāĻāĻŋ āĻĻā§āĻā§āύāĨ¤
ā§Š. āĻĒā§āϰāϝāĻŧā§āĻāύā§āϝāĻŧ āĻāĻĒāĻŋāĻāĻāĻā§āϞ⧠āϏāĻā§āϰāĻŋāϝāĻŧ āĻāϰā§āύ
gcloud services enable \
aiplatform.googleapis.com \
storage.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com
āĻāĻĒāĻŋāĻāĻ | āĻāĻĻā§āĻĻā§āĻļā§āϝ |
| āĻāĻžāϰā§āĻā§āĻā§āϏ āĻāĻāĻ â |
| āĻā§āϞāĻžāĻāĻĄ āϏā§āĻā§āϰā§āĻ â āĻĒāĻŖā§āϝā§āϰ āĻā§āϝāĻžāĻāĻžāϞāĻā§āϰ āĻāĻŦāĻŋ āĻāĻŦāĻ āϤā§āϰāĻŋ āĻāϰāĻž āĻā§āϰāĻžāĻ-āĻ āύ āĻĢāϞāĻžāĻĢāϞ āϏāĻāϰāĻā§āώāĻŖ āĻāϰ⧠|
| āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ â āĻŦā§āϝāĻžāĻāĻāύā§āĻĄāĻā§ āĻāĻāĻāĻŋ āϏāĻžāϰā§āĻāĻžāϰāϞā§āϏ āĻāύā§āĻā§āĻāύāĻžāϰ āĻšāĻŋāϏā§āĻŦā§ āĻšā§āϏā§āĻ āĻāϰ⧠|
| āĻā§āϞāĻžāĻāĻĄ āĻŦāĻŋāϞā§āĻĄ â āϏā§āϰā§āϏ āĻĨā§āĻā§ āĻĄāĻāĻžāϰ āĻāĻŽā§āĻ āϤā§āϰāĻŋ āĻāϰ⧠|
| āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āϰā§āĻāĻŋāϏā§āĻā§āϰāĻŋ â āύāĻŋāϰā§āĻŽāĻŋāϤ āĻĄāĻāĻžāϰ āĻāĻŽā§āĻ āϏāĻāϰāĻā§āώāĻŖ āĻāϰ⧠|
ā§Ē. āĻāĻāĻāĻŋ GCS āĻŦāĻžāĻā§āĻ āϤā§āϰāĻŋ āĻāϰā§āύ
export PROJECT_ID=$(gcloud config get-value project)
gcloud storage buckets create gs://fashion-app-$PROJECT_ID \
--location=us-central1 \
--uniform-bucket-level-access
ā§Ģ. āĻĒāĻŖā§āϝā§āϰ āĻā§āϝāĻžāĻāĻžāϞāĻā§āϰ āĻāĻŦāĻŋ āĻāĻĒāϞā§āĻĄ āĻāϰā§āύ
āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ getProductImage āĻā§āϞāĻāĻŋ gs://$GCS_BUCKET/catalog-assets/images/ āĻĨā§āĻā§ āĻĄā§āĻāĻž āĻĒāĻĄāĻŧā§āĨ¤ gs://$GCS_BUCKET/catalog-assets/images/ āĻā§āϝāĻžāĻāĻžāϞāĻā§āϰ āĻāĻŦāĻŋāĻā§āϞ⧠āĻ āĻŋāĻ āĻāĻ āĻĒāĻžāĻĨā§ āĻāĻĒāϞā§āĻĄ āĻāϰā§āύ:
cd ~/fashion_app_demo
gcloud storage cp flutter_frontend/assets/images/*.png \
gs://fashion-app-$PROJECT_ID/catalog-assets/images/
āĻāĻĒāϞā§āĻĄāĻāĻŋ āϝāĻžāĻāĻžāĻ āĻāϰā§āύ (āĻāĻĒāύāĻŋ .png āĻĢāĻžāĻāϞāĻā§āϞāĻŋāϰ āĻāĻāĻāĻŋ āϤāĻžāϞāĻŋāĻāĻž āĻĻā§āĻāϤ⧠āĻĒāĻžāĻŦā§āύ):
gcloud storage ls gs://fashion-app-$PROJECT_ID/catalog-assets/images/
ā§Ŧ. .env āĻĢāĻžāĻāϞāĻāĻŋ āĻāύāĻĢāĻŋāĻāĻžāϰ āĻāϰā§āύāĨ¤
cd ~/fashion_app_demo/adk_backend
cat > .env << EOF
GOOGLE_CLOUD_PROJECT=$PROJECT_ID
GCS_BUCKET=fashion-app-$PROJECT_ID
EOF
ā§. āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύā§āϰ āĻĄāĻŋāĻĢāϞā§āĻ āĻā§āϰā§āĻĄā§āύāĻļāĻŋāϝāĻŧāĻžāϞ āĻĻāĻŋāϝāĻŧā§ āĻĒā§āϰāĻŽāĻžāĻŖā§āĻāϰāĻŖ āĻāϰā§āύ
āϏā§āĻĨāĻžāύā§āϝāĻŧāĻāĻžāĻŦā§ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻāĻžāϞ⧠āĻāϰāĻžāϰ āĻāĻā§ āĻāĻĒāύāĻžāĻā§ āĻ
āĻŦāĻļā§āϝāĻ āĻāĻāĻŋ āĻāĻžāϞāĻžāϤ⧠āĻšāĻŦā§āĨ¤ āĻā§ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄāĻāĻŋ āĻāĻžāϰā§āĻā§āĻā§āϏ āĻāĻāĻ (āĻā§āĻŽāĻŋāύāĻŋ) āĻāĻŦāĻ āĻā§āϞāĻžāĻāĻĄ āϏā§āĻā§āϰā§āĻā§ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻāϞ āĻĒā§āϰāĻŽāĻžāĻŖā§āĻāϰāĻŖā§āϰ āĻāύā§āϝ āĻāĻĄāĻŋāϏāĻŋ (ADC) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āĨ¤ āĻāĻĄāĻŋāϏāĻŋ āĻāĻžāĻĄāĻŧāĻž, āĻŦā§āϝāĻžāĻāĻāύā§āĻĄāĻāĻŋ āĻāĻžāϞ⧠āĻšāĻŦā§ āĻ āĻŋāĻāĻ, āĻāĻŋāύā§āϤ⧠āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻā§āϰāĻžāĻ-āĻ
āύ āϰāĻŋāĻā§āϝāĻŧā§āϏā§āĻ ā§Ēā§Ļā§§ CREDENTIALS_MISSING ) āϤā§āϰā§āĻāĻŋāϰ āĻāĻžāϰāĻŖā§ āĻŦā§āϝāϰā§āĻĨ āĻšāĻŦā§āĨ¤
āĻāĻāĻāĻŋ āĻĒāϰāĻŋāĻāϝāĻŧāĻĒāϤā§āϰ āĻĻāĻŋāϝāĻŧā§āĻ āĻāĻāϝāĻŧ āĻĒāϰāĻŋāώā§āĻŦāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āϝāĻžāĻŦā§āĨ¤ āĻāĻ āĻĻā§āĻāĻŋ āĻāĻŽāĻžāύā§āĻĄ āĻā§āϰāĻŽāĻžāύā§āϏāĻžāϰ⧠āĻāĻžāϞāĻžāύ:
# 1. Log in (opens a browser; in Cloud Shell, paste the verification code back)
gcloud auth application-default login
# 2. Attach your project as the quota / billing project for ADC
gcloud auth application-default set-quota-project $(gcloud config get-value project)
ADC āϏā§āϏā§āĻĨ āĻāĻā§ āĻāĻŋāύāĻž āϝāĻžāĻāĻžāĻ āĻāϰā§āύ:
gcloud auth application-default print-access-token | head -c 20 && echo "..."
āĻāĻĒāύāĻŋ āĻāĻāĻāĻŋ āĻā§āĻā§āύā§āϰ āĻĒā§āϰāĻžāϝāĻŧ ⧍ā§ĻāĻāĻŋ āĻ
āĻā§āώāϰ āĻĻā§āĻāϤ⧠āĻĒāĻžāĻŦā§āύ, āϝāĻžāϰ āĻĒāϰ⧠... āĻĨāĻžāĻāĻŦā§āĨ¤ āϝāĻĻāĻŋ āĻā§āύ⧠āϤā§āϰā§āĻāĻŋ āĻšāϝāĻŧ, āϤāĻžāϰ āĻŽāĻžāύ⧠āϞāĻāĻāύāĻāĻŋ āϏāĻĢāϞ āĻšāϝāĻŧāύāĻŋ â āϧāĻžāĻĒ ā§§ āĻāĻŦāĻžāϰ āĻāĻžāϞāĻžāύāĨ¤
ā§Ē. đī¸ āϏā§āĻĨāĻžāĻĒāϤā§āϝā§āϰ āϏāĻāĻā§āώāĻŋāĻĒā§āϤ āĻŦāĻŋāĻŦāϰāĻŖ
āĻāĻāύ āϝā§āĻšā§āϤ⧠āĻĒāϰāĻŋāĻŦā§āĻļ āĻĒā§āϰāϏā§āϤā§āϤ, āĻā§āĻĄ āĻĻā§āĻāĻžāϰ āĻāĻā§ āĻāϞā§āύ āϏāĻŋāϏā§āĻā§āĻŽāĻāĻŋ āĻā§āĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰ⧠āϤāĻž āĻŦā§āĻā§ āύā§āĻāϝāĻŧāĻž āϝāĻžāĻāĨ¤
āĻāĻžāϰ-āĻāĻā§āύā§āĻ āϏāĻŋāϏā§āĻā§āĻŽ
āĻŦā§āϝāĻžāĻāĻāύā§āĻĄāĻāĻŋ Go-āĻāϰ āĻāύā§āϝ ADK (āĻāĻā§āύā§āĻ āĻĄā§āĻā§āϞāĻĒāĻŽā§āύā§āĻ āĻāĻŋāĻ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻāĻāĻāĻŋ āĻŽāĻžāϞā§āĻāĻŋ-āĻāĻā§āύā§āĻ āϏāĻŋāϏā§āĻā§āĻŽ āĻšāĻŋāϏā§āĻŦā§ āϤā§āϰāĻŋ āĻāϰāĻž āĻšāϝāĻŧā§āĻā§āĨ¤ āĻāĻžāϰāĻāĻŋ āĻāĻā§āύā§āĻ āĻāĻāϏāĻžāĻĨā§ āĻāĻžāĻ āĻāϰā§, āϝāĻžāĻĻā§āϰ āĻĒā§āϰāϤā§āϝā§āĻā§āϰ āĻāĻāĻāĻŋ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻĻāĻžāϝāĻŧāĻŋāϤā§āĻŦ āϰāϝāĻŧā§āĻā§:
ââââââââââââââââ
â Root Agent â â Routes requests to the right agent
â (gemini-3- â
â flash- â
â preview) â
ââââââââŦââââââââ
â
ââââââââââââââââŧâââââââââââââââ
âŧ âŧ âŧ
ââââââââââââââââââ ââââââââââââ ââââââââââââââââââ
â Fitting Room â â Catalog â â Stylist â
â Agent â â Agent â â Agent â
â (gemini-3.1- â â (gemini- â â (gemini-3.1- â
â pro-preview) â â 3-flash-â â pro-preview) â
â â â preview)â â â
â Tools: â â â â Tools: â
â âĸ fitting_tool â â Tools: â â âĸ fitting_tool â
â âĸ getProduct â â âĸ list â â âĸ getProduct â
â Image â â Products â â Image â
â âĸ catalog_agentâ â âĸ get â â âĸ catalog_agentâ
â (delegation) â â Product â â (delegation) â
â â â Image â â âĸ generate_ â
ââââââââââââââââââ ââââââââââââ â outfit_image â
ââââââââââââââââââ
āĻāĻā§āύā§āĻ | āĻŽāĻĄā§āϞ | āĻā§āĻŽāĻŋāĻāĻž |
āĻŽā§āϞ āĻāĻā§āύā§āĻ | | āĻā§āϰāĻžāĻĢāĻŋāĻ āĻĒā§āϞāĻŋāĻļāĨ¤ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻŦāĻžāϰā§āϤāĻž āĻĒāĻĄāĻŧā§ āĻāĻŦāĻ āϏāĻ āĻŋāĻ āĻŦāĻŋāĻļā§āώāĻā§āĻ āĻāĻā§āύā§āĻā§āϰ āĻāĻžāĻā§ āĻĻāĻžāϝāĻŧāĻŋāϤā§āĻŦ āĻ āϰā§āĻĒāĻŖ āĻāϰā§āĨ¤ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻĻā§āϰā§āϤ āĻ āĻšāĻžāϞāĻāĻž āĻŽāĻĄā§āϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āĻāĻžāϰāĻŖ āĻāĻā§ āĻļā§āϧ⧠āĻĒāĻĨ āύāĻŋāϰā§āϧāĻžāϰāĻŖā§āϰ āϏāĻŋāĻĻā§āϧāĻžāύā§āϤ āύāĻŋāϤ⧠āĻšāϝāĻŧāĨ¤ |
āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻ | | āĻĒāĻŖā§āϝ āĻŦāĻŋāĻļā§āώāĻā§āĻāĨ¤ āĻāĻāĻāĻŋ YAML āĻĢāĻžāĻāϞ āĻĨā§āĻā§ āĻĒāĻŖā§āϝā§āϰ āĻā§āϝāĻžāĻāĻžāϞāĻ āϞā§āĻĄ āĻāϰ⧠āĻāĻŦāĻ āĻĒāĻŖā§āϝ āϏāĻŽā§āĻĒāϰā§āĻāĻŋāϤ āĻĒā§āϰāĻļā§āύā§āϰ āĻāϤā§āϤāϰ āĻĻā§āϝāĻŧāĨ¤ āĻāĻāĻŋ āĻŦā§āĻļ āĻšāĻžāϞāĻāĻž āĻĒā§āϰāĻā§āϤāĻŋāϰ â āĻāϰ āĻāĻžāĻ āĻļā§āϧ⧠āĻĄā§āĻāĻž āĻā§āĻāĻā§ āĻŦā§āϰ āĻāϰāĻžāĨ¤ |
āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻā§āύā§āĻ | | āĻāĻžāϰā§āĻā§āϝāĻŧāĻžāϞ āĻā§āϰāĻžāĻ-āĻ āύ āϏā§āĻĒā§āĻļāĻžāϞāĻŋāϏā§āĻāĨ¤ āĻāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ āĻ āĻĒāĻŖā§āϝā§āϰ āĻāĻŦāĻŋ āύāĻŋāϝāĻŧā§, āϏā§āĻ āĻĒāĻŖā§āϝāĻāĻŋ āĻĒāϰāĻŋāĻšāĻŋāϤ āĻŦā§āϝāĻā§āϤāĻŋāϰ āĻāĻāĻāĻŋ āϏāĻŽāύā§āĻŦāĻŋāϤ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰā§āĨ¤ āĻāĻāĻŋ āĻāϰāĻ āĻāύā§āύāϤ āĻāĻāĻāĻŋ āĻŽāĻĄā§āϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āĻāĻžāϰāĻŖ āĻāĻāĻŋāĻā§ āĻāĻŦāĻŋ āĻŦāĻŋāĻļā§āϞā§āώāĻŖ āĻāϰ⧠āϏāĻŋāĻĻā§āϧāĻžāύā§āϤ āύāĻŋāϤ⧠āĻšāϝāĻŧāĨ¤ |
āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ | | āĻĢā§āϝāĻžāĻļāύ āĻāĻĒāĻĻā§āώā§āĻāĻžāĨ¤ āϏā§āĻĨāĻžāύ, āĻāĻĒāϞāĻā§āώ āĻāĻŦāĻ āĻĒāĻāύā§āĻĻā§āϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰ⧠āĻāĻāĻŋ āĻā§āϝāĻžāĻāĻžāϞāĻ āĻĨā§āĻā§ ā§ŠāĻāĻŋ āĻĒā§āĻļāĻžāĻā§āϰ āϏāĻŽāύā§āĻŦāϝāĻŧ āϤā§āϰāĻŋ āĻāϰā§āĨ¤ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻĒā§āĻļāĻžāĻā§āϰ āĻāύā§āϝ āĻā§āϰāĻžāĻ-āĻ āύ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāĻāĻžāĻĄāĻŧāĻžāĻ, āϏā§āĻāύāĻļā§āϞ āϝā§āĻā§āϤāĻŋāϰ āĻāύā§āϝ āϏāĻā§āώāĻŽ āĻŽāĻĄā§āϞāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āĨ¤ |
āĻĒā§āϰāĻŦā§āĻļ āĻŦāĻŋāύā§āĻĻā§: main.go
āϏāĻŦāĻāĻŋāĻā§ main.go āĻĨā§āĻā§ āĻļā§āϰ⧠āĻšāϝāĻŧ, āϝāĻž āĻāĻā§āύā§āĻāĻā§āϞā§āĻā§ āĻāĻāϤā§āϰāĻŋāϤ āĻāϰ⧠āĻāĻŦāĻ HTTP āϏāĻžāϰā§āĻāĻžāϰ āĻāĻžāϞ⧠āĻāϰā§:
// main.go â simplified for clarity
func main() {
godotenv.Load() // Load .env file
// 1. Create the artifact storage (GCS-backed)
artifacts, _ := gcsartifact.NewService(ctx, bucket)
// 2. Build agents bottom-up (dependencies first)
catagent, _ := catalog.NewCatalogAgent(apikey, "catalog/catalog.yaml")
fitagent, _ := fittingroom.NewFittingRoomAgent(apikey, catagent)
stylistAgent, _ := stylist.NewStylistAgent(apikey, catagent)
ragent, _ := rootagent.NewRootAgent(apikey, fitagent, catagent, stylistAgent)
// 3. Register all agents with a multi-loader
loader, _ := agent.NewMultiLoader(ragent, fitagent, catagent, stylistAgent)
// 4. Create the ADK REST server
restHandler, _ := adkrest.NewServer(adkrest.ServerConfig{
SessionService: session.InMemoryService(),
MemoryService: memory.InMemoryService(),
AgentLoader: loader,
ArtifactService: artifacts,
})
// 5. Mount behind /api/ with CORS support
r := mux.NewRouter()
r.Use(tools.LocalhostCORS)
r.PathPrefix("/api/").Handler(
http.StripPrefix("/api", tools.LogHandler(restHandler)))
http.Server{Addr: ":8080", Handler: r}.ListenAndServe()
}
āĻāϝāĻŧā§āĻāĻāĻŋ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻŦāĻŋāώāϝāĻŧ āϞāĻā§āώāĻŖā§āϝāĻŧ:
- āĻāĻā§āύā§āĻāĻā§āϞ⧠āύāĻŋāĻ āĻĨā§āĻā§ āĻāĻĒāϰ⧠āϤā§āϰāĻŋ āĻāϰāĻž āĻšāϝāĻŧ : āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻāĻāĻŋ āĻĒā§āϰāĻĨāĻŽā§ āϤā§āϰāĻŋ āĻāϰāĻž āĻšāϝāĻŧ, āĻāĻžāϰāĻŖ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ āĻāĻāϝāĻŧāĻ āĻāϰ āĻāĻĒāϰ āύāĻŋāϰā§āĻāϰāĻļā§āϞ (āϤāĻžāϰāĻž āĻĒāĻŖā§āϝ āĻā§āĻāĻāĻžāϰ āĻāĻžāĻāĻāĻŋ āĻāϰ āĻāĻĒāϰ āĻ āϰā§āĻĒāĻŖ āĻāϰā§)āĨ¤
-
agent.NewMultiLoaderāĻāĻžāϰāĻāĻŋ āĻāĻā§āύā§āĻāĻā§āĻ āϰā§āĻāĻŋāϏā§āĻāĻžāϰ āĻāϰā§, āϝāĻžāϤ⧠REST API āύāĻžāĻŽā§āϰ āϏāĻžāĻšāĻžāϝā§āϝ⧠āϏā§āĻā§āϞā§āϰ āϝā§āĻā§āύā§āĻāĻŋāϤ⧠āϰāĻžāĻāĻ āĻāϰāϤ⧠āĻĒāĻžāϰā§āĨ¤ -
adkrest.NewServerāϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ REST API āĻĒā§āϰāĻĻāĻžāύ āĻāϰ⧠â āĻāĻĒāύāĻžāĻā§ āύāĻŋāĻā§ āĻĨā§āĻā§ āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻ āĻšā§āϝāĻžāύā§āĻĄāϞāĻžāϰ āϞāĻŋāĻāϤ⧠āĻšāϝāĻŧ āύāĻžāĨ¤ ADK āĻāĻĒāύāĻžāĻā§ āϏā§āĻļāύ āĻŽā§āϝāĻžāύā§āĻāĻŽā§āύā§āĻ, āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āϏā§āĻā§āϰā§āĻ āĻāĻŦāĻ āĻāĻā§āύā§āĻ āĻāĻā§āϏāĻŋāĻāĻŋāĻāĻļāύā§āϰ āϏā§āĻŦāĻŋāϧāĻž āϏāϰāĻžāϏāϰāĻŋ āĻĻāĻŋāϝāĻŧā§ āĻĨāĻžāĻā§āĨ¤ -
session.InMemoryService()āϏā§āĻļāύāĻā§āϞā§āĻā§ āĻŽā§āĻŽāϰāĻŋāϤ⧠āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§āĨ¤ āĻāϰ āĻŽāĻžāύ⧠āĻšāϞā§, āϏāĻžāϰā§āĻāĻžāϰ āϰāĻŋāϏā§āĻāĻžāϰā§āĻ āĻšāϞ⧠āϏā§āĻļāύāĻā§āϞ⧠āĻšāĻžāϰāĻŋāϝāĻŧā§ āϝāĻžāϝāĻŧ, āϝāĻž āĻĄā§āĻŽā§āϰ āĻāύā§āϝ āĻ āĻŋāĻ āĻāĻā§āĨ¤ āĻĒā§āϰā§āĻĄāĻžāĻāĻļāύā§, āĻāĻĒāύāĻžāϰ āĻāĻāĻāĻŋ āĻĒāĻžāϰāϏāĻŋāϏā§āĻā§āύā§āĻ āϏā§āĻā§āϰ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻāĻāĻŋāϤāĨ¤ -
gcsartifact.NewServiceāĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ (āϤā§āϰāĻŋ āĻāϰāĻž āĻāĻŦāĻŋ) āĻā§āĻāϞ āĻā§āϞāĻžāĻāĻĄ āϏā§āĻā§āϰā§āĻā§ āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§, āĻĢāϞ⧠āϏā§āĻā§āϞ⧠āĻāĻāĻžāϧāĻŋāĻ āĻ āύā§āϰā§āϧā§āϰ āĻĒāϰā§āĻ āĻ āĻā§āώāϤ āĻĨāĻžāĻā§ āĻāĻŦāĻ GCS URI-āĻāϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻļā§āϝāĻŧāĻžāϰ āĻāϰāĻž āϝāĻžāϝāĻŧāĨ¤
ā§Ģ. đ¤ āĻāĻĄāĻŋāĻā§ (āĻāĻā§āύā§āĻ āĻĄā§āĻā§āϞāĻĒāĻŽā§āύā§āĻ āĻāĻŋāĻ) āύāĻŋāϝāĻŧā§ āĻŦāĻŋāϏā§āϤāĻžāϰāĻŋāϤ āĻāϞā§āĻāύāĻž
ADK āĻā§?
āĻāĻā§āύā§āĻ āĻĄā§āĻā§āϞāĻĒāĻŽā§āύā§āĻ āĻāĻŋāĻ (ADK) āĻšāϞ⧠āĻā§āĻāϞā§āϰ āĻāĻāĻāĻŋ āĻāĻĒā§āύ-āϏā§āϰā§āϏ āĻĢā§āϰā§āĻŽāĻāϝāĻŧāĻžāϰā§āĻ, āϝāĻž āĻĻāĻŋāϝāĻŧā§ Go (āĻāĻŦāĻ Python/Java) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻāĻāĻ āĻāĻā§āύā§āĻ āϤā§āϰāĻŋ āĻāϰāĻž āϝāĻžāϝāĻŧāĨ¤ āĻāĻāĻŋ āĻāĻĒāύāĻžāϰ āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύ āĻāĻŦāĻ āĻā§āĻŽāĻŋāύāĻŋ āĻāĻĒāĻŋāĻāĻ-āĻāϰ āĻŽāϧā§āϝāĻŦāϰā§āϤ⧠āϏā§āϤāϰ āĻšāĻŋāϏā§āĻŦā§ āĻāĻžāĻ āĻāϰā§āĨ¤
āĻāĻĒāύāĻŋ āϏāϰāĻžāϏāϰāĻŋ āĻā§āĻŽāĻŋāύāĻŋ āĻāĻĒāĻŋāĻāĻ āĻāϞ āĻāϰāϤ⧠āĻĒāĻžāϰā§āύ āĨ¤ āĻāĻŋāύā§āϤ⧠āϝāĻāύ āĻāĻĒāύāĻžāϰ āĻ ā§āϝāĻžāĻĒā§āϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āĻšāĻŦā§:
- āĻā§āϝāĻžāĻāĻžāϞāĻ āĻĨā§āĻā§ āĻĒāĻŖā§āϝ āĻ āύā§āϏāύā§āϧāĻžāύ āĻāϰā§āύ
- āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āϤā§āϞāĻž āĻāĻŦāĻŋāϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰ⧠āĻāĻŽā§āĻ āϤā§āϰāĻŋ āĻāϰā§āύāĨ¤
- āĻŽāύ⧠āĻāϰā§āύ āĻāĻā§ āĻā§āύ āĻĒā§āĻļāĻžāĻāĻā§āϞā§āϰ āĻĒāϰāĻžāĻŽāϰā§āĻļ āĻĻā§āĻāϝāĻŧāĻž āĻšāϝāĻŧā§āĻāĻŋāϞāĨ¤
- āĻāĻāĻžāϧāĻŋāĻ āĻāĻāĻ āĻāĻā§āύā§āĻā§āϰ āĻŽāϧā§āϝ⧠āϏāĻŽāύā§āĻŦāϝāĻŧ āϏāĻžāϧāύ āĻāϰā§āύ
āĻāĻĒāύāĻžāϰ āĻāĻāĻāĻŋ āĻāĻžāĻ āĻžāĻŽā§ āĻĒā§āϰāϝāĻŧā§āĻāύāĨ¤ ADK āϏā§āĻ āĻāĻžāĻ āĻžāĻŽā§āĻāĻŋ āĻĒā§āϰāĻĻāĻžāύ āĻāϰā§āĨ¤
āĻāĻā§āύā§āĻ āϞā§āĻĒ
āĻĒā§āϰāϤāĻŋāĻāĻŋ ADK āĻāĻā§āύā§āĻ āĻāĻāĻāĻŋ āĻāĻā§āϰ āĻ āύā§āϏāϰāĻŖ āĻāϰā§:
1. Receive a message (from user or another agent)
2. Think â the LLM reasons about what to do
3. Act â call a tool, delegate to a sub-agent, or respond
4. Return â send the result back
āĻāĻ āϞā§āĻĒāĻāĻŋ āĻāĻāĻāĻŋāĻŽāĻžāϤā§āϰ āĻ āύā§āϰā§āϧā§āϰ āĻŽāϧā§āϝ⧠āĻāĻāĻžāϧāĻŋāĻāĻŦāĻžāϰ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ āĻšāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāĻĻāĻžāĻšāϰāĻŖāϏā§āĻŦāϰā§āĻĒ, āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ āϝāĻž āĻāϰāϤ⧠āĻĒāĻžāϰā§:
- "āϏā§āĻāϤ āĻā§āϰāĻŽāĻŖā§āϰ āĻāύā§āϝ āĻāĻŽāĻžāĻā§ āϏāĻžāĻāĻŋāϝāĻŧā§ āĻĻāĻŋāύ" āĻā§āϰāĻšāĻŖ āĻāϰā§āύ
- āĻĒāĻŖā§āϝā§āϰ āϤāĻžāϞāĻŋāĻāĻž āĻĒā§āϤā§
catalog_agentāĻā§āϞāĻāĻŋ āĻāϞ āĻāϰā§āύāĨ¤ - ā§ŠāĻāĻŋ āĻĒā§āĻļāĻžāĻā§āϰ āϏāĻāĻŽāĻŋāĻļā§āϰāĻŖ āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰā§āύ
- āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰāĻžāϰ āĻāύā§āϝ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻĒā§āĻļāĻžāĻā§āϰ āĻāύā§āϝ
fitting_toolāĻāϞ āĻāϰā§āύāĨ¤ - āĻāĻžāĻ āĻžāĻŽā§āĻāϤ JSON āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻž āĻĢā§āϰāϤ āĻĻāĻŋāύ
āĻŽā§āϞ āϧāĻžāϰāĻŖāĻž (āĻāĻ āϰāĻŋāĻĒā§ āĻĨā§āĻā§ āύā§āĻāϝāĻŧāĻž āĻā§āĻĄ āϏāĻš)
āĻāϞāĻāϞāĻāĻŽ āĻāĻā§āύā§āĻ
āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ āĻāĻ āύ āĻāĻāĻāĨ¤ llmagent.New() āĻĻāĻŋāϝāĻŧā§ āϤā§āϰāĻŋ :
// From catalog/agent.go
agent, err := llmagent.New(llmagent.Config{
Name: "catalog_agent", // Unique identifier
Model: m, // Which LLM to use
Description: "An agent that can search and list products from the catalog",
Instruction: instructions, // Persona prompt (embedded from .md file)
Tools: []tool.Tool{listTool, imageTool}, // What the agent can do
})
Instruction āĻĢāĻŋāϞā§āĻĄāĻāĻŋ āĻšāϞ⧠āĻāĻā§āύā§āĻā§āϰ āĻĒāϰāĻŋāĻāϝāĻŧ â āĻāĻāĻŋ āĻāϞāĻāϞāĻāĻŽ-āĻā§ āĻŦāϞ⧠āĻĻā§āϝāĻŧ āϝ⧠āϏ⧠āĻā§ āĻāĻŦāĻ āϤāĻžāϰ āĻāĻāϰāĻŖ āĻā§āĻŽāύ āĻšāĻŦā§āĨ¤ āĻāĻ āϰā§āĻĒā§āϤā§, āύāĻŋāϰā§āĻĻā§āĻļāĻžāĻŦāϞ⧠āĻŽāĻžāϰā§āĻāĻĄāĻžāĻāύ āĻĢāĻžāĻāϞ āĻšāĻŋāϏā§āĻŦā§ āϞā§āĻāĻž āĻšāϝāĻŧ āĻāĻŦāĻ Go-āĻāϰ //go:embed āĻĄāĻŋāϰā§āĻā§āĻāĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻāĻŽā§āĻĒāĻžāĻāϞ āĻāϰāĻžāϰ āϏāĻŽāϝāĻŧ āĻāĻŽāĻŦā§āĻĄ āĻāϰāĻž āĻšāϝāĻŧ:
//go:embed instructions.md
var instructions string
āĻāϰ āĻĢāϞ⧠āĻĒā§āϰāĻŽā§āĻĒāĻāĻā§āϞ⧠āĻāύāϞāĻžāĻāύ āϏā§āĻā§āϰāĻŋāĻ āĻšāĻŋāϏā§āĻŦā§ āύāĻž āĻĨā§āĻā§ āĻāϞāĻžāĻĻāĻž, āϏāĻāϏā§āĻāϰāĻŖāϝā§āĻā§āϝ āύāĻĨāĻŋ āĻšāĻŋāϏā§āĻŦā§ āϏāĻāϰāĻā§āώāĻŋāϤ āĻĨāĻžāĻā§āĨ¤
āϏāϰāĻā§āĻāĻžāĻŽ
āĻā§āϞ āĻšāϞ⧠āĻā§ āĻĢāĻžāĻāĻļāύ āϝāĻž āĻāϞāĻāϞāĻāĻŽ āĻāϞ āĻāϰāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāĻĄāĻŋāĻā§ āĻāϞāĻāϞāĻāĻŽ-āĻāϰ āĻā§āϞ-āĻāϞāĻŋāĻ āĻĢāϰāĻŽā§āϝāĻžāĻ āĻāĻŦāĻ āĻāĻĒāύāĻžāϰ āĻāĻžāĻāĻĒ āĻāϰāĻž āĻā§ āĻĢāĻžāĻāĻļāύā§āϰ āĻŽāϧā§āϝ⧠āĻ āύā§āĻŦāĻžāĻĻā§āϰ āĻāĻžāĻāĻāĻŋ āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§:
// From catalog/agent.go
type ListProductsArgs struct{} // Input (can be empty)
type ListProductsResult struct {
Products []Product `json:"products"` // Output
}
func ListProducts(ctx tool.Context, args ListProductsArgs) (ListProductsResult, error) {
return ListProductsResult{Products: catalogProducts}, nil
}
// Register it:
listTool, _ := functiontool.New(functiontool.Config{
Name: "listProducts",
Description: "list all products in the catalog",
}, ListProducts)
ADK āϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ āĻāĻĒāύāĻžāϰ Go struct-āĻā§āϞ⧠āĻĨā§āĻā§ āĻāĻāĻāĻŋ JSON āϏā§āĻāĻŋāĻŽāĻž āϤā§āϰāĻŋ āĻāϰ⧠āĻāĻŦāĻ āϏā§āĻāĻŋ LLM-āĻ āĻĒāĻžāĻ āĻžāϝāĻŧāĨ¤ āϝāĻāύ LLM listProducts āĻĢāĻžāĻāĻļāύāĻāĻŋ āĻāϞ āĻāϰāĻžāϰ āϏāĻŋāĻĻā§āϧāĻžāύā§āϤ āύā§āϝāĻŧ, āϤāĻāύ ADK āĻāϰā§āĻā§āĻŽā§āύā§āĻāĻā§āϞā§āĻā§ āĻĄāĻŋāϏāĻŋāϰāĻŋāϝāĻŧāĻžāϞāĻžāĻāĻ āĻāϰā§, āĻāĻĒāύāĻžāϰ āĻĢāĻžāĻāĻļāύāĻāĻŋ āĻāϞ āĻāϰ⧠āĻāĻŦāĻ āĻĢāϞāĻžāĻĢāϞāĻāĻŋ āĻĢā§āϰāϤ āĻĒāĻžāĻ āĻžāϝāĻŧāĨ¤
tool.Context āĻĒā§āϝāĻžāϰāĻžāĻŽāĻŋāĻāĻžāϰāĻāĻŋ āĻā§āϞāĻā§āϞāĻŋāĻā§ ADK-āĻāϰ āϰāĻžāύāĻāĻžāĻāĻŽ āĻĒāϰāĻŋāώā§āĻŦāĻžāĻā§āϞāĻŋāϤ⧠āĻ
ā§āϝāĻžāĻā§āϏā§āϏ āĻĻā§āϝāĻŧ â āϝāĻžāϰ āĻŽāϧā§āϝ⧠āϏāĻŦāĻā§āϝāĻŧā§ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻšāϞ⧠āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻāĻā§āϞāĻŋ :
// Save an image as an artifact
ctx.Artifacts().Save(ctx, "my_image", imagePart)
// Load an artifact
resp, _ := ctx.Artifacts().Load(ctx, "my_image")
āĻāĻĒ-āĻāĻā§āύā§āĻ āĻĒā§āϰāϤāĻŋāύāĻŋāϧāĻŋāĻĻāϞ
āĻāĻāĻāύ āĻāĻā§āύā§āĻ agenttool.New() āĻāϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻ
āύā§āϝ āĻāĻāĻāύ āĻāĻā§āύā§āĻāĻā§ āĻā§āϞ āĻšāĻŋāϏā§āĻŦā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻĒāĻžāϰā§:
// From fittingroom/agent.go
Tools: []tool.Tool{
loadartifactstool.New(), // List available artifacts
imgtool, // Get product images
agenttool.New(catalogAgent, nil), // Delegate to catalog agent
fittingTool, // Generate try-on image
},
āϝāĻāύ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻā§āύā§āĻā§āϰ āĻĒāĻŖā§āϝā§āϰ āϤāĻĨā§āϝā§āϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āĻšāϝāĻŧ, āϤāĻāύ āϏ⧠āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻāĻā§ āĻāĻāĻāĻŋ āϏāĻžāϧāĻžāϰāĻŖ āĻā§āϞā§āϰ āĻŽāϤā§āĻ āĻĄāĻžāĻāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāϞāĻāϞāĻāĻŽ āĻāĻāĻŋāĻā§ āĻā§āϞā§āϰ āϤāĻžāϞāĻŋāĻāĻžāϝāĻŧ āĻĻā§āĻāϤ⧠āĻĒāĻžāϝāĻŧ āĻāĻŦāĻ āĻāĻāĻŋāĻā§ āĻāĻžāϞ⧠āĻāϰāĻžāϰ āϏāĻŋāĻĻā§āϧāĻžāύā§āϤ āύāĻŋāϤ⧠āĻĒāĻžāϰā§āĨ¤
āĻ āϧāĻŋāĻŦā§āĻļāύ
āϏā§āĻļāύāĻā§āϞ⧠āĻāĻĨā§āĻĒāĻāĻĨāύā§āϰ āĻāϤāĻŋāĻšāĻžāϏ āĻā§āϰā§āϝāĻžāĻ āĻāϰā§āĨ¤ ADK-āĻāϰ REST API āϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ āĻāĻā§āϞ⧠āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§:
POST /api/apps/{appName}/users/{userId}/sessions â Creates a new session
POST /api/run (with sessionId) â Runs agent within that session
āĻāĻ āĻ ā§āϝāĻžāĻĒāĻāĻŋāϰ āĻāĻāĻāĻŋ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻĄāĻŋāĻāĻžāĻāύ āϏāĻŋāĻĻā§āϧāĻžāύā§āϤ āĻšāϞā§: āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻ āύā§āϰā§āϧā§āϰ āĻāύā§āϝ āĻāĻāĻāĻŋ āύāϤā§āύ āϏā§āĻļāύ āϤā§āϰāĻŋ āĻāϰ⧠(āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻā§āϰāĻžāĻ-āĻ āύ āϏā§āĻŦāϤāύā§āϤā§āϰ), āĻ āύā§āϝāĻĻāĻŋāĻā§ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻāĻ āϏā§āĻļāύ āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ (āĻĢāϞ⧠āĻāĻāĻŋ āĻĒā§āϰā§āĻŦāĻŦāϰā§āϤ⧠āĻĒāϰāĻžāĻŽāϰā§āĻļāĻā§āϞ⧠āĻŽāύ⧠āϰāĻžāĻā§ āĻāĻŦāĻ āĻĒā§āϰāĻžāĻĒā§āϤ āĻŽāϤāĻžāĻŽāϤā§āϰ āĻāĻŋāϤā§āϤāĻŋāϤ⧠āϏā§āĻāĻŋāĻā§ āĻĒāϰāĻŋāĻŽāĻžāϰā§āĻāύ āĻāϰāϤ⧠āĻĒāĻžāϰā§)āĨ¤
āϰāĻžāĻā§āϝ
āϏā§āĻā§āĻ āĻšāϞ⧠āϏā§āĻļāύā§āϰ āϏāĻžāĻĨā§ āϏāĻāϝā§āĻā§āϤ āĻāĻāĻāĻŋ āĻā§-āĻā§āϝāĻžāϞ⧠āϏā§āĻā§āϰāĨ¤ āĻāĻā§āύā§āĻāϰāĻž āϏāĻŽāύā§āĻŦāϝāĻŧ āϏāĻžāϧāύā§āϰ āĻāύā§āϝ āϏā§āĻā§āĻ āϰāĻŋāĻĄ āĻ āϰāĻžāĻāĻ āĻāϰā§:
// Write to state
ctx.State().Set("previously_used_products", "[\"id_bomber\",\"id_hat\"]")
// Read from state
val, err := ctx.State().Get("previously_used_products")
āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ āϤāĻžāϰ āϏā§āĻā§āĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻŽāύ⧠āϰāĻžāĻā§ āϝ⧠āϏ⧠āĻāĻā§ āĻā§āύ āĻĒā§āϰā§āĻĄāĻžāĻā§āĻāĻā§āϞ⧠āϏāĻžāĻā§āϏā§āĻ āĻāϰā§āĻā§, āϝāĻžāϤ⧠āĻĒāϰā§āϰāĻŦāĻžāϰ āϏ⧠āĻāĻŋāύā§āύ āĻĒā§āϰā§āĻĄāĻžāĻā§āĻ āĻŦā§āĻā§ āύāĻŋāϤ⧠āĻĒāĻžāϰā§āĨ¤
āĻĒā§āϰāϤā§āύāĻŦāϏā§āϤā§
āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āĻšāϞ⧠āύāĻžāĻŽāϝā§āĻā§āϤ āĻŦāĻžāĻāύāĻžāϰāĻŋ āĻ āĻŦāĻā§āĻā§āĻ (āϏāĻžāϧāĻžāϰāĻŖāϤ āĻāĻŦāĻŋ), āϝāĻž āĻĒā§āϰāϤāĻŋ āϏā§āĻļāύ⧠āϏāĻāϰāĻā§āώāĻŋāϤ āĻĨāĻžāĻā§āĨ¤ āĻā§āĻā§āϏāĻ āϰā§āϏāĻĒāύā§āϏā§āϰ āĻŽāϤ⧠āύāϝāĻŧ, āĻāĻā§āϞ⧠āĻāϞāĻžāĻĻāĻžāĻāĻžāĻŦā§ āϏāĻāϰāĻā§āώāĻŋāϤ āĻšāϝāĻŧ āĻāĻŦāĻ āύāĻžāĻŽ āĻĻāĻŋāϝāĻŧā§ āĻā§āĻāĻā§ āĻŦā§āϰ āĻāϰāĻž āĻšāϝāĻŧ:
// Save a generated image as an artifact
artName := fmt.Sprintf("generated_fitting_%s_%s", ctx.InvocationID(), uuid.NewString()[:8])
ctx.Artifacts().Save(ctx, artName, imagePart)
// The frontend fetches it via:
// GET /api/apps/{app}/users/{user}/sessions/{session}/artifacts/{artName}
āĻāϰ āĻĢāϞ⧠āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāĻā§āϞ⧠āĻšāĻžāϞāĻāĻž āĻĨāĻžāĻā§ â āĻāĻā§āύā§āĻ āĻļā§āϧ⧠āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻā§āϰ āύāĻžāĻŽāĻāĻŋ āĻĢā§āϰāϤ āĻĻā§āϝāĻŧ āĻāĻŦāĻ āĻĢā§āϰāύā§āĻāĻāύā§āĻĄ āĻāϞāĻžāĻĻāĻžāĻāĻžāĻŦā§ āĻŦāĻžāĻāύāĻžāϰāĻŋ āĻāĻŽā§āĻ āĻĄā§āĻāĻž āϏāĻāĻā§āϰāĻš āĻāϰā§āĨ¤
āĻāϞāĻŦā§āϝāĻžāĻ
āĻāϞāĻŦā§āϝāĻžāĻ āĻšāϞ⧠āĻšā§āĻ āϝāĻž āĻāĻā§āύā§āĻ āϞā§āĻĒā§āϰ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻĒāϝāĻŧā§āύā§āĻā§ āĻāϞā§āĨ¤ āĻāĻā§āϞ⧠āĻāĻā§āϏāĻŋāĻāĻŋāĻāĻļāύāĻā§ āύāĻŋāϰā§āĻā§āώāĻž, āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻŦāĻž āϏāĻāĻā§āώāĻŋāĻĒā§āϤ āĻāϰāϤ⧠āĻĒāĻžāϰā§:
llmagent.Config{
// Runs before the agent starts â used to save uploaded images
BeforeAgentCallbacks: []agent.BeforeAgentCallback{SaveIncomingBlobs},
// Runs before each LLM call â used to inject context
BeforeModelCallbacks: []llmagent.BeforeModelCallback{
ExtractAndInjectUserImage,
InjectPreviousProducts,
},
// Runs after each LLM response â used to extract data
AfterModelCallbacks: []llmagent.AfterModelCallback{SaveSelectedProducts},
}
āϝāĻĻāĻŋ āĻā§āύ⧠āĻāϞāĻŦā§āϝāĻžāĻ āĻāĻāĻāĻŋ āύāύ-āύāĻŋāϞ āϰā§āϏāĻĒāύā§āϏ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰā§, āϤāĻžāĻšāϞ⧠āĻĄāĻŋāĻĢāϞā§āĻ āĻāĻāϰāĻŖāĻāĻŋ āĻāĻĄāĻŧāĻŋāϝāĻŧā§ āϝāĻžāĻāϝāĻŧāĻž āĻšāϝāĻŧāĨ¤ āĻāĻĻāĻžāĻšāϰāĻŖāϏā§āĻŦāϰā§āĻĒ, āĻāĻāĻāĻŋ BeforeModelCallback āϝāĻž āĻāĻāĻāĻŋ āĻā§āϝāĻžāĻļāĻĄ āϰā§āϏāĻĒāύā§āϏ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰā§, āϏā§āĻāĻŋ āĻĒā§āϰāĻā§āϤ LLM āĻāϞāĻāĻŋ āϏāĻŽā§āĻĒā§āϰā§āĻŖāϰā§āĻĒā§ āĻāĻĄāĻŧāĻŋāϝāĻŧā§ āϝāĻžāĻŦā§āĨ¤
JSON āϏā§āĻāĻŋāĻŽāĻž āĻĒā§āϰāϝāĻŧā§āĻ
āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ āĻāĻāϝāĻŧāĻ āĻāϞāĻāϞāĻāĻŽ-āĻā§ āϏā§āĻā§āϰāĻžāĻāĻāĻžāϰā§āĻĄ JSON-āĻ āĻāϤā§āϤāϰ āĻĻāĻŋāϤ⧠āĻŦāĻžāϧā§āϝ āĻāϰā§:
GenerateContentConfig: &genai.GenerateContentConfig{
ResponseMIMEType: "application/json",
ResponseJsonSchema: fittingSchemaMap(), // Defines the expected structure
}
āĻāĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰ⧠āϝ⧠āĻĢā§āϞāĻžāĻāĻžāϰ āĻĢā§āϰāύā§āĻāĻāύā§āĻĄ āϏāϰā§āĻŦāĻĻāĻž āĻĒāĻžāϰā§āϏāϝā§āĻā§āϝ āĻĄā§āĻāĻž āĻā§āϰāĻšāĻŖ āĻāϰā§, āĻā§āύ⧠āĻ āĻĒāϰāĻŋāĻāϞā§āĻĒāĻŋāϤ āĻā§āĻā§āϏāĻ āύāϝāĻŧāĨ¤
āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻ: āϏāϰāϞāϤāĻŽ āĻāĻĻāĻžāĻšāϰāĻŖ
āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻā§āύā§āĻ ( catalog/agent.go ) āĻšāϞ⧠āϏāĻŋāϏā§āĻā§āĻŽā§āϰ āϏāĻŦāĻā§āϝāĻŧā§ āϏāϰāϞ āĻāĻā§āύā§āĻ â ADK āĻĒā§āϝāĻžāĻāĻžāϰā§āύāĻā§āϞ⧠āĻŦā§āĻāĻžāϰ āĻāύā§āϝ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻāĻžāϞ⧠āϏā§āĻāύāĻžāĨ¤
āĻāϤ⧠āĻĻā§āĻāĻŋ āϏāϰāĻā§āĻāĻžāĻŽ āĻāĻā§:
-
listProductsâ āĻāĻāĻāĻŋ YAML āĻĢāĻžāĻāϞ āĻĨā§āĻā§ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻĒāĻŖā§āϝ āĻā§āϝāĻžāĻāĻžāϞāĻ āĻĢā§āϰāϤ āĻĻā§āϝāĻŧāĨ¤ -
getProductImageâ GCS (āĻŦāĻž āϏā§āĻĨāĻžāύā§āϝāĻŧ āĻĢāϞāĻŦā§āϝāĻžāĻ) āĻĨā§āĻā§ āĻāĻāĻāĻŋ āĻĒāĻŖā§āϝā§āϰ āĻāĻŦāĻŋ āϞā§āĻĄ āĻāϰ⧠āĻāĻŦāĻ āĻāĻāĻŋāĻā§ āĻāĻāĻāĻŋ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āĻšāĻŋāϏāĻžāĻŦā§ āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§āĨ¤
getProductImage āĻā§āϞāĻāĻŋ āĻāĻāĻāĻŋ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻĻā§āĻāĻžāϝāĻŧ â āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āĻā§āϝāĻžāĻļāĻŋāĻ āϏāĻš āĻŽāĻžāϞā§āĻāĻŋ-āϏā§āϰā§āϏ āϞā§āĻĄāĻŋāĻ :
// From tools/imagetool.go â simplified
func GetProductImage(ctx tool.Context, args GetProductImageArgs) (GetProductImageResult, error) {
// First: check if it's already an artifact
_, err := ctx.Artifacts().Load(ctx, args.ImageName)
if err == nil {
return GetProductImageResult{Image: args.ImageName}, nil // Cache hit!
}
// Second: try loading from GCS bucket
rc, err := client.Bucket(bucket).Object("catalog-assets/images/" + args.ImageName).NewReader(ctx)
if err != nil {
// Third: fall back to local filesystem
localData, _ := os.ReadFile("../flutter_frontend/assets/images/" + args.ImageName)
ctx.Artifacts().Save(ctx, args.ImageName, &genai.Part{InlineData: ...})
return GetProductImageResult{Image: args.ImageName}, nil
}
// Save to artifact cache and return
ctx.Artifacts().Save(ctx, args.ImageName, &genai.Part{InlineData: ...})
return GetProductImageResult{Image: args.ImageName}, nil
}
āĻā§āϞāĻāĻŋ āĻĒā§āϰāĻĨāĻŽā§ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ, āϤāĻžāϰāĻĒāϰ GCS, āĻāĻŦāĻ āϏāĻŦāĻļā§āώ⧠āϞā§āĻāĻžāϞ āĻĢāĻžāĻāϞāĻā§āϞ⧠āĻā§āώā§āĻāĻž āĻāϰā§āĨ¤ āĻāĻāĻŦāĻžāϰ āϞā§āĻĄ āĻšāϝāĻŧā§ āĻā§āϞā§, āĻāĻŦāĻŋāĻāĻŋ āĻāĻāĻāĻŋ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āĻšāĻŋāϏā§āĻŦā§ āĻā§āϝāĻžāĻļ āĻāϰāĻž āĻšāϝāĻŧ, āĻĢāϞ⧠āĻĒāϰāĻŦāϰā§āϤ⧠āĻāϞāĻā§āϞ⧠āϤāĻžā§āĻā§āώāĻŖāĻŋāĻāĻāĻžāĻŦā§ āϏāĻŽā§āĻĒāύā§āύ āĻšāϝāĻŧāĨ¤
ā§Ŧ. đ§Ē āĻāĻāĻ āĻĒāĻžāĻāĻĒāϞāĻžāĻāύ: āĻāĻā§āύā§āĻāĻĻā§āϰ āĻāĻžāϰā§āϝāĻāϞāĻžāĻĒ
āĻāĻŦāĻžāϰ āĻāϞā§āύ āϏāĻŦāĻā§āϝāĻŧā§ āĻ āϤā§āϝāĻžāϧā§āύāĻŋāĻ āĻĻā§āĻāĻŋ āĻāĻā§āύā§āĻ āύāĻŋāϝāĻŧā§ āĻāϞā§āĻāύāĻž āĻāϰāĻž āϝāĻžāĻ â āϝā§āĻā§āϞ⧠āĻĒā§āϰāĻā§āϤāĻĒāĻā§āώ⧠āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰ⧠āĻāĻŦāĻ āĻĒā§āĻļāĻžāĻ āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰā§āĨ¤
ā§Ŧ.ā§§ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻā§āύā§āĻ
āĻĢāĻžāĻāϞ:
adk_backend/fittingroom/agent.go
āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻā§āύā§āĻ āĻšāϞ⧠'āĻāĻžāϰā§āĻā§āϝāĻŧāĻžāϞ āĻā§āϰāĻžāĻ-āĻ āύ'-āĻāϰ āĻŽā§āϞ āĻāĻžāϞāĻŋāĻāĻžāĻļāĻā§āϤāĻŋāĨ¤ āϝāĻāύ āĻā§āύ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āϤāĻžāϰ āĻāĻŦāĻŋ āĻāĻĒāϞā§āĻĄ āĻāϰ⧠āĻāĻŦāĻ āĻāĻāĻāĻŋ āĻĒāĻŖā§āϝ āĻĒāĻāύā§āĻĻ āĻāϰā§āύ, āϤāĻāύ āĻāĻ āĻāĻā§āύā§āĻāĻāĻŋ āϏā§āĻ āĻĒāĻŖā§āϝāĻāĻŋ āĻĒāϰāĻŋāĻšāĻŋāϤ āĻŦā§āϝāĻā§āϤāĻŋāϰ āĻāĻāĻāĻŋ āϏāĻŽāύā§āĻŦāĻŋāϤ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰā§āĨ¤
fitting_tool â āϧāĻžāĻĒā§ āϧāĻžāĻĒā§
āĻŽā§āϞ āϞāĻāĻŋāĻāĻāĻŋ doFitting āĻĢāĻžāĻāĻļāύā§āϰ āĻŽāϧā§āϝ⧠āĻĨāĻžāĻā§āĨ¤ āĻāĻā§āύā§āĻ āϝāĻāύ āĻāĻāĻŋāĻā§ āĻāϞ āĻāϰā§, āϤāĻāύ āϝāĻž āĻāĻā§ āϤāĻž āύāĻŋāĻā§ āĻĻā§āĻāϝāĻŧāĻž āĻšāϞā§:
āϧāĻžāĻĒ ā§§: āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋāĻāĻŋ āϏāĻŽāĻžāϧāĻžāύ āĻāϰā§āύ
func doFitting(ctx tool.Context, args FittingToolArgs) (FittingToolResult, error) {
if len(args.Accessories) > 2 {
args.Accessories = args.Accessories[:2] // Safety limit: max 2 items
}
var userPart *genai.Part
if strings.HasPrefix(args.UserImage, "gs://") {
// If we have a GCS URI from a previous fitting, use it directly
userPart = &genai.Part{FileData: &genai.FileData{
FileURI: args.UserImage,
MIMEType: gcsURIMimeType(args.UserImage),
}}
} else {
// Otherwise, load the image from artifact storage
userImgResp, err := ctx.Artifacts().Load(ctx, args.UserImage)
userPart = userImgResp.Part
}
āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋ āĻĻā§āĻāĻŋ āĻā§āϏ āĻĨā§āĻā§ āĻāϏāϤ⧠āĻĒāĻžāϰā§:
- āĻāĻāĻāĻŋ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āύāĻžāĻŽ (āϝā§āĻŽāύ
upload_abc123_1) â āĻāĻāĻŋ āĻšāϞ⧠āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ āĻāĻĒāϞā§āĻĄ, āϝāĻžSaveIncomingBlobsāĻāϞāĻŦā§āϝāĻžāĻ āĻĻā§āĻŦāĻžāϰāĻž āϏāĻāϰāĻā§āώāĻŋāϤ āĻšāϝāĻŧāĨ¤ - āĻāĻāĻāĻŋ
gs://URI â āĻāĻāĻŋ āĻĒā§āϰā§āĻŦā§ āϤā§āϰāĻŋ āĻāϰāĻž āĻāĻāĻāĻŋ āĻĢāĻŋāĻāĻŋāĻ āĻĢāϞāĻžāĻĢāϞ, āϝāĻž āĻŦāĻŋāĻāĻŋāύā§āύ āϏā§āĻļāύ⧠āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰā§āϰ āĻāύā§āϝ GCS-āĻ āϏāĻāϰāĻā§āώāĻŋāϤ āĻĨāĻžāĻā§āĨ¤
āĻāĻ āĻĻā§āĻŦā§āϤ-āĻĒāĻĨā§āϰ āύāĻāĻļāĻžāĻāĻŋ āĻāĻā§āĻāĻžāĻā§āϤ: āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ āϝāĻāύ āĻĒāϰāĻŦāϰā§āϤā§āϤ⧠āĻĒā§āĻļāĻžāĻ āĻā§āϰāĻžāĻ-āĻ āύ āϤā§āϰāĻŋ āĻāϰā§, āϤāĻāύ āĻāĻāĻŋ āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽā§āϰ āĻĢāϞāĻžāĻĢāϞ āĻĨā§āĻā§ GCS URL-āĻāĻŋ āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āϝāĻžāϤ⧠āϏāĻŽāϏā§āϤ āĻĒā§āĻļāĻžāĻā§āϰ āĻā§āώā§āϤā§āϰ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻĒāϰāĻŋāĻāϝāĻŧ āĻāĻāĻ āĻĨāĻžāĻā§āĨ¤
āϧāĻžāĻĒ ā§¨: āĻŽāĻžāϞā§āĻāĻŋāĻŽā§āĻĄāĻžāϞ āĻĒā§āϰāĻŽā§āĻĒāĻāĻāĻŋ āϤā§āϰāĻŋ āĻāϰā§āύ
parts := []*genai.Part{
genai.NewPartFromText(toolInstructions), // Identity preservation prompt
genai.NewPartFromText("Reference Person Photo:"),
userPart, // The user's photo
}
for _, acc := range args.Accessories {
accResp, _ := ctx.Artifacts().Load(ctx, acc) // Load product image artifact
parts = append(parts, genai.NewPartFromText("Product Image to Apply:"))
parts = append(parts, accResp.Part) // The product photo
}
toolInstructions ( tool_instructions.md āĻĨā§āĻā§ āĻāĻŽāĻŦā§āĻĄ āĻāϰāĻž) āĻ
āϤā§āϝāύā§āϤ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ â āĻāĻāĻŋ āĻā§āĻŽāĻŋāύāĻŋāĻā§ āύāĻŋāϰā§āĻĻā§āĻļ āĻĻā§āϝāĻŧ āϝā§āύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻĒāϰāĻŋāĻāϝāĻŧ (āĻŽā§āĻ, āĻļāĻžāϰā§āϰāĻŋāĻ āĻāĻ āύ, āϤā§āĻŦāĻā§āϰ āϰāĻ, āĻā§āϞ) āĻ
āĻā§āώā§āĻŖā§āĻŖ āϰā§āĻā§ āĻļā§āϧā§āĻŽāĻžāϤā§āϰ āĻĒā§āĻļāĻžāĻāĻāĻŋ āĻĒā§āϰāϝāĻŧā§āĻ āĻāϰāĻž āĻšāϝāĻŧāĨ¤ āĻāĻ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āύāĻŋāϰā§āĻĻā§āĻļāύāĻžāĻāĻŋ āĻāĻžāĻĄāĻŧāĻž, āĻŽāĻĄā§āϞāĻāĻŋ āĻšāϝāĻŧāϤ⧠āĻŦā§āϝāĻā§āϤāĻŋāĻāĻŋāϰ āĻā§āĻšāĻžāϰāĻž āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰ⧠āĻĢā§āϞāϤ⧠āĻĒāĻžāϰā§āĨ¤
āϧāĻžāĻĒ ā§Š: āĻāĻŦāĻŋ āϤā§āϰāĻŋāϰ āĻāύā§āϝ āĻā§āĻŽāĻŋāύāĻŋāĻā§ āĻĄāĻžāĻā§āύ
client, _ := genai.NewClient(ctx, &genai.ClientConfig{
Backend: genai.BackendVertexAI, // Vertex AI endpoint
Project: os.Getenv("GOOGLE_CLOUD_PROJECT"), // From your .env
Location: "global", // Multi-region endpoint
})
resp, _ := client.Models.GenerateContent(ctx, "gemini-2.5-flash-image",
[]*genai.Content{genai.NewContentFromParts(parts, "user")},
&genai.GenerateContentConfig{
ResponseModalities: []string{"TEXT", "IMAGE"}, // Request both text and image output
Temperature: genai.Ptr(float32(0.2)), // Low temperature for consistency
})
āĻāĻžāϰāĻāĻŋ āĻāĻā§āύā§āĻ āĻāĻŦāĻ āĻāĻŽā§āĻ-āĻā§āύ āĻā§āϞâāϏāĻŦāĻā§āϞā§āĻ āĻāĻāĻāĻŋāĻŽāĻžāϤā§āϰ āĻ
āĻĨā§āύāĻāĻŋāĻā§āĻļāύ āĻĒāĻžāĻĨ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§: Backend: genai.BackendVertexAI , āϝāĻž āĻĒā§āϰāĻā§āĻā§āĻ āĻāĻāĻĄāĻŋ āĻĻā§āĻŦāĻžāϰāĻž āĻ
ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύ āĻĄāĻŋāĻĢāϞā§āĻ āĻā§āϰā§āĻĄā§āύāĻļāĻŋāϝāĻŧāĻžāϞāϏā§āϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻ
āĻĨā§āύāĻāĻŋāĻā§āĻā§āĻĄ āĻšāϝāĻŧāĨ¤ āĻ
āϰā§āĻā§āϏā§āĻā§āϰā§āĻļāύ āĻŽāĻĄā§āϞāĻā§āϞ⧠( gemini-3.1-pro-preview , gemini-3-flash-preview ) āĻāĻŦāĻ āĻāĻŽā§āĻ āĻŽāĻĄā§āϞ ( gemini-2.5-flash-image ) āϏāĻŦāĻā§āϞā§āĻ āĻāĻāĻ Vertex AI āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻā§āϰ āĻĒā§āĻāύ⧠āĻĨāĻžāĻā§ āĻāĻŦāĻ āĻāĻāĻ ADC āĻā§āϞāĻžāĻāĻĄ āϏā§āĻā§āϰā§āĻ āĻ
ā§āϝāĻžāĻā§āϏā§āϏā§āϰ āĻ
āύā§āĻŽā§āĻĻāύāĻ āĻĻā§āϝāĻŧâāĻĒā§āϰāϤāĻŋāĻāĻŋ āĻāϞā§āϰ āĻāύā§āϝ āĻāĻāĻāĻŋāĻŽāĻžāϤā§āϰ āĻā§āϰā§āĻĄā§āύāĻļāĻŋāϝāĻŧāĻžāϞāĨ¤
āϧāĻžāĻĒ ā§Ē: āĻĢāϞāĻžāĻĢāϞāĻāĻŋ āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§āύāĨ¤
// Find the image in the response (may contain both text + image parts)
var genPart *genai.Part
for _, p := range resp.Candidates[0].Content.Parts {
if p.InlineData != nil {
genPart = p
break
}
}
// Save as an ADK artifact
artName := fmt.Sprintf("generated_fitting_%s_%s", ctx.InvocationID(), uuid.NewString()[:8])
ctx.Artifacts().Save(ctx, artName, genPart)
// Also upload to GCS for cross-session reuse
objectName := fmt.Sprintf("generated-fittings/%s.jpg", ctx.InvocationID())
w := storageClient.Bucket(bucket).Object(objectName).NewWriter(ctx)
w.Write(genPart.InlineData.Data)
gcsURI := fmt.Sprintf("gs://%s/%s", bucket, objectName)
return FittingToolResult{ArtifactName: artName, GCSUrl: gcsURI}, nil
āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻā§āϰ āĻŽāϧā§āϝ⧠āĻāĻā§āύā§āĻ āĻšāϏā§āϤāĻžāύā§āϤāϰā§āϰ āĻŽā§āϞ āĻāĻžāĻŦāĻŋāĻāĻžāĻ āĻŋ āĻšāϞ⧠āĻĄā§āϝāĻŧāĻžāϞ-āϏā§āĻ (āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ + āĻāĻŋāϏāĻŋāĻāϏ)āĨ¤ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻāĻāĻŋ āĻŦāϰā§āϤāĻŽāĻžāύ āϏā§āĻļāύā§āϰ āĻŽāϧā§āϝ⧠āϤāĻžā§āĻā§āώāĻŖāĻŋāĻ āĻ ā§āϝāĻžāĻā§āϏā§āϏ āĻĒā§āϰāĻĻāĻžāύ āĻāϰā§, āĻ āύā§āϝāĻĻāĻŋāĻā§ āĻāĻŋāϏāĻŋāĻāϏ āĻāĻāĻāϰāĻāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻāĻā§ (āϝāĻŋāύāĻŋ āĻāĻāĻāĻŋ āĻāĻŋāύā§āύ āϏā§āĻļāύ⧠āĻāĻžāĻ āĻāϰā§āύ) āĻĒāϰāĻŦāϰā§āϤā§āϤ⧠āĻāĻāĻ āĻāĻŦāĻŋāĻāĻŋ āϰā§āĻĢāĻžāϰā§āύā§āϏ āĻāϰāĻžāϰ āϏā§āϝā§āĻ āĻĻā§āϝāĻŧāĨ¤
SaveIncomingBlobs āĻāϞāĻŦā§āϝāĻžāĻ
āĻāĻā§āύā§āĻ āϝā§āĻā§āϤāĻŋ-āϤāϰā§āĻ āĻļā§āϰ⧠āĻāϰāĻžāϰ āĻāĻā§āĻ, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻĒāϞā§āĻĄ āĻāϰāĻž āĻāĻŦāĻŋāĻā§āϞ⧠āϏāĻāϰāĻā§āώāĻŖ āĻāϰāĻžāϰ āĻāύā§āϝ āĻāĻ BeforeAgentCallback āĻāϞā§:
func SaveIncomingBlobs(ctx agent.CallbackContext) (*genai.Content, error) {
for pindex, p := range ctx.UserContent().Parts {
if p.InlineData != nil {
aname := fmt.Sprintf("upload_%s_%d", ctx.InvocationID(), pindex)
ctx.Artifacts().Save(ctx, aname, p)
}
}
return nil, nil // Return nil to proceed with normal agent execution
}
(nil, nil) āϰāĻŋāĻāĻžāϰā§āύ āĻāϰāĻžāϰ āĻŽāĻžāϧā§āϝāĻŽā§, āĻāϞāĻŦā§āϝāĻžāĻāĻāĻŋ āϏāĻāĻā§āϤ āĻĻā§āϝāĻŧ āϝā§, "āĻāĻŽāĻžāϰ āĻĒā§āϰāĻŋāĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āώ â āĻāĻāύ āĻāĻā§āύā§āĻāĻāĻŋāĻā§ āϏā§āĻŦāĻžāĻāĻžāĻŦāĻŋāĻāĻāĻžāĻŦā§ āĻāĻžāϞāĻžāύāĨ¤" āϝāĻĻāĻŋ āĻāĻāĻŋ nil āĻāĻžāĻĄāĻŧāĻž āĻ
āύā§āϝ āĻā§āύ⧠āĻāύā§āĻā§āύā§āĻ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰāϤ, āϤāĻŦā§ āĻāĻāĻŋ āĻāĻā§āύā§āĻāĻāĻŋāĻā§ āϏāĻŽā§āĻĒā§āϰā§āĻŖāϰā§āĻĒā§ āĻļāϰā§āĻ-āϏāĻžāϰā§āĻāĻŋāĻ āĻāϰ⧠āĻĻāĻŋāϤāĨ¤
ā§Ŧ.⧍ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻ
āĻĢāĻžāĻāϞ:
adk_backend/stylist/agent.go
āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻāĻāĻŋ āĻāĻ āϏāĻŋāϏā§āĻā§āĻŽā§āϰ āϏāĻŦāĻā§āϝāĻŧā§ āĻ āϤā§āϝāĻžāϧā§āύāĻŋāĻ āĻŦā§āϝāĻŦāϏā§āĻĨāĻžāĨ¤ āĻāĻāĻŋ āĻŦā§āϝāĻā§āϤāĻŋāĻāϤ āĻĒā§āϰāϝāĻŧā§āĻāύ āĻ āύā§āϝāĻžāϝāĻŧā§ āĻĒā§āĻļāĻžāĻā§āϰ āϏā§āĻĒāĻžāϰāĻŋāĻļ āϤā§āϰāĻŋ āĻāϰ⧠āĻāĻŦāĻ āĻāĻĨā§āĻĒāĻāĻĨāύā§āϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻŦāĻžāϰāĻŦāĻžāϰ āĻĒāϰāĻŋāĻŽāĻžāϰā§āĻāύ⧠āϏāĻšāĻžāϝāĻŧāϤāĻž āĻāϰā§āĨ¤
āϤāĻŋāύāĻāĻŋ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ â āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻā§āϰ āϏā§āĻŽā§āϤāĻŋ
āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻāĻžāϧāĻŋāĻ āĻĒāĻžāϞāĻžāĻŦāĻŋāĻļāĻŋāώā§āĻ āĻāĻĨā§āĻĒāĻāĻĨāύ⧠āĻĒā§āϰāĻžāϏāĻā§āĻāĻŋāĻāϤāĻž āĻŦāĻāĻžāϝāĻŧ āϰāĻžāĻāϤ⧠āϤāĻŋāύāĻāĻŋ āϰā§āĻĢāĻžāϰā§āύā§āϏ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ:
āĻāϞāĻŦā§āϝāĻžāĻ ā§§:
InjectPreviousProducts (āĻŦāĻŋāĻĢā§āϰāĻŽāĻĄā§āϞ)
āϏāĻŽāϏā§āϝāĻžāĻāĻŋ āĻšāϞā§: āϝāĻĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻŦāϞā§āύ "āĻāĻŽāĻžāĻā§ āĻŦāĻŋāĻāĻŋāύā§āύ āĻŦāĻŋāĻāϞā§āĻĒ āĻĻā§āĻāĻžāĻ," āϤāĻžāĻšāϞ⧠āĻāϞāĻāϞāĻāĻŽ (LLM) āĻšāϝāĻŧāϤ⧠āĻāĻŦāĻžāϰāĻ āĻāĻāĻ āĻĒāĻŖā§āϝāĻā§āϞā§āĻ āϏā§āĻĒāĻžāϰāĻŋāĻļ āĻāϰāϤ⧠āĻĒāĻžāϰā§, āĻāĻžāϰāĻŖ āĻāĻāĻŋ āĻāĻā§ āĻā§ āϏā§āĻĒāĻžāϰāĻŋāĻļ āĻāϰā§āĻā§ āϤāĻž āϏāĻšāĻāĻžāϤāĻāĻžāĻŦā§ āĻā§āϰā§āϝāĻžāĻ āĻāϰ⧠āύāĻžāĨ¤
āϏāĻŽāĻžāϧāĻžāύ: āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāϰ āĻĒāϰā§, āĻĒā§āϰā§āĻĄāĻžāĻā§āĻ āĻāĻāĻĄāĻŋāĻā§āϞāĻŋ āϏā§āĻļāύ āϏā§āĻā§āĻā§ āϏāĻāϰāĻā§āώāĻŖ āĻāϰāĻž āĻšāϝāĻŧāĨ¤ āĻĒāϰāĻŦāϰā§āϤ⧠LLM āĻāϞ āĻāϰāĻžāϰ āĻāĻā§, āĻāĻ āĻāϞāĻŦā§āϝāĻžāĻāĻāĻŋ āϏā§āĻā§āϞāĻŋ āĻĒāĻĄāĻŧā§ āĻāĻŦāĻ āĻāĻāĻāĻŋ āĻāĻā§āĻāĻŋāϤ āϝā§āĻ āĻāϰā§:
func InjectPreviousProducts(ctx agent.CallbackContext, req *model.LLMRequest) (*model.LLMResponse, error) {
prev, err := ctx.State().Get(stateKeyPreviousProducts) // Read from session state
if err != nil {
return nil, nil // No previous state â first run
}
// Append hint to the user's message
for i := len(req.Contents) - 1; i >= 0; i-- {
if req.Contents[i].Role == "user" {
req.Contents[i].Parts = append(req.Contents[i].Parts,
genai.NewPartFromText(fmt.Sprintf(
"IMPORTANT: You previously suggested these products: %s. "+
"You MUST pick DIFFERENT complementary products this time.", prev)))
break
}
}
return nil, nil // Continue to LLM call
}
āĻāϞāĻŦā§āϝāĻžāĻ ā§¨:
ExtractAndInjectUserImage (āĻŽāĻĄā§āϞā§āϰ āĻāĻā§)
āϏāĻŽāϏā§āϝāĻžāĻāĻŋ āĻšāϞā§: āϝāĻāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻŽāϤāĻžāĻŽāϤ āĻĻā§āύ ("āĻāϰāĻ āĻā§āϝāĻžāĻā§āϝāĻŧāĻžāϞ āĻāϰā§āύ"), āϤāĻāύ āĻĒāϰāĻŦāϰā§āϤ⧠āĻŽā§āϏā§āĻā§ āϤāĻžāĻāϰ āĻāĻŦāĻŋ āĻāϰ āϝā§āĻā§āϤ āĻāϰāĻž āĻšāϝāĻŧ āύāĻžāĨ¤ āĻāĻŋāύā§āϤ⧠āĻĢāĻŋāĻāĻŋāĻ āĻā§āϞāĻāĻŋāϰ āĻāύā§āϝ āĻāĻŦāĻŋāĻāĻŋ āĻĒā§āϰāϝāĻŧā§āĻāύāĨ¤
āϏāĻŽāĻžāϧāĻžāύ: āĻĒā§āϰāĻĨāĻŽ āĻ āύā§āϰā§āϧā§, āĻāĻ āĻāϞāĻŦā§āϝāĻžāĻāĻāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋāϰ āϰā§āĻĢāĻžāϰā§āύā§āϏ āĻŦā§āϰ āĻāϰ⧠āϏā§āĻā§āĻā§ āϏāĻāϰāĻā§āώāĻŖ āĻāϰā§āĨ¤ āĻĒāϰāĻŦāϰā§āϤ⧠āĻ āύā§āϰā§āϧāĻā§āϞā§āϤā§, āĻāĻāĻŋ āĻĒā§āύāϰāĻžāϝāĻŧ āϤāĻž āϝā§āĻā§āϤ āĻāϰā§:
func ExtractAndInjectUserImage(ctx agent.CallbackContext, req *model.LLMRequest) (*model.LLMResponse, error) {
var foundImgStr string
// Search for user image in the latest message
for i := len(req.Contents) - 1; i >= 0; i-- {
if req.Contents[i].Role == "user" {
for _, part := range req.Contents[i].Parts {
if strings.Contains(part.Text, "User try-on base image") {
foundImgStr = part.Text // Found the GCS URI reference
}
}
break
}
}
if foundImgStr != "" {
ctx.State().Set(stateKeyUserImageStr, foundImgStr) // Save for later
} else {
// Not in current message â retrieve from state and inject
val, _ := ctx.State().Get(stateKeyUserImageStr)
if savedImgStr, ok := val.(string); ok {
// Inject into the latest user message
req.Contents[last].Parts = append(req.Contents[last].Parts,
genai.NewPartFromText("REMINDER: Use this image: " + savedImgStr))
}
}
return nil, nil
}
āĻāϞāĻŦā§āϝāĻžāĻ ā§Š:
SaveSelectedProducts (āĻŽāĻĄā§āϞā§āϰ āĻĒāϰā§)
LLM āĻĒā§āĻļāĻžāĻā§āϰ āĻĒāϰāĻžāĻŽāϰā§āĻļ āĻĻāĻŋāϝāĻŧā§ āϏāĻžāĻĄāĻŧāĻž āĻĻā§āĻāϝāĻŧāĻžāϰ āĻĒāϰ, āĻāĻ āĻāϞāĻŦā§āϝāĻžāĻāĻāĻŋ JSON āĻĒāĻžāϰā§āϏ āĻāϰ⧠āĻĒā§āϰā§āĻĄāĻžāĻā§āĻ āĻāĻāĻĄāĻŋāĻā§āϞ⧠āĻŦā§āϰ āĻāϰ⧠āĻāĻŦāĻ āĻĒāϰāĻŦāϰā§āϤ⧠āϏāĻŽāϝāĻŧā§ āĻŦā§āϝāĻŦāĻšāĻžāϰā§āϰ āĻāύā§āϝ InjectPreviousProducts āĻāϞāĻŦā§āϝāĻžāĻā§āϰ āĻāύā§āϝ āϏā§āĻā§āϞ⧠āϏāĻāϰāĻā§āώāĻŖ āĻāϰ⧠āϰāĻžāĻā§:
func SaveSelectedProducts(ctx agent.CallbackContext, resp *model.LLMResponse, respErr error) (*model.LLMResponse, error) {
for _, part := range resp.Content.Parts {
ids := extractProductIDs(part.Text) // Parse JSON â extract product IDs
if len(ids) > 0 {
data, _ := json.Marshal(ids)
ctx.State().Set(stateKeyPreviousProducts, string(data)) // Save to state
}
}
return nil, nil // Don't modify the response
}
āĻāĻāϤā§āϰā§, āĻāĻ āϤāĻŋāύāĻāĻŋ āĻāϞāĻŦā§āϝāĻžāĻ āĻāĻāĻāĻŋ āĻĢāĻŋāĻĄāĻŦā§āϝāĻžāĻ āϞā§āĻĒ āϤā§āϰāĻŋ āĻāϰā§:
Request 1: User sends styling request + user image
â ExtractAndInjectUserImage SAVES image to state
â LLM generates 3 outfits
â SaveSelectedProducts SAVES product IDs to state
Request 2: User says "make it more casual"
â ExtractAndInjectUserImage INJECTS saved image into prompt
â InjectPreviousProducts INJECTS "don't reuse these IDs"
â LLM generates 3 NEW outfits
â SaveSelectedProducts UPDATES product IDs in state
ā§Ŧ.ā§Š āĻŽā§āϞ āĻāĻā§āύā§āĻ
āĻĢāĻžāĻāϞ:
adk_backend/rootagent/agent.go
āϏāĻŦāĻā§āϝāĻŧā§ āϏāϰāϞ āĻāĻā§āύā§āĻ â āĻŽāĻžāϤā§āϰ ā§Šā§§ āϞāĻžāĻāύ:
func NewRootAgent(project string, fittingAgent, catalogAgent, stylistAgent agent.Agent) (agent.Agent, error) {
m, _ := gemini.NewModel(ctx, "gemini-3-flash-preview", &genai.ClientConfig{
Backend: genai.BackendVertexAI,
Project: project,
Location: "global",
})
return llmagent.New(llmagent.Config{
Name: "root_agent",
Model: m,
Description: "A root agent that delegates to other agents",
Instruction: "You are a helpful shopping assistant. If the user asks about fitting " +
"items or generating images, delegate to the fitting room agent. If the user " +
"asks about products, delegate to the catalog agent. If the user asks for " +
"styling advice, delegate to the stylist agent.",
SubAgents: []agent.Agent{fittingAgent, catalogAgent, stylistAgent},
})
}
āĻāĻāĻŋ gemini-3-flash-preview (āĻĻā§āϰā§āϤāϤāĻŽ āĻŽāĻĄā§āϞ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§, āĻāĻžāϰāĻŖ āϰāĻžāĻāĻāĻŋāĻ āϏāĻāĻā§āϰāĻžāύā§āϤ āϏāĻŋāĻĻā§āϧāĻžāύā§āϤāĻā§āϞ⧠āϏāĻšāĻ â LLM-āĻā§ āĻļā§āϧ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻ
āĻāĻŋāĻĒā§āϰāĻžāϝāĻŧ āĻĒāĻĄāĻŧāϤ⧠āĻšāϝāĻŧ āĻāĻŦāĻ āϏāĻ āĻŋāĻ āϏāĻžāĻŦ-āĻāĻā§āύā§āĻ āĻŦā§āĻā§ āύāĻŋāϤ⧠āĻšāϝāĻŧāĨ¤ āĻā§āύ⧠āĻā§āϞā§āϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āύā§āĻ; SubAgents āϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ āĻĻāĻžāϝāĻŧāĻŋāϤā§āĻŦ āĻ
āϰā§āĻĒāĻŖā§āϰ āĻāĻžāĻāĻāĻŋ āĻāϰā§āĨ¤
ā§. đą āĻĢā§āϞāĻžāĻāĻžāϰ āĻĢā§āϰāύā§āĻāĻāύā§āĻĄ āĻāϰā§āĻāĻŋāĻā§āĻāĻāĻžāϰ
āĻĢā§āϞāĻžāĻāĻžāϰ āĻĢā§āϰāύā§āĻāĻāύā§āĻĄāĻāĻŋ āĻāĻāĻāĻŋ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻāĻžāϰā§āϝāĻāϰ⧠āϰāĻŋāĻā§āĻāϞ āĻļāĻĒāĻŋāĻ āĻ
ā§āϝāĻžāĻĒāĨ¤ āĻāĻāĻ āĻĢāĻŋāĻāĻžāϰāĻā§āϞ⧠flutter_frontend/lib/workshop_tasks/ āĻĢā§āϞā§āĻĄāĻžāϰ⧠āĻĨāĻžāĻā§, āϝāĻž core_app/ āĻ āĻĨāĻžāĻāĻž āĻāĻā§ āĻĨā§āĻā§ āϤā§āϰāĻŋ āĻļāĻĒāĻŋāĻ āĻ
āĻāĻŋāĻā§āĻāϤāĻž āĻĨā§āĻā§ āĻāϞāĻžāĻĻāĻžāĨ¤
MVVM āĻĒā§āϝāĻžāĻāĻžāϰā§āύ
āĻ ā§āϝāĻžāĻĒāĻāĻŋ Provider āĻĒā§āϝāĻžāĻā§āĻ āϏāĻš Model-View-ViewModel āĻāϰā§āĻāĻŋāĻā§āĻāĻāĻžāϰ āĻ āύā§āϏāϰāĻŖ āĻāϰā§:
ââââââââââââââââââââ ââââââââââââââââââââââ ââââââââââââââââââââ
â View (Widget) ââââââ ViewModel (Provider)ââââââ Service (HTTP) â
â â â â â â
â âĸ Renders UI â â âĸ Holds state â â âĸ Makes API callsâ
â âĸ User gestures âââââļâ âĸ Business logic âââââļâ âĸ Parses responseâ
â âĸ Listens for â â âĸ notifyListeners() â â âĸ Returns data â
â state changes â â â â â
ââââââââââââââââââââ ââââââââââââââââââââââ ââââââââââââââââââââ
āĻĒā§āϰāϤāĻŋāĻāĻŋ āϏā§āϤāϰā§āϰ āĻāĻāĻāĻŋ āϏā§āϏā§āĻĒāώā§āĻ āĻā§āĻŽāĻŋāĻāĻž āϰāϝāĻŧā§āĻā§:
- āĻŽāĻĄā§āϞ :
Product,Outfit,StyleRequestāĻŽāϤ⧠āĻĄā§āĻāĻž āĻā§āϞāĻžāϏ āĻāĻŦāĻTryOnStateāĻŽāϤ⧠āĻāύāĻžāĻŽāĨ¤ - ViewModel (
ChangeNotifier): āĻŦāϰā§āϤāĻŽāĻžāύ āĻ āĻŦāϏā§āĻĨāĻž āϧāĻžāϰāĻŖ āĻāϰ⧠āĻāĻŦāĻnotifyListeners()āĻāϰ āĻŽāĻžāϧā§āϝāĻŽā§ UI-āϤ⧠āĻĒāϰāĻŋāĻŦāϰā§āϤāύāϏāĻŽā§āĻš āĻĒā§āϰāĻāĻžāϰ āĻāϰā§āĨ¤ - āĻāĻŋāĻ (āĻāĻāĻā§āĻ):
context.watchāĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠ViewModel-āĻ āϏāĻžāĻŦāϏā§āĻā§āϰāĻžāĻāĻŦ āĻāϰā§āĨ¤() context.watchāĻāĻŦāĻ āĻ āĻŦāϏā§āĻĨāĻžāϰ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻšāϞ⧠āĻĒā§āύāϰā§āύāĻŋāϰā§āĻŽāĻžāĻŖ āĻāϰā§() - āĻĒāϰāĻŋāώā§āĻŦāĻž : ADK āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§ HTTP āĻāϞ āĻāϰ⧠āĻāĻŦāĻ āĻāĻžāĻāĻĒ āĻāϰāĻž āĻĄā§āĻāĻž āĻĢā§āϰāϤ āĻĻā§āϝāĻŧāĨ¤
āϏāĻžāϰā§āĻāĻŋāϏ āϞā§āϝāĻŧāĻžāϰ
āϏāĻžāϰā§āĻāĻŋāϏāĻā§āϞā§āĻā§ āĻ ā§āϝāĻžāĻŦāϏā§āĻā§āϰāĻžāĻā§āĻ āĻāύā§āĻāĻžāϰāĻĢā§āϏ āĻšāĻŋāϏā§āĻŦā§ āϏāĻāĻā§āĻāĻžāϝāĻŧāĻŋāϤ āĻāϰāĻž āĻšāϝāĻŧ, āϝā§āĻā§āϞā§āϰ ADK-āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻāĻŽāĻĒā§āϞāĻŋāĻŽā§āύā§āĻā§āĻļāύ āϰāϝāĻŧā§āĻā§:
// Abstract interface â defines WHAT the service does
abstract class TryItOnService {
Future<(Uint8List?, String?)> generateTryOnImage(
Uint8List userImageBytes,
Uint8List productImageBytes,
);
}
// Concrete implementation â defines HOW (via ADK REST API)
class AdkFittingRoomService implements TryItOnService { ... }
āĻāĻ āĻĒā§āĻĨāĻā§āĻāϰāĻŖā§āϰ āĻ āϰā§āĻĨ āĻšāϞā§, āĻāĻĒāύāĻŋ āĻ ā§āϝāĻžāĻĒā§āϰ āĻŦāĻžāĻāĻŋ āĻ āĻāĻļ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āύāĻž āĻāϰā§āĻ ADK āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ āĻĒāϰāĻŋāĻŦāϰā§āϤ⧠Firebase AI, āĻāĻāĻāĻŋ āĻŽāĻ āϏāĻžāϰā§āĻāĻŋāϏ āĻŦāĻž āĻ āύā§āϝ āϝā§āĻā§āύ⧠āĻāĻŽāĻĒā§āϞāĻŋāĻŽā§āύā§āĻā§āĻļāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻĒāĻžāϰāĻŦā§āύāĨ¤
ā§Š-āϧāĻžāĻĒā§āϰ āĻāĻĒāĻŋāĻāĻ āĻĒā§āϝāĻžāĻāĻžāϰā§āύ
AdkFittingRoomService āĻāĻŦāĻ AdkStylingService āĻāĻāϝāĻŧāĻ ADK āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ āϏāĻžāĻĨā§ āϝā§āĻāĻžāϝā§āĻā§āϰ āĻāύā§āϝ āĻāĻāĻ āĻĒāĻĻā§āϧāϤāĻŋ āĻ
āύā§āϏāϰāĻŖ āĻāϰā§:
āϧāĻžāĻĒ ā§§: āĻāĻāĻāĻŋ āϏā§āĻļāύ āϤā§āϰāĻŋ āĻāϰā§āύ
Future<String> _createSession() async {
final url = Uri.parse(
'$_baseUrl/apps/${Uri.encodeComponent(_appName)}/users/$_userId/sessions');
final response = await _client.post(url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({}));
final body = jsonDecode(response.body) as Map<String, dynamic>;
return body['id'] as String; // Returns the session ID
}
āϧāĻžāĻĒ ā§¨: āĻāĻā§āύā§āĻāĻāĻŋ āĻāĻžāϞāĻžāύ
Future<(String?, String?)> _runAgent({required String sessionId, ...}) async {
final requestBody = jsonEncode({
'appName': _appName,
'userId': _userId,
'sessionId': sessionId,
'newMessage': {
'role': 'user',
'parts': [
{'text': 'Generate a virtual try-on...'},
{'inlineData': {'mimeType': 'image/jpeg', 'data': base64Encode(userImageBytes)}},
{'inlineData': {'mimeType': 'image/png', 'data': base64Encode(productImageBytes)}},
],
},
});
final response = await _client.post(Uri.parse('$_baseUrl/run'), body: requestBody);
// Parse response events for artifact name and GCS URL...
}
āϧāĻžāĻĒ ā§Š: āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻāĻāĻŋ āύāĻŋāϝāĻŧā§ āĻāϏā§āύ
Future<Uint8List?> _loadArtifact({required String sessionId, required String artifactName}) async {
final url = Uri.parse(
'$_baseUrl/apps/$_appName/users/$_userId/sessions/$sessionId/artifacts/$artifactName');
final response = await _client.get(url);
final part = jsonDecode(response.body) as Map<String, dynamic>;
final data = part['inlineData']['data'] as String;
return base64Decode(data); // Returns raw image bytes
}
āĻĄāĻŋāĻāĻžāĻāύ⧠āĻāĻāĻāĻŋ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻĒāĻžāϰā§āĻĨāĻā§āϝ āĻšāϞā§: āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āϏāĻžāϰā§āĻāĻŋāϏ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻ
āύā§āϰā§āϧā§āϰ āĻāύā§āϝ āĻāĻāĻāĻŋ āύāϤā§āύ āϏā§āĻļāύ āϤā§āϰāĻŋ āĻāϰ⧠(āĻĒā§āϰāϤāĻŋāĻŦāĻžāϰ _createSession() āĻāϞ āĻāϰāĻž āĻšāϝāĻŧ), āĻ
āύā§āϝāĻĻāĻŋāĻā§ āϏā§āĻāĻžāĻāϞāĻŋāĻ āϏāĻžāϰā§āĻāĻŋāϏ āĻāĻāĻ āϏā§āĻļāύ āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠( _sessionId ??= await _createSession() ) āϝāĻžāϤ⧠āĻāĻāĻžāϧāĻŋāĻāĻŦāĻžāϰ āĻāĻĨā§āĻĒāĻāĻĨāύ āϏāĻŽā§āĻāĻŦ āĻšāϝāĻŧāĨ¤
āϏā§āĻā§āĻ āĻŽā§āϝāĻžāύā§āĻāĻŽā§āύā§āĻ: āĻĻā§āϝ āĻā§āϰāĻžāĻāĻāĻāĻ āύāĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰ
āĻĢāĻžāĻāϞ:
workshop_tasks/step_1_try_it_on/providers/try_it_on_provider.dart
TryItOnProvider āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻā§āϰāĻžāĻ-āĻ
āύ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻžāĻāĻŋ āĻĒāϰāĻŋāĻāĻžāϞāύāĻž āĻāϰā§āĨ¤ āĻāĻāĻŋ āĻāĻāĻāĻŋ āϏā§āĻā§āĻ āĻŽā§āĻļāĻŋāύ āĻšāĻŋāϏā§āĻŦā§ TryOnState enum āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§:
enum TryOnState { initial, imagePicked, generating, success, error }
class TryItOnProvider with ChangeNotifier {
TryOnState _state = TryOnState.initial;
Uint8List? _userImageBytes;
Uint8List? _generatedImage;
String? _errorMessage;
āĻĒā§āϰāĻžāĻāĻā§āĻ āϏā§āĻā§āĻ āĻā§āϰāĻžāύāĻāĻŋāĻļāύ āϏāĻžāĻŽāĻā§āĻāϏā§āϝ āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰ⧠â āĻāĻĒāύāĻŋ āĻāĻāύā§āĻ āĻĒā§āϰāύ⧠āĻĄā§āĻāĻž āĻŽā§āĻā§ āύāĻž āĻĢā§āϞ⧠āĻāĻŦāĻ UI-āĻā§ āĻ āĻŦāĻšāĻŋāϤ āύāĻž āĻāϰ⧠āϏā§āĻā§āĻ āĻāĻĒāĻĄā§āĻ āĻāϰā§āύ āύāĻž:
void _setGenerating() {
_state = TryOnState.generating;
_errorMessage = null; // Clear any previous error
_wasLastGenerationCached = false;
notifyListeners(); // Tell the UI to rebuild
}
void _setSuccess(Uint8List image, {bool isCached = false}) {
_generatedImage = image;
_errorMessage = null;
_wasLastGenerationCached = isCached;
_state = TryOnState.success;
notifyListeners();
}
āĻĒā§āϰāϧāĻžāύ āĻā§āĻĒāĻžāĻĻāύ āĻĒāĻĻā§āϧāϤāĻŋāĻāĻŋāĻ āϏāĻŦāĻāĻŋāĻā§āĻā§ āĻāĻāϤā§āϰāĻŋāϤ āĻāϰā§:
Future<String?> generateTryOnImage(String productImagePath) async {
final userImageBytes = _userImageBytes;
if (userImageBytes == null) {
_setError('No image selected.');
return _errorMessage;
}
// Check local cache first
final cachedImage = ImageUtils.getCachedImage(_sessionCache, userImageBytes, productUint8List);
if (cachedImage != null) {
_setSuccess(cachedImage, isCached: true);
return null;
}
_setGenerating(); // Triggers loading state in UI
try {
final (generatedBytes, gcsUrl) = await _aiService.generateTryOnImage(
userImageBytes, productUint8List);
if (generatedBytes != null) {
_fittingGcsUrl = gcsUrl; // Save for the stylist agent later
_setSuccess(generatedBytes);
}
} catch (e) {
_setError(e.toString());
}
return _state == TryOnState.success ? null : _errorMessage;
}
UI: āϏā§āĻā§āĻ āϰāĻžāĻāĻāĻžāϰ āĻšāĻŋāϏā§āĻŦā§ āϏā§āĻā§āϰāĻŋāύ
āĻĢāĻžāĻāϞ:
workshop_tasks/step_1_try_it_on/ui/2_try_it_on_screen.dart
āĻā§āϰāĻžāĻ-āĻ
āύ āϏā§āĻā§āϰāĻŋāύāĻāĻŋ āĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰā§āϰ āĻ
āĻŦāϏā§āĻĨāĻžāϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰ⧠āϏāĻžāĻŦ-āϏā§āĻā§āϰāĻŋāύāĻā§āϞāĻŋāϰ āĻŽāϧā§āϝ⧠āϰāĻžāĻāĻāĻŋāĻ āĻāϰāĻžāϰ āĻāύā§āϝ āĻĄāĻžāϰā§āĻ ā§Š-āĻāϰ āĻĒā§āϝāĻžāĻāĻžāϰā§āύ āĻŽā§āϝāĻžāĻāĻŋāĻ āĻ AnimatedSwitcher āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§:
class TryItOnScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final tryOnProvider = context.watch<TryItOnProvider>();
return ScaffoldWithBackgroundNoise(
appBar: const TryOnAppBar(),
body: AnimatedSwitcher(
duration: AppDurations.medium,
child: switch (tryOnProvider.state) {
TryOnState.initial || TryOnState.error => const ChooseImageScreen(),
TryOnState.imagePicked || TryOnState.generating => LoadingScreen(
userImage: tryOnProvider.userImageBytes),
TryOnState.success => const FittingRoomScreen(),
},
),
);
}
}
context.watch āĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰāĻā§ āϏāĻžāĻŦāϏā§āĻā§āϰāĻžāĻāĻŦ āĻāϰā§āĨ¤ āϝāĻāύāĻ notifyListeners() āĻāϞ āĻāϰāĻž āĻšāϝāĻŧ, āĻāĻ āĻāĻāĻā§āĻāĻāĻŋ āϰāĻŋāĻŦāĻŋāϞā§āĻĄ āĻšāϝāĻŧ āĻāĻŦāĻ AnimatedSwitcher āĻŽāϏā§āĻŖāĻāĻžāĻŦā§ āϏā§āĻā§āϰāĻŋāύāĻā§āϞā§āϰ āĻŽāϧā§āϝ⧠āĻā§āϰāĻžāύāĻāĻŋāĻļāύ āĻāϰā§āĨ¤ āĻāĻāĻžāύ⧠Navigator.push āύā§āĻ â āϏā§āĻā§āĻ āĻāύāĻžāĻŽā§āϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰ⧠āϏā§āĻā§āϰāĻŋāύā§āϰ āĻāύā§āĻā§āύā§āĻ āĻāύ-āĻĒā§āϞā§āϏ āĻĒāϰāĻŋāĻŦāϰā§āϤāĻŋāϤ āĻšāϝāĻŧāĨ¤
āĻāĻā§āύā§āĻāĻŋāĻ āĻšāϏā§āϤāĻžāύā§āϤāϰ: āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ â āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ
āϏāĻŦāĻā§āϝāĻŧā§ āĻāĻāϰā§āώāĻŖā§āϝāĻŧ āĻāĻāĻāĻā§āϏ āĻĒā§āϝāĻžāĻāĻžāϰā§āύāĻāĻŋ āĻšāϞā§, āĻ ā§āϝāĻžāĻĒāĻāĻŋ āĻā§āĻāĻžāĻŦā§ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āĻāĻā§āύā§āĻ āĻĨā§āĻā§ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻā§āϰ āĻāĻžāĻā§ āĻāύāĻā§āĻā§āϏāĻ āĻĒā§āϰā§āϰāĻŖ āĻāϰā§āĨ¤
5_fitting_room.dart āĻĢāĻžāĻāϞā§, āĻā§āϰāĻžāĻ-āĻ
āύ āĻāĻŽā§āĻāĻāĻŋ āϤā§āϰāĻŋ āĻšāĻāϝāĻŧāĻžāϰ āĻĒāϰ, "Style Me" āĻŦāĻžāĻāύāĻāĻŋ āĻāĻāĻāĻŋ āĻĢāϰā§āĻŽ āĻā§āϞā§āĨ¤ āϝāĻāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āϏāĻžāĻŦāĻŽāĻŋāĻ āĻāϰā§āύ:
// From 1_style_me_form_sheet.dart
Navigator.pop(context, StyleRequest(
location: _locationController.text.trim(),
occasion: _occasionController.text.trim(),
notes: _notesController.text.trim(),
gcsUserImageUrl: provider.fittingGcsUrl, // GCS URI from fitting result
userImageData: provider.fittingGcsUrl == null
? provider.userImageBytes : null, // Fallback to raw bytes
selectedProductId: provider.selectedProduct?.id, // Product they already tried on
selectedProductTitle: provider.selectedProduct?.title,
));
StyleRequest āĻāϰ āĻŽāϧā§āϝ⧠āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻā§āϰ āĻĒā§āϰāϝāĻŧā§āĻāύā§āϝāĻŧ āϏāĻŦāĻāĻŋāĻā§ āĻ
āύā§āϤāϰā§āĻā§āĻā§āϤ āϰāϝāĻŧā§āĻā§:
- āĻ āĻŦāϏā§āĻĨāĻžāύ āĻ āĻāĻĒāϞāĻā§āώ â āϏā§āĻāĻžāĻāϞāĻŋāĻāϝāĻŧā§āϰ āĻāύā§āϝ āĻā§āĻā§āϏāĻā§āϰ āĻĒā§āϰā§āĻā§āώāĻžāĻĒāĻ
- GCS āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋāϰ URL â āϝāĻžāϤ⧠āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻšā§āĻŦāĻšā§ āĻāĻāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻĒāϏā§āĻĨāĻžāĻĒāύāĻž āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻĒāĻžāϰā§āύāĨ¤
- āύāĻŋāϰā§āĻŦāĻžāĻāĻŋāϤ āĻĒāĻŖā§āϝ â āϤāĻžāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻāĻŋ āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻĒā§āĻļāĻžāĻā§ āĻ āύā§āϤāϰā§āĻā§āĻā§āϤ āĻāϰā§āύāĨ¤
āĻāĻāĻžāĻ āĻšāϞ⧠āĻāĻā§āύā§āĻāĻŋāĻ āĻšā§āϝāĻžāύā§āĻĄāĻ āĻĢ â āϝāĻžāϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻāĻāĻāĻŋ āĻāĻāĻ āĻāĻā§āύā§āĻ āĻĨā§āĻā§ āĻ āύā§āϝāĻāĻŋāϤ⧠āĻŽāĻžāϞā§āĻāĻŋāĻŽā§āĻĄāĻžāϞ āĻāύāĻā§āĻā§āϏāĻ āύāĻŋāϰā§āĻŦāĻŋāĻā§āύ⧠āϏā§āĻĨāĻžāύāĻžāύā§āϤāϰ āĻāϰāĻž āĻšāϝāĻŧ, āĻāĻŦāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āĻļā§āϧā§āĻŽāĻžāϤā§āϰ āĻāĻāĻāĻŋ āϏāĻžāϧāĻžāϰāĻŖ āĻĢāϰā§āĻŽ āĻĻā§āĻāϤ⧠āĻĒāĻžāύāĨ¤
āϏā§āĻāĻžāĻāϞāĻŋāĻ āĻĒā§āϰāĻŦāĻžāĻš: āϏā§āĻāĻžāĻāϞāĻŋāĻāĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰ
āĻĢāĻžāĻāϞ:
workshop_tasks/step_2_style_me/providers/styling_provider.dart
StylingProvider TryItOnProvider āĻā§āϝāĻŧā§ āϏāϰāϞ, āĻāĻžāϰāĻŖ āĻāĻāĻŋ āĻ
āϧāĻŋāĻāĻžāĻāĻļ āĻāĻāĻŋāϞāϤāĻž āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ āĻāĻĒāϰ āĻ
āϰā§āĻĒāĻŖ āĻāϰā§:
class StylingProvider with ChangeNotifier {
StylingState _state = StylingState.initial;
List<Outfit> _outfits = [];
Future<bool> getStyleSuggestions(StyleRequest request) async {
if (_state == StylingState.loading) return false; // Prevent spam
_currentRequest = request;
_setLoading();
try {
final suggestions = await _stylingService.getStyleSuggestions(request);
_setSuccess(suggestions);
return true;
} catch (e) {
_setError('Something went wrong.');
}
return false;
}
// Multi-turn refinement â uses the same session
Future<bool> refineWithFeedback(String feedback) async {
if (_state == StylingState.loading) return false;
_setLoading();
try {
final suggestions = await _stylingService.refineWithFeedback(feedback);
_setSuccess(suggestions);
return true;
} catch (e) {
_setError('Something went wrong.');
}
return false;
}
}
refineWithFeedback āĻŽā§āĻĨāĻĄāĻāĻŋ āĻāĻāĻ āϏā§āĻļāύ⧠āĻāĻāĻāĻŋ āĻĒā§āϞā§āĻāύ āĻā§āĻā§āϏāĻ āĻŽā§āϏā§āĻ āĻĒāĻžāĻ āĻžāϝāĻŧ â āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ ` InjectPreviousProducts āĻāĻŦāĻ ExtractAndInjectUserImage āĻāϞāĻŦā§āϝāĻžāĻāĻā§āϞ⧠āϏā§āĻŦāϝāĻŧāĻāĻā§āϰāĻŋāϝāĻŧāĻāĻžāĻŦā§ āϏāĻŽāϏā§āϤ āĻāύāĻā§āĻā§āϏāĻ āĻŽā§āϝāĻžāύā§āĻāĻŽā§āύā§āĻ āϏāĻžāĻŽāϞ⧠āύā§āϝāĻŧāĨ¤
ā§Ž. đ āĻ ā§āϝāĻžāĻĒāĻāĻŋ āϏā§āĻĨāĻžāύā§āϝāĻŧāĻāĻžāĻŦā§ āĻāĻžāϞāĻžāύ
āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ-āĻāϰ āĻŽāϏā§āĻŖ āĻ āĻāĻŋāĻā§āĻāϤāĻžāϰ āĻāύā§āϝ, āĻā§ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻāĻŽā§āĻĒāĻžāĻāϞ āĻāϰāĻž āĻĢā§āϞāĻžāĻāĻžāϰ āĻāϝāĻŧā§āĻŦ āĻ ā§āϝāĻžāĻĒāĻāĻŋ āĻāĻāĻ āĻĒā§āϰā§āĻ (ā§Žā§Ļā§Žā§Ļ) āĻĨā§āĻā§ āĻĒāϰāĻŋāĻŦā§āĻļāύ āĻāϰā§āĨ¤ āĻāĻāĻāĻŋ āĻĒā§āϰāϏā§āϏ, āĻāĻāĻāĻŋ āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻāĻāĻāϰāĻāϞ, āĻā§āϰāϏ-āĻ āϰāĻŋāĻāĻŋāύ āϏāĻāĻā§āϰāĻžāύā§āϤ āĻā§āύ⧠āĻāĻžāĻŽā§āϞāĻž āύā§āĻ, āĻāύāĻĢāĻŋāĻāĻžāϰā§āĻļāύ āĻĢāĻžāĻāϞ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻžāϰāĻ āĻĒā§āϰāϝāĻŧā§āĻāύ āύā§āĻāĨ¤
āĻļā§āϰ⧠āĻāϰāĻžāϰ āĻāĻā§ â ADC-āĻāĻŋ āϝā§āĻā§āϤāĻŋāĻāĻāĻžāĻŦā§ āϝāĻžāĻāĻžāĻ āĻāϰ⧠āύāĻŋāύāĨ¤
Vertex AI-āĻā§ āĻāϞ āĻāϰāĻžāϰ āĻāύā§āϝ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύ āĻĄāĻŋāĻĢāϞā§āĻ āĻā§āϰā§āĻĄā§āύāĻļāĻŋāϝāĻŧāĻžāϞ āĻĒā§āϰāϝāĻŧā§āĻāύāĨ¤ āĻāĻĒāύāĻŋ āϝāĻĻāĻŋ āĻāĻ āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āϏā§āĻļāύ āĻāĻŦāĻ āĻāĻ āĻā§āĻāϞ āĻ ā§āϝāĻžāĻāĻžāĻāύā§āĻā§ āĻĒā§āϰāĻā§āĻā§āĻ āϏā§āĻāĻāĻĒā§āϰ āϧāĻžāĻĒ ā§ āϏāĻŽā§āĻĒāύā§āύ āĻāϰ⧠āĻĨāĻžāĻā§āύ, āϤāĻžāĻšāϞ⧠āĻāϰ āĻāĻŋāĻā§ āĻāϰāĻžāϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āύā§āĻāĨ¤ āĻāĻĒāύāĻŋ āϝāĻĻāĻŋ āĻŦāĻŋāϰāϤāĻŋāϰ āĻĒāϰ āĻĢāĻŋāϰ⧠āĻāϏā§āύ, āĻ ā§āϝāĻžāĻāĻžāĻāύā§āĻ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰ⧠āĻĨāĻžāĻā§āύ, āĻŦāĻž āύāĻŋāĻļā§āĻāĻŋāϤ āύāĻž āĻšāύ, āϤāĻžāĻšāϞ⧠āϝāĻžāĻāĻžāĻ āĻāϰāĻžāϰ āĻāύā§āϝ ā§Ģ āϏā§āĻā§āύā§āĻĄ āϏāĻŽāϝāĻŧ āύāĻŋāύ:
gcloud auth application-default print-access-token | head -c 20 && echo "..."
āϝāĻĻāĻŋ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻā§āĻā§āύā§āϰ āĻĒā§āϰāĻžāϝāĻŧ ⧍ā§ĻāĻāĻŋ āĻ āĻā§āώāϰ āĻĒā§āϰāĻŋāύā§āĻ āĻāϰā§, āϤāĻžāĻšāϞ⧠āĻāĻĒāύāĻžāϰ āĻāĻžāĻ āĻšāϝāĻŧā§ āĻā§āĻā§āĨ¤ āϝāĻĻāĻŋ āĻā§āύ⧠āϤā§āϰā§āĻāĻŋ āĻšāϝāĻŧ, āϤāĻžāĻšāϞ⧠āĻĒā§āϰāĻā§āĻā§āĻ āϏā§āĻāĻāĻĒā§āϰ āϧāĻžāĻĒ ā§ āĻāĻŦāĻžāϰ āĻāĻžāϞāĻžāύ :
gcloud auth application-default login
gcloud auth application-default set-quota-project $(gcloud config get-value project)
āĻāĻĒāύāĻŋ āĻĻā§āĻāĻŋ āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύ:
- āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ A â āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻ
āĻŦāĻŋāϰāĻžāĻŽ āĻāĻžāϞ⧠āϰāĻžāĻā§ (
./run.sh)āĨ¤ āĻāĻāĻŋ āĻā§āϞāĻž āϰāĻžāĻā§āύāĨ¤ - āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ āĻŦāĻŋ â āĻĢā§āϞāĻžāĻāĻžāϰ āĻāϝāĻŧā§āĻŦ āĻŦāĻŋāϞā§āĻĄ āĻāĻāĻŦāĻžāϰ āĻāĻžāϞāĻžāϝāĻŧ (
flutter build web)āĨ¤ āĻāĻžāĻ āĻļā§āώ āĻšāϞ⧠āĻāĻāĻŋ āĻŦāύā§āϧ āĻšāϝāĻŧā§ āϝāĻžāϝāĻŧāĨ¤
āĻā§āϰāĻŽāĻāĻŋ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āύāϝāĻŧ â āĻāĻĒāύāĻŋ āϝā§āĻā§āύ⧠āĻāĻāĻāĻŋ āĻĒā§āϰāĻĨāĻŽā§ āĻļā§āϰ⧠āĻāϰāϤ⧠āĻĒāĻžāϰā§āύāĨ¤ āĻāĻŋāύā§āϤ⧠āĻĒā§āϰāĻĨāĻŽāĻŦāĻžāϰ āĻāĻžāϞāĻžāύā§āϰ āϏāĻŦāĻā§āϝāĻŧā§ āĻŽāϏā§āĻŖ āĻ āĻāĻŋāĻā§āĻāϤāĻžāϰ āĻāύā§āϝ, āĻĒā§āϰāĻĨāĻŽā§ āĻĢā§āϞāĻžāĻāĻžāϰ āĻŦāĻŋāϞā§āĻĄ āĻāϰā§āύ, āϝāĻžāϤ⧠āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻāĻžāϞ⧠āĻšāĻāϝāĻŧāĻžāϰ āĻŽā§āĻšā§āϰā§āϤ āĻĨā§āĻā§āĻ āĻĒāϰāĻŋāĻŦā§āĻļāύ āĻāϰāĻžāϰ āĻāύā§āϝ āĻāĻāĻāĻŋ UI āĻĒā§āϰāϏā§āϤā§āϤ āĻĨāĻžāĻā§āĨ¤
ā§§. āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ āĻŦāĻŋ â āĻĢā§āϞāĻžāĻāĻžāϰ āĻāϝāĻŧā§āĻŦ āĻŦāĻžāύā§āĻĄā§āϞ āϤā§āϰāĻŋ āĻāϰā§āύ (āĻāĻāĻāĻžāϞā§āύ)
āĻāĻāĻāĻŋ āύāϤā§āύ āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āĻā§āϝāĻžāĻŦ āĻā§āϞā§āύ (āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ āĻĒā§āϝāĻžāύā§āϞā§āϰ āĻāĻĒāϰā§āϰ + āĻāĻŋāĻšā§āύ⧠āĻā§āϞāĻŋāĻ āĻāϰā§āύ), āϤāĻžāϰāĻĒāϰ:
cd ~/fashion_app_demo/flutter_frontend
flutter pub get
flutter build web
āĻāĻāĻŋ flutter_frontend/build/web/ āύāĻžāĻŽā§ āĻāĻāĻāĻŋ āĻĄāĻŋāϰā§āĻā§āĻāϰāĻŋ āϤā§āϰāĻŋ āĻāϰā§, āϝā§āĻāĻžāύ⧠āϏā§āĻā§āϝāĻžāĻāĻŋāĻ āĻĢāĻžāĻāϞ (HTML, JS, assets) āĻĨāĻžāĻā§ āĻāĻŦāĻ āĻāĻžāĻ āĻļā§āώ āĻšāϞ⧠āĻāĻāĻŋ āĻŦāύā§āϧ āĻšāϝāĻŧā§ āϝāĻžāϝāĻŧāĨ¤ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻĄāĻŋāϰā§āĻā§āĻāϰāĻŋāĻāĻŋ āĻĻā§āĻāĻžāĻŽāĻžāϤā§āϰāĻ āĻĢāĻžāĻāϞāĻā§āϞ⧠āĻĒāϰāĻŋāĻŦā§āĻļāύ āĻāϰāĻŦā§āĨ¤
⧍. āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞ āĻ â āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āĻāĻžāϞ⧠āĻāϰā§āύ (āĻĻā§āϰā§āĻāϏā§āĻĨāĻžāϝāĻŧā§ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻž)
āĻāĻĒāύāĻžāϰ āĻŽā§āϞ āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞ āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞā§:
cd ~/fashion_app_demo/adk_backend
./run.sh
āĻāĻĒāύāĻŋ āĻāĻāϰāĻāĻŽ āĻāĻŋāĻā§ āĻĻā§āĻāϤ⧠āĻĒāĻžāĻŦā§āύ:
Serving Flutter web build from ../flutter_frontend/build/web
āĻāĻ āĻāĻžāϰā§āĻŽāĻŋāύāĻžāϞāĻāĻŋ āĻāĻžāϞ⧠āϰāĻžāĻā§āύ â āϝāϤāĻā§āώāĻŖ run.sh āĻĨāĻžāĻāĻŦā§, āĻŦā§āϝāĻžāĻāĻāύā§āĻĄāĻ āϤāϤāĻā§āώāĻŖ āϏāĻāϞ āĻĨāĻžāĻāĻŦā§āĨ¤ āĻāĻāĻŋ āĻŦāύā§āϧ āĻāϰāϤ⧠Ctrl+C āĻāĻžāĻĒā§āύāĨ¤
āϏāĻžāϰā§āĻāĻžāϰāĻāĻŋ ā§Žā§Ļā§Žā§Ļ āĻĒā§āϰā§āĻā§ āϏāĻŦāĻāĻŋāĻā§ āĻāύā§āĻŽā§āĻā§āϤ āĻāϰ⧠āĻĻā§āϝāĻŧ:
-
/āĻāϝāĻŧā§āĻŦ āĻ ā§āϝāĻžāĻĒ (āĻļāĻĒāĻŋāĻ UI) -
/api/â ADK REST āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻ (āĻĢā§āϞāĻžāĻāĻžāϰ āĻ ā§āϝāĻžāĻĒ āĻĻā§āĻŦāĻžāϰāĻž āĻāϞ āĻāϰāĻž āĻšāϝāĻŧ) - ADK Dev UI â āĻĢā§āϞāĻžāĻāĻžāϰ āĻŦāĻŋāϞā§āĻĄ āύāĻž āĻĨāĻžāĻāϞ⧠āĻāĻāĻŋ
/āĻāĻ āĻĒāĻžāĻāϝāĻŧāĻž āϝāĻžāϝāĻŧ; āϏāϰāĻžāϏāϰāĻŋ āĻāĻā§āύā§āĻ āĻĄāĻŋāĻŦāĻžāĻāĻŋāĻāϝāĻŧā§āϰ āĻāύā§āϝ āĻāĻĒāϝā§āĻā§āĨ¤
ā§Š. āĻāϝāĻŧā§āĻŦ āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻā§āϞā§āύ
- āĻā§āϞāĻžāĻāĻĄ āĻļā§āϞā§, āĻāϝāĻŧā§āĻŦ āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻāĻāĻāύ⧠(āĻāĻĒāϰā§āϰ-āĻĄāĻžāύāĻĻāĻŋāĻā§) āĻā§āϞāĻŋāĻ āĻāϰā§āύ â āĻĒā§āϰā§āĻ ā§Žā§Ļā§Žā§Ļ-āϤ⧠āĻĒā§āϰāĻŋāĻāĻŋāĻ āĻĻā§āĻā§āύāĨ¤
- āĻĢā§āϞāĻžāĻāĻžāϰ āĻļāĻĒāĻŋāĻ āĻ ā§āϝāĻžāĻĒāĻāĻŋ āĻāĻāĻāĻŋ āύāϤā§āύ āĻā§āϝāĻžāĻŦā§ āϞā§āĻĄ āĻšāϝāĻŧāĨ¤
- āĻĒāĻŖā§āϝā§āϰ āĻā§āϝāĻžāĻāĻžāϞāĻ āĻŦā§āϰāĻžāĻāĻ āĻāϰā§āύ āĻāĻŦāĻ āĻāĻāĻāĻŋ āĻāĻāĻā§āĻŽ āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰā§āύāĨ¤
- āĻā§āϰāĻžāĻ-āĻ āύ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻž āĻļā§āϰ⧠āĻāϰāϤ⧠āĻŦā§āϝāĻā§āϤāĻŋāϰ āĻāĻāĻāύ⧠(đ¤) āĻā§āϝāĻžāĻĒ āĻāϰā§āύāĨ¤
- āĻāĻāĻāĻŋ āĻāĻŦāĻŋ āĻāĻĒāϞā§āĻĄ āĻāϰā§āύ āĻāĻŦāĻ āĻĻā§āĻā§āύ āĻā§āĻāĻžāĻŦā§ āĻāĻāĻ āĻāĻāĻāĻŋ āĻā§āϰāĻžāĻ-āĻ āύ āĻāĻŽā§āĻ āϤā§āϰāĻŋ āĻāϰā§āĨ¤
- āĻĒā§āĻļāĻžāĻā§āϰ āĻĒāϰāĻžāĻŽāϰā§āĻļ āĻĒā§āϤ⧠'āϏā§āĻāĻžāĻāϞ āĻŽāĻŋ'-āϤ⧠āĻā§āϝāĻžāĻĒ āĻāϰā§āύāĨ¤
- âāĻāĻāĻŋāĻā§ āĻāϰāĻ āĻ āύāĻžāύā§āώā§āĻ āĻžāύāĻŋāĻ āĻāϰā§āύâ-āĻāϰ āĻŽāϤ⧠āĻĢāϞā§-āĻāĻĒ āĻĢāĻŋāĻĄāĻŦā§āϝāĻžāĻ āĻāĻžāĻāĻĒ āĻāϰā§āύ â āĻāĻāĻ āϏā§āĻļāύ⧠āĻĒāϰāĻŋāĻŽāĻžāϰā§āĻāύ
⧝. âī¸ āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ⧠āĻĄā§āĻĒā§āϞāϝāĻŧ āĻāϰā§āύ
āĻĢā§āϞāĻžāĻāĻžāϰ āĻŦāĻŋāϞā§āĻĄāĻāĻŋāĻā§ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§ āĻŦāĻžāύā§āĻĄāϞ āĻāϰā§āύ
āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ āĻāύā§āĻā§āĻāύāĻžāϰāĻāĻŋ āĻāĻĒāĻŋāĻāĻ āĻāĻŦāĻ āĻāĻāĻāĻ āĻāĻāϝāĻŧāĻ āĻāĻāĻāĻŋ āĻāĻŽā§āĻ āĻĨā§āĻā§ āϏāϰāĻŦāϰāĻžāĻš āĻāϰā§āĨ¤ āĻĢā§āϞāĻžāĻāĻžāϰ āĻāϝāĻŧā§āĻŦ āĻŦāĻŋāϞā§āĻĄāĻāĻŋ adk_backend/flutter_web/ -āĻ āĻāĻĒāĻŋ āĻāϰā§āύ â āĻā§āύ āĻāĻāĻāĻ āĻĒāϰāĻŋāĻŦā§āĻļāύ āĻāϰāĻž āĻšāĻŦā§ āϤāĻž āĻŦā§āĻā§ āύā§āĻāϝāĻŧāĻžāϰ āϏāĻŽāϝāĻŧ āĻā§ āϏāĻžāϰā§āĻāĻžāϰ āĻĒā§āϰāĻĨāĻŽā§ āĻāĻ āĻĒāĻžāĻĨāĻāĻŋāĻ āĻĒāϰā§āĻā§āώāĻž āĻāϰā§:
cd ~/fashion_app_demo/flutter_frontend
flutter build web
rm -rf ../adk_backend/flutter_web
cp -r build/web ../adk_backend/flutter_web
(āĻāĻĒāύāĻŋ āϝāĻĻāĻŋ āϏā§āĻĨāĻžāύā§āϝāĻŧāĻāĻžāĻŦā§ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋ āĻāϰ⧠āĻĨāĻžāĻā§āύ, āϤāĻžāĻšāϞ⧠Run-Locally āϧāĻžāĻĒ āĻĨā§āĻā§ āĻāĻĒāύāĻžāϰ āĻāĻžāĻā§ āĻāϤāĻŋāĻŽāϧā§āϝā§āĻ build/web āĻĨāĻžāĻāϤ⧠āĻĒāĻžāϰā§āĨ¤ flutter build web āĻĒā§āύāϰāĻžāϝāĻŧ āĻāĻžāϞāĻžāϞā§āĻ āĻā§āύ⧠āϏāĻŽāϏā§āϝāĻž āύā§āĻāĨ¤)
āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āϏā§āĻĨāĻžāĻĒāύ āĻāϰā§āύ (āĻāĻĒāĻŋāĻāĻ + āĻāĻāĻāĻ āĻĒāϰāĻŋāĻŦā§āĻļāύ āĻāϰā§)
cd ~/fashion_app_demo/adk_backend
gcloud run deploy fashion-app-backend \
--source . \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars "GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GCS_BUCKET=fashion-app-$PROJECT_ID" \
--memory 1Gi \
--cpu 2 \
--timeout 300s \
--min-instances 0 \
--max-instances 3
āĻĄāĻŋāĻĒā§āϞāϝāĻŧāĻŽā§āύā§āĻ āĻļā§āώ āĻšāϞā§, āĻāĻĒāύāĻŋ https://fashion-app-backend-xyz-uc.a.run.app āĻāϰ āĻŽāϤ⧠āĻāĻāĻāĻŋ āϏāĻžāϰā§āĻāĻŋāϏ āĻāĻāĻāϰāĻāϞ āĻĒāĻžāĻŦā§āύāĨ¤ āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻŦā§āϰāĻžāĻāĻāĻžāϰ⧠āĻā§āϞā§āύ â āĻĢā§āϞāĻžāĻāĻžāϰ āĻļāĻĒāĻŋāĻ āĻ
ā§āϝāĻžāĻĒāĻāĻŋ / āĻĨā§āĻā§ āϞā§āĻĄ āĻšāϝāĻŧ, āĻāĻŦāĻ āĻāϰ āĻāĻĒāĻŋāĻāĻ āĻāϞāĻā§āϞ⧠āĻāĻāĻ āĻšā§āϏā§āĻā§āϰ /api/ āϤ⧠āϝāĻžāϝāĻŧāĨ¤ āĻā§āύ⧠āĻĢā§āϰāύā§āĻāĻāύā§āĻĄ āĻāύāĻĢāĻŋāĻāĻžāϰā§āĻļāύ āϏāĻŽā§āĻĒāĻžāĻĻāύāĻžāϰ āĻĒā§āϰāϝāĻŧā§āĻāύ āύā§āĻ, āĻā§āύ⧠āĻāĻĒāĻŋāĻāĻ āĻā§-āĻ āĻĒāĻžāϏ āĻāϰāϤ⧠āĻšāĻŦā§ āύāĻžāĨ¤
āĻĄāĻŋāĻĒā§āϞāϝāĻŧāĻŽā§āύā§āĻ āϝāĻžāĻāĻžāĻ āĻāϰā§āύ
āĻāĻĒāύāĻžāϰ āĻŦā§āϰāĻžāĻāĻāĻžāϰ⧠āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ āĻāĻāĻāϰāĻāϞāĻāĻŋ āĻā§āϞā§āύ āĻāĻŦāĻ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻĒā§āϰāĻā§āϰāĻŋāϝāĻŧāĻžāĻāĻŋ āĻ āύā§āϏāϰāĻŖ āĻāϰā§āύ:
- āĻŦā§āϰāĻžāĻāĻ āĻāϰā§āύ â āĻāĻāĻāĻŋ āĻĒāĻŖā§āϝ āύāĻŋāϰā§āĻŦāĻžāĻāύ āĻāϰā§āύ
- āĻā§āϰāĻžāĻ āĻ āύ â āĻāĻĒāύāĻžāϰ āĻāĻŦāĻŋ āĻāĻĒāϞā§āĻĄ āĻāϰā§āύ â āĻāĻāĻ-āϤā§āϰāĻŋ āĻāĻŦāĻŋāĻāĻŋ āĻĻā§āĻā§āύ
- āϏā§āĻāĻžāĻāϞ āĻŽāĻŋ â āϏā§āĻĨāĻžāύ/āĻ āύā§āώā§āĻ āĻžāύ āĻĒā§āϰāĻŖ āĻāϰā§āύ â āύāĻŋāϰā§āĻŦāĻžāĻāĻŋāϤ āĻĒā§āĻļāĻžāĻāĻā§āϞ⧠āĻĻā§āĻā§āύ
- āĻŽāϤāĻžāĻŽāϤ āĻĻāĻŋāύ â 'āĻāϰāĻ āĻā§āϝāĻžāĻā§āϝāĻŧāĻžāϞ āĻāϰā§āύ' āĻāĻžāĻāĻĒ āĻāϰā§āύ â āĻāĻĒāĻĄā§āĻ āĻāϰāĻž āĻĒā§āĻļāĻžāĻāĻā§āϞ⧠āĻĻā§āĻā§āύ
- āĻŦā§āϝāĻžāĻā§ āϝā§āĻ āĻāϰā§āύ â āĻā§āύāĻžāĻāĻžāĻāĻž āϏāĻŽā§āĻĒāύā§āύ āĻāϰā§āύ
ā§§ā§Ļ. đ āĻāĻĒāϏāĻāĻšāĻžāϰ
āĻāĻĒāύāĻŋ āϝāĻž āϤā§āϰāĻŋ āĻāϰā§āĻā§āύ
āĻāĻĒāύāĻŋ āĻāĻāĻāĻŋ āϏāĻŽā§āĻĒā§āϰā§āĻŖ āĻāĻāĻ-āĻāĻžāϞāĻŋāϤ āĻā§āĻāϰāĻž āĻā§āύāĻžāĻāĻžāĻāĻžāϰ āĻ āĻāĻŋāĻā§āĻāϤāĻž āĻ āύā§āĻŦā§āώāĻŖ āĻāϰā§āĻā§āύ:
- â āĻāĻāĻāĻŋ āĻŽāĻžāϞā§āĻāĻŋ-āĻāĻā§āύā§āĻ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄ āϝā§āĻāĻžāύ⧠ā§Ē āĻāύ āĻŦāĻŋāĻļā§āώāĻžāϝāĻŧāĻŋāϤ āĻāĻā§āύā§āĻ āĻāĻāϏāĻžāĻĨā§ āĻāĻžāĻ āĻāϰā§
- â āĻāĻāĻāĻŋ āĻāĻžāϰā§āĻā§āϝāĻŧāĻžāϞ āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ āϝāĻž āĻāĻĒāύāĻžāϰ āĻĒāĻāύā§āĻĻ āĻ āύā§āϝāĻžāϝāĻŧā§ āĻā§āϰāĻžāĻ-āĻ āύ āĻāĻŦāĻŋ āϤā§āϰāĻŋ āĻāϰ⧠āĻĻā§āϝāĻŧ
- â āĻāĻāĻāύ āĻāĻāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ , āϝ⧠āĻāĻĨā§āĻĒāĻāĻĨāύā§āϰ āĻŽāĻžāϧā§āϝāĻŽā§ āĻĒā§āĻļāĻžāĻā§āϰ āϏāĻŽā§āĻāĻžāϰ āĻŦāĻžāĻāĻžāĻ āĻāϰ⧠āĻāĻŦāĻ āϏā§āĻā§āϞā§āĻā§ āĻāϰāĻ āĻĒāϰāĻŋāĻŽāĻžāϰā§āĻāĻŋāϤ āĻāϰā§āĨ¤
- â āĻāĻāĻāĻŋ āĻā§āϰāϏ-āĻĒā§āϞā§āϝāĻžāĻāĻĢāϰā§āĻŽ āĻĢā§āϞāĻžāĻāĻžāϰ āĻ ā§āϝāĻžāĻĒ āϝāĻž āĻāĻā§āύā§āĻ āĻŦā§āϝāĻžāĻāĻāύā§āĻĄā§āϰ āϏāĻžāĻĨā§ āϏāĻāϝā§āĻā§āϤ āĻšāϝāĻŧ
- â āĻĒāϰāĻŋāĻŦāϰā§āϧāύāϝā§āĻā§āϝ āĻ āϏāĻžāϰā§āĻāĻžāϰāĻŦāĻŋāĻšā§āύ āĻšā§āϏā§āĻāĻŋāĻāϝāĻŧā§āϰ āĻāύā§āϝ āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ āĻĄā§āĻĒā§āϞāϝāĻŧāĻŽā§āύā§āĻ
āĻŽā§āϞ āϧāĻžāϰāĻŖāĻž
āϧāĻžāϰāĻŖāĻž | āϝā§āĻāĻžāύ⧠āĻāĻĒāύāĻŋ āĻāĻāĻŋ āĻĻā§āĻā§āĻā§āύ |
ADK āĻŽāĻžāϞā§āĻāĻŋ-āĻāĻā§āύā§āĻ āĻ āϰā§āĻā§āϏā§āĻā§āϰā§āĻļāύ | āĻĢāĻŋāĻāĻŋāĻ āϰā§āĻŽ, āĻā§āϝāĻžāĻāĻžāϞāĻ āĻāĻŦāĻ āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻāĻā§āύā§āĻāĻĻā§āϰ āĻāĻžāĻā§ āϰā§āĻ āĻāĻā§āύā§āĻ āϰāĻžāĻāĻāĻŋāĻ |
āĻā§āĻŽāĻŋāύāĻŋ āĻŽāĻžāϞā§āĻāĻŋāĻŽā§āĻĄāĻžāϞ āĻāĻŋāϤā§āϰ āϤā§āϰāĻŋ | āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰā§āϰ āĻāĻŦāĻŋāϰ āϏāĻžāĻĨā§ āĻĒāĻŖā§āϝā§āϰ āĻāĻŦāĻŋ āĻāĻāϤā§āϰāĻŋāϤ āĻāϰāĻžāϰ |
āĻāĻĨā§āĻĒāĻāĻĨāύāĻŽā§āϞāĻ āĻāĻāĻ-āĻāϰ āĻāύā§āϝ āϏā§āĻļāύ āĻ āĻŦāϏā§āĻĨāĻž | āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻ āĻĒā§āύāϰāĻžāĻŦā§āϤā§āϤāĻŋāĻŽā§āϞāĻ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻžāϰ āĻāύā§āϝ āϏā§āĻļāύāĻā§āϞ⧠āĻĒā§āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻā§āύ |
āĻŦāĻžāĻāύāĻžāϰāĻŋ āĻĄā§āĻāĻžāϰ āĻāύā§āϝ āĻāϰā§āĻāĻŋāĻĢā§āϝāĻžāĻā§āĻ āϏā§āĻā§āϰā§āĻ | āĻā§āĻā§āϏāĻ āĻĒā§āϰāϤāĻŋāĻā§āϰāĻŋāϝāĻŧāĻž āĻĨā§āĻā§ āĻāĻŦāĻŋāϰ āϏā§āĻā§āϰā§āĻ āĻāϞāĻžāĻĻāĻž āĻāϰāĻž |
āĻŽāĻŋāĻĄāϞāĻāϝāĻŧā§āϝāĻžāϰ āϞāĻāĻŋāĻā§āϰ āĻāύā§āϝ āĻāϞāĻŦā§āϝāĻžāĻ | |
āĻĢā§āϞāĻžāĻāĻžāϰ⧠MVVM + āĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰ | |
āĻāĻā§āύā§āĻāĻŋāĻ āĻšāϏā§āϤāĻžāύā§āϤāϰ | |
āĻĒāϰāĻŦāϰā§āϤ⧠āĻĒāĻĻāĻā§āώā§āĻĒ
- đ¨ āĻāĻā§āύā§āĻā§āϰ āύāĻŋāϰā§āĻĻā§āĻļāĻžāĻŦāϞ⧠āύāĻŋāĻā§āϰ āĻŽāϤ⧠āĻāϰ⧠āϏāĻžāĻāĻžāύ â āϏā§āĻāĻžāĻāϞāĻŋāϏā§āĻā§āϰ āĻŦā§āϝāĻā§āϤāĻŋāϤā§āĻŦ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāϤā§
instructions.mdāϏāĻŽā§āĻĒāĻžāĻĻāύāĻž āĻāϰā§āύāĨ¤ - đī¸ āĻāϰāĻ āĻĒāĻŖā§āϝ āϝā§āĻ āĻāϰā§āύ â āύāϤā§āύ āĻāĻāĻā§āĻŽāĻā§āϞ⧠āĻĻāĻŋāϝāĻŧā§
catalog.yamlāĻāĻĒāĻĄā§āĻ āĻāϰā§āύāĨ¤ - đą āĻŽā§āĻŦāĻžāĻāϞā§āϰ āĻāύā§āϝ āĻŦāĻŋāϞā§āĻĄ āĻāϰā§āύ â
flutter build iosāĻ āĻĨāĻŦāĻžflutter build apkāϰāĻžāύ āĻāϰā§āύ - đ āϏā§āĻĨāĻžāϝāĻŧā§ āϏā§āĻļāύ āϝā§āĻ āĻāϰā§āύ â
InMemoryServiceāĻāĻāĻāĻŋ āĻĄāĻžāĻāĻžāĻŦā§āϏ-āϏāĻŽāϰā§āĻĨāĻŋāϤ āĻāĻŽāĻĒā§āϞāĻŋāĻŽā§āύā§āĻā§āĻļāύ āĻĻāĻŋāϝāĻŧā§ āĻĒā§āϰāϤāĻŋāϏā§āĻĨāĻžāĻĒāύ āĻāϰā§āύ - đ āĻĒā§āϰāĻŽāĻžāĻŖā§āĻāϰāĻŖ āϝā§āĻ āĻāϰā§āύ â IAM āĻĻāĻŋāϝāĻŧā§ āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ āĻāύā§āĻĄāĻĒāϝāĻŧā§āύā§āĻ āϏā§āϰāĻā§āώāĻŋāϤ āĻāϰā§āύ
āϏāĻŽā§āĻĒāĻĻ
- ADK āĻĄāĻā§āĻŽā§āύā§āĻā§āĻļāύ â āĻ āĻĢāĻŋāϏāĻŋāϝāĻŧāĻžāϞ āĻāĻā§āύā§āĻ āĻĄā§āĻā§āϞāĻĒāĻŽā§āύā§āĻ āĻāĻŋāĻ āĻĄāĻā§āϏ
- ADK Go āϏā§āϰā§āϏ āĻā§āĻĄ â āĻāĻŋāĻāĻšāĻžāĻŦ āϰāĻŋāĻĒā§āĻāĻŋāĻāϰāĻŋ
- ADK Go āĻĒā§āϝāĻžāĻā§āĻ āϰā§āĻĢāĻžāϰā§āύā§āϏ â āĻāĻĒāĻŋāĻāĻ āϰā§āĻĢāĻžāϰā§āύā§āϏ
- āĻā§āĻŽāĻŋāύāĻŋ āĻāĻĒāĻŋāĻāĻ āĻĄāĻā§āĻŽā§āύā§āĻā§āĻļāύ â āĻŽāĻĄā§āϞā§āϰ āϏāĻā§āώāĻŽāϤāĻž āĻāĻŦāĻ āύāĻŋāϰā§āĻĻā§āĻļāĻŋāĻāĻž
- āĻĢā§āϞāĻžāĻāĻžāϰ āĻĒā§āϰā§āĻāĻžāĻāĻĄāĻžāϰ āĻĒā§āϝāĻžāĻā§āĻ â āϏā§āĻā§āĻ āĻŽā§āϝāĻžāύā§āĻāĻŽā§āύā§āĻ āĻĄāĻā§āϏ
- āĻā§āϞāĻžāĻāĻĄ āϰāĻžāύ āĻĄāĻā§āĻŽā§āύā§āĻā§āĻļāύ â āĻĄā§āĻĒā§āϞāϝāĻŧāĻŽā§āύā§āĻ āĻāĻŦāĻ āϏā§āĻā§āϞāĻŋāĻ āĻāĻžāĻāĻĄ