SSE nasıl çalışır
stream: true gönderilen istek text/event-stream yanıtı döner. Yanıt satırları data: {...} biçimindedir ve akış data: [DONE] satırıyla biter. Bağlantı performansı için yanıt Cache-Control: no-cache ve X-Accel-Buffering: no header'larıyla gelir; her yanıtta takip için X-Request-ID header'ı bulunur. Kendi reverse proxy'inde response buffering'i kapat.
Token sayımını istemcide yapacaksan istekte stream_options: {"include_usage": true} gönder: yanıtın sonunda choices alanı boş bir array ile usage taşıyan ek bir chunk gelir (OpenAI davranışı). Bu istek gönderilmezse usage chunk'ı da gönderilmez; usage yine de faturalandırma için sunucuda hesaplanır. prompt_tokens_details.cached_tokens ve completion_tokens_details.reasoning_tokens akışta ve non-stream yanıtta bulunur.
curl -N https://api.noxery.net/v1/chat/completions \
-H "Authorization: Bearer $NOXERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-pro-202606","stream":true,"messages":[{"role":"user","content":"Uzun bir açıklama yaz."}]}'Limit aşımı akış başlamadan tespit edilirse olay akışı yerine doğrudan HTTP 429 döner. Akış başladıktan sonraki upstream hataları event: error çerçevesi olarak gelir.
Chat completions olayları
Parçalar upstream biçimiyle iletilir: choices[0].delta.content içindeki metin parçalarını sırayla birleştir. finish_reason içeren son parça ve [DONE] satırı akışı kapatır.
import json
import requests
resp = requests.post(
"https://api.noxery.net/v1/chat/completions",
headers={"Authorization": "Bearer nox-YOUR_KEY"},
json={"model": "deepseek-v4-pro-202606", "stream": True,
"messages": [{"role": "user", "content": "Merhaba"}]},
stream=True,
)
text = ""
for line in resp.iter_lines():
if not line or not line.startswith(b"data: "):
continue
payload = line[len(b"data: "):].decode()
if payload.strip() == "[DONE]":
break
chunk = json.loads(payload)
text += chunk["choices"][0]["delta"].get("content", "") or ""
print(text)Responses olayları
Responses akışında şu olaylar görülür:
| Olay | Anlamı |
|---|---|
| response.created, response.in_progress | Yanıt başladı. |
| response.output_item.added, response.content_part.added | Yeni çıktı öğesi açıldı. |
| response.output_text.delta | Metin parçası. Parçaları sırayla birleştir. |
| response.function_call_arguments.delta, response.custom_tool_call_input.delta | Araç argümanı parçası. |
| response.output_text.done, response.content_part.done, response.output_item.done, response.function_call_arguments.done, response.custom_tool_call_input.done | İlgili bölüm tamamlandı. |
| response.completed | Akış başarıyla bitti. Bu olay gelmeden yanıtı tamamlanmış sayma. |
| response.failed | Akış hata ile bitti; gövdede error alanı bulunur. |
const resp = await fetch("https://api.noxery.net/v1/responses", {
method: "POST",
headers: { Authorization: "Bearer nox-YOUR_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ model: "deepseek-v4-pro-202606", stream: true, input: "Merhaba" }),
});
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buf = "", text = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buf += decoder.decode(value, { stream: true });
const frames = buf.split("\n\n");
buf = frames.pop();
for (const frame of frames) {
const line = frame.split("\n").find((l) => l.startsWith("data:"));
if (!line) continue;
const payload = line.slice(6).trim();
if (payload === "[DONE]") continue;
const event = JSON.parse(payload);
if (event.type === "response.output_text.delta") text += event.delta;
if (event.type === "response.completed") console.log("tamamlandi:", text);
if (event.type === "response.failed") throw new Error(event.response?.error?.message || "stream failed");
}
}Bağlantı terminal olayı gelmeden koparsa yanıtı tamamlanmış gibi kaydetme; isteği baştan gönder. Uzun akışlarda : ile başlayan heartbeat satırlarını yoksay.