1. परिचय

VibeTube पर आपका एक चैनल है, जिस पर डरावने और दिलचस्प वीडियो अपलोड किए जाते हैं. इस चैनल पर हैलोवीन तक हर रात एक शॉर्ट वीडियो अपलोड किया जाता है. दर्शक छोटे-छोटे कमरों में जादू देखना चाहते हैं और वे इसे हर तरह से आप तक पहुंचाते हैं — टिप्पणियों, वॉइस नोट, अपने डरावने दराजों की फ़ोटो, और शाम के समय अपने बरामदे की क्लिप के तौर पर. बैकलॉग में कई आइडिया हैं. हर शाम को एक ही तरह के काम करने होते हैं: फ़ीड में क्या चल रहा है, इस पर रिसर्च करना, बैकलॉग को देखना, दर्शकों के भेजे गए कॉन्टेंट को पढ़ना, एक दिशा चुनना, चैनल की नीति के मुताबिक उसकी जांच करना, स्क्रिप्ट लिखना, पोस्टर बनाना, क्लिप को रेंडर करना, और उसे पब्लिश करना.
जनरेटिव मॉडल, हर काम को अकेले कर सकते हैं. Gemini रिसर्च करता है, सुनता है, देखता है, और लिखता है. इमेज मॉडल, इमेज जनरेट करता है. Veo, वीडियो जनरेट करता है. वे अकेले रात को क्रम से नहीं चला सकते, आपके एक फ़ैसले के लिए नहीं रुक सकते, पैसे खर्च होने से पहले गलत दिशा में जाने से मना नहीं कर सकते, बिना कुछ खोले रेंडर होने के लिए मिनटों तक इंतज़ार नहीं कर सकते, और रिकॉर्ड नहीं छोड़ सकते.
इस कोडलैब में, हम उस शाम को ADK Workflow में बदल देंगे: नोड और एज का एक ड्रॉ किया गया ग्राफ़, जो खुद चलता है. यह आपसे सिर्फ़ तब सवाल पूछता है, जब आपके फ़ैसले की ज़रूरत होती है. साथ ही, हर रन को VibeTube पर एक क्लिप और उसके पोस्टर के साथ खत्म करता है.
प्रॉम्प्ट से यह तय नहीं किया जा सकता कि आउटपुट में कोई क्रम, स्टॉप या चेक शामिल हो. ग्राफ़ से यह काम किया जा सकता है.
आपको क्या सीखने को मिलेगा
- एक एजेंट और टूल के तौर पर इमेज मॉडल.
Agentमें एक मॉडल, निर्देश, और टूल शामिल होते हैं. तीसरा टूल, इमेज मॉडल को कॉल करता है. इसके बाद, पहला रन एक पोस्टर के साथ खत्म होता है. इसके बाद, एक ऐसा वाक्य जो लैब के बाकी हिस्से को आगे बढ़ाता है: प्रॉम्प्ट, ऑर्डर, स्टॉप या चेक का वादा नहीं कर सकता. - ग्राफ़ का स्ट्रक्चर.
Workflowएक एज लिस्ट है. आपने फ़ैन-आउट और जॉइन (JoinNodeपर मिलने वाले पैरलल रीडर) और एक ऐसा राऊटर बनाया है जो अपने एग्ज़िट का नाम खुद तय करता है. इसके लिए, टास्क-मोड एजेंट का इस्तेमाल किया जाता है. यह एजेंट, टूल कॉल के लूप में डायरेक्शन को साफ़ करता है और मुख्य लाइन में फिर से शामिल हो जाता है. - मल्टीमोडल डेटा को प्रोसेस करने वाली पाइपलाइन. ऑडियंस ने चार तरह का कॉन्टेंट भेजा. हर तरह के कॉन्टेंट के लिए एक रीडर है: Gemini, वॉइस नोट को ट्रांसक्राइब करता है, फ़ोटो के कैप्शन लिखता है, क्लिप देखता है, और उनके साउंडट्रैक सुनता है. इसके बाद, हर रीडर एक ही लाइन शेप को एक आरएजी इंजन कॉर्पस में लिखता है. फ़ैन-आउट में मौजूद तीसरा रीडर, मतलब के हिसाब से जानकारी को वापस लाता है और मीडिया को पैसेज के साथ वापस भेजता है.
- निलंबन के दो तरीके, एक ही सिस्टम. एक व्यक्ति (
RequestInput: चार कार्ड, आप जवाब दें) और धीमे टूल (Veo के पीछेLongRunningFunctionTool: एक रसीद) के लिए रन रुक जाता है. दोनों एक ही चीज़ हैं: सेशन स्टोर में एक ओपन कॉल, जिसे उसके आईडी से, फ़ॉर्म से या किसी अन्य प्रोसेस से फिर से शुरू किया जाता है. मीडिया डेस्क की दोनों शाखाएं, राज्य में पोस्टर को नाम के हिसाब से शेयर करती हैं. - कई रातों का डेटा सेव करने की सुविधा. मेमोरी बैंक में दो लाइफ़साइकल कॉलबैक:
before_model_callback, प्रपोज़र के पढ़ने से पहले क्रिएटर की पसंद को याद रखता है.after_agent_callback, स्क्रिप्टर के बाद आज रात की पसंद को याद रखता है. - रिलीज़. ADK
Runnerवाले ऐप्लिकेशन में मौजूद ग्राफ़, पेज पर सर्वर से भेजे गए इवेंट, सेशन अफ़िनिटी के साथ Cloud Run, और एक मल्टीपार्ट POST, जो क्लिप को VibeTube पर पोस्टर के साथ थंबनेल के तौर पर अपलोड करता है.
आपको क्या बनाना होगा
आपके ब्राउज़र में चल रहा एक ऐप्लिकेशन: VibeStudio Workbench. यह एक कंपैनियन पेज है, जिसमें इन-पेज कोड एडिटर, डिस्क पर मौजूद फ़ाइलों और आपके रन किए गए सेशन को पढ़ने वाले वेरिफ़ायर, और एक एम्बेड किया गया adk web शामिल है. इसके सात सेशन, इस कोडलैब के सात पेज हैं. इनमें एक जैसे नंबर और एक जैसे पार्ट लेटर हैं, ताकि दोनों एक साथ बने रहें. हर पेज एक बैंड पर खुलता है. इसमें सेशन के बारे में एक वाक्य में बताया जाता है. साथ ही, इसमें तीन चीज़ें बताई जाती हैं: बदलाव करना, चलाना, और पुष्टि करना. यहां कोई सेक्शन पढ़ें और फिर वर्कबेंच में बदलाव करें. हर बदलाव के बाद, पुष्टि करने वाला पैनल दिखता है. इसमें बताया जाता है कि असल में क्या हुआ.
तीन चीज़ें चलती हैं: Workbench (पोर्ट 4600 पर मौजूद पेज, एडिटर, और पुष्टि करने वाले टूल), आपका बैकएंड (agent/ में Workflow और stage6_video/ के ज़रिए stage0_prompt/ में हर सेशन के लिए एक सैंडबॉक्स ऐप्लिकेशन, जिसे adk web उपलब्ध कराता है), और Google Cloud (Gemini, इमेज मॉडल, आरएजी इंजन, Veo, और मेमोरी बैंक — इन सभी को Vertex AI के ज़रिए आपके क्रेडेंशियल से ऐक्सेस किया जाता है).
सात सेशन
सेशन | आपने क्या बनाया है | आपने ये बदलाव किए हैं |
1 · कहानी | अभी तक कुछ नहीं — रात और उससे बनने वाला ग्राफ़ | — |
2 · इमेज जनरेट करने की सुविधा | एक एजेंट पहला पोस्टर बनाता है |
|
3 · वर्कफ़्लो | रात को एक ग्राफ़ के तौर पर दिखाया गया है: फ़ैन-आउट और जॉइन, राऊटर और उसका लूप |
|
4 · मल्टीमॉडल डेटा को प्रोसेस करना | दर्शकों ने जो भेजा, उसे एक कॉर्पस में पढ़ा; तीसरा रीडर |
|
5 · वीडियो जनरेट करने की सुविधा | निलंबन दो तरह के होते हैं; राज्य में नाम के हिसाब से शेयर किया गया पोस्टर |
|
6 · जानकारी याद रखने की सुविधा | चैनल, एक रात से दूसरी रात के बीच क्या याद रखता है |
|
7 · डिप्लॉय और पब्लिश करना | Cloud Run पर VibeStudio; VibeTube पर रात का समय | कमरे का इवेंट कोड डालें और पब्लिश करें |
इस कोडलैब को इस्तेमाल करने का तरीका. यह कॉन्सेप्ट पर आधारित है: हर सेशन में आइडिया को समझाया जाता है. इसके बाद, कोड को दिखाया जाता है, जैसा कि बदलाव होने के बाद पढ़ा जाता है. इसके बाद, कोड को समझाया जाता है. यह आपको यहां किसी फ़ाइल में बदलाव करने के लिए नहीं कहता. बदलाव, वर्कबेंच में किए जाते हैं. इसमें आपको एक बार में एक बदलाव करने की सुविधा मिलती है. साथ ही, इसके बगल में एक हिंट और इसके नीचे एक पुष्टि करने वाला पैनल होता है. सेशन के बारे में पढ़ें. इसके बाद, पेज पर दी गई जानकारी को देखें.
यह कहां मौजूद होता है
VibeTube पर मौजूद ग्राफ़, थीम, और रूम, Lin के VibeStudio के हॉन्टेड एडिशन से लिए गए हैं. यह मल्टीमोडल कट है. इसमें दर्शकों के भेजे गए कॉन्टेंट और दो तरह के सस्पेंशन पर फ़ोकस किया गया है. इसे Agent Valley Labs के एक पेज वाले इंटरैक्टिव फ़ॉर्मैट में दिखाया गया है. स्टूडियो एक सीनरी है; इसके तहत हर मैकेनिज्म सामान्य है, जिसका इस्तेमाल सहायता पाइपलाइन, कॉन्टेंट की समीक्षा करने के फ़्लो या किसी अन्य चीज़ के लिए किया जा सकता है. इसके लिए, किसी व्यक्ति को रुकना पड़ता है और धीमे काम का इंतज़ार करना पड़ता है.
2. सेट अप
- क्या — एक ऐसा खाता जिससे पेमेंट किया जा सके, एक प्रोजेक्ट, इंस्टॉल की गई लैब, जवाब देने के लिए सही मॉडल, और एक पोर्ट पर बैकग्राउंड में चल रहा वर्कबेंच.
- क्यों — एक पोर्ट पर एक प्रोसेस: पेज, एडिटर, पुष्टि करने वाले लोग,
/api/*, औरadk webएक ही ऑरिजिन शेयर करते हैं. इसलिए, इस लैब में किसी भी चीज़ के लिए दूसरे टर्मिनल या दूसरे पोर्ट की ज़रूरत नहीं होती. - कैसे — क्लोन, दो स्क्रिप्ट. दूसरा थ्रेड, मॉडल को कॉल करता है, वर्कबेंच शुरू करता है, और आरएजी कॉर्पस और मेमोरी बैंक बनाना शुरू करता है. यह सब तब होता है, जब आप पढ़ रहे होते हैं. इससे सेशन 4 और 6 के लिए, ये तैयार रहते हैं.
इस लैब में मौजूद हर चीज़, Cloud Shell में चलती है — gcloud, Python, Node, ffmpeg, और git पहले से ही इंस्टॉल हैं. साथ ही, Gemini, इमेज मॉडल, Veo, आरएजी इंजन, और मेमोरी बैंक को आपके क्रेडेंशियल का इस्तेमाल करके, Vertex AI के ज़रिए ऐक्सेस किया जा सकता है. इस लैब में कोई एपीआई पासकोड नहीं है. साथ ही, आपको अपने लैपटॉप पर कुछ भी इंस्टॉल करने की ज़रूरत नहीं है. Google Cloud SDK, Python 3.12, और Node 20+ वाले लैपटॉप पर भी यही तरीका काम करता है.
इस लैब में आपको एक चीज़ नहीं मिल सकती: बिलिंग की सुविधा वाला Google Cloud प्रोजेक्ट. पहले चरण में, आपको एक ऐसा खाता मिलता है जिससे पेमेंट किया जा सकता है. चौथे चरण में, उस खाते को एक प्रोजेक्ट में बदल दिया जाता है. इन्हें इसी क्रम में करें — चौथे चरण के बाद के हर चरण में, उस प्रोजेक्ट को पढ़ा जाता है जो चौथे चरण में तय किया जाता है.
1 · बिलिंग की सुविधा वाला खाता बनाएं (~1 मिनट)
उस Google खाते से साइन इन करें जिसके लिए बिलिंग की सुविधा चालू है. इस तरह का कोई भी खाता इस्तेमाल किया जा सकता है. अगर आपके पास बिलिंग खाता नहीं है, तो बिना शुल्क के आज़माएं. इससे आपको एक बिलिंग खाता मिलेगा, जो चौथे चरण के लिए ज़रूरी है. अगर आप किसी इंस्ट्रक्टर की मदद से लैब में काम कर रहे हैं, तो पहले इस सेशन के लिए क्रेडिट रिडीम करें. इससे आपके लिए बिलिंग खाता बन जाएगा.
2 · Cloud Shell खोलें (~2 मिनट)
👉🖥 Google Cloud console में सबसे ऊपर मौजूद, Cloud Shell चालू करें पर क्लिक करें. यह हेडर में मौजूद टर्मिनल के आकार का आइकॉन है.

👉🖥 एडिटर खोलें (पेंसिल के साथ खुले फ़ोल्डर का आइकॉन) पर क्लिक करें. इससे Cloud Shell Editor खुल जाएगा. इसमें बाईं ओर फ़ाइल एक्सप्लोरर दिखेगा. अगर आपको पूरी फ़ाइल पढ़नी है, तो यहां जाएं.

👉🖥 अगर आज आपको किसी भी समय अनुमति देने के लिए कहा जाए, तो जारी रखने के लिए अनुमति दें पर क्लिक करें.
👉🖥 एडिटर में टर्मिनल खोलें — यह टैब 1 है. हर 👉💻 चरण यहीं चलता है. टैब 2 वर्कबेंच है. इसे सातवें चरण में खोला जाता है. अगर टर्मिनल पहले से स्क्रीन पर सबसे नीचे नहीं है, तो इसे View → Terminal पर जाकर खोलें:

👉💻 देखें कि आपने किस खाते से साइन इन किया है. यह वही खाता होना चाहिए जिसका इस्तेमाल आपने पहले चरण में किया था:
gcloud auth list
3 · लैब ऐक्सेस करना (~1 मिनट)
👉💻 रिपॉज़िटरी को क्लोन करें:
cd ~
git clone https://github.com/cuppibla/vibe-studio-multimodal
cd vibe-studio-multimodal
4 · अपना प्रोजेक्ट बनाएं (~2 मिनट)
👉💻 एक स्क्रिप्ट आपके बिलिंग खाते को ढूंढती है, उस पर एक प्रोजेक्ट बनाती है, बिलिंग को लिंक करती है, और Cloud Shell को उस प्रोजेक्ट पर ले जाती है:
cd ~/vibe-studio-multimodal
./setup_project.sh
आपको चुने गए बिलिंग खाते के लिए ✓, बनाए गए प्रोजेक्ट के लिए ✓, और इस तरह का मैसेज दिखेगा:
Project ready: vibe-studio-4271 Next: ./setup_codelab.sh
vibe-studio-4271 आपका प्रोजेक्ट आईडी है — आपके प्रोजेक्ट आईडी में अलग अंक होंगे. इसमें चार चीज़ें होती हैं:
बिलिंग | अगर आपके पास खाता है, तो सबसे नया | |
प्रोजेक्ट |
| |
selects | आईडी को | |
waits | प्रोजेक्ट को असल में विज्ञापन दिखाने की अनुमति मिलने तक, दो मिनट तक पोल करता है | |
👉🖥 अब यह प्रोजेक्ट, कंसोल में मौजूद है. इसका आईडी, डैशबोर्ड पर प्रोजेक्ट की जानकारी कार्ड में मौजूद होता है:

5 · लैब को इंस्टॉल और सेट अप करना (~4 मिनट)
👉💻
cd ~/vibe-studio-multimodal
./setup_codelab.sh
एक स्क्रिप्ट, जिसे फिर से चलाना सुरक्षित है — दूसरी बार चलाने पर, पहली बार दिए गए हर जवाब को सेव रखा जाता है. यह शुरुआत में दो सवाल पूछता है. Enter दबाने पर, दोनों के लिए डिफ़ॉल्ट वैल्यू ले ली जाती है:
इवेंट कोड | VibeTube रूम में आपका वीडियो पब्लिश किया जाएगा. अपने शिक्षक से मिला रूम कोड टाइप करें या | |
डिसप्ले नेम | उस व्यक्ति का नाम डालें जिसने रूम बनाया है या अपने खाते से बनाए गए रूम के लिए, Enter दबाएं. | |
दोनों ही .env में दिखते हैं. इन्हें बाद में, .env में जाकर या पब्लिश पेज पर बदला जा सकता है. इसके बाद, यह अपने-आप बाकी काम करता है. जैसे:
uv env | अगर uv मौजूद नहीं है, तो उसे इंस्टॉल करता है. इसके बाद, | |
apis | यह चौथे चरण में चुने गए प्रोजेक्ट पर छह एपीआई चालू करता है. साथ ही, आगे बढ़ने से पहले हर एपीआई के जवाब की पुष्टि करता है: | |
खाता | पक्का करें कि प्रोजेक्ट का डिफ़ॉल्ट Compute सेवा खाता मौजूद हो और उसके पास सेशन 7 के बिल्ड और सेवा के लिए ज़रूरी भूमिकाएं हों | |
.env |
| |
veo · room | पुष्टि करता है कि | |
मॉडल | Gemini को एक असली कॉल करता है, ताकि कोई खराब प्रोजेक्ट सेटअप के समय ही फ़ेल हो जाए, न कि सेशन के दौरान | |
स्टार्टर | यह | |
पेज |
| |
cloud | बैकग्राउंड में आरएजी इंजन कॉर्पस और मेमोरी बैंक बनाना शुरू करता है, ताकि सेशन 4 और 6 उन्हें तैयार पाएं | |
प्रीफ़्लाइट |
| |
6 · प्रीफ़्लाइट पढ़ें (~1 मिनट)
पांचवें चरण में, प्रीफ़्लाइट की जानकारी प्रिंट की गई है. इसमें हर लाइन में असल जांच की जानकारी है, न कि कोई अनुमान:
✓ python 3.12 ✓ auth path A: Vertex via ADC (STUDIO_VERTEX=1) ✓ Google Cloud ADC (project vibe-studio-4271) ✓ Memory Bank SDK ✓ stage0_prompt loads ✓ stage1_fanout loads (0 edges) ✓ stage3_router loads (... edges) ✓ stage4_memory loads (... edges) ✓ stage5_rag loads (... edges) ✓ stage6_video loads (... edges) ✓ node and npm (build the learning center's page) ✓ learning center page built (web/dist) ✓ aiplatform.googleapis.com enabled (Gemini, Veo, Memory Bank, RAG Engine) ... - Memory Bank: still being created in the background - RAG corpus: still being created in the background ✓ session 7 runtime account 123456789-compute@developer.gserviceaccount.com has its roles ✓ learning center running on port 4600 PREFLIGHT GREEN Open session 1 here: https://4600-cs-...cloudshell.dev/step/story
stage1_fanout loads (0 edges) सही कह रही हैं: यह ग्राफ़ खाली है और तीसरे सेशन में आपको इसे भरना है. - की दो लाइनें भी सही हैं — कॉर्पस को आने में एक या दो मिनट लगते हैं और बैंक को करीब बीस सेकंड लगते हैं. आपको चौथे सेशन से पहले इनमें से किसी की भी ज़रूरत नहीं होगी.
👉💻 इसे किसी भी समय फिर से चलाकर देखें कि आपने कितना काम पूरा कर लिया है. यह आपकी फ़ाइलों, आपके प्रोजेक्ट, और चल रहे सर्वर को पढ़ता है, न कि चेकलिस्ट को:
cd ~/vibe-studio-multimodal
uv run python scripts/preflight.py
7 · वर्कबेंच खोलना (~1 मिनट)
वर्कबेंच पहले से चल रहा है. पांचवें चरण में, इसे बैकग्राउंड में शुरू किया गया. पोर्ट 4600 पर एक uvicorn प्रोसेस, जो पेज, हर /api/* रूट, और /workbench पर माउंट किए गए adk web को दिखाती है. इस लैब में कुछ भी शुरू करने की ज़रूरत नहीं होती. साथ ही, इसमें आपको कभी भी इसे रीस्टार्ट करने के लिए नहीं कहा जाता: बदलाव, आपके अगले रन पर लागू होते हैं.
👉🖥 प्रीफ़्लाइट से प्रिंट किए गए लिंक पर क्लिक करें या Cloud Shell में जाकर, वेब की झलक → पोर्ट बदलें → 4600 पर क्लिक करें. इसे टैब 2 कहें. यह सेशन 1 · कहानी पर खुलता है.
ये तीन निर्देश आपको बाद में काम आ सकते हैं. ये सभी ~/vibe-studio-multimodal से जुड़े हैं:
| वर्कबेंच को बंद करता है | |
| इसे फ़ोरग्राउंड में शुरू करता है; Ctrl+C इसे और इससे शुरू की गई हर प्रोसेस को रोकता है | |
|
| |
रिपॉज़िटरी लेआउट
vibe-studio-multimodal/
├── agent/ # the workflow and the platform clients
│ ├── graph.py # the graph: three readers, the proposer, the gate, the router, the script, the desk
│ ├── desk.py # render_desk and render_submit, the LongRunningFunctionTool
│ ├── deliver.py # the delivery console: find the pending call, wait for Veo, answer by id
│ ├── schemas.py # Direction, Directions, CleanedDirection, Script, each with a poster idea
│ ├── cleanup_tools.py # find_policy_hits, suggest_replacement: the task agent's tools
│ ├── policy_words.txt # the policy, as data; policy_replacements.txt, the approved stand-ins
│ ├── backlog.txt # the creator's Halloween ideas; comments.md, the audience's comments
│ ├── audience/ # what else the audience sent: voice/*.mp3, photo/*.jpg, clip/*.mp4
│ ├── media/past/ # six past posters and captions.md, what Gemini sees in each
│ └── platform/ # config, audience (the readers), rag (RAG Engine), images, videogen (Veo), memory (Memory Bank)
├── stage0_prompt/ ... stage6_video/ # one sandbox app per session, runnable in adk web
├── server/ & web/ # the VibeStudio Workbench (FastAPI + React, port 4600)
├── vibestudio/ # the app deployed in session 7, with its own copy of agent/
├── checks/ & scripts/ # the hole registry, the verifiers, preflight, start/stop/restart
└── starter/ # the nine files you edit, as students receive them
3. 1 · कहानी — रात और उसका ग्राफ़
👉🖥 दूसरा टैब, सेशन 1 · कहानी पर खुलता है. इसे पढ़ें: एक व्यक्ति के इर्द-गिर्द छह काम होते हैं — ट्रेंड पर रिसर्च करना, बैकलॉग को खंगालना, एक दिशा चुनना, नीति की जांच करना, स्क्रिप्ट लिखना, क्लिप को रेंडर करना — और यह सिलसिला हर रात दोहराया जाता है. Gemini, रिसर्च करने, बैकलॉग तैयार करने, और स्क्रिप्ट लिखने का काम अकेले कर सकता है. Veo, वीडियो रेंडर करने का काम अकेले कर सकता है. हालांकि, कॉन्टेंट को चुनने और उसकी जांच करने का काम इंसान को ही करना होगा.
रिंग के नीचे, लैब का बनाया गया ग्राफ़ है. इसमें किसी आइडिया से लेकर क्लिप और उसके पोस्टर तक, 13 नोड हैं. किसी नोड पर कर्सर घुमाकर, उसके काम और उसे बनाने वाले सेशन के बारे में जानें. यहां कुछ भी बदलाव करने की ज़रूरत नहीं है. पेज पर मौजूद पहला पोस्टर जनरेट करें बटन, सेशन 2 है.
शब्दावली, इसलिए अगले छह पेज बिना रुके पढ़ें:
शब्द | इसका क्या मतलब है |
एजेंट | एक ADK |
node | ग्राफ़ का एक चरण — Python फ़ंक्शन, एजेंट, जॉइन, और राऊटर |
edge | क्रम से चलने वाले नोड का टपल; ग्राफ़, उनकी एक सूची है. तीसरा सेशन |
session |
|
state | एक डिक्शनरी, जिसे नोड, कुंजी के नाम के हिसाब से शेयर करते हैं. एक नोड |
जानकारी याद रखने की सुविधा | सेशन के बाद भी क्या सेव रहता है — कॉलबैक के ज़रिए मेमोरी बैंक. छठा सेशन |
4. 2 · इमेज जनरेट करना — एक एजेंट और टूल के तौर पर इमेज मॉडल

👉🖥 वर्कबेंच में, सेशन 2 · इमेज जनरेट करना खोलें. ग्राफ़ से पहले, सबसे आसान चीज़ जो काम कर सकती है: एक Agent, जिसके निर्देश पूरी रात गद्य के रूप में हों, तीन Python फ़ंक्शन उसके हाथों के रूप में हों, और एक रन जो एक तस्वीर के साथ खत्म हो.
एजेंट में एक मॉडल, निर्देश, और टूल शामिल होते हैं
stage0_prompt/agent.py, ADK एजेंट के तीन फ़ील्ड के साथ root_agent को तय करता है. model, agent/platform/config.py का Gemini मॉडल है. instruction सिस्टम प्रॉम्प्ट है: एक ही बार में छह काम, जिनमें से आखिरी काम एक तस्वीर है. tools में तीन फ़ंक्शन होते हैं.
root_agent = Agent(
name="solo_channel", model=config.MODEL,
tools=[check_trends, read_backlog, make_poster],
instruction=(
"You run the creator's cozy-spooky short-video channel, alone, every "
"night until Halloween.\n"
"When the creator gives you an idea (or nothing), do ALL of this:\n"
"check what is trending. look at your backlog of ideas. propose a "
"direction and agree on it with the creator. refuse blacklisted "
"subjects (competitor, hateful, gore). then describe the video you "
"would make: a title (<=60 chars) and 3 shots, one visual sentence "
"each. then draw its poster: call make_poster once with one line that "
"names the single image that sells the video, and tell the creator "
"where the poster is.\n"
"Ask the creator to confirm the direction before describing the "
"video."))
मॉडल एक बंद दुनिया की तरह है: यह अपने वेट और कॉन्टेक्स्ट में मौजूद टोकन के आधार पर काम करता है. टूल एक Python फ़ंक्शन है, जिसके लिए मॉडल अनुरोध कर सकता है. एडीके, हर फ़ंक्शन के सिग्नेचर और डॉकस्ट्रिंग को पढ़ता है और उसे मॉडल के लिए डिक्लेयर करता है. जब मॉडल को किसी फ़ंक्शन की ज़रूरत होती है, तो वह function_call इवेंट को ट्रिगर करता है. इसके बाद, रनटाइम Python को चलाता है और कॉन्टेक्स्ट में function_response इवेंट को वापस लिखता है. इसके बाद, मॉडल अपने सामने मौजूद नतीजे के साथ आगे बढ़ता है.
तीन फ़ंक्शन हैं और उनमें से एक ड्रॉ करता है
तीन में से दो लोगों ने रिसर्च पढ़ी. तीसरा व्यक्ति, इमेज मॉडल से पोस्टर बनाने के लिए कहता है:
def check_trends() -> dict:
"""Ten formats trending on the platform right now, with a heat score each."""
from agent.trends import sample_trends
return {"trends": sample_trends()}
def read_backlog() -> dict:
"""The creator's backlog: ideas they noted down to make someday."""
from agent.graph import backlog_notes
return {"backlog": backlog_notes()}
def make_poster(subject: str) -> dict:
"""Draw tonight's poster: one image of `subject` in the channel's cozy
low-poly style. Returns where the PNG landed (path, url) in a few seconds."""
...
make_poster, agent/platform/images.py को कॉल करता है. यह इमेज मॉडल, एक सामान्य फ़ंक्शन के तौर पर रैप किया गया है. ठीक उसी तरह जिस तरह videogen.py, Veo को रैप करता है: हाउस-स्टाइल प्रीफ़िक्स (चैनल का आरामदायक लो-पॉली हैलोवीन लुक, मिडनाइट प्लम के सामने कद्दू का संतरी और मोमबत्ती की रोशनी वाली क्रीम), विषय, वर्टिकल 9:16 फ़्रेम, runs/media/posters के तहत एक PNG, /static/posters पर दिखाया गया है. STUDIO_REAL_IMAGES=0 की मदद से, यह स्टैंड-इन पोस्टर को कॉपी करता है और नतीजे prebaked को फ़्लैग करता है, ताकि लैब कहीं भी चल सके.
MODEL = os.environ.get("STUDIO_IMAGE_MODEL", "gemini-2.5-flash-image")
ASPECT = "9:16"
def generate(subject: str, visual_style: str = "", name: str | None = None) -> dict:
"""One poster for `subject`. Returns where it landed: status, path, url,
prompt, and prebaked=True when the stand-in was used instead of the model."""
सेशन 5 में, यही कॉल ग्राफ़ में एक नोड है.
प्रैक्टिकल: एक बदलाव
शिप किए गए के तौर पर, make_poster एक डिक्शनरी दिखाता है. इसमें बताया जाता है कि पोस्टर को स्किप कर दिया गया था. 👉🖥 वर्कबेंच एडिटर में, TODO लाइन की जगह इमेज मॉडल को कॉल करें:
from agent.platform import images
return images.generate(subject, name="solo")
सेव करें पर क्लिक करें. पुष्टि करने वाली पंक्तियां फ़ाइल को पढ़ती हैं: एजेंट पर तीन टूल, इमेज मॉडल कॉल मौजूद है. 👉🖥 Check the workflow loads पर क्लिक करें. इसके बाद, Open adk web पर क्लिक करें और यह जानकारी भेजें:
tonight's idea: a tiny ghost learning to haunt a sock drawer
क्या उम्मीद करें और क्यों
- जवाब से पहले दो टूल इवेंट, फिर एक सवाल.
check_trendsऔरread_backlogको रन किया गया, क्योंकि निर्देश में जांच करने और देखने के लिए कहा गया था. हालांकि, मॉडल के वेट में इनमें से कोई भी मौजूद नहीं था. जवाब में एक दिशा सुझाई गई है और आपसे पुष्टि करने के लिए कहा गया है. ऐसा इसलिए, क्योंकि निर्देश में पहले सहमति मांगी गई थी. - दूसरे मैसेज में सारी जानकारी दी गई है.
skip the questions, describe the video and draw the posterभेजें. मॉडल, वीडियो के बारे में बताता है. इसके बाद, वह खुद से लिखी गई सब्जेक्ट लाइन के साथmake_posterको एक बार कॉल करता है और आपको बताता है कि पीएनजी फ़ाइल कहां सेव हुई है. पुष्टि करने वाले पैनल में, पंक्तियों के बगल में पोस्टर दिखता है: चैनल के लुक में हैलोवीन का सीन, जिसे करीब आठ सेकंड में बनाया गया है. - यह चैनल क्यों नहीं है. इस रिसर्च को ऐसे गद्य में शामिल किया गया है जिसे उद्धृत नहीं किया जा सकता. इस नीति को उस मॉडल ने सर्टिफ़ाई किया था जिसने निर्देश लिखे थे. साथ ही, पोस्टर को किसी भी जांच से पहले बनाया गया था. एक मैसेज में, समझौते के बारे में बात की गई थी. प्रॉम्प्ट टेक्स्ट, गेट नहीं है. लैब के बाकी हिस्से में, इन छह जॉब को एक ग्राफ़ में अलग-अलग दिखाया जाता है.
पेज के आखिर में, एडीके एजेंट किन चीज़ों से मिलकर बनता है सेक्शन दिया गया है. इसमें आपको ये रेफ़रंस मिलेंगे: मॉडल, वह कॉन्टेक्स्ट जिसके आधार पर मॉडल जवाब देता है, वे टूल और सहयोगी जिनकी मदद से मॉडल काम करता है, हर कॉल को रैप करने वाले कॉलबैक, और सेशन और मेमोरी जो मॉडल से बाहर मौजूद होती हैं.
5. 3 · वर्कफ़्लो — फ़ैन-आउट और जॉइन, राऊटर और लूप

👉🖥 वर्कबेंच में, Session 3 · Workflows के 3a और 3b हिस्से खोलें. हर हिस्से को सैंडबॉक्स ऐप्लिकेशन में बनाया गया है, ताकि उसे adk web में अलग से चलाया जा सके: stage1_fanout में फ़ैन-आउट, stage3_router में राऊटर और उसका लूप.
फ़ैन-आउट और जॉइन (3a)
एडीके Workflow एक एज लिस्ट है. हर एंट्री एक चेन होती है. यह नोड का एक टपल होता है, जो क्रम से चलता है. START को छोड़कर, दोनों चेन एक साथ चलती हैं. JoinNode पर खत्म होने वाली चेन, इसे रिपोर्ट करती है. साथ ही, जॉइन नोड वहां खत्म होने वाली हर चेन का इंतज़ार करता है. इसके बाद, वह आगे बढ़ता है और नोड के नाम से कुंजी वाली एक डिक्शनरी को पास करता है. डिक्शनरी के तौर पर लिखा गया टारगेट, राऊटर के रूट के नामों को नोड से मैप करता है. वर्कबेंच के 3a पेज पर, आकृतियां बनाई गई हैं और किनारों को लिखने की एक गतिविधि दी गई है.
नोड का टाइप | इस तरह लिखा जाता है | यह क्या करता है |
फ़ंक्शन नोड |
| Plain Python. यह |
जॉइन नोड |
| यह हर इनकमिंग चेन की रिपोर्ट मिलने तक इंतज़ार करता है. इसके बाद, उनके सभी आउटपुट को एक डिक्शनरी के तौर पर पास करता है. |
एजेंट नोड |
|
|
राऊटर |
| एक फ़ंक्शन नोड, जिसका रिटर्न आउटगोइंग एज को नाम देता है. |
ह्यूमन इनपुट नोड |
| यह ग्राफ़ को तब तक निलंबित रखता है, जब तक कोई व्यक्ति फ़ॉर्म का जवाब नहीं देता. पांचवां सेशन. |
पहले ग्राफ़ में, सेशन 2 की रिसर्च को नोड के तौर पर दिखाया गया है. agent/graph.py में scan_trends और read_backlog, दो रीडर हैं; read_backlog, आज रात के आइडिया को शेयर की गई स्थिति में भी लिखता है. stage1_fanout/agent.py, जॉइन को तय करता है और EDGES नाम की सूची से इसका Workflow बनाता है. यह सूची खाली होती है (प्रीफ़्लाइट का 0 edges). 👉🖥 इसे दो चेन से भरें:
EDGES = [(START, scan_trends, join_research),
(START, read_backlog, join_research)]
adk web में चलाएं. दो नोड एक साथ जलते हैं, फिर जुड़ते हैं; join_research का इवेंट खोलें और scan_trends कुंजी और read_backlog कुंजी के साथ एक डिक्शनरी पढ़ें. मॉडल को कॉल नहीं किया गया. जॉइन के डिक्शनरी को कुछ भी फिर से फ़ॉर्मैट नहीं करता: इसके बाद वाला नोड, 3b में, एक एजेंट है. एजेंट नोड को उसका node_input उसके मैसेज के तौर पर मिलता है. इसलिए, डिक्शनरी JSON के तौर पर आती है, जिसे मॉडल सीधे पढ़ता है.
राऊटर और लूप (3b)
Workflow में मौजूद Agent, single_turn मोड में चलता है: यह पिछले नोड के आउटपुट को अपने मैसेज के तौर पर लेता है, एक बार मॉडल को कॉल करता है, और एक बार जवाब देता है. output_schema की मदद से, जवाब की पुष्टि Pydantic मॉडल के हिसाब से की जाती है. इसके बाद ही, अगला नोड उसे देखता है. इसलिए, ग्राफ़ में टाइप किए गए ऑब्जेक्ट पास किए जाते हैं, न कि टेक्स्ट. propose_directions, जॉइन की रिसर्च डिक्शनरी पढ़ती हैं और चार कैंडिडेट को पिच करती हैं. हर कैंडिडेट, हैलोवीन का एक सीन है. चौथा उम्मीदवार, चारा है: इसके टाइटल में एक ऐसा शब्द है जिसे चैनल स्वीकार नहीं करता. इसलिए, राउटर के पास पकड़ने के लिए कुछ है. हर कैंडिडेट के पास एक poster_idea होता है. यह एक लाइन होती है, जिसमें उस इमेज का नाम होता है जो वीडियो को बेचती है. स्क्रिप्टर इसे रखता है और मीडिया डेस्क इसे सेशन 5 में ड्रॉ करता है.
राऊटर एक फ़ंक्शन नोड होता है. यह रन के लिए इस्तेमाल किए जाने वाले एज का नाम दिखाता है. मॉडल कॉल नहीं: policy_check, फ़ैसला लेते समय agent/policy_words.txt को पढ़ता है. साथ ही, पूरे शब्दों को डायरेक्शन के टाइटल और ऐंगल से मैच करता है. इसके बाद, कोई स्क्रिप्ट लिखने या पैसे खर्च करने से पहले, उसे रूट करता है. नीति एक डेटा है: फ़ाइल में बदलाव करें और अगली बार चलाने पर यह उसे पढ़ लेगी.
def policy_check(node_input):
"""The policy gate: a router. Refused words in the direction send it to
quarantine; a clean one goes to the scripter. Code, not a model."""
chosen = _as_dict(node_input)
bad = policy_hits(f"{chosen.get('title', '')} {chosen.get('angle', '')}")
return Event(output=node_input, route="BLOCK" if bad else "OK")
stage3_router/agent.py, फ़ैन-आउट के साथ-साथ propose_directions और choose_direction है. यह उस दरवाज़े की जगह काम करता है जिसे आपने सेशन 5 में बनाया था: यह उस उम्मीदवार को चुनता है जिसका नंबर आज रात के आइडिया (..., pick 4) पर खत्म होता है. अगर ऐसा नहीं होता है, तो यह पहले उम्मीदवार को चुनता है और उसे स्टेट में लिखता है. scripter एक single_turn एजेंट है, जो मंज़ूर किए गए आइडिया को Script में बदल देता है: इसमें टाइटल, ब्यौरा, टैग, शुरुआती लाइन, तीन शॉट, और पोस्टर का आइडिया शामिल है. हर शॉट में चैनल के लुक के हिसाब से हैलोवीन की इमेज होती है.
एग्ज़िट न मिलने पर लूप. quarantine को टास्क-मोड एजेंट के तौर पर शिप किया जाता है. Agent में mode होता है: chat, बातचीत का वह लूप होता है जिसे रूट एजेंट किसी व्यक्ति के साथ चलाता है. single_turn, स्ट्रक्चर्ड जवाब के साथ किया गया एक कॉल होता है. वहीं, task, टूल कॉल का वह लूप होता है जिसे एजेंट तब तक खुद चलाता है, जब तक कि वह पहले से मौजूद finish_task को कॉल नहीं करता. इसके आर्ग्युमेंट, ADK को output_schema से मिलते हैं. क्वारंटीन, अस्वीकार किए गए डायरेक्शन पर find_policy_hits को कॉल करता है. साथ ही, हर शब्द के लिए चैनल के मंज़ूर किए गए स्टैंड-इन के लिए suggest_replacement से पूछता है (agent/policy_replacements.txt, डेटा फिर से), फिर से लिखता है, फिर से जांच करता है, और टाइप किए गए CleanedDirection के साथ खत्म करता है. इसे पेज पर पढ़ें; इसे टाइप न करें.
quarantine = Agent(
name="quarantine",
model=config.MODEL,
mode="task",
instruction=QUARANTINE_INSTRUCTION,
tools=[find_policy_hits, suggest_replacement],
output_schema=CleanedDirection)
शिप किए जाने के बाद, चेन सीधे पिक से स्क्रिप्टर तक चलती है. 👉🖥 दोनों के बीच में राऊटर को रखें. इसके दो एग्ज़िट और क्वॉरंटीन से वापस आने का रास्ता होना चाहिए. एक लाइन की जगह तीन लाइनें होनी चाहिए:
(join_research, propose_directions, choose_direction, policy_check),
(policy_check, {"OK": scripter, "BLOCK": quarantine}),
(quarantine, scripter),
👉🖥 दोनों रूट चलाएं. आइडिया को ऐसे ही भेजें: choose_direction, पहले कैंडिडेट को चुनता है, policy_check, OK को जनरेट करता है, और स्क्रिप्टर एक स्ट्रक्चर्ड स्क्रिप्ट लिखता है. नया सेशन पर क्लिक करें और आखिर में , pick 4 लगाकर, आइडिया फिर से भेजें: कैंडिडेट 4, बेट है, policy_check, BLOCK को एमिट करता है, क्वॉरंटीन अपने टूल को कॉल करता है, अस्वीकार किए गए शब्दों को फिर से लिखता है, finish_task को कॉल करता है, और साफ़ किया गया डायरेक्शन, स्क्रिप्टर के पास वापस चला जाता है. पुष्टि करने वाली पंक्तियां, सेशन स्टोर से दोनों रन को पढ़ती हैं.
सेशन 2 के प्रॉम्प्ट के हर वाक्य में अब एक नोड है: रिसर्च में दो रीडर और एक जॉइन है, अस्वीकार करने में एक राऊटर और एक टास्क एजेंट है, स्क्रिप्ट एक एजेंट नोड है. पूरे ग्राफ़ में, स्टैंड-इन पिक दो फ़ंक्शन नोड हैं, direction_gate और persist_direction. ये आपको तब तक सीधे चलते हुए दिखेंगे, जब तक कि पांचवां सेशन दरवाज़े को बंद नहीं कर देता. क्रिएटर के साथ किया गया कानूनी समझौता अब भी स्टैंड-इन है. रिसर्च भी स्टैंड-इन है, जिसमें अब तक दर्शकों की राय नहीं ली गई है.
6. 4 · मल्टीमोडल डेटा को शामिल करना — ऑडियंस ने जो भी भेजा है उसे एक कॉर्पस में शामिल करना

👉🖥 वर्कबेंच में, सेशन 4 · मल्टीमोडल डेटा को शामिल करना, पार्ट 4a, और 4b खोलें. दर्शकों ने सिर्फ़ लिखा नहीं. हर तरह के मीडिया के लिए एक रीडर होता है, जो भेजे गए हर मीडिया को एक ही तरह के टेक्स्ट में बदल देता है. इसके बाद, आरएजी इंजन कॉर्पस में सारा टेक्स्ट सेव हो जाता है. इसके बाद, फ़ैन-आउट में मौजूद तीसरा रीडर, टेक्स्ट के मतलब के हिसाब से उसे खोजता है और मीडिया को वापस भेज देता है.
ऑडियंस ने क्या भेजा (4a)
agent/comments.md में, चैनल के हैलोवीन से जुड़े छह वीडियो पर की गई 12 टिप्पणियां हैं. agent/audience/ में बाकी की चीज़ें शामिल हैं: आठ वॉइस नोट (voice/*.mp3), दर्शकों के अपने कमरों की चौदह फ़ोटो (photo/*.jpg), और छह क्लिप (clip/*.mp4). इनमें से एक क्लिप में, दर्शक की आवाज़ के साथ फ़ोटो को धीरे-धीरे पैन किया गया है. 4a पेज पर, सभी चीज़ें खुल जाती हैं: हर वॉइस नोट चलता है, हर फ़ोटो दिखती है, और हर क्लिप चलती है.

आरएजी इंजन, टेक्स्ट को वापस लाता है. कोई वॉइस नोट, फ़ोटो या क्लिप, कॉर्पस में सिर्फ़ उसी तरह शामिल हो सकती है जिस तरह rag.caption_posters में पहले के पोस्टर शामिल हुए थे: एक मॉडल इसे टेक्स्ट की एक लाइन में बदल देता है, जिसमें इसकी फ़ाइल का नाम होता है. इसके बाद, वह लाइन एक पैसेज बन जाती है और जब पैसेज वापस आता है, तो फ़ाइल भी उसके साथ वापस आ जाती है. agent/platform/audience.py में हर तरह के लिए एक रीडर होता है. हर स्क्रिप्ट, Gemini को एक फ़ाइल और एक प्रॉम्प्ट भेजती है. साथ ही, हर फ़ाइल के लिए एक लाइन लिखती है:
VOICE_PROMPT = ("Transcribe this voice note word for word inside double quotes. Then add: mood: and one word. "
"Plain text on one line, nothing else.")
PHOTO_PROMPT = ("Two sentences: what is in the picture, the palette, the mood. Then: tags: and three short tags. "
"Plain text on one line, no headings, no markdown.")
CLIP_PROMPT = ("Describe the shots in two sentences, then quote what you HEAR on the soundtrack as: heard: \"...\". "
"Plain text on one line, no headings, no markdown.")
def _ask(path: pathlib.Path, mime: str, prompt: str) -> str:
"""One media file in, one line of text out."""
from google.genai import types as gt
client = images._client()
resp = client.models.generate_content(
model=config.MODEL,
contents=[gt.Part.from_bytes(data=path.read_bytes(), mime_type=mime), prompt],
config=gt.GenerateContentConfig(automatic_function_calling=gt.AutomaticFunctionCallingConfig(disable=True)))
return " ".join((resp.text or "").split())
def transcribe_voice() -> pathlib.Path:
"""voice note -> text: Gemini listens."""
files = sorted((AUDIENCE / "voice").glob("*.mp3"))
lines = []
for p in files:
said = _ask(p, "audio/mpeg", VOICE_PROMPT)
lines.append(f"- voice: {p.name} — {said}")
return _write(AUDIENCE / "voice" / "transcripts.md", "voice", "What Gemini heard in the audience's voice notes", lines)
caption_photos, image/jpeg और PHOTO_PROMPT के साथ भी ऐसा ही करता है; watch_clips, video/mp4 और CLIP_PROMPT के साथ भी ऐसा ही करता है. Gemini, एक ही कॉल में तस्वीर देखता है और साउंडट्रैक सुनता है. हर रीडर, लाइन के आकार को एक ही तरह से लिखता है. इसलिए, चंकिंग, एंबेडिंग, और डेटा वापस पाने की प्रोसेस को कभी पता नहीं चलता कि पैसेज किस तरह का है:
- voice: note-03.mp3 — "I want a whole series of the cat judging costumes ..." mood: delighted
- photo: photo-01-ghost-drawer.jpg — A cream wooden drawer, striped socks, a paper-cup ghost ... tags: drawer, socks, cozy
- clip: clip-05.mp4 — A hallway floor, a snail in a sheet and a round vacuum ... heard: "The snail won."
- poster: sock-ghost.png — A sheet ghost one inch above a striped sock ...

कॉर्पस. Vertex AI आरएजी इंजन, दस्तावेज़ों से जानकारी हासिल करता है: कॉर्पस को करीब 120 टोकन के पैसेज में बांटा जाता है. हर पैसेज को text-embedding-005 के साथ एम्बेड किया जाता है. साथ ही, क्वेरी को भी इसी तरह एम्बेड किया जाता है. इसके बाद, क्वेरी का जवाब, शेयर किए गए शब्दों के हिसाब से नहीं, बल्कि मतलब के हिसाब से सबसे नज़दीकी पैसेज के साथ दिया जाता है. "cozy little hauntings at home" से, वह टिप्पणी मिलती है जिसमें छोटे कमरों में छोटे जादू की मांग की गई है. साथ ही, बल्ब को गले लगाते हुए चमगादड़ का वॉइस नोट और वह क्लिप मिलती है जिसके साउंडट्रैक में कहा गया है कि भूत एक पेपर कप है.
corpus = rag.create_corpus(
display_name="vibestudio-feedback",
backend_config=rag.RagVectorDbConfig(
rag_embedding_model_config=rag.RagEmbeddingModelConfig(
vertex_prediction_endpoint=rag.VertexPredictionEndpoint(
publisher_model="publishers/google/models/text-embedding-005"))))
rag.upload_file(
corpus_name=corpus.name, path="agent/comments.md", display_name="comments.md",
transformation_config=rag.TransformationConfig(
chunking_config=rag.ChunkingConfig(chunk_size=120, chunk_overlap=20)))
सेटअप ने कॉर्पस बनाना पहले ही शुरू कर दिया है; 4a पेज की कनेक्ट लाइन से पता चलता है कि यह चालू है या नहीं. अगर सेटअप नहीं हो पाता है, तो यह इसे बनाता है. पेज के बटन या टर्मिनल से: python -m agent.platform.rag कॉर्पस बनाता है और उसे runs/ragcorpus.json में रिकॉर्ड करता है; python -m agent.platform.rag load --audience, audience.READERS में मौजूद हर रीडर को चलाता है. इसके बाद, टिप्पणियों और पोस्टर के कैप्शन के बगल में लिखे गए टेक्स्ट को अपलोड करता है. हर फ़ाइल को उसके नाम से अपलोड करता है और इंडेक्स के जवाब देने का इंतज़ार करता है; python -m agent.platform.rag query "cozy little hauntings at home", ऐसे पैसेज दिखाता है जिनमें क्वेरी का कोई शब्द नहीं होता.
बदलाव करना. शिप किए जाने के समय, READERS में सिर्फ़ read_comments होता है. तीन मीडिया रीडर, एक # के पीछे होते हैं. 👉🖥 वीडियो को अपलोड करने के बाद, उसे एक बार चलाएं: आउटपुट में not read (no reader wired in audience.READERS): voice, photo, clip दिखता है. साथ ही, सिर्फ़ टिप्पणियां और कैप्शन अपलोड होते हैं. इसके बाद, # को मिटाएं :
transcribe_voice, caption_photos, watch_clips,
👉🖥 डेटा को सेव करें और फिर से इंजेस्ट करें. रीडर को 40 आइटम पढ़ने में करीब तीन मिनट लगते हैं. कंसोल में एक बार में एक लाइन दिखती है. जैसे, heard, saw, और watched. साथ ही, ग्रिड में मौजूद हर कार्ड अपनी लाइन से भर जाता है. पुष्टि करने वाली पंक्तियां, फ़ाइल, रीडर के आउटपुट, और कॉर्पस को पढ़ती हैं: चार रीडर कनेक्ट किए गए, आठ वॉइस नोट सुने गए, चौदह फ़ोटो देखी गईं, छह क्लिप देखी गईं, कॉर्पस में पांच फ़ाइलें हैं.
तीसरा रीडर (4b)
दर्शकों से मिलने वाला फ़ीडबैक, रिसर्च का हिस्सा होता है. इसे हर रन के साथ शेयर किया जाता है. इसलिए, इसे ग्राफ़ में उसी जगह शामिल किया जाता है जहां रिसर्च को शामिल किया जाता है: जॉइन में तीसरे रीडर के तौर पर. agent/graph.py में मौजूद read_feedback, आज रात के आइडिया को लेता है और कॉर्पस से सबसे नज़दीकी पैसेज के बारे में पूछता है. इसके बाद, वह join_research को रिपोर्ट करता है, जो तीन पैसेज का इंतज़ार करता है. किनारा (START, read_feedback, join_research), stage5_rag/agent.py में शिप होता है. यह आकार सेशन 3 में सिखाया गया था. आपका बदलाव नोड के अंदर है. यह जानकारी को वापस पाने की प्रोसेस है, न कि मॉडल कॉल. साथ ही, यह डिटरमिनिस्टिक है: एक ही आइडिया से एक जैसे पैसेज मिलते हैं, भले ही प्रपोज़र अलग-अलग हों.
def read_feedback(node_input):
"""The third reader: what the audience sent - comments, and what Gemini
heard and saw in their voice notes, photos and clips - the passages
nearest to tonight's idea, and the media those passages came with.
Retrieval, not a model call."""
from .platform import rag
idea = idea_text(node_input)
query = idea or "what viewers liked and what they complained about"
try:
hits = rag.retrieve(query)
except Exception as e:
print(f" [rag] feedback unavailable ({str(e)[:80]})")
return Event(output={"query": query, "feedback": [], "media": [],
"note": "no corpus connected - run: python -m agent.platform.rag"})
return Event(output={"query": query, "feedback": [h["text"] for h in hits]}) # TODO: RAG_MEDIA
कॉर्पस में मौजूद हर लाइन, किसी वॉइस नोट, फ़ोटो, क्लिप या पोस्टर से ली गई है. साथ ही, इसमें फ़ाइल का नाम भी शामिल है. rag.media_in(hits) उन नामों को पैसेज से पढ़ता है और उन्हें यूआरएल में बदल देता है. इसके बाद, पेज उन यूआरएल को दिखा और चला सकता है. 👉🖥 मीडिया को पैसेज के साथ वापस भेजें, ताकि ऑडियंस ने जो चीज़ें भेजी हैं वे उनकी कही गई बातों के साथ दिखें:
return Event(output={"query": query, "feedback": [h["text"] for h in hits],
"media": rag.media_in(hits)})
👉🖥 किसी आइडिया के साथ stage5_rag को चलाएं. Open read_feedback: क्वेरी आपका आइडिया है. आउटपुट में, सबसे मिलते-जुलते पांच पैसेज और हर फ़ाइल के यूआरएल की media सूची होती है. join_research खोलें: तीन बटन. propose_directions खोलें: पहले से तीसरे उम्मीदवार ने अपने सबूत में feedback का ज़िक्र किया है. पुष्टि करने वाले पैनल में दिखता है कि रीडर ने पंक्तियों के नीचे क्या देखा: एक क्लिप, तीन वॉइस नोट, और फ़्रिज की रोशनी में भूत का पोस्टर.

7. 5 · वीडियो जनरेशन — दो तरह के सस्पेंशन, एक ही तरीका

👉🖥 वर्कबेंच में, सेशन 5 · वीडियो जनरेशन, पार्ट 5a और 5b खोलें. ये stage6_video में बनाए गए हैं. इसमें पूरा ग्राफ़ शामिल है. क्लिप बनाने में कुछ मिनट लगते हैं और पोस्टर बनाने में कुछ सेकंड. इस दौरान, रन दो बार रुकता है: एक बार आपके लिए और एक बार Veo के लिए. दोनों स्टॉप एक ही सिस्टम का हिस्सा हैं. साथ ही, डेस्क की दोनों शाखाएं, नाम के हिसाब से अपना कॉन्टेंट शेयर करती हैं.
निलंबन के दो तरीके (5a)
कोई इंतज़ार नहीं करता. जिस रन को रुकना होता है वह अपने सेशन में एक ओपन कॉल लिखता है और खत्म हो जाता है. इसके बाद, जो भी व्यक्ति या प्रोसेस उस कॉल का जवाब देता है वह उसे जारी रखता है. पेज पर एक टेबल खुलती है:
एक व्यक्ति के लिए · | धीमे टूल के लिए · | |
रन को कौन रोकता है |
|
|
यह किस चीज़ का इंतज़ार कर रहा है | एक व्यक्ति: चार में से एक कार्ड | एक धीमा काम: Veo का ऑपरेशन, मिनट |
सेशन में क्या शामिल होता है | एक ओपन | एक ओपन |
यह कैसे फिर से शुरू होता है | कॉल के आईडी के साथ | उस कॉल के आईडी के साथ एक |
इसे कौन भेजता है |
|
|
इस दौरान, यह वायरस कहां रहता है |
| एक ही पंक्ति, एक ही आईडी · कुछ भी नहीं चलता |

किसी व्यक्ति के लिए. एक ही प्रॉम्प्ट में, "क्रिएटर से पुष्टि करने के लिए कहें" एक सलाह है. सेशन 2 में, एक ही मैसेज में इस बारे में बात की गई. वर्कफ़्लो में, इंजन की वजह से रुकावट आती है. RequestInput देने वाला नोड, रन को निलंबित कर देता है: ADK, आपके message, response_schema, और payload के साथ सेशन में adk_request_input नाम का एक ओपन कॉल लिखता है. साथ ही, उसे एक interrupt_id देता है और कॉलर को वापस भेज देता है. कोई थ्रेड इंतज़ार नहीं कर रहा है. इसे फिर से शुरू करने का एकमात्र तरीका यह है कि उस आईडी वाला function_response भेजा जाए जिसकी पुष्टि आपके स्कीमा के हिसाब से की गई हो. वर्कफ़्लो में भेजा गया चैट मैसेज, एक नया टर्न होता है, न कि कोई जवाब. स्कीमा, फ़ॉर्म भी है: adk web इसे रेंडर करता है और VibeStudio ऐप्लिकेशन, इसी स्कीमा को चार कार्ड के तौर पर रेंडर करता है. direction_gate, उम्मीदवारों के नाम पहले ही राज्य को भेज देता है. 👉🖥 इसे बंद करने का तरीका:
yield RequestInput(
message="Pick tonight's direction: 1, 2, 3 or 4.",
response_schema={
"type": "object",
"properties": {
"pick": {"type": "string", "enum": ["1", "2", "3", "4"]}}},
payload={"candidates": cands})
आपका जवाब persist_direction पर node_input के तौर पर पहुंचता है. यह एक डिक्शनरी है, जिसमें एक कुंजी pick है. चार कैंडिडेट दूसरे तरीके से आते हैं: गेट ने उन्हें candidates के तहत शेयर की गई स्थिति में लिखा और ADK, स्थिति की कुंजी को उसी नाम के पैरामीटर से बाइंड करता है. नोड, चुने गए विकल्प को एक उम्मीदवार में बदल देता है. साथ ही, direction, angle, hook, और user:prefs को Event(state=...) के साथ वापस लिखता है. user: प्रीफ़िक्स वाली कुंजियां, उस उपयोगकर्ता के सभी सेशन में बनी रहती हैं.
धीमी रफ़्तार से काम करने वाले टूल के लिए. Veo को रेंडर होने में कुछ मिनट लगते हैं. हालांकि, ग्राफ़ को रेंडर होने में इतना समय नहीं लगना चाहिए. agent/desk.py में render_submit, जॉब शुरू करता है और तुरंत एक रसीद के साथ वापस आता है. इस रसीद का स्टेटस pending होता है:
def render_submit(prompt: str) -> dict:
"""Submit one Veo render of `prompt`. Returns at once with a pending
receipt; the clip is delivered later, to this call, by id."""
receipt = videogen.start(f"{prompt} {videogen.NO_TEXT}")
return {"status": "pending", "operation": receipt["operation"], "prompt": receipt["prompt"]}
LongRunningFunctionTool में रैप की गई उस रसीद का मतलब ADK के लिए कुछ और होता है: एजेंट की बारी खत्म हो जाती है, वर्कफ़्लो render_desk पर निलंबित हो जाता है, और अपने आईडी और रसीद के साथ ओपन कॉल, runs/sessions.db में एक लाइन होती है. 👉🖥 stage6_video/agent.py में, टूल को रैप करें:
tools=[LongRunningFunctionTool(render_submit)])
किसी दूसरी प्रोसेस से, आईडी के हिसाब से फिर से शुरू करें. agent/deliver.py, सेशन स्टोर में पेंडिंग कॉल ढूंढता है. साथ ही, Veo को तब तक पोल करता है, जब तक क्लिप मौजूद रहती है. इसके बाद, नतीजे को runs/state.json में सेव करता है और उसी सेशन को उस कॉल के आईडी के साथ function_response भेजता है. 👉🖥 जवाब वाला हिस्सा बनाएं:
part = Part(function_response=FunctionResponse(
id=row["call_id"], name=row["name"], response=response))
👉🖥 stage6_video को तब तक चलाएं, जब तक यह दो बार बंद न हो जाए. कोई आइडिया भेजें: रन, आपके स्कीमा से बने फ़ॉर्म पर रुक जाता है. इसके पेलोड में चार कैंडिडेट होते हैं. pick में 2 टाइप करें और सबमिट करें; ग्राफ़ persist_direction पर फिर से शुरू हो जाएगा. किल टेस्ट को यहां आज़माएं: फ़ॉर्म पर निलंबित करें, सर्वर को बंद करें (टैब 1 में scripts/stop.sh), इसे फिर से चालू करें (scripts/restart.sh), सेशन को फिर से खोलें. फ़ॉर्म अब भी मौजूद है, क्योंकि पॉज़ एक पंक्ति है, थ्रेड नहीं. script_ready के बाद, render_desk, render_submit को कॉल करता है, रसीद पाता है, WAITING का जवाब देता है, और रन खत्म हो जाता है. सेशन में कॉल आईडी सेव रहता है. पेज के कंसोल या टैब 1 से डिलीवरी को चलाएं:
cd ~/vibe-studio-multimodal
uv run python -m agent.deliver status # the pending renders, by session, call id and operation
uv run python -m agent.deliver # wait for Veo, answer the newest pending call by id
👉🖥 Refresh adk web पर क्लिक करें: function_response, पेंडिंग कॉल को फ़ॉलो करता है, join_media रिलीज़ करता है, और store_release को चलाता है. पुष्टि करने वाली आठ पंक्तियां, सेशन के दो स्टॉप को पढ़ती हैं: गेट का कॉल और आपका जवाब, रेंडर की रसीद और उसकी डिलीवरी.
राज्य और डेस्क (5b)
मीडिया डेस्क, 3a का स्ट्रक्चर है. इसमें एक फ़ैन-आउट और एक जॉइन है. साथ ही, इसमें एक स्लो ब्रांच है. script_ready, स्क्रिप्ट को दो तरीकों से भेजता है. render_desk क्लिप सबमिट करता है और रन को निलंबित कर देता है. make_poster, सेशन 2 का टूल है, जो एक नोड के तौर पर काम करता है: स्क्रिप्ट का poster_idea, चैनल का स्टाइल, और मेमोरी बैंक में मौजूद क्रिएटर की पसंद के पोस्टर की जानकारी (स्टेट से बाउंड, memory_facts, सेशन 6) इमेज मॉडल को भेजी जाती है. इसके बाद, कुछ ही सेकंड में 9:16 PNG इमेज मिल जाती है. join_media, धीमे वाले के लिए इंतज़ार करता है और store_release, स्टेट में जो मिला उसे लिखता है.
नाम से शेयर करना. store_release को पोस्टर कभी नहीं मिलता. यह poster_url नाम का पैरामीटर तय करता है. साथ ही, ADK इसे शेयर की गई स्थिति से बाइंड करता है, क्योंकि दूसरी ब्रांच के नोड ने उस कुंजी को लिखा है. ब्रांच के बीच कोई पेलोड क्रॉस नहीं होता:
def store_release(node_input, poster_url: str = "", poster_path: str = ""):
"""`poster_url` and `poster_path` are not passed by anyone: ADK binds them
from shared STATE because the parameter names match the keys make_poster
wrote (the STATE_SHARE edit). The two branches of the desk never hand each
other payloads; they share what they made by name."""
render = state.load().get("render") or {} # the delivered clip, written by deliver
url, status = render.get("url") or "", render.get("status", "")
...
if not poster_url:
said += " · poster: not in state (did make_poster write poster_url to state? the STATE_SHARE edit)"
yield Event(output={"status": status, "url": url, "poster_url": poster_url},
state={"render_url": url, "render_status": status, "poster_url": poster_url},
message=f"video: {said} · poster: {poster_url or 'none'}")
शिप किए जाने पर, make_poster आउटपुट के तौर पर पोस्टर और एक मैसेज देता है. साथ ही, store_release कहता है कि poster: not in state. 👉🖥 राज्य के नाम को उसकी फ़ाइनल यील्ड में जोड़ें:
state={"poster_url": rec.get("url", ""), "poster_path": rec.get("path", "")},
message=f"poster: {said}")
👉🖥 एक बार फिर से चलाएं और डिलीवर करें. make_poster का इवेंट खोलें: इसके आउटपुट में पोस्टर का यूआरएल और poster_url के साथ स्टेट डेल्टा. store_release खोलें: इसके मैसेज में पोस्टर का नाम होता है. पेज के इस रन का सेशन ब्लॉक में वही जानकारी दिखती है जो adk web की पंक्ति के स्टेट टैब में दिखती है: सेशन आईडी, जिसकी ज़रूरत फिर से शुरू करने के लिए होती है, वह कॉल जो खुला है, और नोड ने जो कुंजियां लिखी हैं, poster_url उनके बीच. पुष्टि करने वाले पैनल में, क्लिप और पोस्टर अगल-बगल दिखते हैं.

8. 6 · यादें — चैनल को रात के बीच की क्या बातें याद रहती हैं

👉🖥 वर्कबेंच में, stage4_memory में बनाए गए सेशन 6 · मेमोरी, पार्ट 6a, और 6b खोलें. पांचवें सेशन में, एक रन की स्थिति के बारे में बताया गया था. इस सेशन में बताया गया है कि चैनल, रन के बीच क्या याद रखता है: ग्राफ़ को दो कॉलबैक के ज़रिए बाहर से क्या सुनाई देता है.
मेमोरी बैंक (6a)
Vertex AI Memory Bank, किसी व्यक्ति के बारे में लंबे समय तक चलने वाली मेमोरी को मैनेज करता है. फ़ैक्ट, किसी स्कोप के तहत मौजूद होते हैं. जैसे, ऐप्लिकेशन का नाम और यूज़र आईडी. साथ ही, ये आपके तय किए गए विषयों के तहत मौजूद होते हैं. जब memories.generate को कोई जानकारी दी जाती है, तो वह किसी विषय के हिसाब से काम की जानकारी को निकालता है, उसे एम्बेड करता है, और पहले से मौजूद जानकारी के साथ जोड़ता है: नया तथ्य बनाया जाता है, बदले गए तथ्य को अपडेट किया जाता है, और दोहराए गए तथ्य को मर्ज किया जाता है. memories.retrieve, किसी स्कोप के लिए तथ्यों को दिखाता है. दोनों कॉल agent/platform/memory.py में मौजूद होते हैं.
SCOPE = {"app_name": config.APP, "user_id": config.USER}
TOPICS = {
"CREATOR_TASTE": "Which video directions this creator picks and passes on, "
"and how that preference changes over time.",
"CHANNEL_RULES": "Standing instructions the creator states for every video "
"(style, subjects to avoid, format rules).",
"VISUAL_STYLE": "What this creator approves and rejects in a poster: palettes, "
"framing, props and mood of the posters they shipped.",
}
तीसरा विषय है, चैनल पर मौजूद इमेज की क्वालिटी. रिलीज़ ने सेशन 5 में इसके बारे में लिखा: शिप किए गए पोस्टर के बारे में एक वाक्य में बताया गया है और उसे याद रखा गया है. साथ ही, अगले पोस्टर को उसके प्रॉम्प्ट में उस वाक्य के साथ बनाया गया है.
बैंक बनाने के लिए सेटअप पहले ही शुरू हो चुका है. 6a पेज की कनेक्ट लाइन से पता चलता है कि यह चालू है या नहीं. पेज के बटन या टर्मिनल से: python -m agent.platform.bank, बैंक और उसके विषय बनाता है. साथ ही, संसाधन के नाम को runs/memorybank.json में कैश मेमोरी में सेव करता है; python -m agent.platform.bank load, पिछले चार सेशन (स्टाइल के नियम के साथ जानवरों के दो युग, गैजेट का एक युग, हाल ही का फ़ैंटेसी युग) को सीड करता है; python -m agent.platform.bank list दिखाता है कि ट्रांसक्रिप्ट क्या बनीं: तथ्यों के इकट्ठा किए गए स्टेटमेंट, न कि ट्रांसक्रिप्ट.
कॉलबैक (6b)
मेमोरी कोई नोड नहीं है. कॉलबैक एक ऐसा फ़ंक्शन है जिसे Agent को पास किया जाता है; ADK इसे लाइव कॉन्टेक्स्ट के साथ एक तय समय पर कॉल करता है. साथ ही, None को वापस करने से सामान्य कार्रवाई होती है. तीन पेयर: एजेंट के टर्न के आस-पास (before_agent_callback, after_agent_callback, CallbackContext के साथ), हर मॉडल कॉल के आस-पास (LlmRequest के साथ before_model_callback, LlmResponse के साथ after_model_callback), हर टूल कॉल के आस-पास. गार्डरेल, टेलीमेट्री, कैश मेमोरी, और कॉन्टेक्स्ट इंजेक्शन को यहां रखा जाता है. इसके लिए, ग्राफ़ में कोई नोड नहीं होता.
stage4_memory/agent.py में, propose_directions मॉडल को कॉल करने से पहले बैंक को पढ़ता है: recall_taste तथ्यों को फ़ेच करता है, उन्हें MEMORY ब्लॉक के तौर पर अनुरोध में जोड़ता है. इसमें सबसे पुराने तथ्यों को पहले जोड़ा जाता है. साथ ही, मॉडल को बताता है कि वह कैंडिडेट 1 से 3 को मौजूदा पसंद के हिसाब से झुकाए और नियमों को सीमाओं के तौर पर इस्तेमाल करे. यह तथ्यों को memory_facts के तौर पर भी लिखता है, जहां make_poster उन्हें ढूंढता है. 👉🖥 वायर से कनेक्ट करें:
output_schema=Directions,
before_model_callback=recall_taste)
स्क्रिप्टर, क्रिएटर की बारी के बाद उसके चुने गए विकल्प के बारे में लिखता है: remember_pick, राज्य के बारे में direction पढ़ता है, चुने गए विकल्प के बारे में एक वाक्य लिखता है, और उसे memories.generate को सौंप देता है. 👉🖥 वायर से कनेक्ट करें:
output_schema=Script,
after_agent_callback=remember_pick)
👉🖥 खाली मैसेज के साथ चलाएं और कोई कार्ड चुनें. propose_directions इवेंट खोलें: अनुरोध में तीन युग शामिल हैं. साथ ही, पहले से तीसरे उम्मीदवार मौजूदा पसंद की ओर झुकाव रखते हैं, जबकि रुझान कुछ और ही बताते हैं. स्क्रिप्टर के बाद, बैंक दिखाएं पर क्लिक करें: आज रात के पिक के लिए, कोई याद बदली गई या जोड़ी गई. दूसरी रात को भी चलाएं: इसे पहली रात का डेटा याद रहता है.
9. 7 · डिप्लॉय और पब्लिश करना — ऐप्लिकेशन में ग्राफ़, VibeTube पर रात

👉🖥 वर्कबेंच में, सेशन 7 · डिप्लॉय और पब्लिश करें के 7a और 7b हिस्से खोलें.
VibeStudio को डिप्लॉय करना (7a)
सैंडबॉक्स में, adk web ने ग्राफ़ को आगे बढ़ाया. VibeStudio, ADK के Runner की मदद से इसे चलाता है. यह अपने इवेंट लूप के साथ वर्कर थ्रेड पर चलता है. साथ ही, हर इवेंट को एक रन स्टेट में फ़ोल्ड करता है. इसे पेज, सर्वर से भेजे गए इवेंट की मदद से पढ़ता है: रीडर, चार कार्ड के तौर पर आपकी पसंद, पोस्टर जब वह लैंड होता है, और रेंडर जब वह डिलीवर होता है. गेट का जवाब और रेंडर की डिलीवरी एक ही कॉल, function_response का हिस्सा है. साथ ही, ऐप्लिकेशन कंसोल का इंतज़ार करने के बजाय, Veo को पोल करता है.
self._svc = DatabaseSessionService(db_url=config.DB_URL)
self._runner = Runner(app_name=config.APP, agent=wf, session_service=self._svc)
async for ev in self._runner.run_async(user_id=config.USER, session_id=run_id, new_message=message):
self._absorb(ev) # fold the ADK event into the run state, publish one app event
part = Part(function_response=FunctionResponse(id=call_id, name=name, response=response))
vibestudio/server/agent/, लैब के agent/ की बाइट-फ़ॉर-बाइट कॉपी है. इसकी जांच checks/verify_app.py ने की है. agent/graph.py में मौजूद पूरी एज लिस्ट, इस कोडलैब के हर स्ट्रक्चर को एक ही जगह पर दिखाती है. इसमें 13 नोड हैं. यह पहले से भरी हुई होती है, ताकि आपको टाइप न करना पड़े, बल्कि सिर्फ़ पढ़ना पड़े:
(START, scan_trends, join_research),
(START, read_backlog, join_research),
(START, read_feedback, join_research),
(join_research, propose_directions, direction_gate,
persist_direction, policy_check),
(policy_check, {"OK": scripter, "BLOCK": quarantine}),
(quarantine, scripter),
(scripter, script_ready),
(script_ready, render_desk, join_media),
(script_ready, make_poster, join_media),
(join_media, store_release),
👉🖥 वर्कबेंच के डिप्लॉय करें बटन का इस्तेमाल करके डिप्लॉय करें या 👉💻 टैब 1 से:
cd ~/vibe-studio-multimodal
uv run python vibestudio/deploy.py
यह आपके .env से मिली वैल्यू के साथ चलता है:
gcloud run deploy vibestudio --source vibestudio \
--project $GOOGLE_CLOUD_PROJECT --region us-central1 \
--labels dev-tutorial-codelab=vibetube --allow-unauthenticated \
--memory 2Gi --cpu 2 --timeout 3600 --concurrency 40 \
--max-instances 1 --min-instances 1 --session-affinity \
--set-env-vars GOOGLE_CLOUD_PROJECT=...,STUDIO_VERTEX=1,STUDIO_MEMORY_BANK=...,STUDIO_RAG_CORPUS=...,VIBETUBE_URL=...,VIBETUBE_EVENT=...,VIBETUBE_NAME=...,VIBETUBE_PROJECT=...
--source, Cloud Build की मदद से कंटेनर बनाता है और उसे एक ही चरण में डिप्लॉय करता है. पहला बिल्ड बनने में चार या पांच मिनट लगते हैं. --session-affinity में एक वॉर्म इंस्टेंस है. यह उस इंस्टेंस पर निलंबित रन को बनाए रखता है जिसमें यह मौजूद है: सेशन 5 का सेशन स्टोर, एक बार फिर. बड़े पैमाने पर डिप्लॉयमेंट करने पर, सेशन स्टोर VertexAiSessionService पर चला जाता है और अफ़िनिटी खत्म हो जाती है. बिल्ड और सेवा, प्रोजेक्ट के डिफ़ॉल्ट कंप्यूट सेवा खाते के तौर पर चलती हैं. सेटअप के दौरान, इस खाते को ज़रूरी भूमिकाएं दी जाती हैं.
👉🖥 सेवा का यूआरएल खोलें और ऐप्लिकेशन में नाइट मोड चालू करें: कोई आइडिया, कोई पिक, क्लिप और पोस्टर का इंतज़ार करें. इतिहास टैब में दोनों तरह का कॉन्टेंट सेव रहता है.
पब्लिश करना (7b)
पब्लिश करने के लिए, ऐप्लिकेशन से VibeTube पर रूम के एंडपॉइंट पर, vibestudio/server/platform/publish.py में एक मल्टीपार्ट POST भेजा जाता है. क्लिप, वीडियो है. पोस्टर, थंबनेल है. प्रोफ़ाइल, रूम और आपका नाम है:
url = f"{prof['platform_url']}/api/events/{prof['event_code']}/videos"
data = {"title": state.script["title"], "description": state.script["description"],
"duration": "0:08", "displayName": prof["display_name"],
"projectId": prof["project_id"]} # one video per project and room: publishing again replaces it
files = {"videoFile": (clip.name, clip.open("rb"), "video/mp4"),
"thumbnailFile": (poster.name, poster.open("rb"), "image/png")} # the poster, not a frame
r = httpx.post(url, data=data, files=files, timeout=120)
video_id = r.json()["id"] # watch it at {platform}/e/{event}?v={video_id}
VibeTube, हर projectId और रूम के लिए एक वीडियो सेव रखता है. साथ ही, ऐप्लिकेशन जो प्रोजेक्ट भेजता है वह आपका Google Cloud प्रोजेक्ट होता है. इसलिए, फिर से पब्लिश करने पर, वीडियो जोड़ने के बजाय आपका वीडियो बदल जाता है. स्टैंड-इन पोस्टर कभी अपलोड नहीं किया जाता. असली पोस्टर ही थंबनेल होता है.
पिछला बदलाव, कोड की लाइन नहीं, बल्कि एक कॉन्फ़िगरेशन है. 👉🖥 7b पेज पर: VibeStudio का यूआरएल (7a के डिप्लॉय से भरा गया), रूम का इवेंट कोड, ठीक वैसे ही जैसे VibeTube ने इसे स्पेल किया है (वह कोड जो आपने सेटअप को दिया था, जब तक कि आपके शिक्षक ने कोई दूसरा कोड न खोला हो), और आपका नाम. पब्लिश करें को दबाएं. वर्कबेंच, क्लिक को ऐप्लिकेशन पर रिले करता है. ऐप्लिकेशन, नाइट पोस्ट करता है. नीचे दी गई लाइनें, ऐप्लिकेशन और VibeTube से मिले नतीजे को पढ़ती हैं: ऐप्लिकेशन जवाब देता है, नाइट को असली पोस्टर के साथ खत्म किया जाता है, कोड नेम एक ओपन रूम का नाम देता है, VibeTube ने एक वीडियो का आईडी दिखाया, वीडियो वॉल पर है, और उसका थंबनेल आपका पोस्टर है. नतीजे वाले कार्ड में, ऐप्लिकेशन में पोस्टर के बगल में VibeTube पर थंबनेल दिखता है.

10. आपने क्या बनाया
👉🖥 7b पेज के फ़िनाले में पूरा ग्राफ़ दिखाया गया है. इसमें आइडिया से लेकर क्लिप और उसके पोस्टर तक, 13 नोड शामिल हैं. किसी नोड पर कर्सर घुमाकर देखें कि वह क्या करता है और उसे किस सेशन में बनाया गया है.
सेशन | इससे क्या सीखने को मिला | इस तरह लिखा जाता है |
2 · इमेज जनरेट करने की सुविधा | एजेंट: मॉडल, निर्देश, टूल; टूल के तौर पर इमेज मॉडल; प्रॉम्प्ट से क्या नहीं किया जा सकता |
|
3 · वर्कफ़्लो | एज लिस्ट, फ़ैन-आउट, और जॉइन, एक ऐसा राऊटर जिसके पीछे टास्क-मोड लूप है |
|
4 · मल्टीमॉडल डेटा को प्रोसेस करना | हर तरह के लिए एक रीडर, एक लाइन शेप, एक कॉर्पस; मतलब के हिसाब से तीसरा रीडर, मीडिया के साथ |
|
5 · वीडियो जनरेट करने की सुविधा | निलंबन के दो तरीके, एक ही तरीका; सेशन स्टोर; नाम से शेयर किया गया पोस्टर |
|
6 · जानकारी याद रखने की सुविधा | रात के समय की यादें, दो कॉलबैक |
|
7 · डिप्लॉय और पब्लिश करना | Cloud Run पर मौजूद किसी ऐप्लिकेशन में ग्राफ़; VibeTube पर रात का नज़ारा |
|
ग्राफ़ इन पांच नियमों का पालन करता है:
- इंतज़ार करने के बजाय, निलंबित करें. पॉज़, सेशन स्टोर में मौजूद एक लाइन होती है, न कि कोई थ्रेड.
- सभी चीज़ों को उसी तरह से फिर से शुरू करें — ओपन कॉल के आईडी से, चाहे कोई व्यक्ति जवाब दे या कोई प्रोसेस.
- डेटा को हर पेलोड में थ्रेड करने के बजाय, स्टेट में नाम के हिसाब से शेयर करें.
- किसी मॉडल के लिए पेमेंट करने से पहले, कोड की मदद से तय करें कि आपको कौनसा मॉडल खरीदना है. नीति एक टेक्स्ट फ़ाइल और राऊटर होती है. यह रेंडर होने से पहले चलती है.
- कॉर्पस में पहुंचने से पहले, टेक्स्ट के अलावा मौजूद हर चीज़ को टेक्स्ट में बदलें. साथ ही, लाइन में फ़ाइल का नाम शामिल करें, ताकि फ़ाइल को वापस लाया जा सके.
प्रॉम्प्ट से यह तय नहीं किया जा सकता कि आउटपुट में कोई क्रम, स्टॉप या चेक शामिल हो. ग्राफ़ से यह काम किया जा सकता है.
आगे क्या करना है
VertexAiSessionService, उन सेशन के लिए जो किसी इंस्टेंस से ज़्यादा समय तक चलते हैं और--session-affinityको छोड़ देते हैं.- एक ऐसा वेबहुक जो पोलर के बजाय रेंडर के कॉल का जवाब देता है: एक ही
FunctionResponse(id=...), अलग-अलग भेजने वाला. - पब्लिश करने से पहले, दूसरा
RequestInput— स्कीमा, फ़ॉर्म होता है. इसलिए, यह एक नोड होता है और इसमें कोई पेज कोड नहीं होता. - हर रिलीज़ के बाद, दर्शकों की नई टिप्पणियां, वॉइस नोट, और क्लिप को कॉर्पस में जोड़ दिया जाता है. साथ ही, उस पोस्टर को भी जोड़ दिया जाता है जिसके तहत उन्हें भेजा गया था.
व्यवस्थित करें
इस लैब में बनाई गई हर चीज़, चौथे चरण में बनाए गए प्रोजेक्ट में मौजूद होती है. इसलिए, प्रोजेक्ट को मिटाना सबसे सस्ता तरीका है. Cloud Shell में:
gcloud projects delete $(cat ~/project_id.txt)
प्रोजेक्ट को बनाए रखने और सिर्फ़ पैसे चुकाकर इस्तेमाल की जाने वाली सुविधाओं को हटाने के लिए: Cloud Run सेवा (gcloud run services delete vibestudio --region us-central1), आरएजी कॉर्पस, और मेमोरी बैंक (इनके संसाधन के नाम runs/ragcorpus.json और runs/memorybank.json में हैं. साथ ही, कंसोल के एजेंट इंजन और आरएजी इंजन पेज से इन्हें मिटाया जा सकता है), और Artifact Registry में मौजूद कंटेनर इमेज.