बैकग्राउंड फ़ेच एपीआई की मदद से एआई मॉडल डाउनलोड करना

पब्लिश होने की तारीख: 20 फ़रवरी, 2025

बड़े एआई मॉडल को भरोसेमंद तरीके से डाउनलोड करना एक मुश्किल काम है. अगर उपयोगकर्ताओं का इंटरनेट कनेक्शन बंद हो जाता है या वे आपकी वेबसाइट या वेब ऐप्लिकेशन बंद कर देते हैं, तो वे मॉडल की आंशिक रूप से डाउनलोड की गई फ़ाइलें खो देते हैं. ऐसे में, उन्हें आपके पेज पर वापस आने पर, मॉडल को फिर से डाउनलोड करना पड़ता है. बैकग्राउंड फ़ेच एपीआई का इस्तेमाल करके, उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है.

Browser Support

  • Chrome: 74.
  • Edge: 79.
  • Firefox: not supported.
  • Safari: not supported.

Source

सर्विस वर्कर रजिस्टर करना

बैकग्राउंड फ़ेच एपीआई के लिए, आपके ऐप्लिकेशन को सर्विस वर्कर रजिस्टर करना होगा.

if ('serviceWorker' in navigator) {
  window.addEventListener('load', async () => {
    const registration = await navigator.serviceWorker.register('sw.js');
    console.log('Service worker registered for scope', registration.scope);
  });
}

बैकग्राउंड फ़ेच को ट्रिगर करना

ब्राउज़र फ़ेच करते समय, उपयोगकर्ता को प्रोग्रेस दिखाता है. साथ ही, उसे डाउनलोड रद्द करने का तरीका बताता है. डाउनलोड पूरा होने के बाद, ब्राउज़र सर्विस वर्कर शुरू करता है. इसके बाद, ऐप्लिकेशन जवाब के साथ कार्रवाई कर सकता है.

Background Fetch API, ऑफ़लाइन होने पर भी फ़ेच करने की प्रोसेस शुरू करने के लिए तैयार कर सकता है. उपयोगकर्ता के फिर से कनेक्ट होते ही, डाउनलोड शुरू हो जाता है. अगर उपयोगकर्ता ऑफ़लाइन हो जाता है, तो यह प्रोसेस तब तक रुक जाती है, जब तक उपयोगकर्ता फिर से ऑनलाइन नहीं हो जाता.

इस उदाहरण में, उपयोगकर्ता Gemma 2B को डाउनलोड करने के लिए एक बटन पर क्लिक करता है. डेटा फ़ेच करने से पहले, हम यह देखते हैं कि मॉडल को पहले डाउनलोड और कैश किया गया था या नहीं. इससे हम गैर-ज़रूरी संसाधनों का इस्तेमाल नहीं करते. अगर यह कैश मेमोरी में सेव नहीं है, तो हम बैकग्राउंड फ़ेच शुरू करते हैं.

const FETCH_ID = 'gemma-2b';
const MODEL_URL =
  'https://storage.googleapis.com/jmstore/kaggleweb/grader/g-2b-it-gpu-int4.bin';

downloadButton.addEventListener('click', async (event) => {
  // If the model is already downloaded, return it from the cache.
  const modelAlreadyDownloaded = await caches.match(MODEL_URL);
  if (modelAlreadyDownloaded) {
    const modelBlob = await modelAlreadyDownloaded.blob();
    // Do something with the model.
    console.log(modelBlob);
    return;
  }

  // The model still needs to be downloaded.
  // Feature detection and fallback to classic `fetch()`.
  if (!('BackgroundFetchManager' in self)) {
    try {
      const response = await fetch(MODEL_URL);
      if (!response.ok || response.status !== 200) {
        throw new Error(`Download failed ${MODEL_URL}`);
      }
      const modelBlob = await response.blob();
      // Do something with the model.
      console.log(modelBlob);
      return;
    } catch (err) {
      console.error(err);
    }
  }

  // The service worker registration.
  const registration = await navigator.serviceWorker.ready;

  // Check if there's already a background fetch running for the `FETCH_ID`.
  let bgFetch = await registration.backgroundFetch.get(FETCH_ID);

  // If not, start a background fetch.
  if (!bgFetch) {
    bgFetch = await registration.backgroundFetch.fetch(FETCH_ID, MODEL_URL, {
      title: 'Gemma 2B model',
      icons: [
        {
          src: 'icon.png',
          size: '128x128',
          type: 'image/png',
        },
      ],
      downloadTotal: await getResourceSize(MODEL_URL),
    });
  }
});

getResourceSize() फ़ंक्शन, डाउनलोड के बाइट साइज़ की जानकारी देता है. HEAD अनुरोध करके, इसे लागू किया जा सकता है.

const getResourceSize = async (url) => {
  try {
    const response = await fetch(url, { method: 'HEAD' });
    if (response.ok) {
      return response.headers.get('Content-Length');
    }
    console.error(`HTTP error: ${response.status}`);
    return 0;
  } catch (error) {
    console.error('Error fetching content size:', error);
    return 0;
  }
};

रिपोर्ट डाउनलोड होने की प्रोग्रेस

बैकग्राउंड फ़ेच शुरू होने के बाद, ब्राउज़र BackgroundFetchRegistration दिखाता है. इसका इस्तेमाल, उपयोगकर्ता को डाउनलोड की प्रोग्रेस के बारे में बताने के लिए किया जा सकता है. इसके लिए, progress इवेंट का इस्तेमाल करें.

bgFetch.addEventListener('progress', (e) => {
  // There's no download progress yet.
  if (!bgFetch.downloadTotal) {
    return;
  }
  // Something went wrong.
  if (bgFetch.failureReason) {
    console.error(bgFetch.failureReason);
  }
  if (bgFetch.result === 'success') {
    return;
  }
  // Update the user about progress.
  console.log(`${bgFetch.downloaded} / ${bgFetch.downloadTotal}`);
});

डेटा फ़ेच होने की सूचना उपयोगकर्ताओं और क्लाइंट को देना

बैकग्राउंड फ़ेच पूरा होने पर, आपके ऐप्लिकेशन के सर्विस वर्कर को backgroundfetchsuccess इवेंट मिलता है.

यह कोड, सर्विस वर्कर में शामिल होता है. आखिर में किया गया updateUI() कॉल, ब्राउज़र के इंटरफ़ेस को अपडेट करता है. इससे उपयोगकर्ता को बैकग्राउंड फ़ेच के पूरा होने की सूचना मिलती है. आखिर में, क्लाइंट को डाउनलोड पूरा होने के बारे में बताएं. उदाहरण के लिए, postMessage() का इस्तेमाल करें.

self.addEventListener('backgroundfetchsuccess', (event) => {
  // Get the background fetch registration.
  const bgFetch = event.registration;

  event.waitUntil(
    (async () => {
      // Open a cache named 'downloads'.
      const cache = await caches.open('downloads');
      // Go over all records in the background fetch registration.
      // (In the running example, there's just one record, but this way
      // the code is future-proof.)
      const records = await bgFetch.matchAll();
      // Wait for the response(s) to be ready, then cache it/them.
      const promises = records.map(async (record) => {
        const response = await record.responseReady;
        await cache.put(record.request, response);
      });
      await Promise.all(promises);

      // Update the browser UI.
      event.updateUI({ title: 'Model downloaded' });

      // Inform the clients that the model was downloaded.
      self.clients.matchAll().then((clientList) => {
        for (const client of clientList) {
          client.postMessage({
            message: 'download-complete',
            id: bgFetch.id,
          });
        }
      });
    })(),
  );
});

सर्विस वर्कर से मैसेज पाना

क्लाइंट पर डाउनलोड पूरा होने के बारे में भेजे गए मैसेज को पाने के लिए, message इवेंट सुनें. सर्विस वर्कर से मैसेज मिलने के बाद, एआई मॉडल के साथ काम किया जा सकता है. साथ ही, इसे Cache API की मदद से सेव किया जा सकता है.

navigator.serviceWorker.addEventListener('message', async (event) => {
  const cache = await caches.open('downloads');
  const keys = await cache.keys();
  for (const key of keys) {
    const modelBlob = await cache
      .match(key)
      .then((response) => response.blob());
    // Do something with the model.
    console.log(modelBlob);
  }
});

बैकग्राउंड फ़ेच करने की प्रोसेस रद्द करना

उपयोगकर्ता को डाउनलोड की जा रही फ़ाइल को रद्द करने की अनुमति देने के लिए, BackgroundFetchRegistration के abort() तरीके का इस्तेमाल करें.

const registration = await navigator.serviceWorker.ready;
const bgFetch = await registration.backgroundFetch.get(FETCH_ID);
if (!bgFetch) {
  return;
}
await bgFetch.abort();

मॉडल को कैश मेमोरी में सेव करना

डाउनलोड किए गए मॉडल को कैश मेमोरी में सेव करें, ताकि आपके उपयोगकर्ता मॉडल को सिर्फ़ एक बार डाउनलोड करें. Background Fetch API, डाउनलोड करने के अनुभव को बेहतर बनाता है. हालांकि, आपको हमेशा क्लाइंट-साइड एआई में सबसे छोटे मॉडल का इस्तेमाल करना चाहिए.

ये दोनों एपीआई मिलकर, उपयोगकर्ताओं के लिए क्लाइंट-साइड एआई का बेहतर अनुभव देने में आपकी मदद करते हैं.

डेमो

इस तरीके को पूरी तरह से लागू करने का तरीका, डेमो और इसके सोर्स कोड में देखा जा सकता है.

Chrome DevTools का ऐप्लिकेशन पैनल, बैकग्राउंड फ़ेच डाउनलोड करने के लिए खुला है.
Chrome DevTools की मदद से, बैकग्राउंड फ़ेच से जुड़े इवेंट की झलक देखी जा सकती है. इस डेमो में, 1.26 गीगाबाइट की कुल फ़ाइल में से 17.54 मेगाबाइट फ़ाइल डाउनलोड होते हुए दिखाई गई है. ब्राउज़र के डाउनलोड इंडिकेटर में भी, डाउनलोड हो रही फ़ाइल दिखती है.

Acknowledgements

इस गाइड की समीक्षा फ़्रांस्वा बोफ़ोर्ट, आंद्रे बंदारा, सेबैस्टियन बंज़, मॉड नल्पस, और ऐलेक्ज़ेंड्रा क्लेपर ने की है.