AI डेमो हर जगह हैं। एक अकेला Python स्क्रिप्ट एक स्थिर फोटो में चेहरा बदल सकता है, और परिणाम जादुई लगता है। लेकिन कुछ ऐसा बनाना जिसे वास्तविक लोग वास्तव में अपलोड कर सकें, छोड़ सकें और वापस आकर देख सकें? वह पूरी तरह से एक अलग काम है। मैंने हाल ही में एक वेब टूल बनाया है जो एक एनिमेटेड GIF और एक संदर्भ चेहरा (reference face) लेता है, और फिर हर फ्रेम में चेहरा बदलकर वही एनीमेशन वापस देता है। मॉडल विजुअल का भारी काम करता है, फिर भी वास्तविक इंजीनियरिंग प्रयास इसके आसपास के आर्किटेक्चर में लगा: कनेक्शन को जीवित रखना, पेज रिफ्रेश होने पर भी बने रहना, और यह सुनिश्चित करना कि दो मिनट का इन्फरेंस (inference) जॉब 504 Gateway Timeout में गायब न हो जाए।
यह एक प्रोटोटाइप और एक प्रोडक्ट के बीच का अंतर है। इंजीनियर्स डिफ्यूजन आर्किटेक्चर और इन्फरेंस पैरामीटर्स के बारे में बात करना पसंद करते हैं। लेकिन जब कोई यूजर एक घना, दो सौ फ्रेम वाला GIF अपलोड करता है, तो किसी को आपके मॉडल की परवाह नहीं होती यदि ब्राउज़र टैब तीस सेकंड के बाद जवाब दे दे। इन्फरेंस के आसपास का इंफ्रास्ट्रक्चर उतना ही महत्वपूर्ण है जितना कि इन्फरेंस खुद।
इंतज़ार करने की समस्या
मानक वेब आर्किटेक्चर तेज़ प्रतिक्रियाओं की कल्पना करता है। एक यूजर बटन पर क्लिक करता है, सर्वर जवाब देता है, और पेज अपडेट हो जाता है। दर्जनों GIF फ्रेमों में फेस स्वैपिंग इस धारणा को तुरंत तोड़ देती है। मॉडल Replicate के GPUs पर चलता है, मेरे सर्वर पर नहीं, और एक लंबा GIF प्रोसेस होने में आसानी से एक मिनट या उससे अधिक समय ले सकता है। यदि आप इतने लंबे समय तक HTTP रिक्वेस्ट को खुला रखने की कोशिश करते हैं, तो आप मुसीबत को दावत दे रहे हैं। लोड बैलेंसर निष्क्रिय कनेक्शनों को काट देते हैं। ब्राउज़र मान लेते हैं कि नेटवर्क विफल हो गया है और फिर से प्रयास करते हैं। यूजर्स एक ठहरे हुए स्पिनर को देखते रहते हैं और मान लेते हैं कि ऐप खराब है।
मैंने सबमिशन को परिणाम से अलग (decoupling) करके इससे पूरी तरह से बचा। जब कोई यूजर GIF और एक चेहरे की इमेज अपलोड करता है, तो मेरा Next.js बैकएंड Replicate पर एक प्रेडिक्शन शुरू करता है और तुरंत एक जॉब ID वापस कर देता है। यूजर को तुरंत पुष्टि मिल जाती है। वास्तविक परिणाम बाद में वेबहुक (webhook) के माध्यम से आता है जब GPU का काम पूरा हो जाता है। यह पैटर्न कोई नया नहीं है, लेकिन लंबे समय तक चलने वाले मीडिया जॉब्स के लिए यह बिल्कुल आवश्यक है। यह एक अनिश्चित इंतज़ार को एक भरोसेमंद हैंडशेक में बदल देता है: जॉब स्वीकार कर लिया गया है, और काम पूरा होने पर आपको सूचित किया जाएगा।
एक ऐसा स्टेट मशीन बनाएं जिस पर आप भरोसा कर सकें
एक बार जब आप एसिंक्रोनस (asynchronous) हो जाते हैं, तो आपको विजिबिलिटी की आवश्यकता होती है। यूजर्स पेज रिफ्रेश करेंगे। वे टैब बंद करेंगे और उसे फिर से खोलेंगे। वे लिंक कॉपी करेंगे और उसे किसी सहकर्मी को भेजेंगे जो दो घंटे बाद उसे चेक करेगा। जो हुआ है उसका स्थायी रिकॉर्ड (durable record) न होने पर, केवल अराजकता ही हाथ लगेगी।
मैंने Supabase को 'सिंगल सोर्स ऑफ ट्रुथ' के रूप में उपयोग किया। हर अपलोड एक यूनिक जॉब ID के साथ एक रो (row) बनाता है, और वह रो विशिष्ट अवस्थाओं (states) से गुजरती है: queued, processing, succeeded, failed, या expired। जब यूजर पहली बार सबमिट करता है, तो रो 'queued' होती है। जैसे ही Replicate प्रेडिक्शन स्वीकार करता है, यह 'processing' में बदल जाती है। वेबहुक इसे 'succeeded' या 'failed' में धकेलता है। मैंने उन जॉब्स के लिए 'expired' जोड़ा है जो बिना किसी कॉलबैक के बहुत लंबे समय तक रहते हैं, ताकि सिस्टम अनिश्चित काल तक भूतों का पीछा न करता रहे।
TypeScript में बना फ्रंटएंड, छोटे अंतराल पर Supabase को पोल (poll) करता है और वर्तमान स्थिति के अनुसार रेंडर करता है। यह पोलिंग आदिम (primitive) लग सकती है, लेकिन यह रिफ्रेश की समस्या को पूरी तरह से हल कर देती है। एक यूजर अपना लैपटॉप बंद कर सकता है, उसे कल खोल सकता है, और देख सकता है कि चीजें ठीक कहाँ खड़ी हैं क्योंकि प्रोग्रेस का मालिक ब्राउज़र मेमोरी नहीं—डेटाबेस है। Supabase क्रेडिट्स को भी ट्रैक करता है, इसलिए अकाउंटिंग उसी जॉब रिकॉर्ड से जुड़ी रहती है जो स्टेट को ट्रैक करता है। सब कुछ एक ही जगह रहता है।
ब्राउज़र को क्रैश किए बिना फाइलों को संभालना
GIF लोगों की सोच से कहीं अधिक भारी होते हैं। एक फाइल जो AI पाइपलाइन के लिए बिल्कुल सही आकार की है, उसका वजन फिर भी कई मेगाबाइट हो सकता है। ब्राउज़र के अंदर उसे लूपिंग प्रीव्यू के रूप में रेंडर करना प्रदर्शन (performance) को खराब कर देगा, खासकर कम क्षमता वाले डिवाइस पर। मुझे दो पूरी तरह से अलग फाइल पाइपलाइन की आवश्यकता थी: एक AI के लिए, और एक यूजर इंटरफेस के लिए।
प्रीव्यू के लिए, मैं WebAssembly में कंपाइल किए गए FFmpeg का उपयोग करके बड़े GIFs को एनिमेटेड WebP में बदल देता हूँ। यह पूरी तरह से ब्राउज़र में क्लाइंट-साइड पर चलता है। परिणाम एक हल्का प्रीव्यू होता है जो मूल फाइल को छुए बिना इंटरफेस को तेज़ रखता है। Replicate को भेजा गया GIF अपरिवर्तित रहता है। यह अलगाव महत्वपूर्ण है। आप नहीं चाहेंगे कि प्रीव्यू के कंप्रेशन आर्टिफैक्ट्स (compression artifacts) आपके ट्रेनिंग डेटा या आपके फाइनल रेंडर में आ जाएं, और आप यह भी नहीं चाहेंगे कि जब AI अभी भी सोच रहा हो, तब यूजर इंटरफेस कई मेगाबाइट की फाइल के कारण अटक जाए।
FFmpeg WASM अपलोड के ब्राउज़र से बाहर जाने से पहले अन्य GIF कार्यों को भी संभालता है। मैं इसका उपयोग फ्रेम काउंट को पार्स करने, आयामों (dimensions) को मान्य करने और दूषित (corrupted) फाइलों को जल्दी पकड़ने के लिए करता हूँ। समस्या को पकड़ने से पहले कि वह GPU क्रेडिट्स को खत्म कर दे, पैसे और यूजर के धैर्य दोनों की बचत होती है।
एक डेमो को ऐसे सॉफ्टवेयर में बदलना जिस पर लोग भरोसा करें
यहाँ एक व्यापक सबक है जो बाज़ार में मौजूद लगभग हर जनरेटिव AI टूल पर लागू होता है। मॉडल स्वयं काम का केवल तीस प्रतिशत हो सकता है। बाकी सत्तर प्रतिशत वह गैर-आकर्षक बुनियादी काम (plumbing) है जिसके बारे में कोई ट्वीट नहीं करता: स्टेट रिकवरी, वेबहुक सिग्नेचर, फ़ाइल कन्वर्जन, क्रेडिट ट्रैकिंग और ग्रेसफुल फेलियर (graceful failure)।
मेरा स्टैक सरल और सुविचारित है। Next.js और TypeScript इंटरफ़ेस और API रूट्स को संभालते हैं। Replicate मॉडल्स को चलाता है। Supabase स्टेट्स, डेटा और क्रेडिट्स को मैनेज करता है। FFmpeg WASM क्लाइंट-साइड मीडिया वर्क को संभालता है। Animated WebP UI को तेज़ रखता है। प्रत्येक हिस्से का एक ही काम है, और वे नाजुक, लंबे समय तक चलने वाले रिक्वेस्ट के बजाय स्पष्ट स्टेट ट्रांज़िशन के माध्यम से जुड़ते हैं।
जब कोई उपयोगकर्ता फेस स्वैप के लिए क्रेडिट्स का उपयोग करता है, तो वह विश्वसनीयता की अपेक्षा करता है, न कि किसी रिसर्च पेपर की। यदि कोई प्रेडिक्शन विफल हो जाता है, तो सिस्टम को इसका पता होना चाहिए और उसे सूचित करना चाहिए। यदि उपयोगकर्ता प्रतीक्षा करता है, तो उसके पास देखने के लिए एक लाइटवेट प्रीव्यू और एक ऐसा स्टेटस होना चाहिए जो ब्राउज़र रीस्टार्ट होने के बाद भी बना रहे। जब ये विवरण काम करते हैं, तो वे अदृश्य होते हैं, और जब वे काम नहीं करते, तो घातक होते हैं।
फेस स्वैप अपने आप में एक शानदार ट्रिक है। लेकिन यह टूल तभी वास्तविक लगता है क्योंकि एक उपयोगकर्ता अपनी प्रगति खोए बिना अपलोड कर सकता है, छोड़ सकता है और वापस आ सकता है। यही वह चीज़ है जो एक API कॉल को ऐसे सॉफ्टवेयर में बदल देती है जिस पर लोग वास्तव में भरोसा करते हैं।
