البثّ

أرسل stream: true فيتحوّل الرد إلى text/event-stream: أحداث متتابعة تصل كلّما وُلِّد جزء جديد، فيرى المستخدم النصّ ينمو بدل شاشة انتظار صامتة.

البثّ

curl
curl -N https://<host>/v1/chat/completions \
  -H "Authorization: Bearer vx_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vorix-flash",
    "stream": true,
    "messages": [{ "role": "user", "content": "Count to five." }]
  }'

شكل الحدث

كل حدث سطرٌ يبدأ بـ «data: » يليه كائن JSON، وتفصل بين الأحداث سطران فارغان. الجزء النصّي في choices[0].delta.content.

text
data: {"id":"req_9f4d…","object":"chat.completion.chunk","created":1769040000,"model":"vorix-flash","choices":[{"index":0,"delta":{"content":"One"},"finish_reason":null}]}

data: {"id":"req_9f4d…","object":"chat.completion.chunk","created":1769040000,"model":"vorix-flash","choices":[{"index":0,"delta":{"content":", two"},"finish_reason":null}]}

data: {"id":"req_9f4d…","object":"chat.completion.chunk","created":1769040000,"model":"vorix-flash","served_by":"vorix-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":34,"completion_tokens":12,"total_tokens":46,"cost":"$0.000023","cost_micros":23,"estimated":true}}

data: [DONE]

نهاية البثّ

الحدث قبل الأخير يحمل حقل usage كاملًا (العدّادات والكلفة) مع finish_reason: "stop" وdelta فارغ، ثم يصل السطر الأخير data: [DONE] معلنًا انتهاء المجرى. توقّف عنده ولا تحاول تفسيره كـ JSON.

أمثلة كاملة

javascript
const response = await fetch("https://<host>/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VORIX_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "vorix-flash",
    stream: true,
    messages: [{ role: "user", content: "Count to five." }],
  }),
})

const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ""
let usage = null

for (;;) {
  const { done, value } = await reader.read()
  if (done) break

  buffer += decoder.decode(value, { stream: true })

  // Events are separated by a blank line, and a network chunk may cut one
  // in half — keep the remainder buffered until it completes.
  const events = buffer.split("\n\n")
  buffer = events.pop() ?? ""

  for (const event of events) {
    const line = event.trim()
    if (!line.startsWith("data:")) continue

    const payload = line.slice(5).trim()
    if (payload === "[DONE]") break

    const chunk = JSON.parse(payload)
    if (chunk.error) throw new Error(chunk.error.message)
    if (chunk.usage) usage = chunk.usage

    const delta = chunk.choices?.[0]?.delta?.content
    if (delta) process.stdout.write(delta)
  }
}

console.log("\n", usage)
python
import json
import os
import requests

with requests.post(
    "https://<host>/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['VORIX_API_KEY']}"},
    json={
        "model": "vorix-flash",
        "stream": True,
        "messages": [{"role": "user", "content": "Count to five."}],
    },
    stream=True,
    timeout=300,
) as response:
    response.raise_for_status()
    usage = None

    for line in response.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue

        payload = line[5:].strip()
        if payload == "[DONE]":
            break

        chunk = json.loads(payload)
        if "error" in chunk:
            raise RuntimeError(chunk["error"]["message"])
        if "usage" in chunk:
            usage = chunk["usage"]

        delta = chunk["choices"][0]["delta"].get("content", "")
        print(delta, end="", flush=True)

print("\n", usage)

تنبيهات عملية

  • قد تصل الحزمة مقطوعة في منتصف حدث — احتفظ بالبقية في مخزن مؤقت حتى يكتمل.
  • مع البثّ تكون عدّادات التوكن تقديرية (estimated: true) لأنها لا تُعرف إلا بعد الانتهاء.
  • إن انقطع الاتصال أثناء التوليد فما وُلِّد حتى تلك اللحظة يُحاسَب — تعامل مع الانقطاع لا تتجاهله.

خطأ أثناء البثّ

إن تعذّر إكمال التوليد بعد بدء البثّ يصلك حدث يحمل حقل error بنفس صيغة الأخطاء المعتادة، ثم ينتهي المجرى. افحص وجود error في كل حدث قبل قراءة delta.

التاليالأخطاء