સ્ટ્રીમિંગ
stream ને true કરો અને મોડેલ લખતું જાય તેમ જવાબ server-sent events તરીકે આવે છે: પહેલાં રીઝનિંગ, પછી જવાબ, પછી finish reason અને usage સાથેનો છેલ્લો chunk. જ્યારે કોઈ વ્યક્તિ ટેક્સ્ટની રાહ જોતી હોય ત્યારે અને લાંબા જવાબો માટે તેનો ઉપયોગ કરો.
POST https://api.shannon-ai.com/v1/chat/completions
OpenAI SDKs તમને chunks એક પછી એક આપે છે. દરેક chunk ને તે જે લઈને આવ્યો છે તેના આધારે વાંચો: રીઝનિંગનો ટુકડો, જવાબનો ટુકડો, ટૂલ કોલ, અથવા જવાબનો અંત.
from openai import OpenAI, APIError
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.shannon-ai.com/v1",
)
stream = client.chat.completions.create(
model="shannon-3",
messages=[{"role": "user", "content": "Explain server-sent events in three sentences."}],
stream=True,
)
answer, reasoning, tool_calls = [], [], []
finish_reason = usage = None
try:
for chunk in stream:
if chunk.usage:
usage = chunk.usage
if not chunk.choices:
continue
choice = chunk.choices[0]
delta = choice.delta
thought = getattr(delta, "reasoning_content", None)
if thought:
reasoning.append(thought)
if delta.content:
answer.append(delta.content)
print(delta.content, end="", flush=True)
for call in delta.tool_calls or []:
tool_calls.append((call.id, call.function.name, call.function.arguments))
if choice.finish_reason:
finish_reason = choice.finish_reason
except APIError as error:
# A failure after the stream started arrives as an error chunk.
print(f"\nstream failed: {error}")
print(f"\n{finish_reason} {usage}") import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.shannon-ai.com/v1",
});
const stream = await client.chat.completions.create({
model: "shannon-3",
messages: [{ role: "user", content: "Explain server-sent events in three sentences." }],
stream: true,
});
let answer = "";
let reasoning = "";
const toolCalls = [];
let finishReason = null;
let usage = null;
try {
for await (const chunk of stream) {
if (chunk.usage) usage = chunk.usage;
const choice = chunk.choices?.[0];
if (!choice) continue;
const delta = choice.delta;
if (delta.reasoning_content) reasoning += delta.reasoning_content;
if (delta.content) {
answer += delta.content;
process.stdout.write(delta.content);
}
for (const call of delta.tool_calls ?? []) {
toolCalls.push({ id: call.id, name: call.function.name, arguments: call.function.arguments });
}
if (choice.finish_reason) finishReason = choice.finish_reason;
}
} catch (error) {
// A failure after the stream started arrives as an error chunk.
console.error("\nstream failed:", error.message);
}
console.log("\n", finishReason, usage); curl -N https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "shannon-3",
"messages": [{"role": "user", "content": "Explain server-sent events in three sentences."}],
"stream": true
}' સ્ટ્રીમની ફ્રેમિંગ કેવી હોય છે
- જવાબનું સ્ટેટસ
200હોય છે અને હેડર્સcontent-type: text/event-streamઅનેcache-control: no-cacheહોય છે. - દરેક ઇવેન્ટ
data:થી શરૂ થતી એક લાઇન છે, જેની પછી ખાલી લાઇન આવે છે.data:પછીનો ટેક્સ્ટ એક JSON chunk છે.event:કેid:લાઇન્સ નથી. - કોલનથી શરૂ થતી લાઇન, જેમ કે
: ping, કનેક્શન ખુલ્લું રાખતી કોમેન્ટ છે. તેને છોડી દો. - સ્ટ્રીમ
data: [DONE]સાથે પૂરો થાય છે. તેના વિના અટકી જતો સ્ટ્રીમ અધૂરો છે.
Chunks ક્રમમાં
દરેક chunk એક chat.completion.chunk ઓબ્જેક્ટ છે:
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {
"content": "Server-sent"
},
"finish_reason": null
}
]
} એક સ્ટ્રીમના બધા chunks માં એ જ id, created અને model હોય છે. choices માં હંમેશાં એક એન્ટ્રી હોય છે. તેનું delta જે નવું છે તે ધરાવે છે, અને છેલ્લા chunk સુધી finish_reason null રહે છે.
| delta માં કી | પ્રકાર | વર્ણન | કોણ મોકલે છે |
|---|---|---|---|
role | string | હંમેશાં assistant. તે સ્ટ્રીમની શરૂઆતમાં એક જ વાર આવે છે. | હોસ્ટેડ open-weight મોડેલ્સ, shannon-2-lite, shannon-2-pro |
reasoning_content | string | મોડેલના રીઝનિંગનો એક ટુકડો. ટુકડાઓને ક્રમમાં જોડો. | હોસ્ટેડ open-weight મોડેલ્સ, Shannon 3 પરિવાર, shannon-1.6-pro, shannon-coder-1 |
content | string | જવાબનો એક ટુકડો. ટુકડાઓને ક્રમમાં જોડો. | બધા મોડેલ્સ |
tool_calls | array | એક પૂરો ટૂલ કોલ. Tool call deltas જુઓ. | બધા મોડેલ્સ |
પહેલાં રીઝનિંગ, પછી જવાબ, પછી ટૂલ કોલ્સ (જો હોય). chunk ને સ્ટ્રીમમાંની તેની જગ્યાથી નહીં, પણ તેના delta ની કીઝથી વાંચો: delta માં ટેક્સ્ટના પહેલા ટુકડા સાથે role હોઈ શકે છે, અને છેલ્લો ખાલી હોય છે.
આખો સ્ટ્રીમ જેમ મુસાફરી કરે છે તેમ. લાઇનો ટૂંકી રાખવા અહીં દરેક chunk માંથી id, object, created અને model છોડી દેવાયા છે.
data: {"choices":[{"index":0,"delta":{"reasoning_content":"Three sentences:"},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{"reasoning_content":" what it is, how it is framed, why it is used."},"finish_reason":null}]}
: ping
data: {"choices":[{"index":0,"delta":{"content":"Server-sent"},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{"content":" events let a server push text to a client over one HTTP reply."},"finish_reason":null}]}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":1190,"completion_tokens":84,"total_tokens":1274}}
data: [DONE] રીઝનિંગ deltas
રીઝનિંગ કરતું મોડેલ જવાબ પહેલાં તેનું રીઝનિંગ delta.reasoning_content માં મોકલે છે. બંને ટેક્સ્ટ અલગ રાખો: રીઝનિંગને અલગ, ફોલ્ડ થઈ શકે તેવા ભાગ તરીકે બતાવો, અથવા છોડી દો.
reasoning_effort off હોય ત્યારે હોસ્ટેડ open-weight મોડેલ્સ રીઝનિંગ મોકલતા નથી, અને રિક્વેસ્ટમાં response_format હોય ત્યારે પણ નહીં.
shannon-2-lite અને shannon-2-pro પણ જવાબ આપતા પહેલાં રીઝનિંગ કરે છે. આ એન્ડપોઇન્ટ પર તેઓ રીઝનિંગ દરમિયાન : thinking કોમેન્ટ લાઇન્સ મોકલે છે, અને પછી જવાબ.
reasoning_content OpenAI SDKs ના typed મોડેલ્સમાં નથી. Python માં તેને getattr(delta, "reasoning_content", None) થી વાંચો; JavaScript માં delta.reasoning_content જેમ છે તેમ ચાલે છે.
Tool call deltas
ટૂલ કોલ આખો આવે છે: દરેક કોલ માટે એક chunk, જેના delta માં પૂરા arguments સ્ટ્રિંગ સાથેનો કોલ હોય છે. index જવાબના કોલ્સને 0 થી ક્રમાંક આપે છે. arguments ને ટુકડે ટુકડે જોડતો કોડ બદલાવ વિના ચાલે છે, કારણ કે તે એક જ ટુકડો જોડે છે.
{
"tool_calls": [
{
"index": 0,
"id": "call_3d9a7c1e5b2f4a60c8e1d7f09b24a6c5",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Paris\"}"
}
}
]
} કોલ્સ પછી, છેલ્લા chunk માં finish_reason tool_calls હોય છે.
રિક્વેસ્ટમાં tools હોય ત્યારે shannon-1.6-lite, shannon-1.6-pro અને shannon-coder-1 જવાબનો ટેક્સ્ટ જવાબના અંતે એક જ delta તરીકે મોકલે છે.
છેલ્લો chunk
data: [DONE] પહેલાંના છેલ્લા chunk માં ખાલી delta, finish_reason અને રિક્વેસ્ટનું usage હોય છે, બધું એ જ chunk માં. દરેક સ્ટ્રીમમાં તે હોય છે; તમારે stream_options ની જરૂર નથી.
{
"id": "chatcmpl-5f0c1e7a9b3d4c62a8e1f07d2b46c9a3",
"object": "chat.completion.chunk",
"created": 1791625200,
"model": "shannon-3",
"choices": [
{
"index": 0,
"delta": {},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1190,
"completion_tokens": 84,
"total_tokens": 1274
}
} હોસ્ટેડ open-weight મોડેલ્સ પર usage માં prompt_tokens_details.cached_tokens અને completion_tokens_details.reasoning_tokens પણ હોય છે.
web_search: true વાળી જે રિક્વેસ્ટની શોધમાં કંઈક મળ્યું હોય, તેના પછી છેલ્લા chunk માં sources પણ હોય છે, અને તેની પહેલાંનો એક chunk ઉલ્લેખ-ચિહ્નોને delta.annotations તરીકે વહન કરે છે. Built‑in Web Search
| finish_reason | વર્ણન | કોણ મોકલે છે |
|---|---|---|
stop | મોડેલે તેનો જવાબ પૂરો કર્યો, અથવા stop સ્ટ્રિંગ દેખાઈ. | બધા મોડેલ્સ |
tool_calls | જવાબમાં એક કે વધુ ટૂલ કોલ્સ છે. | બધા મોડેલ્સ |
length | જવાબ આઉટપુટ મર્યાદાએ કપાઈ ગયો. | Shannon 3 પરિવાર, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 |
usage ના ફીલ્ડ્સનું વર્ણન એન્ડપોઇન્ટ સાથે આપેલું છે. Chat Completions
Keep-alive લાઇન્સ
મોડેલ કામ કરતું હોય અને હજી મોકલવા જેવું કંઈ ન હોય ત્યારે, સ્ટ્રીમ કોમેન્ટ લાઇન્સ મોકલે છે. તેમાં કોઈ ડેટા હોતો નથી. SSE પાર્સર તેમને આપમેળે છોડી દે છે; કાચી લાઇન્સ વાંચતા કોડે કોલનથી શરૂ થતી દરેક લાઇન છોડવી જ જોઈએ.
| લાઇન | કોણ મોકલે છે | ક્યારે |
|---|---|---|
: ping | Shannon 3 પરિવાર, shannon-1.6-lite, shannon-1.6-pro, shannon-coder-1 | દર 15 સેકન્ડે. |
: keepalive | હોસ્ટેડ open-weight મોડેલ્સ | મોડેલ કામ કરતું હોય ત્યારે દર 15 સેકન્ડે. |
: thinking | shannon-2-lite, shannon-2-pro | મોડેલ રીઝનિંગ કરતું હોય ત્યારે. |
સ્ટ્રીમની અંદરની એરર્સ
સ્ટ્રીમ શરૂ થયા પછી તેનું સ્ટેટસ 200 હોય છે, તેથી નિષ્ફળતા સ્ટ્રીમની અંદર આવે છે: જ્યાં choices હોત ત્યાં error સભ્ય સાથેનો chunk.
data: {"error":{"message":"The model backend failed to answer. Please retry.","type":"api_error","code":null,"param":null}}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":1190,"completion_tokens":12,"total_tokens":1202}}
data: [DONE] એરર chunk પછી પણ finish_reason અને usage સાથેનો છેલ્લો chunk અને data: [DONE] આવે છે. દરેક chunk માં error તપાસો. આ તપાસ વિના અડધેથી નિષ્ફળ થયેલો જવાબ પૂર્ણ લાગે છે.
| પ્રકાર | કોડ | મેસેજ | ક્યારે |
|---|---|---|---|
api_error | The model backend failed to answer. Please retry. | મોડેલ નિષ્ફળ ગયું, અથવા કંઈ લખ્યું નહીં. રિક્વેસ્ટ ફરીથી મોકલો. | |
rate_limit_error | Shannon routes are temporarily busy. Please retry. | મોડેલ આ ક્ષણે વ્યસ્ત છે. થોડી સેકન્ડ રાહ જુઓ અને રિક્વેસ્ટ ફરીથી મોકલો. | |
invalid_request_error | context_length_exceeded | વાતચીત મોડેલની કોન્ટેક્સ્ટ વિન્ડો કરતાં લાંબી છે. ફરીથી મોકલતા પહેલાં તેને ટૂંકી કરો. મેસેજનો ટેક્સ્ટ બદલાય છે. |
હોસ્ટેડ open-weight મોડેલ્સ error સભ્યમાં ફક્ત type અને message મોકલે છે.
OpenAI Python અને JavaScript SDKs તમે ઇટરેટ કરો ત્યારે એરર chunk ને API એરર તરીકે raise કરે છે, તેથી લૂપને તમારા સામાન્ય એરર હેન્ડલિંગમાં મૂકો.
સ્ટેટસ કોડ્સ, એરર બોડી અને શું ફરી પ્રયાસ કરવો તેનું પોતાનું પેજ છે. ભૂલ સંભાળ
કનેક્શન બંધ કરવું
કનેક્શન બંધ કરવાથી ડિલિવરી અટકે છે, રિક્વેસ્ટ નહીં. મોડેલ જવાબ છેક સુધી લખે છે અને રિક્વેસ્ટનો ચાર્જ એવો લાગે છે જાણે તમે બધું વાંચ્યું હોય. ઓછું ચૂકવવા ઓછું માગો: જે મોડેલ તેને લાગુ કરે છે તેના પર નીચું max_tokens સેટ કરો.
સ્ટ્રીમ તમારા સુધી પહોંચતા પહેલાં રસ્તામાં પણ વહેલો પૂરો થઈ શકે છે, ઉદાહરણ તરીકે નેટવર્ક તૂટે ત્યારે કે સર્વર અપડેટ થતું હોય ત્યારે. ત્યારે તે છેલ્લા chunk વિના અને data: [DONE] વિના અટકી જાય છે. એવા જવાબને અધૂરો ગણો અને રિક્વેસ્ટ ફરીથી મોકલો.
SDK વિના સ્ટ્રીમ વાંચવો
સાચો રીડર પાંચ કામ કરે છે: સ્ટ્રીમ પહેલાં આવતી એરર્સને તેના એરર હેન્ડલિંગમાં મોકલે છે, બોડીને લાઇન્સમાં વહેંચે છે, કોમેન્ટ લાઇન્સ છોડે છે, data: [DONE] પર અટકે છે, અને દરેક chunk માં error તપાસે છે.
import json
import requests
response = requests.post(
"https://api.shannon-ai.com/v1/chat/completions",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"model": "shannon-3",
"messages": [{"role": "user", "content": "Explain server-sent events in three sentences."}],
"stream": True,
},
stream=True,
)
# 1. Errors before the stream are plain JSON with their own status.
if response.status_code != 200:
raise RuntimeError(f"{response.status_code}: {response.text}")
answer, done = [], False
for raw in response.iter_lines(): # 2. one line at a time
line = raw.decode("utf-8")
if not line.startswith("data: "): # 3. empty lines and ": ping" comments
continue
data = line[len("data: "):]
if data == "[DONE]": # 4. the end of the stream
done = True
break
chunk = json.loads(data)
if "error" in chunk: # 5. a failure inside the stream
raise RuntimeError(chunk["error"]["message"])
delta = chunk["choices"][0]["delta"]
if delta.get("content"):
answer.append(delta["content"])
if chunk.get("usage"):
print(chunk["choices"][0]["finish_reason"], chunk["usage"])
if not done:
raise RuntimeError("the stream ended before [DONE]")
print("".join(answer)) const response = await fetch("https://api.shannon-ai.com/v1/chat/completions", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "shannon-3",
messages: [{ role: "user", content: "Explain server-sent events in three sentences." }],
stream: true,
}),
});
// 1. Errors before the stream are plain JSON with their own status.
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const decoder = new TextDecoder();
let buffer = "";
let answer = "";
let done = false;
read: for await (const bytes of response.body) {
buffer += decoder.decode(bytes, { stream: true });
const lines = buffer.split("\n"); // 2. one line at a time
buffer = lines.pop(); // keep the unfinished line
for (const line of lines) {
if (!line.startsWith("data: ")) continue; // 3. empty lines and ": ping" comments
const data = line.slice(6);
if (data === "[DONE]") { // 4. the end of the stream
done = true;
break read;
}
const chunk = JSON.parse(data);
if (chunk.error) throw new Error(chunk.error.message); // 5. a failure inside the stream
const choice = chunk.choices[0];
if (choice.delta.content) answer += choice.delta.content;
if (chunk.usage) console.log(choice.finish_reason, chunk.usage);
}
}
if (!done) throw new Error("the stream ended before [DONE]");
console.log(answer); Python ઉદાહરણ requests પેકેજ વાપરે છે. JavaScript ઉદાહરણ Node.js 18 કે તેથી નવા પર ચાલે છે.
અન્ય ફોર્મેટ્સના સ્ટ્રીમ્સ
Responses અને Messages એન્ડપોઇન્ટ્સ પણ સ્ટ્રીમ કરે છે. તેમની ફ્રેમ્સમાં ઇવેન્ટના નામ સાથેની event: લાઇન અને તેના JSON સાથેની data: લાઇન હોય છે. દરેક પેજ તેની ઇવેન્ટ્સ ક્રમમાં યાદી કરે છે.
| સ્ટ્રીમમાં | Chat Completions | Responses | Messages |
|---|---|---|---|
| ફ્રેમ્સ | data: લાઇન્સ | event: અને data: લાઇન્સ | event: અને data: લાઇન્સ |
| રીઝનિંગ આમાં આવે છે | delta.reasoning_content | response.reasoning_summary_text.delta | thinking_delta |
| જવાબનો ટેક્સ્ટ આમાં આવે છે | delta.content | response.output_text.delta | text_delta |
| Usage આમાં આવે છે | છેલ્લો chunk | response.completed | message_delta |
| સ્ટ્રીમ આનાથી પૂરો થાય છે | છેલ્લો chunk, પછી data: [DONE] | response.completed | message_stop |