Asset Studio को कैसे लागू किया गया
शुरुआत
पिछली पोस्ट How We Make Games में मैंने बताया था कि हम कौन-कौन से गेम किस क्रम में बना रहे हैं। उस पोस्ट में Asset Studio का ज़िक्र बहुत संक्षेप में आया था। लगभग इतना ही कि यह Story Quiz और Mystery के character और background assets को साथ में manage करने वाला एक tool है।
इस पोस्ट में मैं उसी बात को actual implementation के आधार पर खोलना चाहता हूँ। Asset Studio सिर्फ image generate करने वाली screen नहीं है। Omnilude में अभी यह वह जगह है जहाँ हम assets इकट्ठा करते हैं, prompts को refine करते हैं, generation jobs चलाते हैं, results को review करते हैं, और फिर उन्हें library में register करते हैं। Frontend backoffice workbench की तरह काम करता है, game-service asset domain को संभालता है, और ai-service generation execution को संभालता है।
Asset Studio को अलग से क्यों बनाया गया
जब आप सच में game बनाना शुरू करते हैं, तो assets उम्मीद से कहीं जल्दी बिखर जाते हैं। Story Quiz में characters, backgrounds और block images हैं। Mystery में scenario characters, locations और note images हैं। एक ही व्यक्ति अगर एक ही worldbuilding पर काम कर रहा हो, तब भी prompts, style presets, generated results, approval states और actual usage को अलग-अलग screens में manage करना जल्दी ही मुश्किल हो जाता है।
इसीलिए Asset Studio को शुरू से gallery की तुलना में workshop की तरह design किया गया। महत्वपूर्ण बात यह है कि यह tool किसी एक genre तक सीमित नहीं है। यह Story Quiz में पहले से बने assets और Mystery drafts से लाए गए assets को एक ही तरीके से संभालता है, generated results को reviewable library के रूप में रखता है, और बाद में यह भी track करता है कि वे assets दूसरे domains में वास्तव में उपयोग हो रहे हैं या नहीं। इस नज़रिए के बिना AI generation सुविधाजनक तो लग सकती है, लेकिन operational asset के रूप में टिकती नहीं है।
Backoffice screen की संरचना कैसी है
Frontend backoffice में Asset Studio के लिए dedicated routes हैं। Backgrounds और characters अलग entry points से खुलते हैं, लेकिन अंदर वे एक ही workbench components को share करते हैं। List screen tree view और flat view दोनों को support करती है, और हाल में edit किए गए items भी दिखाती है। यानी आप directory-centric तरीके से भी काम कर सकते हैं और recent activity के आधार पर भी वापस जा सकते हैं।
Detail screen में जाने पर structure और साफ़ हो जाती है। यह screen वास्तव में एक full asset production console है। ऊपर नाम और approval state manage की जाती है। Body में import sources, prompts, generation, media और history को tabs में handle किया जाता है। Implementation में दिखता है कि import source search state और generated media action state page level पर रखी गई है। उद्देश्य यह है कि tab बदलने पर context न टूटे।
यहाँ एक महत्वपूर्ण split है। Asset management APIs, जैसे list fetch करना, directories update करना, या generated result register करना, ये सब /api/asset-studio/* के रास्ते game-service तक जाती हैं। दूसरी तरफ actual generation request Asset Studio API से नहीं जाती, बल्कि /api/media-generation/generate के जरिए ai-service तक जाती है। यह separation जानबूझकर किया गया है। Asset management और generation execution एक ही screen में हैं, लेकिन उनकी responsibility एक जैसी नहीं है।
Actual generation flow कैसे चलता है
User experience अपने आप में काफी सीधा है। आप एक asset खोलते हैं, existing asset या Story Quiz या Mystery source लाते हैं, prompt adjust करते हैं, और generate दबाते हैं। लेकिन अंदर flow इस तरह बँटा हुआ है।
- Backoffice detail screen current
assetItem.generationConfigपढ़ती है। - Generation request
/api/media-generation/generateपर भेजी जाती है, और frontend तुरंतjobIdप्राप्त करता है। - Frontend उसी
jobIdसे backbone SSE stream को subscribe करता है और progress events लेता है। ai-serviceactual provider के जरिए result बनाता है और उसे storage में upload करता है।- Frontend SSE से
outputUrlऔरsourceUrlलेकर preview दिखाता है। - अगर result ठीक लगे, तो user उसे
/api/asset-studio/asset-items/{id}/mediaके जरिए register करता है।
यह आख़िरी step बहुत महत्वपूर्ण है। Generation खत्म होते ही result सीधे Asset Studio library में save नहीं हो जाता। Generated result पहले review target की तरह माना जाता है। वह operational asset तभी बनता है जब user registration action दबाता है। Implementation में भी यह साफ़ दिखता है। Generation hook SSE events से preview state बनाता है, और एक अलग action createGeneratedMediaApi को call करके result को library में डालती है।
इसी structure की वजह से Asset Studio सिर्फ prompt box नहीं है। यह review के साथ आने वाली production pipeline बन जाता है। Failed results, ambiguous results, और pipeline post-processing results को temporary state में रखा जा सकता है, और बाद में चुने हुए results ही register किए जा सकते हैं।
game-service क्या संभालता है
game-service का Asset Studio सिर्फ CRUD bundle नहीं है। व्यवहार में यह asset library के वास्तविक owner के काफी करीब है। Controller level पर भी directories, items, import, export/import portability, generated media, winner selection, reorder, bulk move और import source lookup एक ही domain में grouped हैं।
यह service तीन कारणों से खास तौर पर महत्वपूर्ण है।
1. यह existing game domains से sources लाता है
AssetStudioImportService Mystery के DraftLocation और DraftCharacter, और Story Quiz के StoryQuizBackgroundAsset और StoryCharacter को पढ़कर उन्हें import source cards में बदलता है। यह सिर्फ names नहीं लाता। यह prompt, provider, stylePreset और metadata को भी साथ लाता है। इसलिए Asset Studio वह जगह नहीं है जहाँ हर asset zero से शुरू होता है, बल्कि वह जगह है जहाँ existing game data से asset production आगे बढ़ती है।
2. यह generated results को operational assets में बदलता है
AssetGeneratedMediaService generated results को library records के रूप में save करता है और उनमें से एक को winner के रूप में mark करने देता है। जब image type का winner बदलता है, तो item thumbnail भी update हो जाता है। दूसरी तरफ अगर asset पहले से use में है, तो उसके representative media को आसानी से delete नहीं किया जा सकता। यानी generated results को इकट्ठा करना और operational asset को adopt करना, ये दोनों अलग रखे गए हैं।
3. यह track करता है कि asset सच में use हो रहा है या नहीं
AssetReferenceSyncService check करता है कि कोई URL Story Quiz और Mystery के अंदर वास्तव में use हो रहा है या नहीं, और उसी हिसाब से isReferenced sync करता है। Story Quiz side पर यह covers, cards, default character images, emotion images, backgrounds और block media को देखता है। Mystery side पर यह scenario thumbnails, character avatars, notes और object images को check करता है। इसी वजह से Asset Studio सिर्फ सुंदर asset repository नहीं है, बल्कि live content से जुड़ा हुआ asset management tool है।
ai-service क्या संभालता है
ai-service की responsibility और भी साफ़ है। यह service asset library को नहीं जानती। यह generation execution को संभालती है। Backoffice से भेजे गए generationConfig को interpret करती है, तय करती है कि कौन सा provider और workflow इस्तेमाल होगा, job को asynchronous तरीके से चलाती है, और SSE के जरिए progress stream करती है।
Implementation में MediaGenerationService पहले account-level concurrency slots check करती है। उसके बाद GenerationConfigParser settings parse करता है। यहाँ precedence बहुत महत्वपूर्ण है। generationConfig.media[mediaType].providers[providerCode] सबसे ऊपर है, उसके बाद default, और अंत में root level fallback के रूप में काम करता है। इस structure की वजह से एक ही asset media type और provider के हिसाब से अलग settings रख सकता है।
Parsing पूरी होने के बाद ai-service तुरंत generate नहीं करता। वह काम को DTE job queue में डालता है। Frontend को मिलने वाला jobId आगे SSE subscription key के रूप में भी वही रहता है। यानी backoffice किसी लंबे request पर block नहीं होता, बल्कि job ID के आधार पर asynchronous generation process को track करता है।
ComfyUI integration क्यों महत्वपूर्ण है
Current implementation में Asset Studio की सबसे दिलचस्प चीज़ों में से एक ComfyUI integration है। ComfyUIProvider workflows को application code में hardcode नहीं करता। Runtime settings provider configuration से पढ़ी जाती हैं, और executable workflows database के workflow records से आते हैं। साथ ही, यह सिर्फ prompt-to-image नहीं, बल्कि media-to-media pipelines भी support करता है।
यह इसलिए महत्वपूर्ण है क्योंकि Asset Studio की generation settings सिर्फ एक plain prompt string नहीं हैं। Users workflowId, workflowPipeline, seed, width, height और input image URL जैसे runtime overrides साथ में भेज सकते हैं। Actual implementation में, pipeline workflow चुनने के बाद existing generated media को input बनाकर post-processing या transformation भी किया जा सकता है।
इसका नतीजा यह है कि AI generation screen एक generic prompt input box नहीं रहती, बल्कि data-driven workflow runner बन जाती है। एक ही character को किसी दूसरे provider, दूसरे workflow या दूसरी input image के साथ फिर से generate किया जा सकता है, और result को review करके बाद में library में जमा किया जा सकता है।
आगे चलकर ComfyUI पर अलग से एक और विस्तार वाली पोस्ट लिखना भी ठीक रहेगा।
game-service और ai-service को अलग क्यों रखा गया
यह सिर्फ MSA preference का मामला नहीं है। Asset domain और generation runtime अलग तरह से fail होते हैं, उनके lifecycle अलग हैं, और operations के नज़रिए से उन्हें अलग तरह से देखा जाता है।
game-service उन जानकारियों को संभालता है जिन्हें लंबे समय तक रहना है, जैसे directory structure, approval state, actual usage, portability और history। दूसरी तरफ ai-service इस बात को संभालता है कि कौन से providers अभी available हैं, कौन सा workflow चुनना चाहिए, इस समय कितनी jobs चल सकती हैं, और generation किस stage तक पहुँची है। अगर इन दोनों concerns को मिला दिया जाए, तो implementation कुछ समय तक convenient लग सकती है, लेकिन boundary बहुत जल्दी धुंधली हो जाती है।
Current structure में Asset Studio इन दोनों को जोड़ता है। Backoffice एक ही screen से काम करता है, लेकिन storage और execution को अलग-अलग संभालता है। यही separation आगे Story Quiz और Mystery से बाहर भी नए genres जुड़ने पर asset library और generation infrastructure को स्वतंत्र रूप से evolve करने की अनुमति देती है।
समापन
पिछली पोस्ट में Asset Studio सिर्फ एक गुजरती हुई पंक्ति थी। लेकिन अगर actual implementation को follow किया जाए, तो यह केवल image generation feature नहीं है। Omnilude में Asset Studio एक production system है जो game assets को इकट्ठा करता है, existing domains से sources लाता है, AI generation jobs चलाता है, results को review करता है, और यह track करता है कि वे assets वास्तव में use हो रहे हैं या नहीं।
इसीलिए मैं Asset Studio को game development की side screen की तरह नहीं देखता। यह Story Quiz, Mystery और पूरी production pipeline के मिलने वाले बिंदु के ज्यादा करीब लगता है। अगली पोस्ट में मैं scope को और छोटा करके यह समझाना चाहता हूँ कि यह asset system actual publishing pipeline या किसी specific genre के production flow के अंदर कैसे इस्तेमाल होता है।
Reviewer की नज़र से दोबारा पढ़ने पर भी यह पोस्ट थोड़ी dense और कुछ हद तक cipher जैसी लगती है।
मैं blog को attached images support करने लायक update करने और पुरानी posts को भी revisit करने की योजना बना रहा हूँ, ताकि overall readability बेहतर हो सके।
फिर भी, क्योंकि इस पोस्ट को लिखने में काफी मेहनत लगी है, मैं इसे वैसे भी publish करूँगा।