Maonyesho ya AI yapo kila mahali. Script moja ya Python inaweza kubadilisha uso kwenye picha tuli, na matokeo yanaonekana kama uchawi. Lakini kujenga kitu ambacho watu halisi wanaweza kukipandisha (upload), kukiacha, na kisha kurudi kukikuta? Hilo ni kazi tofauti kabisa. Hivi karibuni nilijenga zana ya wavuti inayochukua GIF inayocheza na uso wa rejeleo, kisha inarudisha animation hiyo hiyo ikiwa na uso uliobadilishwa kwenye kila fremu. Modeli inafanya kazi kubwa ya kuona (visual heavy lifting), lakini juhudi halisi za kihandisi ziliwekwa kwenye usanifu (architecture) inayozunguka: kuweka miunganisho hai, kuhimili kusasishwa kwa ukurasa (page refreshes), na kuhakikisha kazi ya inference ya dakika mbili haipotei kwenye 504 Gateway Timeout.
Hii ndiyo pengo kati ya prototaipe na bidhaa. Wahandisi wanapenda kuzungumzia usanifu wa diffusion na vigezo vya inference. Lakini mtumiaji anapopandisha GIF nzito yenye fremu mia mbili, hakuna anayejali kuhusu modeli yako ikiwa tab ya kivinjari (browser tab) itakataa baada ya sekunde thirti. Miundombinu inayozunguka inference ni muhimu sawa na inference yenyewe.
Tatizo la Kusubiri
Usanifu wa kawaida wa wavuti unadhani majibu ni ya haraka. Mtumiaji anabonyeza kitufe, seva inajibu, na ukurasa unasasishwa. Kubadilisha uso kwenye fremu nyingi za GIF kunavunja dhana hiyo mara moja. Modeli inafanya kazi kwenye GPU za Replicate, si kwenye seva yangu, na GIF ndefu inaweza kuchukua dakika moja au zaidi kuchakatwa. Ukijaribu kuweka ombi la HTTP wazi kwa muda huo mrefu, unatafuta matatizo. Load balancers hukata miunganisho isiyotumika (idle connections). Kivinjari (browser) hudhani mtandao umefeli na kujaribu tena. Watumiaji hutazama spinner iliyoganda na kudhani programu imeharibika.
Nilikwepa hili kabisa kwa kutenganisha uwasilishaji (submission) na matokeo. Mtumiaji anapopandisha GIF na picha ya uso, backend yangu ya Next.js huanza utabiri (prediction) kwenye Replicate na kurudisha ID ya kazi mara moja. Mtumiaji anapata uthibitisho wa haraka. Matokeo halisi yanakuja baadaye kupitia webhook mara tu kazi ya GPU inapomalizika. Mtindo huu si wa ajabu, lakini kwa kazi za media zinazochukua muda mrefu, ni muhimu sana. Unageuza kusubiri kutorabika kuwa makubaliano ya uhakika: kazi imekubaliwa, na utajulishwa itakapomalizika.
Kujenga State Machine Unayoweza Kuamini
Ukianza kutumia mfumo wa asynchronous, unahitaji uwezo wa kuona kinachoendelea (visibility). Watumiaji watasafisha ukurasa. Watafunga tab na kuifungua tena. Watanakili kiungo na kumtumia mfanyakazi mwenzake ambaye atakikagua baada ya saa mbili. Bila rekodi ya kudumu ya kilichotokea, unapata vurugu.
Nilitumia Supabase kama chanzo kimoja cha ukweli (single source of truth). Kila upandishaji (upload) unaunda mstari (row) wenye ID ya kazi ya kipekee, na mstari huo unapita katika hali (states) maalum: queued, processing, succeeded, failed, au expired. Mtumiaji anapobonyeza submit kwa mara ya kwanza, mstari huo unawekwa kwenye queue (queued). Wakati Replicate inapokubali utabiri, inahamia kwenye processing. Webhook inaupeleka kwenye succeeded au failed. Niliongeza expired kwa kazi zinazokaa kwa muda mrefu bila callback, ili mfumo usihangaike na vitu visivyokuwepo (chase ghosts) milele.
Frontend, iliyojengwa kwa TypeScript, hufanya polling kwenye Supabase kwa muda mfupi na kuonyesha hali ya sasa. Polling hii inaonekana ya kizamani, lakini inatatua tatizo la kusafisha ukurasa (refresh) kikamilifu. Mtumiaji anaweza kufunga laptop yake, kuifungua kesho, na kuona hali ilivyo kwa usahihi kwa sababu kanzi data (database)—si kumbukumbu ya kivinjari (browser memory)—ndiyo inayomiliki maendeleo hayo. Supabase pia hufuatilia mikopo (credits), hivyo hesabu inabaki imeunganishwa na rekodi ile ile ya kazi inayofuatilia hali. Kila kitu kipo sehemu moja.
Kushughulikia Faili Bila Kulemea Kivinjari
GIF ni nzito kuliko watu wanavyofikiri. Faili ambalo lina ukubwa unaofaa kwa AI pipeline bado linaweza kuwa na megabytes kadhaa. Kuonyesha (rendering) hilo kama preview inayojirudia ndani ya kivinjari kutaharibu utendaji, hasa kwenye vifaa vya hali ya chini. Nilihitaji mifumo miwili tofauti kabisa ya faili: mmoja kwa ajili ya AI, na mmoja kwa ajili ya kiolesura cha mtumiaji (user interface).
Kwa ajili ya previews, nabadilisha GIF kubwa kuwa WebP inayocheza kwa kutumia FFmpeg iliyokusanywa (compiled) kwenda WebAssembly. Hii inafanya kazi upande wa mteja (client-side) ndani ya kivinjari. Matokeo yake ni preview nyepesi inayofanya kiolesura kiwe na kasi bila kugusa faili asilia. GIF inayotumwa kwa Replicate inabaki bila kuguswa. Utengano huo ni muhimu. Hutaki makosa ya kubana (compression artifacts) kutoka kwenye preview kuingia kwenye data yako ya mafunzo au render yako ya mwisho, na hutaki kiolesura cha mtumiaji kukwama kwenye faili kubwa la megabytes nyingi wakati AI bado inafikiri.
FFmpeg WASM pia hushughulikia kazi nyingine za GIF kabla ya upandishaji (upload) kuondoka kwenye kivinjari. Naitumia kuchanganua idadi ya fremu, kuhakiki vipimo, na kukamata faili zilizoharibika mapema. Kukamata tatizo kabla halijatumia mikopo ya GPU kunaokoa pesa na uvumilivu wa mtumiaji.
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.
