AI-translated from English; not yet reviewed by a fluent editor.

# OpenAI Realtime দিয়ে স্থানীয় ব্রাউজারে কণ্ঠের কথোপকথন তৈরি করুন

> WebRTC-তে OpenAI Realtime দিয়ে ব্রাউজারের মাইক্রোফোনের স্থানীয় কথোপকথন তৈরি করুন। সম্পূর্ণ সার্ভার ও পেজ কোড API key সার্ভারে রাখে এবং শব্দ পরীক্ষা, মাইক্রোফোন থামানো ও ব্যর্থতা সামলানো দেখায়।

By BIG CHANGE Editorial

Published: 2026-10-19T19:20:34.863Z
Updated: 2026-10-19T19:20:34.863Z
Canonical: https://bigchange.ai/blog/openai-realtime-browser-voice-webrtc-guide

![Conceptual charcoal illustration of a desktop microphone beside a blank browser on a monitor and a small speaker.](https://bigchange.ai/api/media/file/realtime-browser-voice-hero-v1.png)
AI-generated conceptual illustration by BIG CHANGE; no actual OpenAI interface, browser test or heard reply is depicted.

OpenAI Realtime API ব্রাউজারকে WebRTC দিয়ে মাইক্রোফোনের শব্দ পাঠাতে এবং কথিত উত্তর বাজাতে দেয়। এই নির্দেশিকা `gpt-realtime-2.1` দিয়ে একটি স্থানীয় কথোপকথন তৈরি করে। API key আপনার কম্পিউটারের Node সার্ভারে থাকে। মডেলে প্রবেশাধিকার ও billing-সহ OpenAI API project চাই; ChatGPT subscription API ব্যবহারের খরচ দেয় না। BIG CHANGE বর্তমান নথি ও নমুনা কোড পরীক্ষা করেছে, কিন্তু অর্থপ্রদত্ত session খোলেনি বা উত্তর শোনেনি।

## বড় পরিবর্তন

- **কী বদলেছে:** OpenAI সরাসরি Realtime কথোপকথনের জন্য ব্রাউজার WebRTC পথ নথিভুক্ত করেছে। স্থানীয় সার্ভার project key রেখে ব্রাউজারের connection offer-এর বদলে answer আনে।
- **কেন গুরুত্বপূর্ণ:** বড় কণ্ঠপণ্য তৈরির আগে ডেভেলপার স্থানীয় পেজে মাইক্রোফোন থেকে কথিত উত্তর পর্যন্ত পুরো পথ পরীক্ষা করতে পারেন। Project মালিক key নিয়ন্ত্রণ করেন এবং API খরচ দেন।
- **যা খেয়াল রাখতে হবে:** স্থানীয় বিনিময় চললেই production প্রস্তুতি প্রমাণ হয় না। শেয়ার করা ব্যবস্থায় caller authentication ও খরচ নিয়ন্ত্রণ চাই; বাতিল বা timeout request ইতিমধ্যে OpenAI পৌঁছে যেতে পারে।

## শুরুর আগে

Node.js 22.6 বা পরের version এবং কাজ করে এমন মাইক্রোফোন ও speaker-সহ বর্তমান ব্রাউজার নিন। মাইক্রোফোনে প্রবেশে নিরাপদ context চাই; `http://localhost` এই স্থানীয় উদাহরণে উপযুক্ত। `gpt-realtime-2.1` access এবং billing চালু করা OpenAI API project key নিন। আগে rate ও spend limits দেখুন। মডেল পেজ Free tier অসমর্থিত বলে। স্বাভাবিক secret manager বা স্থানীয় shell ব্যবস্থা দিয়ে key server process environment-এ রাখুন। এটি `index.html`-এ রাখবেন না, `.env` ফাইলে commit বা transcript-এ paste করবেন না। [OpenAI WebRTC নির্দেশিকা](https://developers.openai.com/api/docs/guides/voice-webrtc) বিশ্বস্ত সার্ভারের বিনিময় নথিভুক্ত করে; [মডেল পেজ](https://developers.openai.com/api/docs/models/gpt-realtime-2.1) বর্তমান প্রবেশাধিকার ও দাম জানায়।

এটি Realtime API-র unified `/v1/realtime/calls` route। WebRTC নির্দেশিকায় `/v1/live/sessions` দিয়ে GPT-Live-ও আছে, তবে session protocol আলাদা। নিচের route ও payload একসঙ্গে রাখুন। উদাহরণ নিজের কম্পিউটারে বাঁধা; স্থানীয় Host ও Origin পরীক্ষা শেয়ার করা সেবার ব্যবহারকারীর authentication করে না।

1. ডেমোর জন্য ফাঁকা directory তৈরি করে সেখান থেকে Express install করুন:

```bash
npm init -y
npm install express
```

Installation `package.json` তৈরি করে ও web-server dependency যোগ করে। পরের দুই ফাইল একই directory-তে রাখুন। কোড Node-এর নিজস্ব `fetch`, `FormData` ও `AbortSignal.timeout` ব্যবহার করে; পরীক্ষিত ব্যবস্থায় Node.js 22.6 বা পরের version চাই।

2. নিচেরটি `server.mjs` নামে রাখুন। এটি ব্রাউজারের SDP offer (প্রস্তাবিত WebRTC connection-এর বর্ণনা) গ্রহণ করে Realtime session settings-সহ OpenAI পাঠায়। সাধারণ API key শুধু সার্ভারেই পড়া হয়।

```javascript
import express from "express";

const app = express();
// This demo accepts only the local page, including protection against DNS rebinding.
app.use((req, res, next) => {
  const hosts = ["localhost:3000", "127.0.0.1:3000"];
  if (!hosts.includes(req.get("host"))) return res.status(403).send("Local host required");
  if (req.method === "POST" && req.get("origin") !== `http://${req.get("host")}`) {
    return res.status(403).send("Same-origin local page required");
  }
  next();
});
app.use(express.text({ type: "application/sdp", limit: "64kb" }));

app.get("/", (_req, res) => res.sendFile("index.html", { root: process.cwd() }));

app.post("/session", async (req, res) => {
  if (!process.env.OPENAI_API_KEY) return res.status(500).send("Server API key missing");
  if (typeof req.body !== "string" || !req.body.startsWith("v=")) {
    return res.status(400).send("Expected an SDP offer");
  }

  const form = new FormData();
  form.set("sdp", req.body);
  form.set("session", JSON.stringify({
    type: "realtime",
    model: "gpt-realtime-2.1",
    output_modalities: ["audio"],
    audio: { output: { voice: "marin" } },
    instructions: "Be a concise, helpful voice assistant. Do not claim access to external tools."
  }));

  try {
    const upstream = await fetch("https://api.openai.com/v1/realtime/calls", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
      body: form,
      signal: AbortSignal.timeout(25000)
    });
    const answer = await upstream.text();
    if (!upstream.ok) {
      console.error("Realtime session rejected", upstream.status);
      return res.status(502).send(`OpenAI session request failed (${upstream.status})`);
    }
    res.type("application/sdp").send(answer);
  } catch (error) {
    console.error("Realtime session network failure", error.name);
    res.status(502).send("Could not reach the Realtime API");
  }
});

app.listen(3000, "127.0.0.1", () => console.log("Open http://localhost:3000"));
```

সার্ভার `127.0.0.1:3000`-এ bind হয়ে শুধু স্থানীয় পেজের host ও POST origin গ্রহণ করে এবং SDP answer ফেরায়। 25 সেকেন্ড upstream deadline এই উদাহরণের সিদ্ধান্ত। Timeout বা ব্রাউজার বিচ্ছিন্ন হওয়া মানে OpenAI request নেয়নি নয়; অনিশ্চিত সূচনা পুনরাবৃত্তির আগে ব্যবহার দেখুন।

3. নিচেরটি `index.html` নামে রাখুন। পেজ **Start voice**-এর পরে মাইক্রোফোন অনুমতি চায়, স্থানীয় সার্ভারে offer পাঠায় এবং আসা audio বাজায়। **Stop** connection বন্ধ ও microphone tracks থামায়, setup চললেও। 30 সেকেন্ড setup timer-ও উদাহরণের সিদ্ধান্ত, API guarantee নয়।

```html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Local Realtime voice check</title>
<button id="start">Start voice</button>
<button id="stop" disabled>Stop</button>
<p id="status" role="status">Idle</p>
<audio id="reply" autoplay controls></audio>
<script type="module">
  const start = document.querySelector("#start");
  const stop = document.querySelector("#stop");
  const status = document.querySelector("#status");
  const reply = document.querySelector("#reply");
  let current;

  function closeSession(session = current, message = "Stopped") {
    if (!session) return;
    session.closed = true;
    clearTimeout(session.timer);
    session.abort.abort();
    session.mic?.getTracks().forEach(track => track.stop());
    if (session.pc) session.pc.onconnectionstatechange = null;
    session.dc?.close();
    session.pc?.close();
    if (current === session) {
      current = null;
      reply.srcObject = null;
      start.disabled = false;
      stop.disabled = true;
      status.textContent = message;
    }
  }

  start.onclick = async () => {
    const session = { abort: new AbortController(), closed: false };
    current = session;
    start.disabled = true;
    stop.disabled = false;
    status.textContent = "Requesting microphone";
    session.timer = setTimeout(() => closeSession(session, "Setup timed out; microphone stopped"), 30000);
    try {
      const mic = await navigator.mediaDevices.getUserMedia({ audio: true });
      if (session.closed) { mic.getTracks().forEach(track => track.stop()); return; }
      session.mic = mic;
      const pc = session.pc = new RTCPeerConnection();
      pc.ontrack = event => { if (!session.closed) reply.srcObject = event.streams[0]; };
      pc.onconnectionstatechange = () => {
        if (session.closed) return;
        status.textContent = `Connection: ${pc.connectionState}`;
        if (pc.connectionState === "connected") clearTimeout(session.timer);
        if (["failed", "closed", "disconnected"].includes(pc.connectionState)) {
          closeSession(session, "Connection ended; microphone stopped. Start a new session.");
        }
      };
      pc.addTrack(mic.getAudioTracks()[0], mic);
      const dc = session.dc = pc.createDataChannel("oai-events");
      dc.onmessage = message => {
        if (session.closed) return;
        try {
          const event = JSON.parse(message.data);
          if (event.type === "session.created") status.textContent = "Session ready: speak when connected";
          if (event.type === "response.done") {
            status.textContent = `Response status: ${event.response?.status || "unknown"}; verify audible playback`;
          }
          if (event.type === "error") closeSession(session, `Realtime error: ${event.error?.message || "unknown"}; stopped`);
        } catch { closeSession(session, "Invalid event; stopped"); }
      };
      dc.onclose = () => { if (!session.closed) closeSession(session, "Event channel closed; stopped"); };
      dc.onerror = () => closeSession(session, "Event channel failed; stopped");
      const offer = await pc.createOffer();
      await pc.setLocalDescription(offer);
      if (session.closed) return;
      // The official WebRTC example submits the generated offer directly.
      const response = await fetch("/session", {
        method: "POST",
        headers: { "Content-Type": "application/sdp" },
        body: offer.sdp,
        signal: session.abort.signal
      });
      if (!response.ok) throw new Error(await response.text());
      const answer = await response.text();
      if (session.closed) return;
      await pc.setRemoteDescription({ type: "answer", sdp: answer });
      if (!session.closed && pc.connectionState !== "connected") status.textContent = "Signaling complete; waiting for connection";
    } catch (error) {
      if (!session.closed) closeSession(session, `Start failed: ${error.message}`);
    }
  };
  stop.onclick = () => closeSession();
  window.addEventListener("pagehide", () => closeSession());
</script>
</html>
```

Peer বা event-channel ব্যর্থতা এবং পেজ ছাড়লেও ব্রাউজার session বন্ধ করে। Stop বা timeout-এর পরে অনুমতি আসতে পারে; দেরির track বন্ধ হয়। Status line `response.done` ও তার ঘোষিত অবস্থা দেখায়। শুধু এই event উত্তর শোনা গেছে বা বাতিল/ব্যর্থ response সফল হয়েছে প্রমাণ করে না।

4. দুই ফাইলের directory থেকে সার্ভার চালান; তার process environment-এ `OPENAI_API_KEY` আগে থেকে set থাকতে হবে:

```bash
node server.mjs
```

খুলুন: `http://localhost:3000`. আপনার **Start voice**, **Stop**, **Idle** অবস্থা ও audio player দেখা উচিত। **Start voice** ক্লিক করে মাইক্রোফোন অনুমতি দিন এবং ছোট, অসংবেদনশীল প্রশ্ন বলুন। OpenAI-এর [Realtime conversations নির্দেশিকা](https://developers.openai.com/api/docs/guides/realtime-conversations) বলে default voice activity detection কথার পর বিরতিকে উত্তর শুরু করতে ব্যবহার করতে পারে। নিজের run সফল কিনা দেখুন: মাইক্রোফোন সক্রিয়, connection `connected` অবস্থায়, `session.created` event এসেছে, কথা শোনা যাচ্ছে এবং `response.done` completed response বলছে। **Stop** ক্লিক করে microphone indicator নিভেছে নিশ্চিত করুন। এই পরীক্ষা আপনার করার; BIG CHANGE অর্থপ্রদত্ত browser session চালায়নি।

## যাচাই ব্যর্থ হলে

মাইক্রোফোন অনুমতি না পেলে বা device না দেখলে browser permission ও device দেখুন, তারপর স্থানীয় `localhost` URL বা HTTPS নিন। পেজ `/session` failure দেখালে server HTTP status, key, project model access, billing, rate limits ও endpoint দেখুন। সার্ভার ইচ্ছাকৃতভাবে key বা OpenAI response body ছাপে না। 502 নেটওয়ার্ক ব্যর্থতা বা 25 সেকেন্ড deadline-ও বোঝাতে পারে; অনিশ্চিত upstream request গৃহীত হয়েছে কি না জানায় না।

Signaling সফল কিন্তু connection ব্যর্থ হলে page status, network restriction ও ফেরত SDP answer দেখুন। সংযোগ সচল কিন্তু নীরব হলে mic input ও বাছাই output দেখুন। Autoplay বন্ধ থাকতে পারে: audio control-এ **Play** ক্লিক করে প্রয়োজনে থামিয়ে নতুন session শুরু করুন। প্রতি ব্যর্থতায় **Stop** ব্যবহার করে microphone indicator নিভেছে নিশ্চিত করুন। Request ফল অনিশ্চিত হলে বারবার শুরুর আগে project usage দেখুন।

## খরচ, গোপনীয়তা ও সীমা

OpenAI অনুযায়ী `gpt-realtime-2.1`-এর noncached text input/output দাম **প্রতি দশ লক্ষ tokens $4/$24** এবং audio input/output **প্রতি দশ লক্ষ tokens $32/$64**; 19 অক্টোবর 2026 যাচাই। খরচ ব্যবহৃত tokens অনুযায়ী, পরের turns-এ আগের conversation context-সহ। ব্যবহারের আগে [মডেলের মূল্য ও সীমা](https://developers.openai.com/api/docs/models/gpt-realtime-2.1) এবং নিজের project usage দেখুন; শুধু সময় দিয়ে session bill অনুমান করা যায় না। [Realtime conversations নির্দেশিকা](https://developers.openai.com/api/docs/guides/realtime-conversations) সর্বোচ্চ session 60 মিনিট বলে।

Session চলাকালে মাইক্রোফোনের audio OpenAI যায়। পাঠানোর অধিকার আছে এমন কথা বলুন; ব্যক্তিগত বা তৃতীয় পক্ষের audio এড়ান। স্থানীয় পেজে sign-in বা প্রতি ব্যবহারকারীর budget control নেই। শেয়ার করা সেবায় authenticated, rate-limited `/session` access ও server-derived safety identifier চাই; স্থানীয় Host ও Origin পরীক্ষা যথেষ্ট নয়। উদাহরণ বাইরের tools বা phone call করে না। Latency, নির্ভরযোগ্যতা, কথার মান, সাশ্রয় বা production deployment ফল মাপা হয়নি।

## উৎস ও আরও পড়ুন

- [OpenAI WebRTC নির্দেশিকা](https://developers.openai.com/api/docs/guides/voice-webrtc): unified Realtime server exchange, browser audio path ও আলাদা GPT-Live protocol।
- [OpenAI Realtime conversations নির্দেশিকা](https://developers.openai.com/api/docs/guides/realtime-conversations): session events, turn behavior, response status ও সময়সীমা।
- [OpenAI `gpt-realtime-2.1` মডেল পেজ](https://developers.openai.com/api/docs/models/gpt-realtime-2.1): model access, token মূল্য ও rate limits। উদাহরণ চালানোর সময় মূল্য ও প্রবেশাধিকার আবার দেখুন।

## Sources

- [OpenAI WebRTC নির্দেশিকা](https://developers.openai.com/api/docs/guides/voice-webrtc) — Realtime unified calls interface, trusted key, SDP, browser audio ও আলাদা GPT-Live protocol।
- [OpenAI Realtime কথোপকথন](https://developers.openai.com/api/docs/guides/realtime-conversations) — Session events, VAD, response status ও 60 মিনিট সময়।
- [OpenAI gpt-realtime-2.1 মডেল](https://developers.openai.com/api/docs/models/gpt-realtime-2.1) — মডেলভিত্তিক token মূল্য ও প্রবেশাধিকার।
- [OpenAI কণ্ঠের খরচ অনুকূল করা](https://developers.openai.com/api/docs/guides/voice-latency-cost) — Context ও প্রতি response ব্যবহার।
- [OpenAI API ও ChatGPT billing](https://help.openai.com/en/articles/9039756-managing-billing-for-chatgpt-and-the-api-platform) — আলাদা billing ব্যবস্থা।
