> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Supabase के साथ स्ट्रीमिंग और कैशिंग

> **Note**
>
> **कैसे करें गाइड** · मानता है कि आपने [ElevenAPI क्विकस्टार्ट](/docs/hi/eleven-api/quickstart) पूरा कर लिया है और आपका Supabase अकाउंट है।

## परिचय

इस गाइड में आप सीखेंगे कि Supabase Edge Functions, Supabase Storage और ElevenLabs का इस्तेमाल करके स्पीच जनरेट, स्ट्रीम, स्टोर और कैश करने के लिए एज API कैसे बनाएं।

## आवश्यकताएं

* API key वाला ElevenLabs अकाउंट। [API key](https://elevenlabs.io/app/settings/api-keys)
* [Supabase](https://supabase.com) अकाउंट ([database.new](https://database.new) से मुफ़्त अकाउंट के लिए साइन अप कर सकते हैं)।
* आपकी मशीन पर [Supabase CLI](https://supabase.com/docs/guides/local-development) इंस्टॉल हो।
* आपकी मशीन पर [Deno runtime](https://docs.deno.com/runtime/getting_started/installation/) इंस्टॉल हो और वैकल्पिक रूप से [अपने पसंदीदा IDE में सेटअप किया गया हो](https://docs.deno.com/runtime/getting_started/setup_your_environment)।

## सेटअप

### लोकल Supabase प्रोजेक्ट बनाएं

[Supabase CLI](https://supabase.com/docs/guides/local-development) इंस्टॉल करने के बाद, लोकली नया Supabase प्रोजेक्ट बनाने के लिए यह कमांड चलाएं:

```bash
supabase init
```

### स्टोरेज बकेट कॉन्फ़िगर करें

`config.toml` फ़ाइल में यह कॉन्फ़िगरेशन जोड़कर आप Supabase CLI को अपने-आप स्टोरेज बकेट जनरेट करने के लिए कॉन्फ़िगर कर सकते हैं:

**`./supabase/config.toml`**

```toml ./supabase/config.toml
[storage.buckets.audio]
public = false
file_size_limit = "50MiB"
allowed_mime_types = ["audio/mp3"]
objects_path = "./audio"
```

> **Note**
>
> `supabase start` चलाने पर यह आपके लोकल Supabase प्रोजेक्ट में नया स्टोरेज बकेट बनाएगा। अगर आप इसे अपने होस्ट किए गए Supabase प्रोजेक्ट में पुश करना चाहते हैं, तो `supabase seed
>   buckets --linked` चला सकते हैं।

### Supabase Edge Functions के लिए बैकग्राउंड टास्क कॉन्फ़िगर करें

लोकल डेवलपमेंट के दौरान Supabase Edge Functions में बैकग्राउंड टास्क इस्तेमाल करने के लिए, आपको `config.toml` फ़ाइल में यह कॉन्फ़िगरेशन जोड़ना होगा:

**`./supabase/config.toml`**

```toml ./supabase/config.toml
[edge_runtime]
policy = "per_worker"
```

> **Note**
>
> `per_worker` पॉलिसी के साथ चलाने पर, Function में किए गए बदलाव अपने-आप रीलोड नहीं होंगे। आपको
> `supabase functions serve` चलाकर इसे मैन्युअली रीस्टार्ट करना होगा।

### स्पीच जनरेशन के लिए Supabase Edge Function बनाएं

यह कमांड चलाकर नया Edge Function बनाएं:

```bash
supabase functions new text-to-speech
```

अगर आप VS Code या Cursor इस्तेमाल कर रहे हैं, तो जब CLI "Generate VS Code settings for Deno? \[y/N]" पूछे, तो `y` चुनें!

### एनवायरनमेंट वेरिएबल सेट अप करें

`supabase/functions` डायरेक्टरी में नई `.env` फ़ाइल बनाएं और ये वेरिएबल जोड़ें:

**`supabase/functions/.env`**

```env supabase/functions/.env
# Find / create an API key at https://elevenlabs.io/app/settings/api-keys
ELEVENLABS_API_KEY=your_api_key
```

### डिपेंडेंसीज़

प्रोजेक्ट कुछ डिपेंडेंसीज़ इस्तेमाल करता है:

* Supabase डेटाबेस के साथ इंटरैक्ट करने के लिए [@supabase/supabase-js](https://supabase.com/docs/reference/javascript) लाइब्रेरी।
* टेक्स्ट टू स्पीच API के साथ इंटरैक्ट करने के लिए ElevenLabs [JavaScript SDK](/docs/hi/eleven-api/quickstart)।
* रिक्वेस्ट पैरामीटर से हैश जनरेट करने के लिए ओपन-सोर्स [object-hash](https://www.npmjs.com/package/object-hash)।

Supabase Edge Function [Deno runtime](https://deno.land/) इस्तेमाल करता है, इसलिए आपको डिपेंडेंसीज़ इंस्टॉल करने की ज़रूरत नहीं है। इसके बजाय, आप `npm:` प्रीफ़िक्स के ज़रिए उन्हें [import](https://docs.deno.com/examples/npm/) कर सकते हैं।

## Supabase Edge Function का कोड लिखें

अपनी नई `supabase/functions/text-to-speech/index.ts` फ़ाइल में यह कोड जोड़ें:

**`supabase/functions/text-to-speech/index.ts`**

```ts supabase/functions/text-to-speech/index.ts
// Setup type definitions for built-in Supabase Runtime APIs
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { createClient } from "jsr:@supabase/supabase-js@2";
import { ElevenLabsClient } from "npm:elevenlabs";
import * as hash from "npm:object-hash";

const supabase = createClient(
  Deno.env.get("SUPABASE_URL")!,
  Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
);

const elevenlabs = new ElevenLabsClient({
  apiKey: Deno.env.get("ELEVENLABS_API_KEY"),
});

// Upload audio to Supabase Storage in a background task
async function uploadAudioToStorage(stream: ReadableStream, requestHash: string) {
  const { data, error } = await supabase.storage
    .from("audio")
    .upload(`${requestHash}.mp3`, stream, {
      contentType: "audio/mp3",
    });

  console.log("Storage upload result", { data, error });
}

Deno.serve(async (req) => {
  // To secure your function for production, you can for example validate the request origin,
  // or append a user access token and validate it with Supabase Auth.
  console.log("Request origin", req.headers.get("host"));
  const url = new URL(req.url);
  const params = new URLSearchParams(url.search);
  const text = params.get("text");
  const voiceId = params.get("voiceId") ?? "JBFqnCBsd6RMkjVDRZzb";

  const requestHash = hash.MD5({ text, voiceId });
  console.log("Request hash", requestHash);

  // Check storage for existing audio file
  const { data } = await supabase.storage.from("audio").createSignedUrl(`${requestHash}.mp3`, 60);

  if (data) {
    console.log("Audio file found in storage", data);
    const storageRes = await fetch(data.signedUrl);
    if (storageRes.ok) return storageRes;
  }

  if (!text) {
    return new Response(JSON.stringify({ error: "Text parameter is required" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  try {
    console.log("ElevenLabs API call");
    const response = await elevenlabs.textToSpeech.stream(voiceId, {
      output_format: "mp3_44100_128",
      model_id: "eleven_multilingual_v2",
      text,
    });

    const stream = new ReadableStream({
      async start(controller) {
        for await (const chunk of response) {
          controller.enqueue(chunk);
        }
        controller.close();
      },
    });

    // Branch stream to Supabase Storage
    const [browserStream, storageStream] = stream.tee();

    // Upload to Supabase Storage in the background
    EdgeRuntime.waitUntil(uploadAudioToStorage(storageStream, requestHash));

    // Return the streaming response immediately
    return new Response(browserStream, {
      headers: {
        "Content-Type": "audio/mpeg",
      },
    });
  } catch (error) {
    console.log("error", { error });
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500,
      headers: { "Content-Type": "application/json" },
    });
  }
});
```

### कोड को विस्तार से समझें

कोड में कुछ बातों पर ध्यान देना ज़रूरी है। आइए इसे चरण-दर-चरण समझते हैं।

#### आने वाली रिक्वेस्ट को हैंडल करें

आने वाली रिक्वेस्ट को हैंडल करने के लिए `Deno.serve` हैंडलर इस्तेमाल करें। डेमो में हम रिक्वेस्ट origin को वैलिडेट नहीं करते, लेकिन आप रिक्वेस्ट origin को वैलिडेट कर सकते हैं या यूज़र access token जोड़कर उसे [Supabase Auth](https://supabase.com/docs/guides/functions/auth) से वैलिडेट कर सकते हैं।

आने वाली रिक्वेस्ट से फ़ंक्शन `text` और `voiceId` पैरामीटर निकालता है। `voiceId` पैरामीटर वैकल्पिक है और डिफ़ॉल्ट रूप से "Allison" वॉइस के ElevenLabs ID पर सेट होता है।

`object-hash` लाइब्रेरी से फ़ंक्शन रिक्वेस्ट पैरामीटर का हैश जनरेट करता है। इस हैश का इस्तेमाल Supabase Storage में मौजूद ऑडियो फ़ाइलों को जांचने के लिए होता है।

```ts {1,5-8}
Deno.serve(async (req) => {
// To secure your function for production, you can for example validate the request origin,
// or append a user access token and validate it with Supabase Auth.
console.log("Request origin", req.headers.get("host"));
const url = new URL(req.url);
const params = new URLSearchParams(url.search);
const text = params.get("text");
const voiceId = params.get("voiceId") ?? "JBFqnCBsd6RMkjVDRZzb";

const requestHash = hash.MD5({ text, voiceId });
console.log("Request hash", requestHash);

// ...
})
```

#### Supabase Storage में मौजूद ऑडियो फ़ाइल देखें

Supabase Storage में [स्मार्ट CDN पहले से मौजूद है](https://supabase.com/docs/guides/storage/cdn/smart-cdn), जिससे आप अपनी फ़ाइलों को आसानी से कैश और सर्व कर सकते हैं।

यहां फ़ंक्शन Supabase Storage में मौजूदा ऑडियो फ़ाइल जांचता है। फ़ाइल मौजूद होने पर, फ़ंक्शन Supabase Storage से फ़ाइल लौटाता है।

```ts {4,9}
const { data } = await supabase
  .storage
  .from("audio")
  .createSignedUrl(`${requestHash}.mp3`, 60);

if (data) {
  console.log("Audio file found in storage", data);
  const storageRes = await fetch(data.signedUrl);
  if (storageRes.ok) return storageRes;
}
```

#### स्पीच को स्ट्रीम के रूप में जनरेट करें और दो ब्रांच में बांटें

ElevenLabs API की स्ट्रीमिंग क्षमताओं से फ़ंक्शन एक स्ट्रीम जनरेट करता है। इसका फ़ायदा यह है कि बड़े टेक्स्ट के लिए भी आप तुरंत यूज़र को ऑडियो स्ट्रीम करना शुरू कर सकते हैं, और बैकग्राउंड में स्ट्रीम को Supabase Storage में अपलोड कर सकते हैं।

इससे सबसे बेहतर यूज़र अनुभव मिलता है और बड़े टेक्स्ट ब्लॉक भी जादुई रूप से तेज़ लगते हैं। यहां जादू लाइन 17 पर होता है, जहां `stream.tee()` मेथड readable stream को दो ब्रांच में बांटता है: एक ब्राउज़र के लिए और एक Supabase Storage के लिए।

```ts {1,17,20,22-27}
try {
  const response = await elevenlabs.textToSpeech.stream(voiceId, {
    output_format: "mp3_44100_128",
    model_id: "eleven_multilingual_v2",
    text,
  });

  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of response) {
        controller.enqueue(chunk);
      }
      controller.close();
    },
  });

  // Branch stream to Supabase Storage
  const [browserStream, storageStream] = stream.tee();

  // Upload to Supabase Storage in the background
  EdgeRuntime.waitUntil(uploadAudioToStorage(storageStream, requestHash));

  // Return the streaming response immediately
  return new Response(browserStream, {
    headers: {
      "Content-Type": "audio/mpeg",
    },
  });
} catch (error) {
  console.log("error", { error });
  return new Response(JSON.stringify({ error: error.message }), {
    status: 500,
    headers: { "Content-Type": "application/json" },
  });
}
```

#### बैकग्राउंड में ऑडियो स्ट्रीम को Supabase Storage में अपलोड करें

पिछले चरण में लाइन 20 पर मौजूद `EdgeRuntime.waitUntil` मेथड, `uploadAudioToStorage` फ़ंक्शन के ज़रिए बैकग्राउंड में ऑडियो स्ट्रीम को Supabase Storage में अपलोड करने के लिए इस्तेमाल होता है। इससे फ़ंक्शन तुरंत ब्राउज़र को स्ट्रीमिंग रिस्पॉन्स लौटा सकता है, जबकि ऑडियो Supabase Storage में अपलोड हो रहा होता है।

स्टोरेज ऑब्जेक्ट बन जाने के बाद, अगली बार जब आपके यूज़र उन्हीं पैरामीटर के साथ रिक्वेस्ट करेंगे, तो फ़ंक्शन Supabase Storage CDN से ऑडियो फ़ाइल लौटाएगा।

```ts {2,8-10}
// Upload audio to Supabase Storage in a background task
async function uploadAudioToStorage(
  stream: ReadableStream,
  requestHash: string,
) {
  const { data, error } = await supabase.storage
    .from("audio")
    .upload(`${requestHash}.mp3`, stream, {
      contentType: "audio/mp3",
    });

  console.log("Storage upload result", { data, error });
}
```

## लोकली चलाएं

फ़ंक्शन को लोकली चलाने के लिए ये कमांड चलाएं:

```bash
supabase start
```

लोकल Supabase स्टैक के चालू हो जाने के बाद, फ़ंक्शन शुरू करने और लॉग देखने के लिए यह कमांड चलाएं:

```bash
supabase functions serve
```

### आज़माएं

फ़ंक्शन को काम करते सुनने के लिए `http://127.0.0.1:54321/functions/v1/text-to-speech?text=hello%20world` पर जाएं।

इसके बाद, अपने लोकल Supabase Storage बकेट में ऑडियो फ़ाइल देखने के लिए `http://127.0.0.1:54323/project/default/storage/buckets/audio` पर जाएं।

## Supabase पर डिप्लॉय करें

अगर आपने पहले से नहीं किया है, तो [database.new](https://database.new) पर नया Supabase अकाउंट बनाएं और लोकल प्रोजेक्ट को अपने Supabase अकाउंट से लिंक करें:

```bash
supabase link
```

हो जाने पर, फ़ंक्शन डिप्लॉय करने के लिए यह कमांड चलाएं:

```bash
supabase functions deploy
```

### फ़ंक्शन सीक्रेट्स सेट करें

अब जब आपके सभी सीक्रेट्स लोकली सेट हो गए हैं, तो अपने Supabase प्रोजेक्ट में सीक्रेट्स सेट करने के लिए यह कमांड चलाएं:

```bash
supabase secrets set --env-file supabase/functions/.env
```

## फ़ंक्शन टेस्ट करें

फ़ंक्शन को इस तरह डिज़ाइन किया गया है कि इसे सीधे `<audio>` एलिमेंट के स्रोत के रूप में इस्तेमाल किया जा सकता है।

```html
<audio
  src="https://${SUPABASE_PROJECT_REF}.supabase.co/functions/v1/text-to-speech?text=Hello%2C%20world!&voiceId=JBFqnCBsd6RMkjVDRZzb"
  controls
/>
```

## अगले चरण

#### [TTS स्ट्रीमिंग](/docs/hi/eleven-api/guides/how-to/text-to-speech/streaming)

आसान शुरुआत के लिए Supabase के बिना ऑडियो को क्रमिक रूप से स्ट्रीम करें।

#### [API रेफरेंस](/docs/hi/api-reference/text-to-speech/stream)

पूरा TTS स्ट्रीमिंग API रेफरेंस और पैरामीटर।