🤖 āĻ—ā§āϰāĻžāĻĢ RAG, ADK āĻāĻŦāĻ‚ āĻŽā§‡āĻŽā§‹āϰāĻŋ āĻŦā§āϝāĻžāĻ‚āĻ• āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ•āϟāĻŋ āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ AI āĻāĻœā§‡āĻ¨ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

ā§§. āĻ­ā§‚āĻŽāĻŋāĻ•āĻž

āĻ•āĻ­āĻžāϰ

ā§§. āĻšā§āϝāĻžāϞ⧇āĻžā§āϜ

āĻĻ⧁āĻ°ā§āϝ⧋āĻ— āĻŽā§‹āĻ•āĻžāĻŦāĻŋāϞāĻž āĻĒāϰāĻŋāĻ¸ā§āĻĨāĻŋāϤāĻŋāϤ⧇, āĻāĻ•āĻžāϧāĻŋāĻ• āĻ¸ā§āĻĨāĻžāύ⧇ āĻ­āĻŋāĻ¨ā§āύ āĻ­āĻŋāĻ¨ā§āύ āĻĻāĻ•ā§āώāϤāĻž, āϏāĻŽā§āĻĒāĻĻ āĻ“ āϚāĻžāĻšāĻŋāĻĻāĻžāϏāĻŽā§āĻĒāĻ¨ā§āύ āĻœā§€āĻŦāĻŋāϤāĻĻ⧇āϰ āĻŽāĻ§ā§āϝ⧇ āϏāĻŽāĻ¨ā§āĻŦāϝāĻŧ āϏāĻžāϧāύ⧇āϰ āϜāĻ¨ā§āϝ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻžāύ āĻĄā§‡āϟāĻž āĻŦā§āϝāĻŦāĻ¸ā§āĻĨāĻžāĻĒāύāĻž āĻāĻŦāĻ‚ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻ•ā§āώāĻŽāϤāĻžāϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āĻšāϝāĻŧāĨ¤ āĻāχ āĻ•āĻ°ā§āĻŽāĻļāĻžāϞāĻžāϟāĻŋ āφāĻĒāύāĻžāϕ⧇ āĻāĻŽāύ āĻāĻ•āϟāĻŋ āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ āĻāφāχ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āϤ⧈āϰāĻŋ āĻ•āϰāϤ⧇ āĻļ⧇āĻ–āĻžāĻŦ⧇ āϝāĻž āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻŦāĻŋāώāϝāĻŧāϗ⧁āϞ⧋āϕ⧇ āĻāĻ•āĻ¤ā§āϰāĻŋāϤ āĻ•āϰ⧇:

  1. đŸ—„ī¸ āĻ—ā§āϰāĻžāĻĢ āĻĄā§‡āϟāĻžāĻŦ⧇āϏ (āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ) : āωāĻ¤ā§āϤāϰāĻœā§€āĻŦā§€, āĻĻāĻ•ā§āώāϤāĻž āĻāĻŦāĻ‚ āϏāĻŽā§āĻĒāĻĻ⧇āϰ āĻŽāĻ§ā§āϝ⧇āĻ•āĻžāϰ āϜāϟāĻŋāϞ āϏāĻŽā§āĻĒāĻ°ā§āĻ• āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇āĨ¤
  2. 🔍 āĻāφāχ-āϚāĻžāϞāĻŋāϤ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ : āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻŋāĻ• āĻ“ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ
  3. 📸 āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āĻĒā§āϰāϏ⧇āϏāĻŋāĻ‚ : āĻ›āĻŦāĻŋ, āϞ⧇āĻ–āĻž āĻāĻŦāĻ‚ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĨ⧇āϕ⧇ āĻ•āĻžāĻ āĻžāĻŽā§‹āĻ—āϤ āĻĄā§‡āϟāĻž āĻŦ⧇āϰ āĻ•āϰāĻž
  4. 🤖 āĻŽāĻžāĻ˛ā§āϟāĻŋ-āĻāĻœā§‡āĻ¨ā§āϟ āĻ…āĻ°ā§āϕ⧇āĻ¸ā§āĻŸā§āϰ⧇āĻļāύ : āϜāϟāĻŋāϞ āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋āϰ āϜāĻ¨ā§āϝ āĻŦāĻŋāĻļ⧇āώāĻžāϝāĻŧāĻŋāϤ āĻāĻœā§‡āĻ¨ā§āϟāĻĻ⧇āϰ āĻŽāĻ§ā§āϝ⧇ āϏāĻŽāĻ¨ā§āĻŦāϝāĻŧ āϏāĻžāϧāύ āĻ•āϰ⧁āύ
  5. 🧠 āĻĻā§€āĻ°ā§āϘāĻŽā§‡āϝāĻŧāĻžāĻĻā§€ āĻ¸ā§āĻŽā§ƒāϤāĻŋ : āĻ­āĻžāĻ°ā§āĻŸā§‡āĻ•ā§āϏ āĻāφāχ āĻŽā§‡āĻŽā§‹āϰāĻŋ āĻŦā§āϝāĻžāĻ‚āϕ⧇āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤāĻ•āϰāĻŖ

āĻ•āĻĨā§‹āĻĒāĻ•āĻĨāύ

⧍. āφāĻĒāύāĻŋ āϝāĻž āϤ⧈āϰāĻŋ āĻ•āϰāĻŦ⧇āύ

āĻāĻ•āϟāĻŋ āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰ āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āĻ• āĻ—ā§āϰāĻžāĻĢ āĻĄā§‡āϟāĻžāĻŦ⧇āϏ, āϝāĻžāϰ āĻŽāĻ§ā§āϝ⧇ āϰāϝāĻŧ⧇āϛ⧇:

  • đŸ—ēī¸ āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āϝāĻ•ā§āϤāĻŋāĻĻ⧇āϰ āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇āϰ āĻ¤ā§āϰāĻŋāĻŽāĻžāĻ¤ā§āϰāĻŋāĻ• āχāĻ¨ā§āϟāĻžāϰ⧇āĻ•ā§āϟāĻŋāĻ­ āĻ—ā§āϰāĻžāĻĢ āĻ­āĻŋāĻœā§āϝ⧁āϝāĻŧāĻžāϞāĻžāχāĻœā§‡āĻļāύ
  • 🔍 āĻŦ⧁āĻĻā§āϧāĻŋāĻĻā§€āĻĒā§āϤ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ (āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ, āϏāĻŋāĻŽāĻžāĻ¨ā§āϟāĻŋāĻ•, āĻāĻŦāĻ‚ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ)
  • 📸 āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āφāĻĒāϞ⧋āĻĄ āĻĒāĻžāχāĻĒāϞāĻžāχāύ (āĻ›āĻŦāĻŋ/āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĨ⧇āϕ⧇ āĻāύāϟāĻŋāϟāĻŋ āύāĻŋāĻˇā§āĻ•āĻžāĻļāύ)
  • 🤖 āϜāϟāĻŋāϞ āĻ•āĻžāϜ āϏāĻŽāĻ¨ā§āĻŦāϝāĻŧ⧇āϰ āϜāĻ¨ā§āϝ āĻŽāĻžāĻ˛ā§āϟāĻŋ-āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ
  • 🧠 āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤāĻ•ā§ƒāϤ āϝ⧋āĻ—āĻžāϝ⧋āϗ⧇āϰ āϜāĻ¨ā§āϝ āĻŽā§‡āĻŽāϰāĻŋ āĻŦā§āϝāĻžāĻ‚āĻ• āχāĻ¨ā§āϟāĻŋāĻ—ā§āϰ⧇āĻļāύ

ā§Š. āĻŽā§‚āϞ āĻĒā§āϰāϝ⧁āĻ•ā§āϤāĻŋ

āωāĻĒāĻžāĻĻāĻžāύ

āĻĒā§āϰāϝ⧁āĻ•ā§āϤāĻŋ

āωāĻĻā§āĻĻ⧇āĻļā§āϝ

āĻĄāĻžāϟāĻžāĻŦ⧇āϏ

āĻ•ā§āϞāĻžāωāĻĄ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ

āύ⧋āĻĄ (āωāĻ¤ā§āϤāϰāĻžāϧāĻŋāĻ•āĻžāϰ⧀, āĻĻāĻ•ā§āώāϤāĻž) āĻāĻŦāĻ‚ āĻāϜ (āϏāĻŽā§āĻĒāĻ°ā§āĻ•) āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧁āύ

āĻāφāχ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ

āĻŽāĻŋāĻĨ⧁āύ + āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚āϏ

āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻ—āϤ āĻŦā§‹āĻāĻžāĻĒāĻĄāĻŧāĻž + āϏāĻžāĻĻ⧃āĻļā§āϝ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ

āĻāĻœā§‡āĻ¨ā§āϟ āĻĢā§āϰ⧇āĻŽāĻ“āϝāĻŧāĻžāĻ°ā§āĻ•

ADK (āĻāĻœā§‡āĻ¨ā§āϟ āĻĄā§‡āϭ⧇āϞāĻĒāĻŽā§‡āĻ¨ā§āϟ āĻ•āĻŋāϟ)

āĻāφāχ āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧁āύ

āĻ¸ā§āĻŽā§ƒāϤāĻŋ

āĻ­āĻžāĻ°ā§āĻŸā§‡āĻ•ā§āϏ āĻāφāχ āĻŽā§‡āĻŽāϰāĻŋ āĻŦā§āϝāĻžāĻ‚āĻ•

āĻĻā§€āĻ°ā§āϘāĻŽā§‡āϝāĻŧāĻžāĻĻā§€ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻĒāĻ›āĻ¨ā§āĻĻ āϏāĻ‚āϰāĻ•ā§āώāĻŖ

āĻĢā§āϰāĻ¨ā§āϟāĻāĻ¨ā§āĻĄ

āϰāĻŋāĻ…ā§āϝāĻžāĻ•ā§āϟ + āĻĨā§āϰāĻŋ.āĻœā§‡āĻāϏ

āχāĻ¨ā§āϟāĻžāϰ⧇āĻ•ā§āϟāĻŋāĻ­ 3D āĻ—ā§āϰāĻžāĻĢ āĻ­āĻŋāĻœā§āϝ⧁āϝāĻŧāĻžāϞāĻžāχāĻœā§‡āĻļāύ

⧍. đŸ› ī¸ āĻĒāϰāĻŋāĻŦ⧇āĻļ āĻĒā§āϰāĻ¸ā§āϤ⧁āϤāĻŋ (āφāĻĒāύāĻŋ āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻļāĻĒ⧇ āĻĨāĻžāĻ•āϞ⧇ āĻāχ āĻ…āĻ‚āĻļāϟāĻŋ āĻŦāĻžāĻĻ āĻĻāĻŋāύ)

āĻĒā§āϰāĻĨāĻŽ āĻ…āĻ‚āĻļ: āĻŦāĻŋāϞāĻŋāĻ‚ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰ⧁āύ

āĻāχ āϕ⧋āĻĄāĻ˛ā§āϝāĻžāĻŦāϟāĻŋ āϚāĻžāϞāĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āφāĻĒāύāĻžāϰ āĻ•āĻŋāϛ⧁ āĻ•ā§āϰ⧇āĻĄāĻŋāϟ āϏāĻš āĻāĻ•āϟāĻŋ āĻŦāĻŋāϞāĻŋāĻ‚ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āĻĒā§āϰāϝāĻŧā§‹āϜāύāĨ¤ āĻļ⧁āϰ⧁ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻāχ āϕ⧋āĻĄāĻ˛ā§āϝāĻžāĻŦ⧇āϰ āωāĻĒāϰ⧇āϰ āĻŦā§āϝāĻžāύāĻžāϰ āĻĨ⧇āϕ⧇ āĻ•ā§āϰ⧇āĻĄāĻŋāϟ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤ āφāĻĒāύāĻŋ āϝāĻĻāĻŋ āχāϤāĻŋāĻŽāĻ§ā§āϝ⧇āχ āĻāĻ•āϟāĻŋ āĻŦāĻŋāϞāĻŋāĻ‚ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āϏāĻžāĻĨ⧇ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻĨāĻžāϕ⧇āύ, āϤāĻžāĻšāϞ⧇ āφāĻĒāύāĻŋ āĻāχ āϧāĻžāĻĒāϟāĻŋ āĻāĻĄāĻŧāĻŋāϝāĻŧ⧇ āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āĻĻā§āĻŦāĻŋāϤ⧀āϝāĻŧ āĻĒāĻ°ā§āĻŦ: āωāĻ¨ā§āĻŽā§āĻ•ā§āϤ āĻĒāϰāĻŋāĻŦ⧇āĻļ

  1. 👉 āϏāϰāĻžāϏāϰāĻŋ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ- āĻ āϝ⧇āϤ⧇ āĻāχ āϞāĻŋāĻ™ā§āϕ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ
  2. 👉 āφāϜ āϝ⧇āϕ⧋āύ⧋ āϏāĻŽāϝāĻŧ⧇ āĻ…āύ⧁āĻŽā§‹āĻĻāύ⧇āϰ āϜāĻ¨ā§āϝ āĻ…āύ⧁āϰ⧋āϧ āĻ•āϰāĻž āĻšāϞ⧇, āϚāĻžāϞāĻŋāϝāĻŧ⧇ āϝāĻžāĻ“āϝāĻŧāĻžāϰ āϜāĻ¨ā§āϝ 'Authorize'-āĻ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύāĨ¤ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻ…āύ⧁āĻŽā§‹āĻĻāύ āĻ•āϰāϤ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ
  3. 👉 āϝāĻĻāĻŋ āĻ¸ā§āĻ•ā§āϰāĻŋāύ⧇āϰ āύāĻŋāĻšā§‡ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞāϟāĻŋ āĻĻ⧇āĻ–āĻž āύāĻž āϝāĻžāϝāĻŧ, āϤāĻžāĻšāϞ⧇ āĻāϟāĻŋ āϖ⧁āϞ⧁āύ:
    • āĻ­āĻŋāω āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ
    • āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ⧇ āύāϤ⧁āύ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ āϖ⧁āϞ⧁āύ
  4. 👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āϝāĻžāϚāĻžāχ āĻ•āϰ⧁āύ āϝ⧇ āφāĻĒāύāĻŋ āχāϤāĻŋāĻŽāĻ§ā§āϝ⧇āχ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•ā§ƒāϤ āĻāĻŦāĻ‚ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟāϟāĻŋ āφāĻĒāύāĻžāϰ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āφāχāĻĄāĻŋāϤ⧇ āϏ⧇āϟ āĻ•āϰāĻž āφāϛ⧇:
    gcloud auth list
    
  5. 👉đŸ’ģ āĻ—āĻŋāϟāĻšāĻžāĻŦ āĻĨ⧇āϕ⧇ āĻŦ⧁āϟāĻ¸ā§āĻŸā§āĻ°ā§āϝāĻžāĻĒ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟāϟāĻŋ āĻ•ā§āϞ⧋āύ āĻ•āϰ⧁āύ:
    git clone https://github.com/gca-americas/way-back-home.git
    

āϤ⧃āϤ⧀āϝāĻŧ āĻĒāĻ°ā§āĻŦ: āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, init āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟāϟāĻŋāϕ⧇ āĻāĻ•ā§āϏāĻŋāĻ•āĻŋāωāĻŸā§‡āĻŦāϞ āĻ•āϰ⧇ āϚāĻžāϞāĻžāύ:

cd ~/way-back-home/level_2
./init.sh

ā§Š. đŸ› ī¸ āĻĒāϰāĻŋāĻŦ⧇āĻļ āϏ⧇āϟāφāĻĒ

ā§§. āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āϖ⧁āϞ⧁āύ

āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āϝāĻĻāĻŋ āĻ¸ā§āĻ•ā§āϰāĻŋāύ⧇āϰ āύ⧀āĻšā§‡ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞāϟāĻŋ āĻĻ⧇āĻ–āĻž āύāĻž āϝāĻžāϝāĻŧ, āϤāĻžāĻšāϞ⧇ āĻāϟāĻŋ āϖ⧁āϞ⧁āύ:

  • āĻ­āĻŋāω āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ
  • āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ

āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ⧇ āύāϤ⧁āύ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ āϖ⧁āϞ⧁āύ

⧍. āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āφāĻĒāύāĻžāϰ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āφāχāĻĄāĻŋ āϏ⧇āϟ āĻ•āϰ⧁āύ:

gcloud config set project $(cat ~/project_id.txt) --quiet

👉đŸ’ģ āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧ API-āϗ⧁āϞ⧋ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰ⧁āύ (āĻāϤ⧇ āĻĒā§āϰāĻžāϝāĻŧ ⧍-ā§Š āĻŽāĻŋāύāĻŋāϟ āϏāĻŽāϝāĻŧ āϞāĻžāĻ—āĻŦ⧇):

gcloud services enable compute.googleapis.com \
                       aiplatform.googleapis.com \
                       run.googleapis.com \
                       cloudbuild.googleapis.com \
                       artifactregistry.googleapis.com \
                       spanner.googleapis.com \
                       storage.googleapis.com

ā§Š. āϏ⧇āϟāφāĻĒ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ āϚāĻžāϞāĻžāύ

👉đŸ’ģ āϏ⧇āϟāφāĻĒ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟāϟāĻŋ āϚāĻžāϞāĻžāύ:

cd ~/way-back-home/level_2
./setup.sh

āĻāϟāĻŋ āφāĻĒāύāĻžāϰ āϜāĻ¨ā§āϝ .env āϤ⧈āϰāĻŋ āĻ•āϰāĻŦ⧇āĨ¤ āφāĻĒāύāĻžāϰ āĻ•ā§āϞāĻžāωāĻĄāĻļ⧇āϞ⧇, way_back_home āĻĒā§āϰāĻœā§‡āĻ•ā§āϟāϟāĻŋ āϖ⧁āϞ⧁āύāĨ¤ level_2 āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ⧇āϰ āύāĻŋāĻšā§‡ āφāĻĒāύāĻŋ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ āϝ⧇ āφāĻĒāύāĻžāϰ āϜāĻ¨ā§āϝ .env āĻĢāĻžāχāϞāϟāĻŋ āϤ⧈āϰāĻŋ āĻšāϝāĻŧ⧇āϛ⧇āĨ¤ āϝāĻĻāĻŋ āφāĻĒāύāĻŋ āĻāϟāĻŋ āϖ⧁āρāĻœā§‡ āύāĻž āĻĒāĻžāύ, āϤāĻŦ⧇ āĻāϟāĻŋ āĻĻ⧇āĻ–āĻžāϰ āϜāĻ¨ā§āϝ View -> Toggle Hidden File āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤ āĻ“āĻĒ⧇āύ_āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ

ā§Ē. āύāĻŽā§āύāĻž āĻĄā§‡āϟāĻž āϞ⧋āĻĄ āĻ•āϰ⧁āύ

👉đŸ’ģ āĻŦā§āϝāĻžāĻ•āĻāĻ¨ā§āĻĄā§‡ āϝāĻžāύ āĻāĻŦāĻ‚ āĻĄāĻŋāĻĒ⧇āĻ¨ā§āĻĄā§‡āĻ¨ā§āϏāĻŋāϗ⧁āϞ⧋ āχāύāĻ¸ā§āϟāϞ āĻ•āϰ⧁āύ:

cd ~/way-back-home/level_2/backend
uv sync

👉đŸ’ģ āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āϝāĻ•ā§āϤāĻŋāĻĻ⧇āϰ āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϤāĻĨā§āϝ āϞ⧋āĻĄ āĻ•āϰ⧁āύ:

uv run python ~/way-back-home/level_2/backend/setup_data.py

āĻāϰ āĻĢāϞ⧇ āϤ⧈āϰāĻŋ āĻšāϝāĻŧ:

  • āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āχāύāĻ¸ā§āĻŸā§āϝāĻžāĻ¨ā§āϏ ( survivor-network )
  • āĻĄāĻžāϟāĻžāĻŦ⧇āϏ ( graph-db )
  • āϏāĻŽāĻ¸ā§āϤ āύ⧋āĻĄ āĻāĻŦāĻ‚ āĻāϜ āĻŸā§‡āĻŦāĻŋāϞ
  • āϕ⧋āϝāĻŧ⧇āϰāĻŋ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāĻĒāĻžāĻ°ā§āϟāĻŋ āĻ—ā§āϰāĻžāĻĢ āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āφāωāϟāĻĒ⧁āϟ :
============================================================
SUCCESS! Database setup complete.
============================================================

Instance:  survivor-network
Database:  graph-db
Graph:     SurvivorGraph

Access your database at:
https://console.cloud.google.com/spanner/instances/survivor-network/databases/graph-db?project=waybackhome

āφāωāϟāĻĒ⧁āĻŸā§‡ Access your database at āĻĒāϰ⧇āϰ āϞāĻŋāĻ™ā§āϕ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āφāĻĒāύāĻŋ āϗ⧁āĻ—āϞ āĻ•ā§āϞāĻžāωāĻĄ āĻ•āύāϏ⧋āϞ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āϖ⧁āϞāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύāĨ¤

āĻ–ā§‹āϞāĻž_āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ

āĻāĻŦāĻ‚ āφāĻĒāύāĻŋ āϗ⧁āĻ—āϞ āĻ•ā§āϞāĻžāωāĻĄ āĻ•āύāϏ⧋āϞ⧇ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ!

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ

ā§Ē. 🚀 āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“āϤ⧇ āĻ—ā§āϰāĻžāĻĢ āĻĄā§‡āϟāĻž āĻ­āĻŋāĻœā§āϝ⧁āϝāĻŧāĻžāϞāĻžāχāϜ āĻ•āϰāĻž

āĻāχ āύāĻŋāĻ°ā§āĻĻ⧇āĻļāĻŋāĻ•āĻžāϟāĻŋ āφāĻĒāύāĻžāϕ⧇ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āϏāϰāĻžāϏāϰāĻŋ āϗ⧁āĻ—āϞ āĻ•ā§āϞāĻžāωāĻĄ āĻ•āύāϏ⧋āϞ⧇ āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰ āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āĻ• āĻ—ā§āϰāĻžāĻĢ āĻĄā§‡āϟāĻž āĻĻ⧇āĻ–āϤ⧇ āĻ“ āϤāĻžāϰ āϏāĻžāĻĨ⧇ āχāĻ¨ā§āϟāĻžāϰāĻ…ā§āϝāĻžāĻ•ā§āϟ āĻ•āϰāϤ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰ⧇āĨ¤ āφāĻĒāύāĻžāϰ āĻāφāχ āĻāĻœā§‡āĻ¨ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰāĻžāϰ āφāϗ⧇ āĻĄā§‡āϟāĻž āϝāĻžāϚāĻžāχ āĻ•āϰāϤ⧇ āĻāĻŦāĻ‚ āĻ—ā§āϰāĻžāĻĢ⧇āϰ āĻ•āĻžāĻ āĻžāĻŽā§‹ āĻŦ⧁āĻāϤ⧇ āĻāϟāĻŋ āĻāĻ•āϟāĻŋ āϚāĻŽā§ŽāĻ•āĻžāϰ āωāĻĒāĻžāϝāĻŧāĨ¤

ā§§. āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“ āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰ⧁āύ

  1. āĻļ⧇āώ āϧāĻžāĻĒ⧇, āϞāĻŋāĻ™ā§āĻ•āϟāĻŋāϤ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧇ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“ āϖ⧁āϞāϤ⧇ āϭ⧁āϞāĻŦ⧇āύ āύāĻžāĨ¤

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“

⧍. āĻ—ā§āϰāĻžāĻĢ⧇āϰ āĻ—āĻ āύ āĻŦā§‹āĻāĻž (āĻŦ⧃āĻšā§Ž āϚāĻŋāĻ¤ā§āϰ)

āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰ āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āĻ• āĻĄā§‡āϟāĻžāϏ⧇āϟāϟāĻŋāϕ⧇ āĻāĻ•āϟāĻŋ āϞāϜāĻŋāĻ• āĻĒāĻžāϜāϞ āĻŦāĻž āϗ⧇āĻŽ āĻ¸ā§āĻŸā§‡āϟ āĻšāĻŋāϏ⧇āĻŦ⧇ āĻ­āĻžāĻŦ⧁āύ:

āϏāĻ¤ā§āϤāĻž

āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡ āĻ­ā§‚āĻŽāĻŋāĻ•āĻž

āϏāĻžāĻĻ⧃āĻļā§āϝ

āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āϝāĻ•ā§āϤāĻŋāϰāĻž

āĻāĻœā§‡āĻ¨ā§āϟ/āϖ⧇āϞ⧋āϝāĻŧāĻžāĻĄāĻŧāϰāĻž

āϖ⧇āϞ⧋āϝāĻŧāĻžāĻĄāĻŧāϰāĻž

āĻŦāĻžāϝāĻŧā§‹āĻŽ

āϝ⧇āĻ–āĻžāύ⧇ āϤāĻžāϰāĻž āĻ…āĻŦāĻ¸ā§āĻĨāĻŋāϤ

āĻŽāĻžāύāϚāĻŋāĻ¤ā§āϰ āĻ…āĻžā§āϚāϞ

āĻĻāĻ•ā§āώāϤāĻž

āϤāĻžāϰāĻž āϝāĻž āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇

āĻ•ā§āώāĻŽāϤāĻž

āϚāĻžāĻšāĻŋāĻĻāĻž

āϤāĻžāĻĻ⧇āϰ āϝāĻž āĻ…āĻ­āĻžāĻŦ (āϏāĻ‚āĻ•āϟ)

āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ/āĻ…āĻ­āĻŋāϝāĻžāύ

āϏāĻŽā§āĻĒāĻĻ

āĻŦāĻŋāĻļā§āĻŦ⧇ āĻĒāĻžāĻ“āϝāĻŧāĻž āϜāĻŋāύāĻŋāϏāĻĒāĻ¤ā§āϰ

āϞ⧁āϟ

āϞāĻ•ā§āĻˇā§āϝ : āĻāφāχ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āĻ•āĻžāϜ āĻšāϞ⧋ āĻŦāĻžāϝāĻŧā§‹āĻŽ (āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύāĻ—āϤ āϏ⧀āĻŽāĻžāĻŦāĻĻā§āϧāϤāĻž) āĻŦāĻŋāĻŦ⧇āϚāύāĻž āĻ•āϰ⧇ āĻĻāĻ•ā§āώāϤāĻž (āϏāĻŽāĻžāϧāĻžāύ)-āϕ⧇ āϚāĻžāĻšāĻŋāĻĻāĻž (āϏāĻŽāĻ¸ā§āϝāĻž)-āϰ āϏāĻžāĻĨ⧇ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻžāĨ¤

🔗 āĻĒā§āϰāĻžāĻ¨ā§āϤ (āϏāĻŽā§āĻĒāĻ°ā§āĻ•):

  • SurvivorInBiome : āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ āĻŸā§āĻ°ā§āϝāĻžāĻ•āĻŋāĻ‚
  • SurvivorHasSkill : āĻĻāĻ•ā§āώāϤāĻžāϰ āϤāĻžāϞāĻŋāĻ•āĻž
  • SurvivorHasNeed : āϏāĻ•ā§āϰāĻŋāϝāĻŧ āϏāĻŽāĻ¸ā§āϝāĻžāϗ⧁āϞāĻŋāϰ āϤāĻžāϞāĻŋāĻ•āĻž
  • SurvivorFoundResource : āϜāĻŋāύāĻŋāϏāĻĒāĻ¤ā§āϰ⧇āϰ āϤāĻžāϞāĻŋāĻ•āĻž
  • SurvivorCanHelp : āĻ…āύ⧁āĻŽāĻŋāϤ āϏāĻŽā§āĻĒāĻ°ā§āĻ• (āĻāφāχ āĻāϟāĻŋ āĻ—āĻŖāύāĻž āĻ•āϰ⧇!)

ā§Š. āĻ—ā§āϰāĻžāĻĢ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻ•āϰāĻž

āĻĄā§‡āϟāĻžāϰ āĻŽāĻ§ā§āϝ⧇ 'Story' āĻĻ⧇āĻ–āϤ⧇ āϚāϞ⧁āύ āĻ•āϝāĻŧ⧇āĻ•āϟāĻŋ āϕ⧋āϝāĻŧ⧇āϰāĻŋ āϚāĻžāϞāĻžāύ⧋ āϝāĻžāĻ•āĨ¤

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ GQL (āĻ—ā§āϰāĻžāĻĢ āϕ⧋āϝāĻŧ⧇āϰāĻŋ āĻ˛ā§āϝāĻžāĻ™ā§āϗ⧁āϝāĻŧ⧇āϜ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āĨ¤ āĻāĻ•āϟāĻŋ āϕ⧋āϝāĻŧ⧇āϰāĻŋ āϚāĻžāϞāĻžāύ⧋āϰ āϜāĻ¨ā§āϝ, GRAPH SurvivorNetwork āĻāϰ āĻĒāϰ⧇ āφāĻĒāύāĻžāϰ āĻŽā§āϝāĻžāϚ āĻĒā§āϝāĻžāϟāĻžāĻ°ā§āύāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤

👉 āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ ā§§: āĻŦāĻŋāĻļā§āĻŦāĻŦā§āϝāĻžāĻĒā§€ āϤāĻžāϞāĻŋāĻ•āĻž (āϕ⧇ āϕ⧋āĻĨāĻžāϝāĻŧ āφāϛ⧇āύ?) āĻāϟāĻŋāχ āφāĻĒāύāĻžāϰ āĻ­āĻŋāĻ¤ā§āϤāĻŋ - āωāĻĻā§āϧāĻžāϰ āĻ…āĻ­āĻŋāϝāĻžāύ⧇āϰ āϜāĻ¨ā§āϝ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ āĻŦā§‹āĻāĻž āĻ…āĻ¤ā§āϝāĻ¨ā§āϤ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖāĨ¤

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[:SurvivorInBiome]->(b:Biomes)
RETURN TO_JSON(result) AS json_result

āĻĢāϞāĻžāĻĢāϞ āύāĻŋāĻšā§‡ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋ āĻŦāϞ⧇ āφāĻļāĻž āĻ•āϰāĻž āϝāĻžāϝāĻŧ: āϕ⧋āϝāĻŧ⧇āϰāĻŋā§§

👉 āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ ⧍: āĻĻāĻ•ā§āώāϤāĻž āĻŽā§āϝāĻžāĻŸā§āϰāĻŋāĻ•ā§āϏ (āϏāĻžāĻŽāĻ°ā§āĻĨā§āϝ) āĻāĻ–āύ āϝ⧇āĻšā§‡āϤ⧁ āφāĻĒāύāĻŋ āϜāĻžāύ⧇āύ āϕ⧇ āϕ⧋āĻĨāĻžāϝāĻŧ āφāϛ⧇, āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰ⧁āύ āϤāĻžāϰāĻž āϕ⧀ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ āĨ¤

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasSkill]->(k:Skills)
RETURN TO_JSON(result) AS json_result

āĻĢāϞāĻžāĻĢāϞ āύāĻŋāĻšā§‡ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋ āĻŦāϞ⧇ āφāĻļāĻž āĻ•āϰāĻž āϝāĻžāϝāĻŧ: āϕ⧋āϝāĻŧ⧇āϰāĻŋ⧍

👉 āĻĒā§āϰāĻļā§āύ ā§Š: āĻ•āĻžāϰāĻž āϏāĻ‚āĻ•āĻŸā§‡ āφāϛ⧇āύ? ("āĻŽāĻŋāĻļāύ āĻŦā§‹āĻ°ā§āĻĄ") āĻĻ⧇āϖ⧁āύ āĻ•āĻžāϰāĻž āϏāĻžāĻšāĻžāĻ¯ā§āϝāĻĒā§āϰāĻžāĻ°ā§āĻĨā§€ āĻāĻŦāĻ‚ āϤāĻžāĻĻ⧇āϰ āϕ⧀ āĻĒā§āϰāϝāĻŧā§‹āϜāύāĨ¤

GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasNeed]->(n:Needs)
RETURN TO_JSON(result) AS json_result

āĻĢāϞāĻžāĻĢāϞ āύāĻŋāĻšā§‡ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋ āĻŦāϞ⧇ āφāĻļāĻž āĻ•āϰāĻž āϝāĻžāϝāĻŧ: āϕ⧋āϝāĻŧ⧇āϰāĻŋā§Š

🔎 [āϐāĻšā§āĻ›āĻŋāĻ•] āĻŽāĻŋāϞāύ āϘāϟāĻžāύ⧋ - āϕ⧇ āĻ•āĻžāϕ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇?

āĻāχāĻ–āĻžāύ⧇āχ āĻ—ā§āϰāĻžāĻĢāϟāĻŋ āĻļāĻ•ā§āϤāĻŋāĻļāĻžāϞ⧀ āĻšāϝāĻŧ⧇ āĻ“āϠ⧇! āĻāχ āϕ⧋āϝāĻŧ⧇āϰāĻŋāϟāĻŋ āĻāĻŽāύ āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰāĻĻ⧇āϰ āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰ⧇, āϝāĻžāĻĻ⧇āϰ āĻ…āĻ¨ā§āϝ āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰāĻĻ⧇āϰ āϚāĻžāĻšāĻŋāĻĻāĻž āĻŽā§‡āϟāĻžāύ⧋āϰ āĻŽāϤ⧋ āĻĻāĻ•ā§āώāϤāĻž āϰāϝāĻŧ⧇āϛ⧇ āĨ¤

GRAPH SurvivorNetwork
MATCH result = (helper:Survivors)-[:SurvivorHasSkill]->(skill:Skills)-[:SkillTreatsNeed]->(need:Needs)<-[:SurvivorHasNeed]-(helpee:Survivors)
RETURN TO_JSON(result) AS json_result

āĻĢāϞāĻžāĻĢāϞ āύāĻŋāĻšā§‡ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋ āĻŦāϞ⧇ āφāĻļāĻž āĻ•āϰāĻž āϝāĻžāϝāĻŧ: āϕ⧋āϝāĻŧ⧇āϰāĻŋā§Ē

āĻāχ āϕ⧋āϝāĻŧ⧇āϰāĻŋāϟāĻŋ āϝāĻž āĻ•āϰ⧇:

āĻļ⧁āϧ⧁ 'āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϚāĻŋāĻ•āĻŋā§ŽāϏāĻžāϝāĻŧ āĻĒā§‹āĻĄāĻŧāĻžāϰ āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āĻ•āϰāĻž āĻšāϝāĻŧ' (āϝāĻž āĻ¸ā§āĻ•āĻŋāĻŽāĻž āĻĨ⧇āϕ⧇ āĻ¸ā§āĻĒāĻˇā§āϟ) āĻĻ⧇āĻ–āĻžāύ⧋āϰ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤ⧇, āĻāχ āϕ⧋āϝāĻŧ⧇āϰāĻŋāϟāĻŋ āϖ⧁āρāĻœā§‡ āĻĒāĻžāϝāĻŧ:

  • āĻĄāĻžāσ āĻāϞ⧇āύāĻž āĻĢā§āϰāĻ¸ā§āϟ (āϝāĻŋāύāĻŋ āϚāĻŋāĻ•āĻŋā§ŽāϏāĻžāĻļāĻžāĻ¸ā§āĻ¤ā§āϰ⧇ āĻĒā§āϰāĻļāĻŋāĻ•ā§āώāĻŖāĻĒā§āϰāĻžāĻĒā§āϤ) → āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ → āĻ•ā§āϝāĻžāĻĒā§āĻŸā§‡āύ āϤāĻžāύāĻžāĻ•āĻžāϕ⧇ (āϝāĻŋāύāĻŋ āĻĻāĻ—ā§āϧ āĻšāϝāĻŧ⧇āϛ⧇āύ)āĨ¤
  • āĻĄā§‡āĻ­āĻŋāĻĄ āĻšā§‡āύ (āϝāĻŋāύāĻŋ āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϚāĻŋāĻ•āĻŋā§ŽāϏāĻžāϝāĻŧ āĻĻāĻ•ā§āώ) → āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ → āϞ⧇āĻĢāĻŸā§‡āĻ¨ā§āϝāĻžāĻ¨ā§āϟ āĻĒāĻžāĻ°ā§āĻ•āϕ⧇ (āϝāĻžāϰ āĻ—ā§‹āĻĄāĻŧāĻžāϞāĻŋ āĻŽāϚāϕ⧇ āϗ⧇āϛ⧇)āĨ¤

āϕ⧇āύ āĻāϟāĻŋ āĻļāĻ•ā§āϤāĻŋāĻļāĻžāϞ⧀:

āφāĻĒāύāĻžāϰ āĻāφāχ āĻāĻœā§‡āĻ¨ā§āϟ āϝāĻž āĻ•āϰāĻŦ⧇:

āϝāĻ–āύ āϕ⧋āύ⧋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āϜāĻŋāĻœā§āĻžāĻžāϏāĻž āĻ•āϰ⧇āύ "āϕ⧇ āĻĒā§‹āĻĄāĻŧāĻžāϰ āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ?" , āϤāĻ–āύ āĻāĻœā§‡āĻ¨ā§āϟ āϝāĻž āĻ•āϰāĻŦ⧇ āϤāĻž āĻšāϞ⧋:

  1. āĻāĻ•āχ āϰāĻ•āĻŽ āĻ—ā§āϰāĻžāĻĢ āϕ⧋āϝāĻŧ⧇āϰāĻŋ āϚāĻžāϞāĻžāύ
  2. āωāĻ¤ā§āϤāϰ: "āĻĄāσ āĻĢā§āϰāĻ¸ā§āĻŸā§‡āϰ āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āĻŦāĻŋāώāϝāĻŧ⧇ āĻĒā§āϰāĻļāĻŋāĻ•ā§āώāĻŖ āφāϛ⧇ āĻāĻŦāĻ‚ āϤāĻŋāύāĻŋ āĻ•ā§āϝāĻžāĻĒā§āĻŸā§‡āύ āϤāĻžāύāĻžāĻ•āĻžāϕ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤"
  3. āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ āĻŽāĻ§ā§āϝāĻŦāĻ°ā§āϤ⧀ āĻŸā§‡āĻŦāĻŋāϞ āĻŦāĻž āϏāĻŽā§āĻĒāĻ°ā§āĻ• āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āϜāĻžāύāĻžāϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āύ⧇āχ!

ā§Ģ. 🚀 āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ⧇ āĻāφāχ-āϚāĻžāϞāĻŋāϤ āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚

ā§§. āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϕ⧇āύ? (āϕ⧋āύ⧋ āĻ•āĻžāϜ āĻ•āϰāϤ⧇ āĻšāĻŦ⧇ āύāĻž, āĻļ⧁āϧ⧁ āĻĒāĻĄāĻŧāĻžāϰ āϜāĻ¨ā§āϝ)

āϟāĻŋāϕ⧇ āĻĨāĻžāĻ•āĻžāϰ āĻĒāϰāĻŋāĻ¸ā§āĻĨāĻŋāϤāĻŋāϤ⧇ āϏāĻŽāϝāĻŧ āĻ…āĻ¤ā§āϝāĻ¨ā§āϤ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĨ¤ āϝāĻ–āύ āϕ⧋āύ⧋ āĻœā§€āĻŦāĻŋāϤ āĻŦā§āϝāĻ•ā§āϤāĻŋ āϕ⧋āύ⧋ āϜāϰ⧁āϰāĻŋ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāϰ āĻ•āĻĨāĻž āϜāĻžāύāĻžāϝāĻŧ, āϝ⧇āĻŽāύ I need someone who can treat burns āĻŦāĻž Looking for a medic , āϤāĻ–āύ āĻĄāĻžāϟāĻžāĻŦ⧇āϏ āĻĨ⧇āϕ⧇ āϏāĻ āĻŋāĻ• āĻĻāĻ•ā§āώāϤāĻžāϰ āύāĻžāĻŽ āĻ…āύ⧁āĻŽāĻžāύ āĻ•āϰ⧇ āϤāĻžāϰāĻž āϏāĻŽāϝāĻŧ āύāĻˇā§āϟ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ āύāĻžāĨ¤

āĻŦāĻžāĻ¸ā§āϤāĻŦ āĻĒāϰāĻŋāĻ¸ā§āĻĨāĻŋāϤāĻŋ : āĻŦ⧇āρāĻšā§‡ āϝāĻžāĻ“āϝāĻŧāĻž āĻŦā§āϝāĻ•ā§āϤāĻŋ: Captain Tanaka has burns—we need medical help NOW!

'āĻŽā§‡āĻĄāĻŋāĻ•' āĻāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāϚāϞāĻŋāϤ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ → ā§ĻāϟāĻŋ āĻĢāϞāĻžāĻĢāϞ ❌

āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻŋāĻ• āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ → 'āĻŽā§‡āĻĄāĻŋāϕ⧇āϞ āĻŸā§āϰ⧇āύāĻŋāĻ‚', 'āĻĢāĻžāĻ°ā§āĻ¸ā§āϟ āĻāχāĻĄ' āϖ⧁āρāĻœā§‡ āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϛ⧇ ✅

āĻāĻœā§‡āĻ¨ā§āϟāĻĻ⧇āϰ āĻ āĻŋāĻ• āĻāϟāĻžāχ āĻĒā§āϰāϝāĻŧā§‹āϜāύ: āĻŦ⧁āĻĻā§āϧāĻŋāĻĻā§€āĻĒā§āϤ, āĻŽāĻžāύ⧁āώ⧇āϰ āĻŽāϤ⧋ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻŦā§āϝāĻŦāĻ¸ā§āĻĨāĻž āϝāĻž āĻļ⧁āϧ⧁ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āύāϝāĻŧ, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āωāĻĻā§āĻĻ⧇āĻļā§āϝāĻ“ āĻŦā§‹āĻā§‡āĨ¤

⧍. āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āĻŽāĻĄā§‡āϞ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻāĻŽā§āĻŦ⧇āĻĄāĻŋāĻ‚

āĻāĻ–āύ āϚāϞ⧁āύ āϗ⧁āĻ—āϞ⧇āϰ text-embedding-004 āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻŸā§‡āĻ•ā§āϏāϟāϕ⧇ āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚-āĻ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻŽāĻĄā§‡āϞ āϤ⧈āϰāĻŋ āĻ•āϰāĻŋāĨ¤

👉 āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“āϤ⧇, āĻāχ SQL āϟāĻŋ āϚāĻžāϞāĻžāύ (āĻāĻ–āĻžāύ⧇ $YOUR_PROJECT_ID āĻāϰ āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ āφāĻĒāύāĻžāϰ āφāϏāϞ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āφāχāĻĄāĻŋ āĻŦāϏāĻžāύ):

â€ŧī¸ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ⧇ , āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟāϟāĻŋ āĻĻ⧇āĻ–āϤ⧇ File -> Open Folder -> way-back-home/level_2 āϖ⧁āϞ⧁āύāĨ¤

āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ_āφāχāĻĄāĻŋ

👉 āύāĻŋāĻšā§‡āϰ āϕ⧋āϝāĻŧ⧇āϰāĻŋāϟāĻŋ āĻ•āĻĒāĻŋ āĻ•āϰ⧇ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“āϤ⧇ āĻĒ⧇āĻ¸ā§āϟ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āϤāĻžāϰāĻĒāϰ āϰāĻžāύ āĻŦāĻžāϟāύ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ:

CREATE OR REPLACE MODEL TextEmbeddings
INPUT(content STRING(MAX))
OUTPUT(embeddings STRUCT<values ARRAY<FLOAT32>>)
REMOTE OPTIONS (
    endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/text-embedding-004'
);

āĻāϟāĻŋ āϝāĻž āĻ•āϰ⧇ :

  • āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ⧇ āĻāĻ•āϟāĻŋ āĻ­āĻžāĻ°ā§āϚ⧁āϝāĻŧāĻžāϞ āĻŽāĻĄā§‡āϞ āϤ⧈āϰāĻŋ āĻ•āϰ⧇ (āĻŽāĻĄā§‡āϞ⧇āϰ āϕ⧋āύ⧋ āĻ“āϝāĻŧ⧇āϟ āĻ¸ā§āĻĨāĻžāύ⧀āϝāĻŧāĻ­āĻžāĻŦ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŋāϤ āĻĨāĻžāϕ⧇ āύāĻž)
  • āĻ­āĻžāĻ°ā§āĻŸā§‡āĻ•ā§āϏ āĻāφāχ-āϤ⧇ āϗ⧁āĻ—āϞ⧇āϰ text-embedding-004 āύāĻŋāĻ°ā§āĻĻ⧇āĻļ āĻ•āϰ⧇āĨ¤
  • āϚ⧁āĻ•ā§āϤāĻŋāϟāĻŋ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰ⧇: āχāύāĻĒ⧁āϟ āĻšāϞ⧋ āĻŸā§‡āĻ•ā§āϏāϟ, āφāωāϟāĻĒ⧁āϟ āĻšāϞ⧋ āĻāĻ•āϟāĻŋ ā§­ā§Ŧā§Ž-āĻŽāĻžāĻ¤ā§āϰāĻžāϰ āĻĢā§āϞ⧋āϟ āĻ…ā§āϝāĻžāϰ⧇āĨ¤

"āϰāĻŋāĻŽā§‹āϟ āĻ…āĻĒāĻļāύ" āϕ⧇āύ?

  • āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āύāĻŋāĻœā§‡ āĻŽāĻĄā§‡āϞāϟāĻŋ āϚāĻžāϞāĻžāϝāĻŧ āύāĻžāĨ¤
  • āφāĻĒāύāĻŋ āϝāĻ–āύ ML.PREDICT āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āύ, āϤāĻ–āύ āĻāϟāĻŋ API-āĻāϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ Vertex AI-āϕ⧇ āĻ•āϞ āĻ•āϰ⧇āĨ¤
  • āϜāĻŋāϰ⧋-āχāϟāĻŋāĻāϞ : āĻĄā§‡āϟāĻž āĻĒāĻžāχāĻĨāύ⧇ āĻāĻ•ā§āϏāĻĒā§‹āĻ°ā§āϟ, āĻĒā§āϰāϏ⧇āϏ āĻāĻŦāĻ‚ āĻĒ⧁āύāϰāĻžāϝāĻŧ āχāĻŽā§āĻĒā§‹āĻ°ā§āϟ āĻ•āϰāĻžāϰ āϕ⧋āύ⧋ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āύ⧇āχāĨ¤

Run āĻŦāĻžāϟāύ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ, āĻāϟāĻŋ āϏāĻĢāϞ āĻšāϞ⧇ āφāĻĒāύāĻŋ āύ⧀āĻšā§‡āϰ āĻŽāϤ⧋ āĻĢāϞāĻžāĻĢāϞ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ:

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻĢāϞāĻžāĻĢāϞ

ā§Š. āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āĻ•āϞāĻžāĻŽ āϝ⧋āĻ— āĻ•āϰ⧁āύ

👉 āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϏāĻ‚āϰāĻ•ā§āώāϪ⧇āϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻ•āϞāĻžāĻŽ āϝ⧋āĻ— āĻ•āϰ⧁āύ:

ALTER TABLE Skills ADD COLUMN skill_embedding ARRAY<FLOAT32>;

Run āĻŦāĻžāϟāύ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ, āĻāϟāĻŋ āϏāĻĢāϞ āĻšāϞ⧇ āφāĻĒāύāĻŋ āύ⧀āĻšā§‡āϰ āĻŽāϤ⧋ āĻĢāϞāĻžāĻĢāϞ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ:

āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚_āĻĢāϞāĻžāĻĢāϞ

ā§Ē. āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

👉 āĻĒā§āϰāϤāĻŋāϟāĻŋ āĻĻāĻ•ā§āώāϤāĻžāϰ āϜāĻ¨ā§āϝ āϭ⧇āĻ•ā§āϟāϰ āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϤ⧈āϰāĻŋ āĻ•āϰāϤ⧇ āĻāφāχ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύ:

UPDATE Skills
SET skill_embedding = (
    SELECT embeddings.values
    FROM ML.PREDICT(
        MODEL TextEmbeddings,
        (SELECT name AS content)
    )
)
WHERE skill_embedding IS NULL;

Run āĻŦāĻžāϟāύ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύ, āĻāϟāĻŋ āϏāĻĢāϞ āĻšāϞ⧇ āφāĻĒāύāĻŋ āύ⧀āĻšā§‡āϰ āĻŽāϤ⧋ āĻĢāϞāĻžāĻĢāϞ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ:

āĻĻāĻ•ā§āώāϤāĻž_āĻĢāϞāĻžāĻĢāϞ

āϝāĻž āϘāĻŸā§‡ : āĻĒā§āϰāϤāĻŋāϟāĻŋ āĻĻāĻ•ā§āώāϤāĻžāϰ āύāĻžāĻŽ (āϝ⧇āĻŽāύ, "āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž") āϤāĻžāϰ āĻ…āĻ°ā§āĻĨāĻ—āϤ āϤāĻžā§ŽāĻĒāĻ°ā§āϝ āĻĒā§āϰāĻ•āĻžāĻļāĻ•āĻžāϰ⧀ āĻāĻ•āϟāĻŋ ā§­ā§Ŧā§Ž-āĻŽāĻžāĻ¤ā§āϰāĻžāϰ āϭ⧇āĻ•ā§āϟāϰ⧇ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰāĻŋāϤ āĻšāϝāĻŧāĨ¤

ā§Ģ. āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϝāĻžāϚāĻžāχ āĻ•āϰ⧁āύ

👉 āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚āϗ⧁āϞ⧋ āϤ⧈āϰāĻŋ āĻšāϝāĻŧ⧇āϛ⧇ āĻ•āĻŋāύāĻž āϤāĻž āϝāĻžāϚāĻžāχ āĻ•āϰ⧁āύ:

SELECT 
    skill_id,
    name,
    ARRAY_LENGTH(skill_embedding) AS embedding_dimensions
FROM Skills
LIMIT 5;

āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āφāωāϟāĻĒ⧁āϟ :

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻĢāϞāĻžāĻĢāϞ

āĻāĻ–āύ āφāĻŽāϰāĻž āφāĻŽāĻžāĻĻ⧇āϰ āϏāĻŋāύāĻžāϰāĻŋāĻ“ āĻĨ⧇āϕ⧇ āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻŦā§āϝāĻŦāĻšāĻžāϰ⧇āϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰāĻŦ : 'āĻŽā§‡āĻĄāĻŋāĻ•' āĻļāĻŦā§āĻĻāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž āϏāĻ‚āĻ•ā§āϰāĻžāĻ¨ā§āϤ āĻĻāĻ•ā§āώāϤāĻž āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰāĻžāĨ¤

👉 'āĻŽā§‡āĻĄāĻŋāĻ•'-āĻāϰ āĻŽāϤ⧋ āĻĻāĻ•ā§āώāϤāĻž āϖ⧁āρāϜ⧁āύ:

WITH query_embedding AS (
    SELECT embeddings.values AS val
    FROM ML.PREDICT(MODEL TextEmbeddings, (SELECT "medic" AS content))
)
SELECT
    s.name AS skill_name,
    s.category,
    COSINE_DISTANCE(s.skill_embedding, (SELECT val FROM query_embedding)) AS distance
FROM Skills AS s
WHERE s.skill_embedding IS NOT NULL
ORDER BY distance ASC
LIMIT 10;
  • āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āϏāĻžāĻ°ā§āϚ āϟāĻžāĻ°ā§āĻŽ 'medic'-āϕ⧇ āĻāĻ•āϟāĻŋ āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚-āĻ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ āĻ•āϰ⧇āĨ¤
  • āĻāϟāĻŋ query_embedding āĻŸā§‡āĻŽā§āĻĒā§‹āϰāĻžāϰāĻŋ āĻŸā§‡āĻŦāĻŋāϞ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇āĨ¤

āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āĻĢāϞāĻžāĻĢāϞ (āĻ•āĻŽ āĻĻā§‚āϰāĻ¤ā§āĻŦ = āĻŦ⧇āĻļāĻŋ āϏāĻžāĻĻ⧃āĻļā§āϝāĻĒā§‚āĻ°ā§āĻŖ):

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻĢāϞāĻžāĻĢāϞ

ā§­. āĻŦāĻŋāĻļā§āϞ⧇āώāϪ⧇āϰ āϜāĻ¨ā§āϝ āĻœā§‡āĻŽāĻŋāύāĻŋ āĻŽāĻĄā§‡āϞ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻœā§‡āĻŽāĻŋāύāĻŋ

👉 āĻāĻ•āϟāĻŋ āĻœā§‡āύāĻžāϰ⧇āϟāĻŋāĻ­ āĻāφāχ āĻŽāĻĄā§‡āϞ āϰ⧇āĻĢāĻžāϰ⧇āĻ¨ā§āϏ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ (āĻāĻ–āĻžāύ⧇ $YOUR_PROJECT_ID āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧ āφāĻĒāύāĻžāϰ āφāϏāϞ āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āφāχāĻĄāĻŋ āĻŦāϏāĻžāύ):

CREATE OR REPLACE MODEL GeminiPro
INPUT(prompt STRING(MAX))
OUTPUT(content STRING(MAX))
REMOTE OPTIONS (
    endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/gemini-2.5-pro',
    default_batch_size = 1
);

āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚āϏ āĻŽāĻĄā§‡āϞ āĻĨ⧇āϕ⧇ āĻĒāĻžāĻ°ā§āĻĨāĻ•ā§āϝ :

  • āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ : āĻŸā§‡āĻ•ā§āϏāϟ → āϭ⧇āĻ•ā§āϟāϰ (āϏāĻžāĻĻ⧃āĻļā§āϝ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ⧇āϰ āϜāĻ¨ā§āϝ)
  • āĻŽāĻŋāĻĨ⧁āύ : āĻŽā§‚āϞ āϞ⧇āĻ–āĻž → āϤ⧈āϰāĻŋ āĻ•āϰāĻž āϞ⧇āĻ–āĻž (āϝ⧁āĻ•ā§āϤāĻŋ/āĻŦāĻŋāĻļā§āϞ⧇āώāϪ⧇āϰ āϜāĻ¨ā§āϝ)

āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ_āĻĢāϞāĻžāĻĢāϞ

ā§Ž. āϏāĻžāĻŽāĻžā§āϜāĻ¸ā§āϝ āĻŦāĻŋāĻļā§āϞ⧇āώāϪ⧇āϰ āϜāĻ¨ā§āϝ āĻŽāĻŋāĻĨ⧁āύ āϰāĻžāĻļāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤

👉 āĻŽāĻŋāĻļāύ⧇āϰ āϏāĻžāĻŽāĻžā§āϜāĻ¸ā§āϝāϤāĻžāϰ āϜāĻ¨ā§āϝ āϏāĻžāϰāĻ­āĻžāχāĻ­āĻžāϰ āĻœā§‹āĻĄāĻŧāĻžāϗ⧁āϞ⧋ āĻŦāĻŋāĻļā§āϞ⧇āώāĻŖ āĻ•āϰ⧁āύ:

WITH PairData AS (
    SELECT
        s1.name AS Name_A,
        s2.name AS Name_B,
        CONCAT(
            "Assess compatibility of these two survivors for a resource-gathering mission. ",
            "Survivor 1: ", s1.name, ". ",
            "Survivor 2: ", s2.name, ". ",
            "Give a score from 1-10 and a 1-sentence reason."
        ) AS prompt
    FROM Survivors s1
    JOIN Survivors s2 ON s1.survivor_id < s2.survivor_id
    LIMIT 1
)
SELECT
    Name_A,
    Name_B,
    content AS ai_assessment
FROM ML.PREDICT(
    MODEL GeminiPro,
    (SELECT Name_A, Name_B, prompt FROM PairData)
);

āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āφāωāϟāĻĒ⧁āϟ :

Name_A          | Name_B            | ai_assessment
----------------|-------------------|----------------
"David Chen"    | "Dr. Elena Frost" | "**Score: 9/10** Their compatibility is extremely high as David's practical, hands-on scavenging skills are perfectly complemented by Dr. Frost's specialized knowledge to identify critical medical supplies and avoid biological hazards."

ā§Ŧ. 🚀 āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āĻšā§‡āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āφāĻĒāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ āĻ°â€ā§āϝāĻžāĻ— āĻāĻœā§‡āĻ¨ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ

ā§§. āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ⧇āϰ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤ āĻŦāĻŋāĻŦāϰāĻŖ

āĻāχ āĻ…āĻ‚āĻļāϟāĻŋ āĻāĻ•āϟāĻŋ āĻŦāĻšā§-āĻĒāĻĻā§āϧāϤāĻŋāϰ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻŦā§āϝāĻŦāĻ¸ā§āĻĨāĻž āϤ⧈āϰāĻŋ āĻ•āϰ⧇ āϝāĻž āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟāϕ⧇ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āύ āϧāϰāϪ⧇āϰ āϕ⧋āϝāĻŧ⧇āϰāĻŋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰāĻžāϰ āύāĻŽāύ⧀āϝāĻŧāϤāĻž āĻĻ⧇āϝāĻŧāĨ¤ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽāϟāĻŋāϰ āϤāĻŋāύāϟāĻŋ āĻ¸ā§āϤāϰ āϰāϝāĻŧ⧇āϛ⧇: āĻāĻœā§‡āĻ¨ā§āϟ āĻ¸ā§āϤāϰ , āϟ⧁āϞ āĻ¸ā§āϤāϰ , āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻ¸ā§āϤāϰ āĨ¤

āĻ¸ā§āĻĨāĻžāĻĒāĻ¤ā§āϝ_āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ_āϏāĻžāĻ°ā§āϚ

āϤāĻŋāύāϟāĻŋ āĻ¸ā§āϤāϰ āϕ⧇āύ?

  • āĻĻāĻžāϝāĻŧāĻŋāĻ¤ā§āĻŦ⧇āϰ āĻĒ⧃āĻĨāϕ⧀āĻ•āϰāĻŖ : āĻāĻœā§‡āĻ¨ā§āϟ āĻ…āĻ­āĻŋāĻĒā§āϰāĻžāϝāĻŧ⧇āϰ āωāĻĒāϰ, āϟ⧁āϞ āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏ⧇āϰ āωāĻĒāϰ, āĻāĻŦāĻ‚ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ⧇āϰ āωāĻĒāϰ āĻŽāύ⧋āϝ⧋āĻ— āĻĻ⧇āϝāĻŧāĨ¤
  • āύāĻŽāύ⧀āϝāĻŧāϤāĻž : āĻāĻœā§‡āĻ¨ā§āϟ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻĒāĻĻā§āϧāϤāĻŋ āĻĒā§āϰāϝāĻŧā§‹āĻ— āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ āĻ…āĻĨāĻŦāĻž āĻāφāχ-āϕ⧇ āĻ¸ā§āĻŦāϝāĻŧāĻ‚āĻ•ā§āϰāĻŋāϝāĻŧāĻ­āĻžāĻŦ⧇ āϰ⧁āϟ āĻ•āϰāϤ⧇ āĻĻāĻŋāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤
  • āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāĻœā§‡āĻļāύ : āĻĒāĻĻā§āϧāϤāĻŋ āϜāĻžāύāĻž āĻĨāĻžāĻ•āϞ⧇ āĻŦā§āϝāϝāĻŧāĻŦāĻšā§āϞ āĻāφāχ āĻŦāĻŋāĻļā§āϞ⧇āώāĻŖ āĻāĻĄāĻŧāĻŋāϝāĻŧ⧇ āϝāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧāĨ¤

āĻāχ āĻ…āĻ‚āĻļ⧇, āφāĻĒāύāĻŋ āĻĒā§āϰāϧāĻžāύāϤ āϏāĻŋāĻŽāĻžāĻ¨ā§āϟāĻŋāĻ• āϏāĻžāĻ°ā§āϚ (RAG) āĻĒā§āϰāϝāĻŧā§‹āĻ— āĻ•āϰāĻŦ⧇āύ – āĻ…āĻ°ā§āĻĨāĻžā§Ž āĻļ⧁āϧ⧁ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āύāϝāĻŧ, āĻ…āĻ°ā§āĻĨ⧇āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡āĻ“ āĻĢāϞāĻžāĻĢāϞ āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰāĻŦ⧇āύāĨ¤ āĻĒāϰāĻŦāĻ°ā§āϤ⧀āϤ⧇, āφāĻŽāϰāĻž āĻŦā§āϝāĻžāĻ–ā§āϝāĻž āĻ•āϰāĻŦ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āϚ āĻāĻ•āĻžāϧāĻŋāĻ• āĻĒāĻĻā§āϧāϤāĻŋāϕ⧇ āĻāĻ•āĻ¤ā§āϰāĻŋāϤ āĻ•āϰ⧇āĨ¤

⧍. RAG āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻŋāϝāĻŧ⧇ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/services/hybrid_search_service.py

# TODO: REPLACE_SQL āĻŽāĻ¨ā§āϤāĻŦā§āϝāϟāĻŋ āϖ⧁āρāϜ⧁āύ

āĻāχ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

        # This is your working query from the successful run!
        sql = """
            WITH query_embedding AS (
                SELECT embeddings.values AS val
                FROM ML.PREDICT(
                    MODEL TextEmbeddings,
                    (SELECT @query AS content)
                )
            )
            SELECT
                s.survivor_id,
                s.name AS survivor_name,
                s.biome,
                sk.skill_id,
                sk.name AS skill_name,
                sk.category,
                COSINE_DISTANCE(
                    sk.skill_embedding, 
                    (SELECT val FROM query_embedding)
                ) AS distance
            FROM Survivors s
            JOIN SurvivorHasSkill shs ON s.survivor_id = shs.survivor_id
            JOIN Skills sk ON shs.skill_id = sk.skill_id
            WHERE sk.skill_embedding IS NOT NULL
            ORDER BY distance ASC
            LIMIT @limit
        """

ā§Š. āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻŋāĻ• āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āϏāϰāĻžā§āϜāĻžāĻŽā§‡āϰ āϏāĻ‚āĻœā§āĻžāĻž

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻŋāϝāĻŧ⧇ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/tools/hybrid_search_tools.py

hybrid_search_tools.py āĻĢāĻžāχāϞ⧇, # TODO: REPLACE_SEMANTIC_SEARCH_TOOL āĻāχ āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύāĨ¤

👉 āĻāχ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

async def semantic_search(query: str, limit: int = 10) -> str:
    """
    Force semantic (RAG) search using embeddings.
    
    Use this when you specifically want to find things by MEANING,
    not just matching keywords. Great for:
    - Finding conceptually similar items
    - Handling vague or abstract queries
    - When exact terms are unknown
    
    Example: "healing abilities" will find "first aid", "surgery", 
    "herbalism" even though no keywords match exactly.
    
    Args:
        query: What you're looking for (describe the concept)
        limit: Maximum results
        
    Returns:
        Semantically similar results ranked by relevance
    """
    try:
        service = _get_service()
        result = service.smart_search(
            query, 
            force_method=SearchMethod.RAG,
            limit=limit
        )
        
        return _format_results(
            result["results"],
            result["analysis"],
            show_analysis=True
        )
        
    except Exception as e:
        return f"Error in semantic search: {str(e)}"

āϝāĻ–āύ āĻāĻœā§‡āĻ¨ā§āϟ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ :

  • āϏāĻžāĻĻ⧃āĻļā§āϝ āϜāĻžāύāϤ⧇ āϚāĻžāĻ“āϝāĻŧāĻž āϕ⧋āϝāĻŧ⧇āϰāĻŋ ("X-āĻāϰ āĻ…āύ⧁āϰ⧂āĻĒ āĻ•āĻŋāϛ⧁ āϖ⧁āρāϜ⧁āύ")
  • āϧāĻžāϰāĻŖāĻžāĻ—āϤ āĻĒā§āϰāĻļā§āύ ("āφāϰ⧋āĻ—ā§āϝ⧇āϰ āĻ•ā§āώāĻŽāϤāĻž")
  • āϝāĻ–āύ āĻ…āĻ°ā§āĻĨ āĻŦā§‹āĻāĻž āĻ…āĻ¤ā§āϝāĻ¨ā§āϤ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ

ā§Ē. āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āϏāĻŋāĻĻā§āϧāĻžāĻ¨ā§āϤ āύāĻŋāĻ°ā§āĻĻ⧇āĻļāĻŋāĻ•āĻž (āύāĻŋāĻ°ā§āĻĻ⧇āĻļāĻžāĻŦāϞ⧀)

āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧ, āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻŋāĻ• āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ āĻ…āĻ‚āĻļāϟāĻŋ āύāĻŋāĻ°ā§āĻĻ⧇āĻļāύāĻžāϰ āϏāĻžāĻĨ⧇ āĻ•āĻĒāĻŋ-āĻĒ⧇āĻ¸ā§āϟ āĻ•āϰ⧁āύāĨ¤

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻŋāϝāĻŧ⧇ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻ āĻŋāĻ• āϟ⧁āϞāϟāĻŋ āύāĻŋāĻ°ā§āĻŦāĻžāϚāύ āĻ•āϰāϤ⧇ āĻāχ āύāĻŋāĻ°ā§āĻĻ⧇āĻļāύāĻžāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇:

agent.py āĻĢāĻžāχāϞ⧇, # TODO: REPLACE_SEARCH_LOGIC āĻāχ āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύ āĻāĻŦāĻ‚ āĻĒ⧁āϰ⧋ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

- `semantic_search`: Force RAG/embedding search
  Use for: "Find similar to X", conceptual queries, unknown terminology
  Example: "Find skills related to healing"

👉 # TODO: ADD_SEARCH_TOOL āĻāχ āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύ āĻāĻŦāĻ‚ āĻĒ⧁āϰ⧋ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

    semantic_search,         # Force RAG

ā§Ģ. āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āϚ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇ āϤāĻž āĻŦā§‹āĻāĻž (āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻĒāĻĄāĻŧāĻžāϰ āϜāĻ¨ā§āϝ, āϕ⧋āύ⧋ āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ⧇āϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āύ⧇āχ)

āϧāĻžāĻĒ ā§¨-ā§Ē-āĻ, āφāĻĒāύāĻŋ āϏāĻŋāĻŽāĻžāĻ¨ā§āϟāĻŋāĻ• āϏāĻžāĻ°ā§āϚ (RAG) āĻĒā§āϰāϝāĻŧā§‹āĻ— āĻ•āϰ⧇āϛ⧇āύ, āϝāĻž āĻšāϞ⧋ āĻŽā§‚āϞ āϏāĻžāĻ°ā§āϚ āĻĒāĻĻā§āϧāϤāĻŋ āĻāĻŦāĻ‚ āĻāϟāĻŋ āĻ…āĻ°ā§āĻĨ⧇āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āĻĢāϞāĻžāĻĢāϞ āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰ⧇āĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āφāĻĒāύāĻŋ āĻšāϝāĻŧāϤ⧋ āϞāĻ•ā§āĻˇā§āϝ āĻ•āϰ⧇āϛ⧇āύ āϝ⧇ āĻāχ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽāϟāĻŋāϕ⧇ "āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āϚ" āĻŦāϞāĻž āĻšāϝāĻŧāĨ¤ āύāĻŋāĻšā§‡ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϞ⧋ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻāχ āϏāĻŦāĻ•āĻŋāϛ⧁ āĻāĻ•āϏāĻžāĻĨ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇:

āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āĻŽāĻžāĻ°ā§āϜ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇ :

way-back-home/level_2/backend/services/hybrid_search_service.py āĻĢāĻžāχāϞ⧇, āϝāĻ–āύ hybrid_search() āĻ•āϞ āĻ•āϰāĻž āĻšāϝāĻŧ, āϤāĻ–āύ āϏāĻžāĻ°ā§āĻ­āĻŋāϏāϟāĻŋ āϏāĻžāĻ°ā§āϚ āĻ•āϰāĻžāϰ āĻĒāĻžāĻļāĻžāĻĒāĻžāĻļāĻŋ āĻĢāϞāĻžāĻĢāϞāϗ⧁āϞ⧋ āĻŽāĻžāĻ°ā§āϜāĻ“ āĻ•āϰ⧇:

# Location: backend/services/hybrid_search_service.py

    rank_kw = keyword_ranks.get(surv_id, float('inf'))
    rank_rag = rag_ranks.get(surv_id, float('inf'))

    rrf_score = 0.0
    if rank_kw != float('inf'):
        rrf_score += 1.0 / (K + rank_kw)
    if rank_rag != float('inf'):
        rrf_score += 1.0 / (K + rank_rag)

    combined_score = rrf_score

āĻāχ āϕ⧋āĻĄāĻ˛ā§āϝāĻžāĻŦ⧇āϰ āϜāĻ¨ā§āϝ , āφāĻĒāύāĻŋ āϏāĻŋāĻŽāĻžāĻ¨ā§āϟāĻŋāĻ• āϏāĻžāĻ°ā§āϚ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ (RAG) āχāĻŽāĻĒā§āϞāĻŋāĻŽā§‡āĻ¨ā§āϟ āĻ•āϰ⧇āϛ⧇āύ, āϝāĻž āĻšāϞ⧋ āĻāϰ āĻ­āĻŋāĻ¤ā§āϤāĻŋāĨ¤ āϏāĻžāĻ°ā§āĻ­āĻŋāϏāϟāĻŋāϤ⧇ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻāĻŦāĻ‚ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āĻŽā§‡āĻĨāĻĄāϗ⧁āϞ⧋ āχāϤāĻŋāĻŽāĻ§ā§āϝ⧇āχ āχāĻŽāĻĒā§āϞāĻŋāĻŽā§‡āĻ¨ā§āϟ āĻ•āϰāĻž āφāϛ⧇ - āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟ āĻāχ āϤāĻŋāύāϟāĻŋāχ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇!

āĻ…āĻ­āĻŋāύāĻ¨ā§āĻĻāύ! āφāĻĒāύāĻŋ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āϚ āϏāĻš āφāĻĒāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ āĻ°â€ā§āϝāĻžāĻ— āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻĢāϞāĻ­āĻžāĻŦ⧇ āϏāĻŽā§āĻĒāĻ¨ā§āύ āĻ•āϰ⧇āϛ⧇āύ!

ā§­. 🚀 ADK Web āĻĻāĻŋāϝāĻŧ⧇ āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟ āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰāĻž

āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟ āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰāĻžāϰ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āϏāĻšāϜ āωāĻĒāĻžāϝāĻŧ āĻšāϞ⧋ ` adk web āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž, āϝāĻž āĻāĻ•āϟāĻŋ āĻ…āĻ¨ā§āϤāĻ°ā§āύāĻŋāĻ°ā§āĻŽāĻŋāϤ āĻšā§āϝāĻžāϟ āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏ āϏāĻš āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟāϕ⧇ āϚāĻžāϞ⧁ āĻ•āϰ⧇āĨ¤

ā§§. āĻāĻœā§‡āĻ¨ā§āϟ āϚāĻžāϞāĻžāύ⧋

👉đŸ’ģ āĻŦā§āϝāĻžāĻ•āĻāĻ¨ā§āĻĄ āĻĄāĻŋāϰ⧇āĻ•ā§āϟāϰāĻŋāϤ⧇ (āϝ⧇āĻ–āĻžāύ⧇ āφāĻĒāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰāĻž āφāϛ⧇) āϝāĻžāύ āĻāĻŦāĻ‚ āĻ“āϝāĻŧ⧇āĻŦ āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏāϟāĻŋ āϚāĻžāϞ⧁ āĻ•āϰ⧁āύ::

cd ~/way-back-home/level_2/backend
uv run adk web

āĻāχ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āĻāĻœā§‡āĻ¨ā§āϟ āϚāĻžāϞ⧁ āĻ•āϰ⧇ āϝāĻž āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇

agent/agent.py

āĻāĻŦāĻ‚ āĻĒāϰ⧀āĻ•ā§āώāĻžāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻ“āϝāĻŧ⧇āĻŦ āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏ āĻ–ā§‹āϞ⧇āĨ¤

👉 āχāωāφāϰāĻāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

āĻāχ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āĻāĻ•āϟāĻŋ āĻ¸ā§āĻĨāĻžāύ⧀āϝāĻŧ āχāωāφāϰāĻāϞ (āϏāĻžāϧāĻžāϰāĻŖāϤ http://127.0.0.1:8000 āĻŦāĻž āĻāχ āϜāĻžāϤ⧀āϝāĻŧ) āφāωāϟāĻĒ⧁āϟ āĻšāĻŋāϏ⧇āĻŦ⧇ āĻĻ⧇āĻŦ⧇āĨ¤ āĻāϟāĻŋ āφāĻĒāύāĻžāϰ āĻŦā§āϰāĻžāωāϜāĻžāϰ⧇ āϖ⧁āϞ⧁āύāĨ¤

adk āĻ“āϝāĻŧ⧇āĻŦ

āχāωāφāϰāĻāϞ-āϟāĻŋāϤ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āφāĻĒāύāĻŋ āĻāĻĄāĻŋāϕ⧇ āĻ“āϝāĻŧ⧇āĻŦ āχāωāφāχ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύāĨ¤ āωāĻĒāϰ⧇āϰ āĻŦāĻžāĻŽ āϕ⧋āĻŖ āĻĨ⧇āϕ⧇ 'āĻāĻœā§‡āĻ¨ā§āϟ' āύāĻŋāĻ°ā§āĻŦāĻžāϚāύ āĻ•āϰāϤ⧇ āϭ⧁āϞāĻŦ⧇āύ āύāĻžāĨ¤

adk_ui

⧍. āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻ•ā§āώāĻŽāϤāĻž āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰāĻž

āĻāĻœā§‡āĻ¨ā§āϟāϟāĻŋ āφāĻĒāύāĻžāϰ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύāϗ⧁āϞ⧋āϕ⧇ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻ¤ā§āϤāĻžāϰ āϏāĻžāĻĨ⧇ āϏāĻ āĻŋāĻ• āĻĒāĻĨ⧇ āϚāĻžāϞāĻŋāϤ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĄāĻŋāϜāĻžāχāύ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āύ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻĒāĻĻā§āϧāϤāĻŋ āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ āĻĻ⧇āĻ–āϤ⧇ āĻšā§āϝāĻžāϟ āωāχāĻ¨ā§āĻĄā§‹āϤ⧇ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āχāύāĻĒ⧁āϟāϗ⧁āϞ⧋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻĻ⧇āϖ⧁āύāĨ¤

āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āύāĻž āĻŽāĻŋāϞāϞ⧇āĻ“ āĻ…āĻ°ā§āĻĨ āĻ“ āϧāĻžāϰāĻŖāĻžāϰ āĻ­āĻŋāĻ¤ā§āϤāĻŋāϤ⧇ āφāχāĻŸā§‡āĻŽ āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰ⧇āĨ¤

āĻĒāϰ⧀āĻ•ā§āώāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāĻļā§āύ: (āύ⧀āĻšā§‡āϰ āϝ⧇āϕ⧋āύ āĻāĻ•āϟāĻŋ āĻŦ⧇āϛ⧇ āύāĻŋāύ)

Who can help with injuries?
What abilities are related to survival?

āϕ⧀ āϕ⧀ āĻĻ⧇āĻ–āϤ⧇ āĻšāĻŦ⧇:

  • āϝ⧁āĻ•ā§āϤāĻŋāϤ⧇ āϏāĻŋāĻŽāĻžāĻ¨ā§āϟāĻŋāĻ• āĻŦāĻž āĻ°â€ā§āϝāĻžāĻ— āϏāĻžāĻ°ā§āĻšā§‡āϰ āωāĻ˛ā§āϞ⧇āĻ– āĻĨāĻžāĻ•āĻž āωāϚāĻŋāϤāĨ¤
  • āφāĻĒāύāĻžāϰ āĻāĻŽāύ āĻĢāϞāĻžāĻĢāϞ āĻĻ⧇āĻ–āĻž āωāϚāĻŋāϤ āϝāĻž āϧāĻžāϰāĻŖāĻžāĻ—āϤāĻ­āĻžāĻŦ⧇ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ (āϝ⧇āĻŽāύ, "āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž" āϜāĻŋāĻœā§āĻžāĻžāϏāĻž āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ "āϏāĻžāĻ°ā§āϜāĻžāϰāĻŋ")āĨ¤
  • āĻĢāϞāĻžāĻĢāϞ⧇ đŸ§Ŧ āφāχāĻ•āύāϟāĻŋ āĻĨāĻžāĻ•āĻŦ⧇āĨ¤

āϜāϟāĻŋāϞ āϕ⧋āϝāĻŧ⧇āϰāĻŋāϰ āϜāĻ¨ā§āϝ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻāĻŦāĻ‚ āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻ—āϤ āωāĻĒāϞāĻŦā§āϧāĻŋāϰ āϏāĻŽāĻ¨ā§āĻŦāϝāĻŧ āϘāϟāĻžāϝāĻŧāĨ¤

āĻĒāϰ⧀āĻ•ā§āώāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāĻļā§āύ: (āύ⧀āĻšā§‡āϰ āϝ⧇āϕ⧋āύ āĻāĻ•āϟāĻŋ āĻŦ⧇āϛ⧇ āύāĻŋāύ)

Find someone who can fly a plane in the volcanic area
Who has healing abilities in the FOSSILIZED?
Who has healing abilities in the mountains?

āϕ⧀ āϕ⧀ āĻĻ⧇āĻ–āϤ⧇ āĻšāĻŦ⧇:

  • āϝ⧁āĻ•ā§āϤāĻŋāϤ⧇ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āϏāĻžāĻ°ā§āĻšā§‡āϰ āωāĻ˛ā§āϞ⧇āĻ– āĻĨāĻžāĻ•āĻž āωāϚāĻŋāϤāĨ¤
  • āĻĢāϞāĻžāĻĢāϞ āĻ…āĻŦāĻļā§āϝāχ āωāĻ­āϝāĻŧ āĻŽāĻžāύāĻĻāĻŖā§āĻĄā§‡āϰ (āϧāĻžāϰāĻŖāĻž + āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ/āĻŦāĻŋāĻ­āĻžāĻ—) āϏāĻžāĻĨ⧇ āĻŽāĻŋāϞāϤ⧇ āĻšāĻŦ⧇āĨ¤
  • āωāĻ­āϝāĻŧ āĻĒāĻĻā§āϧāϤāĻŋāϤ⧇ āĻĒā§āϰāĻžāĻĒā§āϤ āĻĢāϞāĻžāĻĢāϞ⧇ 🔀 āφāχāĻ•āύ āĻĨāĻžāĻ•āĻŦ⧇ āĻāĻŦāĻ‚ āϏ⧇āϗ⧁āϞ⧋ āϏāĻ°ā§āĻŦā§‹āĻšā§āϚ āĻ°â€ā§āϝāĻžāĻ™ā§āϕ⧇ āĻĨāĻžāĻ•āĻŦ⧇āĨ¤

👉đŸ’ģ āĻŸā§‡āĻ¸ā§āϟāĻŋāĻ‚ āĻļ⧇āώ āĻšāϞ⧇, āφāĻĒāύāĻžāϰ āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āϞāĻžāχāύ⧇ Ctrl+C āĻšā§‡āĻĒ⧇ āĻĒā§āϰāϏ⧇āϏāϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰ⧁āύāĨ¤

ā§Ž. 🚀 āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύāϟāĻŋ āϚāĻžāϞāĻžāύ⧋

āĻĢ⧁āϞ āĻ¸ā§āĻŸā§āϝāĻžāĻ• āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ⧇āϰ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤ āĻŦāĻŋāĻŦāϰāĻŖ

āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ_āĻĢ⧁āϞāĻ¸ā§āĻŸā§āϝāĻžāĻ•

āϏ⧇āĻļāύāϏāĻžāĻ°ā§āĻ­āĻŋāϏ āĻāĻŦāĻ‚ āϰāĻžāύāĻžāϰ āϝ⧋āĻ— āĻ•āϰ⧁āύ

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ chat.py āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ āĻāĻŦāĻ‚ āĻāχ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻžāύ (āĻāĻ—āĻŋāϝāĻŧ⧇ āϝāĻžāĻ“āϝāĻŧāĻžāϰ āφāϗ⧇ āφāϗ⧇āϰ āĻĒā§āϰāϏ⧇āϏāϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰāϤ⧇ 'ctrl+C' āϚāĻžāĻĒāϤ⧇ āϭ⧁āϞāĻŦ⧇āύ āύāĻž):

cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py

chat.py āĻĢāĻžāχāϞ⧇, # TODO: REPLACE_INMEMORY_SERVICES āĻāχ āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύ āĻāĻŦāĻ‚ āĻĒ⧁āϰ⧋ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

    session_service = InMemorySessionService()
    memory_service = InMemoryMemoryService()

chat.py āĻĢāĻžāχāϞ⧇, # TODO: REPLACE_RUNNER āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύ āĻāĻŦāĻ‚ āĻāχ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

runner = Runner(
    agent=root_agent, 
    session_service=session_service,
    memory_service=memory_service,
    app_name="survivor-network"
)

ā§§. āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ āĻļ⧁āϰ⧁ āĻ•āϰ⧁āύ

āϝāĻĻāĻŋ āφāϗ⧇āϰ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞāϟāĻŋ āĻāĻ–āύāĻ“ āϚāĻžāϞ⧁ āĻĨāĻžāϕ⧇, āϤāĻžāĻšāϞ⧇ Ctrl+C āĻšā§‡āĻĒ⧇ āϏ⧇āϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰ⧁āύāĨ¤

👉đŸ’ģ āĻ…ā§āϝāĻžāĻĒāϟāĻŋ āϚāĻžāϞ⧁ āĻ•āϰ⧁āύ:

cd ~/way-back-home/level_2/
./start_app.sh

āϝāĻ–āύ āĻŦā§āϝāĻžāĻ•āĻāĻ¨ā§āĻĄ āϏāĻĢāϞāĻ­āĻžāĻŦ⧇ āϚāĻžāϞ⧁ āĻšāĻŦ⧇, āφāĻĒāύāĻŋ āύ⧀āĻšā§‡āϰ āĻŽāϤ⧋ Local: http://localhost:5173/" āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ: āϏāĻžāĻŽāύ⧇

👉 āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ āĻĨ⧇āϕ⧇ Local: http://localhost:5173/ -āĻ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧁āύāĨ¤

āĻ•āĻĨā§‹āĻĒāĻ•āĻĨāύ

āĻĒā§āϰāĻļā§āύ :

Find skills similar to healing

āĻšā§āϝāĻžāϟ

āϝāĻž āϘāĻŸā§‡ :

  • āĻāĻœā§‡āĻ¨ā§āϟ āϏāĻžāĻĻ⧃āĻļā§āϝ āĻ…āύ⧁āϰ⧋āϧ āĻļāύāĻžāĻ•ā§āϤ āĻ•āϰ⧇
  • 'āĻšāĻŋāϞāĻŋāĻ‚'-āĻāϰ āϜāĻ¨ā§āϝ āĻāĻŽāĻŦ⧇āĻĄāĻŋāĻ‚ āϤ⧈āϰāĻŋ āĻ•āϰ⧇
  • āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻ—āϤāĻ­āĻžāĻŦ⧇ āϏāĻžāĻĻ⧃āĻļā§āϝāĻĒā§‚āĻ°ā§āĻŖ āĻĻāĻ•ā§āώāϤāĻž āϖ⧁āρāĻœā§‡ āĻŦ⧇āϰ āĻ•āϰāϤ⧇ āϕ⧋āϏāĻžāχāύ āĻĻā§‚āϰāĻ¤ā§āĻŦ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āĨ¤
  • āĻĢ⧇āϰāϤ: āĻĒā§āϰāĻžāĻĨāĻŽāĻŋāĻ• āϚāĻŋāĻ•āĻŋā§ŽāϏāĻž (āϝāĻĻāĻŋāĻ“ āύāĻžāĻŽāϗ⧁āϞ⧋ 'āφāϰ⧋āĻ—ā§āϝ' āĻāϰ āϏāĻžāĻĨ⧇ āĻŽā§‡āϞ⧇ āύāĻž)

āĻĒā§āϰāĻļā§āύ :

Find medical skills in the mountains

āϝāĻž āϘāĻŸā§‡ :

  1. āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āωāĻĒāĻžāĻĻāĻžāύ : category='medical' āϜāĻ¨ā§āϝ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻ•āϰ⧁āύ
  2. āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻŋāĻ• āωāĻĒāĻžāĻĻāĻžāύ : 'āĻŽā§‡āĻĄāĻŋāϕ⧇āϞ' āĻļāĻŦā§āĻĻāϟāĻŋ āĻ…āĻ¨ā§āϤāĻ°ā§āϭ⧁āĻ•ā§āϤ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āϏāĻžāĻĻ⧃āĻļā§āϝ āĻ…āύ⧁āϏāĻžāϰ⧇ āĻ•ā§āϰāĻŽ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰ⧁āύāĨ¤
  3. āĻāĻ•āĻ¤ā§āϰ⧀āĻ•āϰāĻŖ : āωāĻ­āϝāĻŧ āĻĒāĻĻā§āϧāϤāĻŋāϤ⧇ āĻĒā§āϰāĻžāĻĒā§āϤ āĻĢāϞāĻžāĻĢāϞāϕ⧇ āĻ…āĻ—ā§āϰāĻžāϧāĻŋāĻ•āĻžāϰ āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ•āĻ¤ā§āϰāĻŋāϤ āĻ•āϰ⧁āύ 🔀

āĻĒā§āϰāĻļā§āύ (āϐāĻšā§āĻ›āĻŋāĻ•) :

Who is good at survival and in the forest?

āϝāĻž āϘāĻŸā§‡ :

  • āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āϖ⧁āρāĻœā§‡ āĻĒāĻžāĻ“āϝāĻŧāĻž āϗ⧇āϛ⧇: biome='forest'
  • āĻļāĻŦā§āĻĻāĻžāĻ°ā§āĻĨāĻ—āϤ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ: "āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻž"-āϰ āĻ…āύ⧁āϰ⧂āĻĒ āĻĻāĻ•ā§āώāϤāĻž
  • āϏāĻ°ā§āĻŦā§‹āĻ¤ā§āϤāĻŽ āĻĢāϞāĻžāĻĢāϞ⧇āϰ āϜāĻ¨ā§āϝ āĻšāĻžāχāĻŦā§āϰāĻŋāĻĄ āωāĻ­āϝāĻŧ⧇āϰāχ āϏāĻŽāĻ¨ā§āĻŦāϝāĻŧ āĻ•āϰ⧇āĨ¤

👉đŸ’ģ āĻŸā§‡āĻ¸ā§āϟāĻŋāĻ‚ āĻļ⧇āώ āĻšāϞ⧇, āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ Ctrl+C āĻšā§‡āĻĒ⧇ āĻāϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰ⧁āύāĨ¤

ā§Ē. (āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻ•āĻ°ā§āĻŽāĻļāĻžāϞāĻžāϰ āĻ…āĻ‚āĻļāĻ—ā§āϰāĻšāĻŖāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āϜāĻ¨ā§āϝ) āφāĻĒāύāĻžāϰ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ āĻšāĻžāϞāύāĻžāĻ—āĻžāĻĻ āĻ•āϰ⧁āύāĨ¤

👉đŸ’ģ āϏāĻŽāĻžāĻĒā§āϤāĻŋ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟāϟāĻŋ āϚāĻžāϞāĻžāύ:

cd ~/way-back-home/level_2
./set_level_2.sh

āĻāĻ–āύ waybackhome.dev āϖ⧁āϞ⧁āύ, āĻāĻŦāĻ‚ āφāĻĒāύāĻŋ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāĻŦ⧇āύ āφāĻĒāύāĻžāϰ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ āφāĻĒāĻĄā§‡āϟ āĻšāϝāĻŧ⧇ āϗ⧇āϛ⧇āĨ¤ āϞ⧇āϭ⧇āϞ ⧍ āϏāĻĢāϞāĻ­āĻžāĻŦ⧇ āϏāĻŽā§āĻĒāĻ¨ā§āύ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻ…āĻ­āĻŋāύāĻ¨ā§āĻĻāύ!

āĻšā§‚āĻĄāĻŧāĻžāĻ¨ā§āϤ āĻĢāϞāĻžāĻĢāϞ

⧝. â˜•ī¸ [āϐāĻšā§āĻ›āĻŋāĻ•] āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āĻĒāĻžāχāĻĒāϞāĻžāχāύ (āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻĒāĻ āύāϝ⧋āĻ—ā§āϝ) — āϟ⧁āϞāĻŋāĻ‚ āϞ⧇āϝāĻŧāĻžāϰ

āφāĻŽāĻžāĻĻ⧇āϰ āϕ⧇āύ āĻāĻ•āϟāĻŋ āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āĻĒāĻžāχāĻĒāϞāĻžāχāύ āĻĒā§āϰāϝāĻŧā§‹āϜāύ?

āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻžāϰ āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āĻ• āĻļ⧁āϧ⧁ āĻŸā§‡āĻ•ā§āϏāϟ-āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ• āύāϝāĻŧāĨ¤ āĻŽāĻžāϠ⧇ āĻĨāĻžāĻ•āĻž āĻŦ⧇āρāĻšā§‡ āĻĨāĻžāĻ•āĻž āĻŦā§āϝāĻ•ā§āϤāĻŋāϰāĻž āϏāϰāĻžāϏāϰāĻŋ āĻšā§āϝāĻžāĻŸā§‡āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āĻ…āϏāĻ‚āĻ—āĻ āĻŋāϤ āĻĄā§‡āϟāĻž āĻĒāĻžāĻ āĻžāύ:

  • 📸 āĻ›āĻŦāĻŋ : āϏāĻŽā§āĻĒāĻĻ, āĻŦāĻŋāĻĒāĻĻ āĻŦāĻž āϏāϰāĻžā§āϜāĻžāĻŽā§‡āϰ āĻ›āĻŦāĻŋ
  • đŸŽĨ āĻ­āĻŋāĻĄāĻŋāĻ“ : āĻ…āĻŦāĻ¸ā§āĻĨāĻžāϰ āĻĒā§āϰāϤāĻŋāĻŦ⧇āĻĻāύ āĻŦāĻž āϜāϰ⧁āϰāĻŋ āϏāĻžāĻšāĻžāĻ¯ā§āϝ⧇āϰ āĻŦāĻžāĻ°ā§āϤāĻž
  • 📄 āĻĒāĻžāĻ ā§āϝ : āĻŽāĻžāϠ⧇āϰ āύ⧋āϟ āĻŦāĻž āϞāĻ—

āφāĻŽāϰāĻž āϕ⧋āύ āĻĢāĻžāχāϞāϗ⧁āϞ⧋ āĻĒā§āϰāϏ⧇āϏ āĻ•āϰāĻ›āĻŋ?

āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āϧāĻžāĻĒ⧇ āφāĻŽāϰāĻž āĻŦāĻŋāĻĻā§āϝāĻŽāĻžāύ āĻĄā§‡āϟāĻž āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻ•āϰāϞ⧇āĻ“, āĻāĻ–āĻžāύ⧇ āφāĻŽāϰāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻž āĻĢāĻžāχāϞāϗ⧁āϞ⧋ āĻĒā§āϰāϏ⧇āϏ āĻ•āϰāĻŋāĨ¤ chat.py āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏāϟāĻŋ āĻĄāĻžāχāύāĻžāĻŽāĻŋāĻ•āĻ­āĻžāĻŦ⧇ āĻĢāĻžāχāϞ āĻ…ā§āϝāĻžāϟāĻžāϚāĻŽā§‡āĻ¨ā§āϟāϗ⧁āϞ⧋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧇:

āĻ‰ā§ŽāϏ

āĻŦāĻŋāώāϝāĻŧāĻŦāĻ¸ā§āϤ⧁

āϞāĻ•ā§āĻˇā§āϝ

āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤāĻŋ

āĻ›āĻŦāĻŋ/āĻ­āĻŋāĻĄāĻŋāĻ“/āϞ⧇āĻ–āĻž

āĻ—ā§āϰāĻžāĻĢ⧇ āϝ⧋āĻ— āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āϤāĻĨā§āϝ

āĻšā§āϝāĻžāĻŸā§‡āϰ āĻĒā§āϰāϏāĻ™ā§āĻ—

āĻāχ āĻšāϞ⧋ āϏāϰāĻŦāϰāĻžāĻšāϗ⧁āϞ⧋āϰ āĻāĻ•āϟāĻŋ āĻ›āĻŦāĻŋāĨ¤

āωāĻĻā§āĻĻ⧇āĻļā§āϝ āĻāĻŦāĻ‚ āĻ…āϤāĻŋāϰāĻŋāĻ•ā§āϤ āĻŦāĻŋāĻŦāϰāĻŖ

āĻĒāϰāĻŋāĻ•āĻ˛ā§āĻĒāĻŋāϤ āĻĒāĻĻā§āϧāϤāĻŋ: āĻ…āύ⧁āĻ•ā§āϰāĻŽāĻŋāĻ• āĻāĻœā§‡āĻ¨ā§āϟ āĻĒāĻžāχāĻĒāϞāĻžāχāύ

āφāĻŽāϰāĻž āĻāĻ•āϟāĻŋ āϏāĻŋāϕ⧋āϝāĻŧ⧇āύāĻļāĻŋāϝāĻŧāĻžāϞ āĻāĻœā§‡āĻ¨ā§āϟ ( multimedia_agent.py ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻŋ āϝāĻž āĻŦāĻŋāĻļ⧇āώāĻžāϝāĻŧāĻŋāϤ āĻāĻœā§‡āĻ¨ā§āϟāϗ⧁āϞ⧋āϕ⧇ āĻāĻ•āϏāĻžāĻĨ⧇ āĻļ⧃āĻ™ā§āĻ–āϞāĻŋāϤ āĻ•āϰ⧇:

āĻ¸ā§āĻĨāĻžāĻĒāĻ¤ā§āϝ_āφāĻĒāϞ⧋āĻĄāĻŋāĻ‚

āĻāϟāĻŋ backend/agent/multimedia_agent.py āϤ⧇ āĻāĻ•āϟāĻŋ SequentialAgent āĻšāĻŋāϏ⧇āĻŦ⧇ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤

āϟ⧁āϞāĻŋāĻ‚ āϞ⧇āϝāĻŧāĻžāϰāϟāĻŋ āϏ⧇āχāϏāĻŦ āϏāĻ•ā§āώāĻŽāϤāĻž āĻĒā§āϰāĻĻāĻžāύ āĻ•āϰ⧇ āϝāĻž āĻāĻœā§‡āĻ¨ā§āϟāϰāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤ āϟ⧁āϞāϗ⧁āϞ⧋ āĻ•āĻžāĻ°ā§āϝāĻĒāĻĻā§āϧāϤāĻŋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧇ — āϝ⧇āĻŽāύ āĻĢāĻžāχāϞ āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻž, āĻāύāϟāĻŋāϟāĻŋ āύāĻŋāĻˇā§āĻ•āĻžāĻļāύ āĻ•āϰāĻž āĻāĻŦāĻ‚ āĻĄā§‡āϟāĻžāĻŦ⧇āϏ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰāĻžāĨ¤

ā§§. āϟ⧁āϞāϏ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ

👉đŸ’ģ level_2/backend/agent/tools/extraction_tools.py āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ āĻ…āĻĨāĻŦāĻž āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϟāĻžāχāĻĒ āĻ•āϰ⧁āύāĨ¤ āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ āϖ⧁āϞ⧁āύāĨ¤ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/tools/extraction_tools.py

⧍. upload_media āϟ⧁āϞ āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ āĻ•āϰ⧁āύ

āĻāχ āϟ⧁āϞāϟāĻŋ āĻ¸ā§āĻĨāĻžāύ⧀āϝāĻŧ āĻĢāĻžāχāϞāϕ⧇ āϗ⧁āĻ—āϞ āĻ•ā§āϞāĻžāωāĻĄ āĻ¸ā§āĻŸā§‹āϰ⧇āĻœā§‡ āφāĻĒāϞ⧋āĻĄ āĻ•āϰ⧇āĨ¤

👉 def upload_media(file_path: str, survivor_id: Optional[str] = None) -> Dict[str, Any]: āĻāϰ āĻŽāĻ§ā§āϝ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āϕ⧋āĻĄāϟāĻŋ GCS-āĻ āĻĢāĻžāχāϞ āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻžāϰ āĻĒāĻĻā§āϧāϤāĻŋ āĻāĻŦāĻ‚ āĻĢāĻžāχāϞ⧇āϰ āϧāϰāύ āĻļāύāĻžāĻ•ā§āϤ āĻ•āϰāĻž āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ:

    """
    Upload media file to GCS and detect its type.
    
    Args:
        file_path: Path to the local file
        survivor_id: Optional survivor ID to associate with upload
        
    Returns:
        Dict with gcs_uri, media_type, and status
    """
    try:
        if not file_path:
            return {"status": "error", "error": "No file path provided"}
        
        # Strip quotes if present
        file_path = file_path.strip().strip("'").strip('"')
        
        if not os.path.exists(file_path):
            return {"status": "error", "error": f"File not found: {file_path}"}
        
        gcs_uri, media_type, signed_url = gcs_service.upload_file(file_path, survivor_id)
        
        return {
            "status": "success",
            "gcs_uri": gcs_uri,
            "signed_url": signed_url,
            "media_type": media_type.value,
            "file_name": os.path.basename(file_path),
            "survivor_id": survivor_id
        }
    except Exception as e:
        logger.error(f"Upload failed: {e}")
        return {"status": "error", "error": str(e)}

ā§Š. extract_from_media āϟ⧁āϞāϟāĻŋ āĻĒā§āϰāϝāĻŧā§‹āĻ— āĻ•āϰ⧁āύ

āĻāχ āϟ⧁āϞāϟāĻŋ āĻāĻ•āϟāĻŋ āϰāĻžāωāϟāĻžāϰ — āĻāϟāĻŋ media_type āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰ⧇ āĻāĻŦāĻ‚ āϏāĻ āĻŋāĻ• āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟāϰ⧇ (āĻŸā§‡āĻ•ā§āϏāϟ, āχāĻŽā§‡āϜ āĻŦāĻž āĻ­āĻŋāĻĄāĻŋāĻ“) āĻĒā§āϰ⧇āϰāĻŖ āĻ•āϰ⧇āĨ¤

👉 async def extract_from_media(gcs_uri: str, media_type: str, signed_url: Optional[str] = None) -> Dict[str, Any]: ` āĻĢāĻžāĻ‚āĻļāύ⧇āϰ āĻŽāĻ§ā§āϝ⧇, āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻž āĻŽāĻŋāĻĄāĻŋāϝāĻŧāĻž āĻĨ⧇āϕ⧇ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻāύāϟāĻŋāϟāĻŋ āĻāĻŦāĻ‚ āϰāĻŋāϞ⧇āĻļāύāĻļāĻŋāĻĒ āĻŦ⧇āϰ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ, āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄāϟāĻŋ āϤāĻž-āχ āĻĻ⧇āĻ–āĻžāϝāĻŧāĨ¤

    """
    Extract entities and relationships from uploaded media.
    
    Args:
        gcs_uri: GCS URI of the uploaded file
        media_type: Type of media (text/image/video)
        signed_url: Optional signed URL for public/temporary access
        
    Returns:
        Dict with extraction results
    """
    try:
        if not gcs_uri:
             return {"status": "error", "error": "No GCS URI provided"}

        # Select appropriate extractor
        if media_type == MediaType.TEXT.value or media_type == "text":
            result = await text_extractor.extract(gcs_uri)
        elif media_type == MediaType.IMAGE.value or media_type == "image":
            result = await image_extractor.extract(gcs_uri)
        elif media_type == MediaType.VIDEO.value or media_type == "video":
            result = await video_extractor.extract(gcs_uri)
        else:
            return {"status": "error", "error": f"Unsupported media type: {media_type}"}
            
        # Inject signed URL into broadcast info if present
        if signed_url:
            if not result.broadcast_info:
                result.broadcast_info = {}
            result.broadcast_info['thumbnail_url'] = signed_url
        
        return {
            "status": "success",
            "extraction_result": result.to_dict(), # Return valid JSON dict instead of object
            "summary": result.summary,
            "entities_count": len(result.entities),
            "relationships_count": len(result.relationships),
            "entities": [e.to_dict() for e in result.entities],
            "relationships": [r.to_dict() for r in result.relationships]
        }
    except Exception as e:
        logger.error(f"Extraction failed: {e}")
        return {"status": "error", "error": str(e)}

āĻŽā§‚āϞ āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ āĻŦāĻŋāĻŦāϰāĻŖ:

  • āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āχāύāĻĒ⧁āϟ : āφāĻŽāϰāĻž generate_content āĻĢāĻžāĻ‚āĻļāύ⧇ āĻŸā§‡āĻ•ā§āϏāϟ āĻĒā§āϰāĻŽā§āĻĒāϟ ( _get_extraction_prompt() ) āĻāĻŦāĻ‚ āχāĻŽā§‡āϜ āĻ…āĻŦāĻœā§‡āĻ•ā§āϟ āωāĻ­āϝāĻŧāχ āĻĒāĻžāϏ āĻ•āϰāĻŋāĨ¤
  • āĻ¸ā§āĻŸā§āϰāĻžāĻ•āϚāĻžāĻ°ā§āĻĄ āφāωāϟāĻĒ⧁āϟ : response_mime_type="application/json" āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰ⧇ āϝ⧇ LLM āĻŦ⧈āϧ JSON āϰāĻŋāϟāĻžāĻ°ā§āύ āĻ•āϰāĻŦ⧇, āϝāĻž āĻĒāĻžāχāĻĒāϞāĻžāχāύ⧇āϰ āϜāĻ¨ā§āϝ āĻ…āĻ¤ā§āϝāĻ¨ā§āϤ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖāĨ¤
  • āϚāĻžāĻ•ā§āώ⧁āώ āϏāĻ¤ā§āϤāĻž āϏāĻ‚āϝ⧋āĻ— : āĻĒā§āϰāĻŽā§āĻĒāϟāϟāĻŋāϤ⧇ āĻĒāϰāĻŋāϚāĻŋāϤ āϏāĻ¤ā§āϤāĻž āĻ…āĻ¨ā§āϤāĻ°ā§āϭ⧁āĻ•ā§āϤ āϰāϝāĻŧ⧇āϛ⧇ āϝāĻžāϤ⧇ āĻœā§‡āĻŽāĻŋāύāĻŋ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ•ā§āώāϰ āϚāĻŋāύāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

ā§Ē. save_to_spanner āϟ⧁āϞ āĻĒā§āϰāϝāĻŧā§‹āĻ— āĻ•āϰ⧁āύ

āĻāχ āϟ⧁āϞāϟāĻŋ āύāĻŋāĻˇā§āĻ•āĻžāĻļāĻŋāϤ āϏāĻ¤ā§āϤāĻž āĻāĻŦāĻ‚ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āϗ⧁āϞāĻŋāϕ⧇ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ āĻĄāĻŋāĻŦāĻŋ-āϤ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇āĨ¤

👉 def save_to_spanner(extraction_result: Any, survivor_id: Optional[str] = None) -> Dict[str, Any]: āĻāϰ āĻŽāĻ§ā§āϝ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āϕ⧋āĻĄāϟāĻŋ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ āĻĄāĻŋāĻŦāĻŋ-āϤ⧇ āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟ āĻ•āϰāĻž āĻāύāϟāĻŋāϟāĻŋ āĻāĻŦāĻ‚ āϰāĻŋāϞ⧇āĻļāύāĻļāĻŋāĻĒāϗ⧁āϞāĻŋ āϕ⧀āĻ­āĻžāĻŦ⧇ āϏ⧇āĻ­ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ, āϤāĻž āύāĻŋāϝāĻŧ⧇ āφāϞ⧋āϚāύāĻž āĻ•āϰ⧇āĨ¤

    """
    Save extracted entities and relationships to Spanner Graph DB.
    
    Args:
        extraction_result: ExtractionResult object (or dict from previous step if passed as dict)
        survivor_id: Optional survivor ID to associate with the broadcast
        
    Returns:
        Dict with save statistics
    """
    try:
        # Handle if extraction_result is passed as the wrapper dict from extract_from_media
        result_obj = extraction_result
        if isinstance(extraction_result, dict) and 'extraction_result' in extraction_result:
             result_obj = extraction_result['extraction_result']
        
        # If result_obj is a dict (from to_dict()), reconstruct it
        if isinstance(result_obj, dict):
            from extractors.base_extractor import ExtractionResult
            result_obj = ExtractionResult.from_dict(result_obj)
        
        if not result_obj:
            return {"status": "error", "error": "No extraction result provided"}
            
        stats = spanner_service.save_extraction_result(result_obj, survivor_id)
        
        return {
            "status": "success",
            "entities_created": stats['entities_created'],
            "entities_existing": stats['entities_found_existing'],
            "relationships_created": stats['relationships_created'],
            "broadcast_id": stats['broadcast_id'],
            "errors": stats['errors'] if stats['errors'] else None
        }
    except Exception as e:
        logger.error(f"Spanner save failed: {e}")
        return {"status": "error", "error": str(e)}

āĻāĻœā§‡āĻ¨ā§āϟāĻĻ⧇āϰ āωāĻ¨ā§āύāϤ āĻŽāĻžāύ⧇āϰ āϏāϰāĻžā§āϜāĻžāĻŽ āĻĒā§āϰāĻĻāĻžāύ⧇āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āφāĻŽāϰāĻž āĻĄā§‡āϟāĻžāϰ āĻ…āĻ–āĻŖā§āĻĄāϤāĻž āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāĻŋ āĻāĻŦāĻ‚ āĻāĻ•āχ āϏāĻžāĻĨ⧇ āϤāĻžāĻĻ⧇āϰ āϝ⧁āĻ•ā§āϤāĻŋāĻŦā§‹āϧ⧇āϰ āĻ•ā§āώāĻŽāϤāĻžāϕ⧇āĻ“ āĻ•āĻžāĻœā§‡ āϞāĻžāĻ—āĻžāχāĨ¤

ā§Ģ. GCS āĻĒāϰāĻŋāώ⧇āĻŦāĻž āφāĻĒāĻĄā§‡āϟ āĻ•āϰ⧁āύ

GCSService āϗ⧁āĻ—āϞ āĻ•ā§āϞāĻžāωāĻĄ āĻ¸ā§āĻŸā§‹āϰ⧇āĻœā§‡ āĻĢāĻžāχāϞ āφāĻĒāϞ⧋āĻĄā§‡āϰ āĻ•āĻžāϜāϟāĻŋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧇āĨ¤

👉đŸ’ģ level_2/backend/services/gcs_service.py āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ, āĻ…āĻĨāĻŦāĻž āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ⧇ āĻĢāĻžāχāϞāϟāĻŋ āĻ–ā§‹āϞāĻžāϰ āϜāĻ¨ā§āϝ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āϟāĻžāχāĻĒ āĻ•āϰ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/services/gcs_service.py

👉 def upload_file(self, file_path: str, survivor_id: Optional[str] = None) -> Tuple[str, MediaType, str]: āĻŽāĻ§ā§āϝ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āϕ⧋āĻĄāϟāĻŋ āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻ—ā§āϰāĻžāĻĢ āĻĄāĻŋāĻŦāĻŋ-āϤ⧇ āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟ āĻ•āϰāĻž āĻāύāϟāĻŋāϟāĻŋ āĻāĻŦāĻ‚ āϰāĻŋāϞ⧇āĻļāύāĻļāĻŋāĻĒāϗ⧁āϞāĻŋ āϕ⧀āĻ­āĻžāĻŦ⧇ āϏ⧇āĻ­ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ, āϤāĻž āύāĻŋāϝāĻŧ⧇ āφāϞ⧋āϚāύāĻž āĻ•āϰ⧇āĨ¤

        blob = self.bucket.blob(blob_name)
        blob.upload_from_filename(file_path)

āĻāχ āĻŦāĻŋāώāϝāĻŧāϟāĻŋāϕ⧇ āĻāĻ•āϟāĻŋ āϏāĻžāĻ°ā§āĻ­āĻŋāϏ⧇ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰāĻŋāϤ āĻ•āϰāĻžāϰ āĻĢāϞ⧇, āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āφāϰ GCS āĻŦāĻžāϕ⧇āϟ, āĻŦā§āϞāĻŦ āύ⧇āĻŽ āĻŦāĻž āϏāĻžāχāύāĻĄ āχāωāφāϰāĻāϞ āĻœā§‡āύāĻžāϰ⧇āĻļāύ āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āϜāĻžāύāĻžāϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āĻšāϝāĻŧ āύāĻžāĨ¤ āĻāϟāĻŋ āĻļ⧁āϧ⧁ 'āφāĻĒāϞ⧋āĻĄ' āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻ…āύ⧁āϰ⧋āϧ āĻ•āϰ⧇āĨ¤

ā§Ŧ. āϕ⧇āύ āĻāĻœā§‡āĻ¨ā§āϟāĻŋāĻ• āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋ > āĻĒā§āϰāϚāϞāĻŋāϤ āĻĒāĻĻā§āϧāϤāĻŋāϏāĻŽā§‚āĻš?

āĻāĻœā§‡āĻ¨ā§āϟāĻŋāĻ• āϏ⧁āĻŦāĻŋāϧāĻž:

āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝ

āĻŦā§āϝāĻžāϚ āĻĒāĻžāχāĻĒāϞāĻžāχāύ

āχāϭ⧇āĻ¨ā§āϟ-āϚāĻžāϞāĻŋāϤ

āĻāĻœā§‡āĻ¨ā§āϟāĻŋāĻ• āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋

āϜāϟāĻŋāϞāϤāĻž

āύāĻŋāĻŽā§āύ (ā§§ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ)

āωāĻšā§āϚ (ā§Ģ+ āĻĒāϰāĻŋāώ⧇āĻŦāĻž)

āύāĻŋāĻŽā§āύ (ā§§āϟāĻŋ āĻĒāĻžāχāĻĨāύ āĻĢāĻžāχāϞ: multimedia_agent.py )

āϰāĻžāĻˇā§āĻŸā§āϰ⧀āϝāĻŧ āĻŦā§āϝāĻŦāĻ¸ā§āĻĨāĻžāĻĒāύāĻž

āĻŦ⧈āĻļā§āĻŦāĻŋāĻ• āϚāϞāĻ•

āĻ•āĻ āĻŋāύ (āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āύ)

āĻāϕ⧀āĻ­ā§‚āϤ (āĻāĻœā§‡āĻ¨ā§āϟ āϰāĻžāĻˇā§āĻŸā§āϰ)

āĻ¤ā§āϰ⧁āϟāĻŋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž

āĻĻ⧁āĻ°ā§āϘāϟāύāĻž

āύ⧀āϰāĻŦ āϞāĻ—

āχāĻ¨ā§āϟāĻžāϰ⧇āĻ•ā§āϟāĻŋāĻ­ ("āφāĻŽāĻŋ āĻĢāĻžāχāϞāϟāĻŋ āĻĒāĻĄāĻŧāϤ⧇ āĻĒāĻžāϰāĻŋāύāĻŋ")

āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž

āĻ•āύāϏ⧋āϞ āĻĒā§āϰāĻŋāĻ¨ā§āϟ

āĻ­ā§‹āϟāĻ—ā§āϰāĻšāĻŖ āĻĒā§āϰāϝāĻŧā§‹āϜāύ

āϤāĻžā§ŽāĻ•ā§āώāĻŖāĻŋāĻ• (āĻšā§āϝāĻžāĻŸā§‡āϰ āĻ…āĻ‚āĻļ)

āĻ…āĻ­āĻŋāϝ⧋āϜāύāϝ⧋āĻ—ā§āϝāϤāĻž

āĻ¸ā§āĻĨāĻŋāϰ āϝ⧁āĻ•ā§āϤāĻŋ

āĻ•āĻ ā§‹āϰ āĻ•āĻžāĻ°ā§āϝāĻžāĻŦāϞ⧀

āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻžāύ (āĻāϞāĻāϞāĻāĻŽ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰ⧇)

āĻĒā§āϰāϏāĻ™ā§āĻ— āϏāĻšā§‡āϤāύāϤāĻž

āϕ⧋āύ⧋āϟāĻŋāχ āύāĻž

āϕ⧋āύ⧋āϟāĻŋāχ āύāĻž

āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ (āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āωāĻĻā§āĻĻ⧇āĻļā§āϝ āϜāĻžāύ⧇)

āϕ⧇āύ āĻāϟāĻŋ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ: multimedia_agent.py (āĻāĻ•āϟāĻŋ āϏāĻŋāϕ⧋āϝāĻŧ⧇āύāĻļāĻŋāϝāĻŧāĻžāϞāĻāĻœā§‡āĻ¨ā§āϟ āϝāĻžāϰ ā§ĒāϟāĻŋ āϏāĻžāĻŦ-āĻāĻœā§‡āĻ¨ā§āϟ āϰāϝāĻŧ⧇āϛ⧇: āφāĻĒāϞ⧋āĻĄ → āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟ → āϏ⧇āĻ­ → āϏāĻžāĻŽāĻžāϰāĻŋ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇, āφāĻŽāϰāĻž āϜāϟāĻŋāϞ āĻĒāϰāĻŋāĻ•āĻžāĻ āĻžāĻŽā§‹ āĻāĻŦāĻ‚ āĻ­āĻ™ā§āϗ⧁āϰ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟāϗ⧁āϞ⧋āϕ⧇ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻžāύ, āĻ•āĻĨā§‹āĻĒāĻ•āĻĨāύāĻŽā§‚āϞāĻ• āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ āϞāϜāĻŋāĻ• āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰāĻŋāĨ¤

ā§§ā§Ļ. â˜•ī¸ [āϐāĻšā§āĻ›āĻŋāĻ•] āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āĻĒāĻžāχāĻĒāϞāĻžāχāύ (āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻĒāĻ āύāϝ⧋āĻ—ā§āϝ) — āĻāĻœā§‡āĻ¨ā§āϟ āϞ⧇āϝāĻŧāĻžāϰ

āĻāĻœā§‡āĻ¨ā§āϟ āϞ⧇āϝāĻŧāĻžāϰāϟāĻŋ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻ¤ā§āϤāĻž āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰ⧇ — āĻāχ āĻāĻœā§‡āĻ¨ā§āϟāϗ⧁āϞ⧋ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āύ āϟ⧁āϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻ•āĻžāϜ āϏāĻŽā§āĻĒāĻ¨ā§āύ āĻ•āϰ⧇āĨ¤ āĻĒā§āϰāϤāĻŋāϟāĻŋ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āĻāĻ•āϟāĻŋ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ­ā§‚āĻŽāĻŋāĻ•āĻž āĻĨāĻžāϕ⧇ āĻāĻŦāĻ‚ āĻāϟāĻŋ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āĻ•āĻžāϛ⧇ āĻĒā§āϰāĻžāϏāĻ™ā§āĻ—āĻŋāĻ• āϤāĻĨā§āϝ āĻĒā§āϰ⧇āϰāĻŖ āĻ•āϰ⧇āĨ¤ āύāĻŋāĻšā§‡ āĻāĻ•āϟāĻŋ āĻŽāĻžāĻ˛ā§āϟāĻŋāĻāĻœā§‡āĻ¨ā§āϟ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡āϰ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ āĻĄāĻžāϝāĻŧāĻžāĻ—ā§āϰāĻžāĻŽ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϞ⧋āĨ¤

āĻāĻœā§‡āĻ¨ā§āϟ_āĻĄāĻžāϝāĻŧāĻžāĻ—ā§āϰāĻžāĻŽ

ā§§. āĻāĻœā§‡āĻ¨ā§āϟ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ

👉đŸ’ģ level_2/backend/agent/multimedia_agent.py āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ āĻ…āĻĨāĻŦāĻž āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϟāĻžāχāĻĒ āĻ•āϰ⧁āύāĨ¤ āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ āϖ⧁āϞ⧁āύāĨ¤ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py

⧍. āφāĻĒāϞ⧋āĻĄ āĻāĻœā§‡āĻ¨ā§āϟ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰ⧁āύ

āĻāχ āĻāĻœā§‡āĻ¨ā§āϟ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻŦāĻžāĻ°ā§āϤāĻž āĻĨ⧇āϕ⧇ āĻāĻ•āϟāĻŋ āĻĢāĻžāχāϞ āĻĒāĻžāĻĨ āϏāĻ‚āĻ—ā§āϰāĻš āĻ•āϰ⧇ āĻāĻŦāĻ‚ āϤāĻž GCS-āĻ āφāĻĒāϞ⧋āĻĄ āĻ•āϰ⧇āĨ¤

multimedia_agent.py āĻĢāĻžāχāϞ⧇ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄāϟāĻŋāϰ āϏāĻžāĻšāĻžāĻ¯ā§āϝ⧇ upload_agent āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ, āϝāĻž GCS-āĻ āφāĻĒāϞ⧋āĻĄ āĻ•āϰ⧇:

upload_agent = LlmAgent(
    name="UploadAgent",
    model="gemini-2.5-flash",
    instruction="""Extract the file path from the user's message and upload it.

Use `upload_media(file_path, survivor_id)` to upload the file.
The survivor_id is optional - include it if the user mentions a specific survivor (e.g., "survivor Sarah" -> "Sarah").
If the user provides a path like "/path/to/file", use that.

Return the upload result with gcs_uri and media_type.""",
    tools=[upload_media],
    output_key="upload_result"
)

ā§Š. āύāĻŋāĻˇā§āĻ•āĻžāĻļāύ āĻāĻœā§‡āĻ¨ā§āϟāϕ⧇ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰ⧁āύ

āĻāχ āĻāĻœā§‡āĻ¨ā§āϟāϟāĻŋ āĻœā§‡āĻŽāĻŋāύāĻŋ āĻ­āĻŋāĻļāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻž āĻŽāĻŋāĻĄāĻŋāϝāĻŧāĻž 'āĻĻ⧇āϖ⧇' āĻāĻŦāĻ‚ āĻ•āĻžāĻ āĻžāĻŽā§‹āĻ—āϤ āĻĄā§‡āϟāĻž āύāĻŋāĻˇā§āĻ•āĻžāĻļāύ āĻ•āϰ⧇āĨ¤

multimedia_agent.py āĻĢāĻžāχāϞ⧇ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄāϟāĻŋ extraction_agent āϤ⧈āϰāĻŋ āĻ•āϰ⧇, āϝāĻž āφāĻĒāϞ⧋āĻĄ āĻ•āϰāĻž āĻŽāĻŋāĻĄāĻŋāϝāĻŧāĻž āĻĨ⧇āϕ⧇ āϤāĻĨā§āϝ āύāĻŋāĻˇā§āĻ•āĻžāĻļāύ āĻ•āϰ⧇:

extraction_agent = LlmAgent(
    name="ExtractionAgent", 
    model="gemini-2.5-flash",
    instruction="""Extract information from the uploaded media.

Previous step result: {upload_result}

Use `extract_from_media(gcs_uri, media_type, signed_url)` with the values from the upload result.
The gcs_uri is in upload_result['gcs_uri'], media_type in upload_result['media_type'], and signed_url in upload_result['signed_url'].

Return the extraction results including entities and relationships found.""",
    tools=[extract_from_media],
    output_key="extraction_result"
)

āϞāĻ•ā§āĻˇā§āϝ āĻ•āϰ⧁āύ, instruction āϕ⧀āĻ­āĻžāĻŦ⧇ {upload_result} -āĻāϰ āωāĻ˛ā§āϞ⧇āĻ– āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇ — ADK-āϤ⧇ āĻāĻœā§‡āĻ¨ā§āϟāĻĻ⧇āϰ āĻŽāĻ§ā§āϝ⧇ āĻāĻ­āĻžāĻŦ⧇āχ āĻ¸ā§āĻŸā§‡āϟ āφāĻĻāĻžāύ-āĻĒā§āϰāĻĻāĻžāύ āĻ•āϰāĻž āĻšāϝāĻŧ āĨ¤

ā§Ē. āĻ¸ā§āĻĒā§āϝāĻžāύāĻžāϰ āĻāĻœā§‡āĻ¨ā§āϟāϕ⧇ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰ⧁āύ

āĻāχ āĻāĻœā§‡āĻ¨ā§āϟ āύāĻŋāĻˇā§āĻ•āĻžāĻļāĻŋāϤ āϏāĻ¤ā§āϤāĻž āĻ“ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āϗ⧁āϞ⧋āϕ⧇ āĻ—ā§āϰāĻžāĻĢ āĻĄā§‡āϟāĻžāĻŦ⧇āϏ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇āĨ¤

multimedia_agent.py āĻĢāĻžāχāϞ⧇ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ spanner_agent āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ, āϝāĻž āϏāĻ‚āĻ—ā§ƒāĻšā§€āϤ āϤāĻĨā§āϝ āĻĄā§‡āϟāĻžāĻŦ⧇āϏ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇:

spanner_agent = LlmAgent(
    name="SpannerAgent",
    model="gemini-2.5-flash", 
    instruction="""Save the extracted information to the database.

Upload result: {upload_result}
Extraction result: {extraction_result}

Use `save_to_spanner(extraction_result, survivor_id)` to save to Spanner.
Pass the WHOLE `extraction_result` object/dict from the previous step.
Include survivor_id if it was provided in the upload step.

Return the save statistics.""",
    tools=[save_to_spanner],
    output_key="spanner_result"
)

āĻāχ āĻāĻœā§‡āĻ¨ā§āϟ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āωāĻ­āϝāĻŧ āϧāĻžāĻĒ ( upload_result āĻāĻŦāĻ‚ extraction_result ) āĻĨ⧇āϕ⧇ āĻĒā§āϰāĻžāϏāĻ™ā§āĻ—āĻŋāĻ• āϤāĻĨā§āϝ āĻ—ā§āϰāĻšāĻŖ āĻ•āϰ⧇āĨ¤

ā§Ģ. āϏāĻžāĻŽāĻžāϰāĻŋ āĻāĻœā§‡āĻ¨ā§āϟāϕ⧇ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ āĻ•āϰ⧁āύ

āĻāχ āĻāĻœā§‡āĻ¨ā§āϟāϟāĻŋ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āϏāĻŽāĻ¸ā§āϤ āϧāĻžāĻĒ⧇āϰ āĻĢāϞāĻžāĻĢāϞāϕ⧇ āϏāĻ‚āĻļā§āϞ⧇āώāĻŖ āĻ•āϰ⧇ āĻāĻ•āϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻŦāĻžāĻ¨ā§āϧāĻŦ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āϤ⧈āϰāĻŋ āĻ•āϰ⧇āĨ¤

multimedia_agent.py āĻĢāĻžāχāϞ⧇, āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄā§‡āϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ summary_agent āϜāĻ¨ā§āϝ āĻĒā§āϰāĻŽā§āĻĒāϟ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŖ āĻ•āϰāĻž āĻšāϝāĻŧ, āϝāĻž āĻĢāϞāĻžāĻĢāϞ⧇āϰ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āĻ•āϰ⧇:

USE_MEMORY_BANK = os.getenv("USE_MEMORY_BANK", "false").lower() == "true"
save_msg = "6. Mention that the data is also being synced to the memory bank." if USE_MEMORY_BANK else ""

summary_instruction = f"""Provide a user-friendly summary of the media processing.

Upload: {{upload_result}}
Extraction: {{extraction_result}}
Database: {{spanner_result}}

Summarize:
1. What file was processed (name and type)
2. Key information extracted (survivors, skills, needs, resources found) - list names and counts
3. Relationships identified
4. What was saved to the database (broadcast ID, number of entities)
5. Any issues encountered
{save_msg}

Be concise but informative."""

āĻāχ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āϕ⧋āύ⧋ āϟ⧁āϞ⧇āϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āύ⧇āχ — āĻāϟāĻŋ āϕ⧇āĻŦāϞ āĻļ⧇āϝāĻŧāĻžāϰ āĻ•āϰāĻž āĻ•āύāĻŸā§‡āĻ•ā§āϏāϟ āĻĒāĻĄāĻŧ⧇ āĻāĻŦāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻĒāϰāĻŋāĻšā§āĻ›āĻ¨ā§āύ āϏāĻžāϰāĻžāĻ‚āĻļ āϤ⧈āϰāĻŋ āĻ•āϰ⧇ āĻĻ⧇āϝāĻŧāĨ¤

🧠 āĻ¸ā§āĻĨāĻžāĻĒāĻ¤ā§āϝ⧇āϰ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ

āĻ¸ā§āϤāϰ

āĻĢāĻžāχāϞ

āĻĻāĻžāϝāĻŧāĻŋāĻ¤ā§āĻŦ

āϟ⧁āϞāĻŋāĻ‚

extraction_tools.py + gcs_service.py

āϕ⧀āĻ­āĻžāĻŦ⧇ — āφāĻĒāϞ⧋āĻĄ, āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟ, āϏ⧇āĻ­ āĻ•āϰ⧁āύ

āĻāĻœā§‡āĻ¨ā§āϟ

multimedia_agent.py

āϕ⧀ — āĻĒāĻžāχāĻĒāϞāĻžāχāύāϟāĻŋ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧁āύ

ā§§ā§§. 🚀 āĻŽāĻžāĻ˛ā§āϟāĻŋāĻŽā§‹āĻĄāĻžāϞ āĻĄā§‡āϟāĻž āĻĒāĻžāχāĻĒāϞāĻžāχāύ — āĻ…āĻ°ā§āϕ⧇āĻ¸ā§āĻŸā§āϰ⧇āĻļāύ

āφāĻŽāĻžāĻĻ⧇āϰ āύāϤ⧁āύ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽā§‡āϰ āĻŽā§‚āϞ āĻ­āĻŋāĻ¤ā§āϤāĻŋ āĻšāϞ⧋ backend/agent/multimedia_agent.py āϤ⧇ āϏāĻ‚āĻœā§āĻžāĻžāϝāĻŧāĻŋāϤ MultimediaExtractionPipeline āĨ¤ āĻāϟāĻŋ ADK (āĻāĻœā§‡āĻ¨ā§āϟ āĻĄā§‡āϭ⧇āϞāĻĒāĻŽā§‡āĻ¨ā§āϟ āĻ•āĻŋāϟ) āĻĨ⧇āϕ⧇ āϏāĻŋāϕ⧋āϝāĻŧ⧇āύāĻļāĻŋāϝāĻŧāĻžāϞ āĻāĻœā§‡āĻ¨ā§āϟ āĻĒā§āϝāĻžāϟāĻžāĻ°ā§āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āĨ¤

ā§§. āϕ⧇āύ āĻ…āύ⧁āĻ•ā§āϰāĻŽāĻŋāĻ•?

āĻāĻ•āϟāĻŋ āφāĻĒāϞ⧋āĻĄ āĻĒā§āϰāĻ•ā§āϰāĻŋāϝāĻŧāĻžāĻ•āϰāĻŖ āĻāĻ•āϟāĻŋ āϰ⧈āĻ–āĻŋāĻ• āύāĻŋāĻ°ā§āĻ­āϰāĻļā§€āϞāϤāĻžāϰ āĻļ⧃āĻ™ā§āĻ–āϞ:

  1. āĻĢāĻžāχāϞāϟāĻŋ (āφāĻĒāϞ⧋āĻĄ) āύāĻž āĻ•āϰāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āφāĻĒāύāĻŋ āĻĄā§‡āϟāĻž āĻŦ⧇āϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ āύāĻžāĨ¤
  2. āĻĄā§‡āϟāĻž āĻāĻ•ā§āϏāĻŸā§āĻ°ā§āϝāĻžāĻ•ā§āϟ (Extraction) āύāĻž āĻ•āϰāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āφāĻĒāύāĻŋ āϤāĻž āϏ⧇āĻ­ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ āύāĻžāĨ¤
  3. āĻĢāϞāĻžāĻĢāϞ āύāĻž āĻĒāĻžāĻ“āϝāĻŧāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āφāĻĒāύāĻŋ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ āύāĻž (āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧁āύ)āĨ¤

āĻāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ SequentialAgent āĻāĻ•āĻĻāĻŽ āωāĻĒāϝ⧁āĻ•ā§āϤāĨ¤ āĻāϟāĻŋ āĻāĻ•āϟāĻŋ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āφāωāϟāĻĒ⧁āϟāϕ⧇ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āĻ•āύāĻŸā§‡āĻ•ā§āϏāϟ/āχāύāĻĒ⧁āϟ āĻšāĻŋāϏ⧇āĻŦ⧇ āĻĒā§āϰ⧇āϰāĻŖ āĻ•āϰ⧇āĨ¤

⧍. āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āϏāĻ‚āĻœā§āĻžāĻž

āϚāϞ⧁āύ āĻĻ⧇āϖ⧇ āύ⧇āĻ“āϝāĻŧāĻž āϝāĻžāĻ• multimedia_agent.py āĻĢāĻžāχāϞ⧇āϰ āĻāĻ•āĻĻāĻŽ āύāĻŋāĻšā§‡ āĻĒāĻžāχāĻĒāϞāĻžāχāύāϟāĻŋ āϕ⧀āĻ­āĻžāĻŦ⧇ āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇: 👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ āĻāĻŦāĻ‚ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻžāύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py

āĻāϟāĻŋ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āωāĻ­āϝāĻŧ āϧāĻžāĻĒ āĻĨ⧇āϕ⧇āχ āχāύāĻĒ⧁āϟ āĻ—ā§āϰāĻšāĻŖ āĻ•āϰ⧇āĨ¤ # TODO: REPLACE_ORCHESTRATION āĻ•āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āϖ⧁āρāϜ⧁āύāĨ¤ āĻāχ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āϞāĻžāχāύāϟāĻŋ āύāĻŋāĻšā§‡āϰ āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇ āĻĒā§āϰāϤāĻŋāĻ¸ā§āĻĨāĻžāĻĒāύ āĻ•āϰ⧁āύ :

    sub_agents=[upload_agent, extraction_agent, spanner_agent, summary_agent]

ā§Š. āϰ⧁āϟ āĻāĻœā§‡āĻ¨ā§āĻŸā§‡āϰ āϏāĻžāĻĨ⧇ āϏāĻ‚āϝ⧋āĻ— āĻ•āϰ⧁āύ

👉đŸ’ģ āϟāĻžāĻ°ā§āĻŽāĻŋāύāĻžāϞ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•āĻŽāĻžāĻ¨ā§āĻĄāϟāĻŋ āϚāĻžāϞāĻŋāϝāĻŧ⧇ āĻ•ā§āϞāĻžāωāĻĄ āĻļ⧇āϞ āĻāĻĄāĻŋāϟāϰ-āĻ āĻĢāĻžāχāϞāϟāĻŋ āϖ⧁āϞ⧁āύ:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

Locate the comment # TODO: REPLACE_ADD_SUBAGENT . Replace this whole line with the following code:

    sub_agents=[multimedia_agent],

This single object effectively bundles four "experts" into one callable entity.

4. Data Flow Between Agents

Each agent stores its output in a shared context that subsequent agents can access:

architecture_uploading

5. Open application (skip if app is still running)

👉đŸ’ģ Start App:

cd ~/way-back-home/level_2/
./start_app.sh

👉 Click Local: http://localhost:5173/ from the terminal.

6. Test Image Upload

👉 In the chat interface, choose any of the photo here and upload to the UI:

In the chat interface, tell the agent about your specific context:

Here is the survivor note

And then attach the image here.

upload_input

upload_result

👉đŸ’ģ In the terminal, when you finished testing, press "Ctrl+C" to end the process.

6. Verify Multimodal Uploading in GCS Bucket

gcs

  • Select your bucket and click into media .

āĻŽāĻŋāĻĄāĻŋāϝāĻŧāĻž

  • View your uploaded image here. uploaded_img

7. Verify Multimodal Uploading in Spanner (Optional)

Below is example output in UI for test_photo1 .

  • Open the Google Cloud Console Spanner .
  • Select your instance: Survivor Network
  • Select your database: graph-db
  • In the left sidebar, click Spanner Studio

👉 In Spanner Studio, query the new data:

SELECT 
  s.name AS Survivor,
  s.role AS Role,
  b.name AS Biome,
  r.name AS FoundResource,
  s.created_at
FROM Survivors s
LEFT JOIN SurvivorInBiome sib ON s.survivor_id = sib.survivor_id
LEFT JOIN Biomes b ON sib.biome_id = b.biome_id
LEFT JOIN SurvivorFoundResource sfr ON s.survivor_id = sfr.survivor_id
LEFT JOIN Resources r ON sfr.resource_id = r.resource_id
ORDER BY s.created_at DESC;

We can verify it by see the result below:

spanner_verify

12. â˜•ī¸ [Optional] Memory Bank with Agent Engine

1. How Memory Works

The system uses a dual-memory approach to handle both immediate context and long-term learning.

memory_bank

2. What Are Memory Topics?

Memory Topics define the categories of information the agent should remember across conversations. Think of them as filing cabinets for different types of user preferences.

Our 2 Topics:

  1. search_preferences : How the user likes to search
    • Do they prefer keyword or semantic search?
    • What skills/biomes do they search for often?
    • Example memory: "User prefers semantic search for medical skills"
  2. urgent_needs_context : What crises they're tracking
    • What resources are they monitoring?
    • Which survivors are they concerned about?
    • Example memory: "User is tracking medicine shortage in Northern Camp"

3. Setting Up Memory Topics

Custom memory topics define what the agent should remember. These are configured when deploying the Agent Engine.

👉đŸ’ģ In the terminal, open the file in the Cloud Shell Editor by running:

cloudshell edit ~/way-back-home/level_2/backend/deploy_agent.py

This opens ~/way-back-home/level_2/backend/deploy_agent.py in your editor.

We define structure MemoryTopic objects to guide the LLM on what information to extract and save.

👉In the file deploy_agent.py , replace the # TODO: SET_UP_TOPIC with the following:

# backend/deploy_agent.py

    custom_topics = [
        # Topic 1: Survivor Search Preferences
        MemoryTopic(
            custom_memory_topic=CustomMemoryTopic(
                label="search_preferences",
                description="""Extract the user's preferences for how they search for survivors. Include:
                - Preferred search methods (keyword, semantic, direct lookup)
                - Common filters used (biome, role, status)
                - Specific skills they value or frequently look for
                - Geographic areas of interest (e.g., "forest biome", "mountain outpost")
                
                Example: "User prefers semantic search for finding similar skills."
                Example: "User frequently checks for survivors in the Swamp Biome."
                """,
            )
        ),
        # Topic 2: Urgent Needs Context
        MemoryTopic(
            custom_memory_topic=CustomMemoryTopic(
                label="urgent_needs_context",
                description="""Track the user's focus on urgent needs and resource shortages. Include:
                - Specific resources they are monitoring (food, medicine, ammo)
                - Critical situations they are tracking
                - Survivors they are particularly concerned about
                
                Example: "User is monitoring the medicine shortage in the Northern Camp."
                Example: "User is looking for a doctor for the injured survivors."
                """,
            )
        )
    ]

4. Agent Integration

The agent code must be aware of the Memory Bank to save and retrieve information.

👉đŸ’ģ In the terminal, open the file in the Cloud Shell Editor by running:

cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py

This opens ~/way-back-home/level_2/backend/agent/agent.py in your editor.

Agent Creation

When creating the agent, we pass the after_agent_callback to ensure sessions are saved to memory after interactions. The add_session_to_memory function runs asynchronously to avoid slowing down the chat response.

👉In the file agent.py , locate the comment # TODO: REPLACE_ADD_SESSION_MEMORY , Replace this whole line with the following code:

async def add_session_to_memory(
        callback_context: CallbackContext
) -> Optional[types.Content]:
    """Automatically save completed sessions to memory bank in the background"""
    if hasattr(callback_context, "_invocation_context"):
        invocation_context = callback_context._invocation_context
        if invocation_context.memory_service:
            # Use create_task to run this in the background without blocking the response
            asyncio.create_task(
                invocation_context.memory_service.add_session_to_memory(
                    invocation_context.session
                )
            )
            logger.info("Scheduled session save to memory bank in background")

Background Saving

👉In the file agent.py , locate the comment # TODO: REPLACE_ADD_MEMORY_BANK_TOOL , Replace this whole line with the following code:

if USE_MEMORY_BANK:
    agent_tools.append(PreloadMemoryTool())

👉In the file agent.py , locate the comment # TODO: REPLACE_ADD_CALLBACK , Replace this whole line with the following code:

    after_agent_callback=add_session_to_memory if USE_MEMORY_BANK else None

Set Up Vertex AI Session Service

👉đŸ’ģ In the terminal, open the file chat.py in the Cloud Shell Editor by running:

cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py

👉In chat.py file, locate the comment # TODO: REPLACE_VERTEXAI_SERVICES , Replace this whole line with the following code:

    session_service = VertexAiSessionService(
        project=project_id,
        location=location,
        agent_engine_id=agent_engine_id
    )
    memory_service = VertexAiMemoryBankService(
        project=project_id,
        location=location,
        agent_engine_id=agent_engine_id
    )

13. â˜•ī¸ [Optional] Attach Agent with Agent Engine

1. Setup & Deployment

Before testing the memory features, you need to deploy the agent with the new memory topics and ensure your environment is configured correctly.

We have provided a convenience script to handle this process.

Running the Deployment Script

👉đŸ’ģ In the terminal, run the deployment script:

cd ~/way-back-home/level_2
./deploy_and_update_env.sh

This script performs the following actions:

  • Runs backend/deploy_agent.py to register the agent and memory topics with Vertex AI.
  • Captures the new Agent Engine ID .
  • Automatically updates your .env file with AGENT_ENGINE_ID .
  • Ensures USE_MEMORY_BANK=TRUE is set in your .env file.

[!IMPORTANT] If you make changes to custom_topics in deploy_agent.py , you must re-run this script to update the Agent Engine.

Verify Memory Bank

Now you can verify that the memory bank is working by teaching the agent a preference and checking if it persists across sessions.

Step One. Open the application

Open the Application again by following the instruction below: If the previous terminal is still running, end it by pressing Ctrls+C .

👉đŸ’ģ Start App:

cd ~/way-back-home/level_2/
./start_app.sh

👉 Click Local: http://localhost:5173/ from the terminal.

Step Two. Testing Memory Bank with Text

In the chat interface, tell the agent about your specific context:

"I'm planning a medical rescue mission in the mountains. I need survivors with first aid and climbing skills."

👉 Wait ~30 seconds for the memory to process in the background.

Step Three. Start a New Session

Refresh the page to clear the current conversation history (short-term memory).

Ask a question that relies on the context you provided earlier:

"What kind of missions am I interested in?"

Expected Response :

"Based on your previous conversations, you're interested in:

  • Medical rescue missions
  • Mountain/high-altitude operations
  • Skills needed: first aid, climbing

Would you like me to find survivors matching these criteria?"

Step Four. Test with Image Upload

Upload an image, and ask:

remember this

You can choose any of the photo here or your own and upload to the UI:

Step Five. Verify in Vertex AI Agent Engine

Go to Google Cloud Console Agent Engine

  1. Make sure you select the project from top left project selector: project selector
  2. Verify the agent engine you just deployed from previous command use_memory_bank.sh : agent engine Click into the agent engine you just created.
  3. Click the Memories Tab in this deployed agent, you can view all the memory here. view memory

👉đŸ’ģ When you finish testing, in you terminal, click "Ctrl + C" to end the process.

🎉 Congratulations! You just attached the memory bank to your agent!

14. â˜•ī¸ [Optional] Deploy to Cloud Run

1. Run the Deployment Script

👉đŸ’ģ Run the deployment script:

cd ~/way-back-home/level_2
./deploy_cloud_run.sh

After it successfully deployed, you will have the url, this is deployed url for you! āĻŽā§‹āϤāĻžāϝāĻŧ⧇āύ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇

👉đŸ’ģ Before you grab the url, grant the permission by running:

source .env && gcloud run services add-iam-policy-binding survivor-frontend --region $REGION --member=allUsers --role=roles/run.invoker && gcloud run services add-iam-policy-binding survivor-backend --region $REGION --member=allUsers --role=roles/run.invoker

Go to the deployed url, and you will see you application live there!

2. Understanding the Build Pipeline

The cloudbuild.yaml file defines the following sequential steps:

  1. Backend Build : Builds the Docker image from backend/Dockerfile .
  2. Backend Deploy : Deploys the backend container to Cloud Run.
  3. Capture URL : Gets the new Backend URL.
  4. Frontend Build :
    • Installs dependencies.
    • Builds the React app, injecting VITE_API_URL= .
  5. Frontend Image : Builds the Docker image from frontend/Dockerfile (packaging the static assets).
  6. Frontend Deploy : Deploys the frontend container.

3. Verify Deployment

Once the build completes (check the logs link provided by the script), you can verify:

  1. Go to the Cloud Run Console .
  2. Find the survivor-frontend service.
  3. Click the URL to open the application.
  4. Perform a search query to ensure the frontend can talk to the backend.

(OPTIONAL) 4. Manual Deployment

If you prefer to run the commands manually or understand the process better, here is how to use cloudbuild.yaml directly.

Writing cloudbuild.yaml

A cloudbuild.yaml file tells Google Cloud Build what steps to execute.

  • steps : A list of sequential actions. Each step runs in a container (eg, docker , gcloud , node , bash ).
  • substitutions : Variables that can be passed at build time (eg, $_REGION ).
  • workspace : A shared directory where steps can share files (like how we share backend_url.txt ).

Running the Deployment

To deploy manually without the script, use the gcloud builds submit command. You MUST pass the required substitution variables.

# Load your env vars first or replace these values manually
export PROJECT_ID=your-project-id
export REGION=us-central1

gcloud builds submit --config cloudbuild.yaml \
    --project "$PROJECT_ID" \
    --substitutions _REGION="us-central1",_GOOGLE_API_KEY="",_AGENT_ENGINE_ID="your-agent-id",_USE_MEMORY_BANK="TRUE",_GOOGLE_GENAI_USE_VERTEXAI="TRUE"

15. Conclusion

1. What You've Built

✅ Graph Database : Spanner with nodes (survivors, skills) and edges (relationships)
✅ AI Search : Keyword, semantic, and hybrid search with embeddings
✅ Multimodal Pipeline : Extract entities from images/video with Gemini
✅ Multi-Agent System : Coordinated workflow with ADK
✅ Memory Bank : Long-term personalization with Vertex AI
✅ Production Deployment : Cloud Run + Agent Engine

2. Architecture Summary

architecture_fullstack

3. Key Learnings

  1. Graph RAG : Combines graph database structure with semantic embeddings for intelligent search
  2. Multi-Agent Patterns : Sequential pipelines for complex, multi-step workflows
  3. Multimodal AI : Extract structured data from unstructured media (images/video)
  4. Stateful Agents : Memory Bank enables personalization across sessions

4. Workshop Content

5. Resources