AI ഡെമോകൾ എവിടെയും കാണാം. ഒരു സിംഗിൾ Python സ്ക്രിപ്റ്റ് ഉപയോഗിച്ച് ഒരു സ്റ്റാറ്റിക് ഫോട്ടോയിലെ മുഖം മാറ്റാൻ സാധിക്കും, അതിന്റെ ഫലം അത്ഭുതകരമായിരിക്കും. എന്നാൽ യഥാർത്ഥ ആളുകൾക്ക് അപ്ലോഡ് ചെയ്യാനും, ഉപയോഗിച്ചു നിർത്താനും, പിന്നീട് തിരിച്ചുവരാനും കഴിയുന്ന ഒന്ന് നിർമ്മിക്കുക എന്നത് തികച്ചും വ്യത്യസ്തമായ ഒരു ജോലിയാണ്. ഞാൻ അടുത്തിടെ ഒരു വെബ് ടൂൾ നിർമ്മിച്ചു; ഇത് ഒരു അനിമേറ്റഡ് GIF-ഉം ഒരു റഫറൻസ് മുഖവും സ്വീകരിച്ച്, എല്ലാ ഫ്രെയിമുകളിലും ആ മുഖം മാറ്റി അതേ അനിമേഷൻ തിരികെ നൽകുന്നു. മോഡൽ ആണ് ഇതിന്റെ ദൃശ്യപരമായ പ്രധാന ജോലികൾ ചെയ്യുന്നത്, എന്നാൽ യഥാർത്ഥ എഞ്ചിനീയറിംഗ് പരിശ്രമം അതിന്റെ ചുറ്റുമുള്ള ആർക്കിടെക്ചറിലായിരുന്നു: കണക്ഷനുകൾ നിലനിർത്തുക, പേജ് റിഫ്രഷ് ചെയ്യുമ്പോഴും തകരാറില്ലാതെ പ്രവർത്തിക്കുക, കൂടാതെ രണ്ട് മിനിറ്റ് നീണ്ടുനിൽക്കുന്ന ഒരു inference ജോബ് 504 Gateway Timeout ആയി മാറുന്നില്ലെന്ന് ഉറപ്പാക്കുക എന്നിവയായിരുന്നു അത്.
ഇതൊരു പ്രോട്ടോടൈപ്പും പ്രോഡക്റ്റും തമ്മിലുള്ള വ്യത്യാസമാണ്. എഞ്ചിനീയർമാർ diffusion ആർക്കിടെക്ചറുകളെക്കുറിച്ചും inference പാരാമീറ്ററുകളെക്കുറിച്ചും സംസാരിക്കാൻ ഇഷ്ടപ്പെടുന്നു. എന്നാൽ ഒരു ഉപയോക്താവ് ഇരുനൂറ് ഫ്രെയിമുകളുള്ള ഒരു വലിയ GIF അപ്ലോഡ് ചെയ്യുമ്പോൾ, മുപ്പത് സെക്കൻഡിന് ശേഷം ബ്രൗസർ ടാബ് പരാജയപ്പെട്ടാൽ നിങ്ങളുടെ മോഡലിനെക്കുറിച്ച് ആരും ശ്രദ്ധിക്കില്ല. Inference-നെ ചുറ്റിപ്പറ്റിയുള്ള ഇൻഫ്രാസ്ട്രക്ചറിനും inference പോലെ തന്നെ പ്രാധാന്യമുണ്ട്.
കാത്തിരിക്കലിലെ പ്രശ്നം
സാധാരണ വെബ് ആർക്കിടെക്ചർ വേഗത്തിലുള്ള പ്രതികരണങ്ങളെയാണ് പ്രതീക്ഷിക്കുന്നത്. ഒരു ഉപയോക്താവ് ഒരു ബട്ടൺ ക്ലിക്ക് ചെയ്യുന്നു, സെർവർ മറുപടി നൽകുന്നു, പേജ് അപ്ഡേറ്റ് ആകുന്നു. ഡസൻ കണക്കിന് GIF ഫ്രെയിമുകളിലുടനീളം മുഖം മാറ്റുന്നത് ഈ അനുമാനത്തെ ഉടൻ തന്നെ തകർക്കുന്നു. മോഡൽ പ്രവർത്തിക്കുന്നത് Replicate-ന്റെ GPU-കളിലാണ്, എന്റെ സെർവറിലല്ല, അതിനാൽ ഒരു വലിയ GIF പ്രോസസ്സ് ചെയ്യാൻ ഒരു മിനിറ്റോ അതിൽ കൂടുതലോ എളുപ്പത്തിൽ എടുക്കാം. ഇത്രയും നേരം ഒരു HTTP റിക്വസ്റ്റ് തുറന്നു പിടിക്കാൻ ശ്രമിച്ചാൽ അത് പ്രശ്നങ്ങൾക്ക് കാരണമാകും. Load balancers ഉപയോഗശൂന്യമായ കണക്ഷനുകൾ വിച്ഛേദിക്കും. ബ്രൗസറുകൾ നെറ്റ്വർക്ക് പരാജയപ്പെട്ടുവെന്ന് കരുതി വീണ്ടും ശ്രമിക്കും. ഉപയോക്താക്കൾ ഫ്രീസ് ആയ ഒരു സ്പിന്നർ നോക്കി ഇരിക്കുകയും ആപ്പ് തകരാറിലായെന്ന് കരുതുകയും ചെയ്യും.
സബ്മിഷനും റിസൾട്ടും തമ്മിൽ വേർതിരിച്ചുകൊണ്ട് (decoupling) ഞാൻ ഇത് പൂർണ്ണമായും ഒഴിവാക്കി. ഒരു ഉപയോക്താവ് ഒരു GIF-ഉം ഒരു മുഖത്തിന്റെ ചിത്രവും അപ്ലോഡ് ചെയ്യുമ്പോൾ, എന്റെ Next.js ബാക്കെൻഡ് Replicate-ൽ ഒരു prediction ആരംഭിക്കുകയും ഉടൻ തന്നെ ഒരു job ID നൽകുകയും ചെയ്യുന്നു. ഉപയോക്താവിന് ഉടനടി സ്ഥിരീകരണം ലഭിക്കുന്നു. GPU ജോലി പൂർത്തിയാകുമ്പോൾ webhook വഴി യഥാർത്ഥ ഫലം പിന്നീട് ലഭിക്കുന്നു. ഈ രീതി പുതിയതല്ല, എന്നാൽ ദീർഘനേരം നീണ്ടുനിൽക്കുന്ന മീഡിയ ജോബുകൾക്ക് ഇത് അത്യന്താപേക്ഷിതമാണ്. ഇത് പ്രവചനാതീതമായ കാത്തിരിപ്പിനെ ആത്മവിശ്വാസമുള്ള ഒരു കൈമാറ്റമാക്കി മാറ്റുന്നു: ജോലി സ്വീകരിക്കപ്പെട്ടു, അത് പൂർത്തിയാകുമ്പോൾ നിങ്ങൾക്ക് അറിയിപ്പ് ലഭിക്കും.
നിങ്ങൾക്ക് വിശ്വസിക്കാവുന്ന ഒരു സ്റ്റേറ്റ് മെഷീൻ നിർമ്മിക്കുക
നിങ്ങൾ asynchronous രീതിയിലേക്ക് മാറുമ്പോൾ, നിങ്ങൾക്ക് വിസിബിലിറ്റി ആവശ്യമാണ്. ഉപയോക്താക്കൾ പേജ് റിഫ്രഷ് ചെയ്തേക്കാം. അവർ ടാബ് അടച്ച് വീണ്ടും തുറന്നേക്കാം. അവർ ലിങ്ക് കോപ്പി ചെയ്ത് ഒരു സഹപ്രവർത്തകന് അയച്ചേക്കാം, അവർ അത് രണ്ട് മണിക്കൂർ കഴിഞ്ഞ് പരിശോധിച്ചേക്കാം. എന്ത് സംഭവിച്ചു എന്നതിനെക്കുറിച്ച് കൃത്യമായ റെക്കോർഡ് ഇല്ലെങ്കിൽ, അവിടെ കുഴപ്പങ്ങൾ ഉണ്ടാകും.
സിംഗിൾ സോഴ്സ് ഓഫ് ട്രൂത്ത് (single source of truth) ആയി ഞാൻ Supabase ഉപയോഗിച്ചു. ഓരോ അപ്ലോഡും ഒരു യുണീക് job ID ഉള്ള ഒരു റോ (row) സൃഷ്ടിക്കുന്നു, ആ റോ പ്രത്യേക സ്റ്റേറ്റുകളിലൂടെ നീങ്ങുന്നു: queued, processing, succeeded, failed, അല്ലെങ്കിൽ expired. ഉപയോക്താവ് ആദ്യമായി സബ്മിറ്റ് ചെയ്യുമ്പോൾ, റോ 'queued' അവസ്ഥയിലായിരിക്കും. Replicate പ്രെഡിക്ഷൻ സ്വീകരിക്കുന്ന നിമിഷം അത് 'processing' ലേക്ക് മാറുന്നു. Webhook അത് 'succeeded' അല്ലെങ്കിൽ 'failed' ലേക്ക് മാറ്റുന്നു. ഒരു callback ഇല്ലാതെ ദീർഘനേരം നിൽക്കുന്ന ജോബുകൾക്കായി ഞാൻ 'expired' എന്ന സ്റ്റേറ്റ് കൂടി ചേർത്തു, അങ്ങനെ സിസ്റ്റം അനന്തമായി ഒന്നിനെ തേടി നടക്കാതിരിക്കും.
TypeScript ഉപയോഗിച്ച് നിർമ്മിച്ച ഫ്രണ്ട്എൻഡ്, ചെറിയ ഇടവേളകളിൽ Supabase-ൽ നിന്ന് വിവരങ്ങൾ ശേഖരിക്കുകയും (polling) നിലവിലെ സ്റ്റേറ്റ് എന്താണോ അത് കാണിക്കുകയും ചെയ്യുന്നു. ഈ polling രീതി പ്രാഥമികമായി തോന്നാമെങ്കിലും, ഇത് റിഫ്രഷ് പ്രശ്നം പൂർണ്ണമായും പരിഹരിക്കുന്നു. ഒരു ഉപയോക്താവിന് അവരുടെ ലാപ്ടോപ്പ് അടച്ചു വെച്ച്, നാളെ അത് തുറക്കുമ്പോൾ കാര്യങ്ങൾ എവിടെ എത്തി എന്ന് കൃത്യമായി കാണാൻ കഴിയും, കാരണം ബ്രൗസർ മെമ്മറിയല്ല, ഡാറ്റാബേസ് ആണ് പുരോഗതി കൈകാര്യം ചെയ്യുന്നത്. Supabase ക്രെഡിറ്റുകളും ട്രാക്ക് ചെയ്യുന്നു, അതിനാൽ സ്റ്റേറ്റ് ട്രാക്ക് ചെയ്യുന്ന അതേ ജോബ് റെക്കോർഡുമായി അക്കൗണ്ടിംഗും ബന്ധപ്പെട്ടിരിക്കുന്നു. എല്ലാം ഒരിടത്ത് തന്നെ നിലനിൽക്കുന്നു.
ബ്രൗസറിനെ ബാധിക്കാതെ ഫയലുകൾ കൈകാര്യം ചെയ്യുക
ആളുകൾ വിചാരിക്കുന്നതിനേക്കാൾ ഭാരമുള്ളവയാണ് GIFs. AI പൈപ്പ്ലൈനിന് അനുയോജ്യമായ ഒരു ഫയലിന് പോലും മെഗാബൈറ്റുകളുടെ വലിപ്പം ഉണ്ടാകാം. അത് ബ്രൗസറിനുള്ളിൽ ഒരു ലൂപ്പിംഗ് പ്രിവ്യൂ ആയി കാണിക്കുന്നത് പെർഫോമൻസിനെ ബാധിക്കും, പ്രത്യേകിച്ച് കുറഞ്ഞ ശേഷിയുള്ള ഉപകരണങ്ങളിൽ. എനിക്ക് രണ്ട് വ്യത്യസ്ത ഫയൽ പൈപ്പ്ലൈനുകൾ ആവശ്യമായിരുന്നു: ഒന്ന് AI-ക്ക് വേണ്ടി, മറ്റൊന്ന് യൂസർ ഇന്റർഫേസിനായി.
പ്രിവ്യൂകൾക്കായി, WebAssembly-ലേക്ക് കംപൈൽ ചെയ്ത FFmpeg ഉപയോഗിച്ച് ഞാൻ വലിയ GIF-കളെ അനിമേറ്റഡ് WebP-ലേക്ക് മാറ്റുന്നു. ഇത് പൂർണ്ണമായും ക്ലയന്റ് സൈഡിൽ ബ്രൗസറിൽ തന്നെ പ്രവർത്തിക്കുന്നു. ഇതിന്റെ ഫലം ഒറിജിനൽ ഫയലിൽ തൊടാതെ തന്നെ ഇന്റർഫേസ് വേഗത്തിൽ പ്രവർത്തിപ്പിക്കാൻ സഹായിക്കുന്ന ഒരു ലൈറ്റ് വെയ്റ്റ് പ്രിവ്യൂ ആണ്. Replicate-ലേക്ക് അയക്കുന്ന GIF മാറ്റമില്ലാതെ തന്നെ ഇരിക്കുന്നു. ഈ വേർതിരിവ് പ്രധാനമാണ്. പ്രിവ്യൂവിൽ നിന്നുള്ള compression artifacts നിങ്ങളുടെ ട്രെയിനിംഗ് ഡാറ്റയിലോ ഫൈനൽ റെൻഡറിലോ കലരാൻ നിങ്ങൾ ആഗ്രഹിക്കില്ല, കൂടാതെ AI ചിന്തിച്ചുകൊണ്ടിരിക്കുമ്പോൾ ഒരു മൾട്ടി-മെഗാബൈറ്റ് ഫയൽ കാരണം യൂസർ ഇന്റർഫേസ് തടസ്സപ്പെടാനും നിങ്ങൾ ആഗ്രഹിക്കില്ല.
അപ്ലോഡ് ബ്രൗസറിൽ നിന്ന് പുറത്തുപോകുന്നതിന് മുമ്പ് മറ്റ് GIF ജോലികളും FFmpeg WASM കൈകാര്യം ചെയ്യുന്നു. ഫ്രെയിം എണ്ണം പരിശോധിക്കാനും, ഡൈമൻഷനുകൾ ശരിയാണോ എന്ന് ഉറപ്പാക്കാനും, കേടുപാടുള്ള ഫയലുകൾ നേരത്തെ കണ്ടെത്താനും ഞാൻ ഇത് ഉപയോഗിക്കുന്നു. GPU ക്രെഡിറ്റുകൾ നഷ്ടപ്പെടുന്നതിന് മുമ്പ് പ്രശ്നങ്ങൾ കണ്ടെത്തുന്നത് പണവും ഉപയോക്താവിന്റെ ക്ഷമയും ലാഭിക്കാൻ സഹായിക്കുന്നു.
Turning a Demo Into Software People Trust
There is a broader lesson here that applies to nearly every generative AI tool on the market. The model itself might be thirty percent of the work. The other seventy percent is the unglamorous plumbing that nobody tweets about: state recovery, webhook signatures, file conversion, credit tracking, and graceful failure.
My stack is simple and deliberate. Next.js and TypeScript handle the interface and API routes. Replicate runs the models. Supabase manages states, data, and credits. FFmpeg WASM handles client-side media work. Animated WebP keeps the UI fast. Each piece has one job, and they connect through explicit state transitions rather than fragile, long-lived requests.
When a user trades credits for a face swap, they expect reliability, not a research paper. If a prediction fails, the system should know and say so. If the user waits, they should have a lightweight preview to look at and a status that survives a browser restart. These details are invisible when they work, and fatal when they do not.
The face swap itself is a neat trick. But the tool only feels real because a user can upload, leave, and return without losing their place. That is what turns an API call into software people actually trust.
