اے آئی (AI) ڈیمو ہر جگہ موجود ہیں۔ ایک سادہ سا Python اسکرپٹ کسی ساکن تصویر میں چہرہ بدل سکتا ہے، اور اس کا نتیجہ جادوئی لگتا ہے۔ لیکن کچھ ایسا بنانا جسے اصل لوگ واقعی اپ لوڈ کر سکیں، چھوڑ کر جا سکیں، اور پھر واپس آ سکیں؟ یہ ایک بالکل مختلف کام ہے۔ میں نے حال ہی میں ایک ویب ٹول بنایا ہے جو ایک اینیمیٹڈ GIF اور ایک ریفرنس چہرہ لیتا ہے، اور پھر ہر فریم میں چہرہ بدل کر وہی اینیمیشن واپس کرتا ہے۔ ماڈل بصری طور پر زیادہ کام کرتا ہے، لیکن اصل انجینئرنگ کی کوشش اس کے گرد موجود آرکیٹیکچر میں لگی: کنکشنز کو زندہ رکھنا، پیج ریفریش سے بچنا، اور یہ یقینی بنانا کہ دو منٹ کا انفرنس (inference) جاب 504 Gateway Timeout میں غائب نہ ہو جائے۔
یہ ایک پروٹو ٹائپ اور ایک پروڈکٹ کے درمیان کا فرق ہے۔ انجینئرز کو ڈفیوژن آرکیٹیکچرز (diffusion architectures) اور انفرنس پیرامیٹرز کے بارے میں بات کرنا پسند ہے۔ لیکن جب کوئی صارف دو سو فریموں والا ایک بھاری GIF اپ لوڈ کرتا ہے، تو اگر براؤزر ٹیب تیس سیکنڈ کے بعد جواب دے دے تو کسی کو آپ کے ماڈل کی پرواہ نہیں ہوتی۔ انفرنس کے گرد موجود انفراسٹرکچر اتنا ہی اہم ہے جتنا کہ خود انفرنس۔
انتظار کا مسئلہ
معیاری ویب آرکیٹیکچر تیز رسپانس کا فرض کرتا ہے۔ صارف ایک بٹن پر کلک کرتا ہے، سرور جواب دیتا ہے، اور پیج اپ ڈیٹ ہو جاتا ہے۔ درجنوں GIF فریموں پر فیس سویپنگ اس مفروضے کو فوری طور پر توڑ دیتی ہے۔ ماڈل Replicate کے GPUs پر چلتا ہے، میرے سرور پر نہیں، اور ایک طویل GIF کو پروسیس ہونے میں آسانی سے ایک منٹ یا اس سے زیادہ وقت لگ سکتا ہے۔ اگر آپ اتنی دیر تک HTTP ریکویسٹ کو کھلا رکھنے کی کوشش کرتے ہیں، تو آپ خود مشکل کو دعوت دے رہے ہیں۔ لوڈ بیلنسرز (Load balancers) غیر فعال کنکشنز کو کاٹ دیتے ہیں۔ براؤزرز فرض کرتے ہیں کہ نیٹ ورک فیل ہو گیا ہے اور دوبارہ کوشش کرتے ہیں۔ صارفین ایک منجمد اسپنر (frozen spinner) کو دیکھتے رہتے ہیں اور سمجھ لیتے ہیں کہ ایپ خراب ہو گئی ہے۔
میں نے سبمیشن کو رزلٹ سے الگ (decoupling) کر کے اس سے مکمل طور پر بچا لیا۔ جب کوئی صارف GIF اور چہرے کی تصویر اپ لوڈ کرتا ہے، تو میرا Next.js بیک اینڈ Replicate پر ایک پریڈکشن شروع کرتا ہے اور فوری طور پر ایک job ID واپس کر دیتا ہے۔ صارف کو فوری تصدیق مل جاتی ہے۔ اصل نتیجہ بعد میں ویب ہک (webhook) کے ذریعے پہنچتا ہے جب GPU کا کام مکمل ہو جاتا ہے۔ یہ پیٹرن کوئی غیر معمولی چیز نہیں ہے، لیکن طویل عرصے تک چلنے والے میڈیا جابز کے لیے یہ انتہائی ضروری ہے۔ یہ ایک غیر یقینی انتظار کو ایک پراعتماد ہینڈ شیک میں بدل دیتا ہے: جاب قبول کر لی گئی ہے، اور کام مکمل ہونے پر آپ کو مطلع کر دیا جائے گا۔
ایک ایسا اسٹیٹ مشین (State Machine) بنائیں جس پر آپ بھروسہ کر سکیں
جب آپ غیر ہم آہنگ (asynchronous) طریقے پر کام شروع کرتے ہیں، تو آپ کو ویزیبلٹی (visibility) کی ضرورت ہوتی ہے۔ صارفین پیج ریفریش کریں گے۔ وہ ٹیب بند کر کے دوبارہ کھولیں گے۔ وہ لنک کاپی کریں گے اور اپنے کسی ساتھی کو بھیجیں گے جو دو گھنٹے بعد اسے چیک کرے گا۔ یہ جانے بغیر کہ کیا ہوا، آپ کے پاس صرف افراتفری ہوگی۔
میں نے Supabase کو 'سنگل سورس آف ٹرتھ' (single source of truth) کے طور پر استعمال کیا۔ ہر اپ لوڈ ایک منفرد job ID کے ساتھ ایک رو (row) تخلیق کرتا ہے، اور وہ رو مخصوص اسٹیٹس سے گزرتی ہے: queued، processing، succeeded، failed، یا expired۔ جب صارف پہلی بار سبمٹ کرتا ہے، تو رو 'queued' ہوتی ہے۔ جیسے ہی Replicate پریڈکشن قبول کرتا ہے، یہ 'processing' میں منتقل ہو جاتی ہے۔ ویب ہک اسے 'succeeded' یا 'failed' پر بھیج دیتا ہے۔ میں نے ان جابز کے لیے 'expired' کا اسٹیٹ بھی شامل کیا جو کال بیک کے بغیر بہت زیادہ دیر تک رک جاتی ہیں، تاکہ سسٹم بے مقصد تلاش میں نہ لگا رہے۔
TypeScript میں بنا ہوا فرنٹ اینڈ، مختصر وقفوں پر Supabase کو پول (poll) کرتا ہے اور موجودہ اسٹیٹ کے مطابق رینڈر کرتا ہے۔ یہ پولنگ دیکھنے میں سادہ لگتی ہے، لیکن یہ ریفریش کے مسئلے کو مکمل طور پر حل کر دیتی ہے۔ صارف اپنا لیپ ٹاپ بند کر سکتا ہے، اسے کل کھول سکتا ہے، اور دیکھ سکتا ہے کہ چیزیں کہاں تک پہنچی ہیں کیونکہ ڈیٹا بیس—براؤزر میموری نہیں—ترقی (progress) کا مالک ہے۔ Supabase کریڈٹس کو بھی ٹریک کرتا ہے، اس لیے اکاؤنٹنگ اسی جاب ریکارڈ کے ساتھ جڑی رہتی ہے جو اسٹیٹ کو ٹریک کرتا ہے۔ سب کچھ ایک ہی جگہ موجود ہے۔
براؤزر کو بوجھ دیے بغیر فائلوں کو ہینڈل کرنا
GIF لوگ سمجھتے ہیں اس سے کہیں زیادہ بھاری ہوتی ہیں۔ ایک فائل جو AI پائپ لائن کے لیے بالکل صحیح سائز کی ہو سکتی ہے، اس کا وزن پھر بھی کئی میگا بائٹس ہو سکتا ہے۔ اسے براؤزر کے اندر لوپنگ پری ویو کے طور پر رینڈر کرنا کارکردگی کو تباہ کر دے گا، خاص طور پر کم درجے کے آلات (lower-end devices) پر۔ مجھے دو بالکل الگ فائل پائپ لائنز کی ضرورت تھی: ایک AI کے لیے، اور ایک یوزر انٹرفیس کے لیے۔
پری ویوز کے لیے، میں WebAssembly میں کمپائل شدہ FFmpeg کا استعمال کرتے ہوئے بڑے GIFs کو اینیمیٹڈ WebP میں تبدیل کرتا ہوں۔ یہ مکمل طور پر کلائنٹ سائیڈ پر براؤزر میں چلتا ہے۔ اس کا نتیجہ ایک ہلکا پھلکا پری ویو ہوتا ہے جو اصل فائل کو چھوئے بغیر انٹرفیس کو تیز رکھتا ہے۔ Replicate کو بھیجی جانے والی GIF کو تبدیل نہیں کیا جاتا ہے۔ یہ علیحدگی اہم ہے۔ آپ نہیں چاہیں گے کہ پری ویو کے کمپریشن آرٹیکٹس (compression artifacts) آپ کے ٹریننگ ڈیٹا یا آپ کے فائنل رینڈر میں شامل ہو جائیں، اور آپ یہ بھی نہیں چاہیں گے کہ جب AI ابھی سوچ رہا ہو تو یوزر انٹرفیس کئی میگا بائٹس کی فائل کی وجہ سے رک جائے۔
FFmpeg WASM اپ لوڈ ہونے سے پہلے براؤزر سے باہر جانے سے پہلے دیگر GIF ٹاسک بھی سنبھالتا ہے۔ میں اسے فریم کاؤنٹ معلوم کرنے، ڈائمینشنز کی تصدیق کرنے، اور خراب فائلوں کو جلد پکڑنے کے لیے استعمال کرتا ہوں۔ کسی مسئلے کو اس سے پہلے پکڑ لینا کہ وہ GPU کریڈٹس ضائع کرے، پیسے اور صارف کے صبر دونوں کی بچت کرتا ہے۔
ڈیمو کو ایسے سافٹ ویئر میں بدلنا جس پر لوگ بھروسہ کریں
یہاں ایک وسیع تر سبق ہے جو مارکیٹ میں موجود تقریباً ہر جنریٹیو اے آئی (generative AI) ٹول پر لاگو ہوتا ہے۔ ماڈل خود کام کا صرف تیس فیصد ہو سکتا ہے۔ باقی ستر فیصد وہ غیر پرکشش پس منظر کا کام (plumbing) ہے جس کے بارے میں کوئی ٹویٹ نہیں کرتا: اسٹیٹ ریکوری (state recovery)، ویب ہک سگنیچرز (webhook signatures)، فائل کنورژن (file conversion)، کریڈٹ ٹریکنگ (credit tracking)، اور باوقار طریقے سے ناکامی (graceful failure)۔
میرا اسٹیک سادہ اور سوچ سمجھ کر بنایا گیا ہے۔ Next.js اور TypeScript انٹرفیس اور API روٹس کو سنبھالتے ہیں۔ Replicate ماڈلز چلاتا ہے۔ Supabase اسٹیٹس، ڈیٹا اور کریڈٹس کا انتظام کرتا ہے۔ FFmpeg WASM کلائنٹ سائیڈ میڈیا کے کام کو سنبھالتا ہے۔ Animated WebP UI کو تیز رکھتا ہے۔ ہر حصے کا ایک مخصوص کام ہے، اور وہ کمزور اور طویل مدتی درخواستوں کے بجائے واضح اسٹیٹ ٹرانزیشنز (explicit state transitions) کے ذریعے ایک دوسرے سے جڑے ہوئے ہیں۔
جب کوئی صارف فیس سویپ (face swap) کے لیے اپنے کریڈٹس استعمال کرتا ہے، تو وہ بھروسہ مند نظام کی توقع رکھتا ہے، نہ کہ کسی تحقیقی مقالے کی۔ اگر کوئی پیشگوئی (prediction) ناکام ہو جائے، تو سسٹم کو اس کا علم ہونا چاہیے اور اسے بتانا چاہیے۔ اگر صارف انتظار کر رہا ہو، تو اس کے پاس دیکھنے کے لیے ایک ہلکا پھلکا پری ویو (lightweight preview) ہونا چاہیے اور ایک ایسا اسٹیٹس ہونا چاہیے جو براؤزر ری اسٹارٹ ہونے کے بعد بھی برقرار رہے۔ جب یہ چیزیں صحیح کام کرتی ہیں تو یہ نظر نہیں آتیں، لیکن جب یہ ناکام ہوتی ہیں تو تباہ کن ثابت ہوتی ہیں۔
فیس سویپ بذات خود ایک دلچسپ ٹرک ہے۔ لیکن یہ ٹول صرف اس لیے حقیقی محسوس ہوتا ہے کیونکہ صارف فائل اپ لوڈ کر کے، چھوڑ کر، اور دوبارہ واپس آ سکتا ہے بغیر اپنی جگہ کھوئے (یعنی جہاں سے چھوڑا تھا وہیں سے شروع کر سکے)۔ یہی وہ چیز ہے جو ایک API کال کو ایسے سافٹ ویئر میں بدل دیتی ہے جس پر لوگ واقعی بھروسہ کرتے ہیں۔
