Realtime HTTP API

بث ASR مباشر من صوت ما زال يصل

أرسل إطارات PCM16 متسلسلة واستقبل صفرًا أو أكثر من نتائج النسخ الجزئية والنهائية لكل طلب.

POST/http/stt-stream

هذه هي عملية HTTP المباشرة القياسية لـASR المباشر. يمثل POST /http/realtime-asr اسمًا مستعارًا للتوافق؛ وينبغي للعملاء الجدد استخدام هذا المسار. تستخدم حزم SDK لـJavaScript وPython في الإصدار 0.18.0 بروتوكول Socket.IO ولا تستدعي أيًا من مساري HTTP.

أرسل طلب POST واحدًا لكل مقطع صوت عند وصوله. ابدأ كل جسم بترويسة التحكم نفسها المكونة من 18 بايتًا: البايتات 0..15 هي UUID جديد غير صفري بصيغته الثنائية الخام؛ ويحتوي البايت 16 على is_start في bit 0 وis_final في bit 1؛ والبايت 17 هو اللغة (0=ar و1=en و2=codeswitch و255=auto). أبقِ بتات الأعلام المحجوزة صفرًا. ألحق صوت PCM16 خامًا أحادي القناة وغير فارغ بترتيب little-endian وتردد 16 kHz، من دون ترويسة WAV. اضبط is_start في المقطع الأول فقط، ولا تضبط أي علم في المقاطع الوسيطة، واضبط is_final في آخر مقطع يحوي صوتًا؛ واضبط العلمين معًا لتدفق من مقطع واحد.

تحتوي استجابة 200 صفرًا أو أكثر من سجلات JSON المفصولة بأسطر جديدة. خزّن عبر قراءات الشبكة وحلّل الأسطر المكتملة. عامل is_speech_final بوصفه حدًا للكلام. لا تكمل التدفق إلا بعد ملاحظة is_final: true؛ فبت النهاية في الطلب وانتهاء استجابة HTTP، بما في ذلك 200 فارغة، ليسا إشارتَي اكتمال. عامل seq بوصفه مبهمًا وعالج السجلات وفق ترتيب وصولها الملحوظ. وإذا بدأ الخرج، ينهي أي فشل لاحق بثَّ 200 الجزئي من دون إلحاق خطأ JSON.

استخدم X-Api-Key بقدرة ASR الفوري من خلفية موثوقة. ضع حدًا زمنيًا لكل POST وقراءة وللتدفق كاملًا. لا يُعرّف إعادة تشغيل المقاطع ولا استئناف الجلسة؛ بعد فشل ملتبس، أوقف التدفق القديم وتخلص من الحالة المؤقتة وأعد البدء باستخدام UUID جديد. لا يحدد العقد العام ما إذا كان ينبغي تداخل طلبات POST للمقاطع أو تسلسلها؛ فاستخدم نمط التنسيق المخصص لبيئتك. ويحافظ انتهاء نافذة الاستجابة غير النهائية العادية بعد ثانيتين على الجلسة. ويلغي إجهاض طلب POST أو انقضاء مهلة الاستجابة النهائية الجلسةَ. كما تنتهي صلاحية الجلسة بعد 60 ثانية من دون صوت عميل مقبول أو استجابة من محرك الاستدلال.

المصادقة

ApiKeyAuth
X-Api-Key<token>

الموضع: header

جسم الطلب

application/octet-stream

جسم الاستجابة

application/x-ndjson

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -sS --fail-with-body --connect-timeout 10 --max-time 120 -X POST \  "https://example.com/http/stt-stream" \  -H "Origin: https://example.com" \  -H "Content-Type: application/octet-stream" \  --data-binary @request.bin

صفر أو أكثر من سجلات ASR المباشر بصيغة NDJSON. بعد بدء الخرج، ينهي أي فشل لاحق البثَّ الجزئي من دون إلحاق خطأ JSON. ويتطلب الاكتمال ملاحظة سجل يحتوي is_final: true.

application/x-ndjson

المثال partial

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "seq": 0,
  "transcription": "hello wor",
  "words": [
    {
      "start_time": 0,
      "end_time": 0.45,
      "word": "hello"
    }
  ],
  "is_speech_final": false,
  "is_final": false
}

المثال final

{
  "id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "seq": 0,
  "transcription": "hello world",
  "words": [
    {
      "start_time": 0,
      "end_time": 0.45,
      "word": "hello"
    },
    {
      "start_time": 0.46,
      "end_time": 0.9,
      "word": "world"
    }
  ],
  "is_speech_final": true,
  "is_final": true
}

ترويسة تحكم أو UUID أو بايت لغة أو حمولة PCM غير صالحة

application/json

الترويسة قصيرة أو UUID صفري

{
  "error": "invalid audio upload",
  "code": "VALIDATION_FILE_CORRUPT",
  "detail": "invalid audio upload",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

بايت لغة غير صالح

{
  "error": "invalid language",
  "code": "VALIDATION_INVALID_LANGUAGE",
  "detail": "invalid language",
  "job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

حمولة PCM فارغة

{
  "error": "audio upload is empty",
  "code": "VALIDATION_FILE_CORRUPT",
  "detail": "audio upload is empty",
  "job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

عدد بايتات حمولة PCM فردي

{
  "error": "audio must contain int16 samples",
  "code": "VALIDATION_INVALID_FORMAT",
  "detail": "audio must contain int16 samples",
  "job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

غير مصرح

application/json

المثال missing_key

{
  "error": "Invalid authentication",
  "code": "AUTH_UNAUTHORIZED",
  "detail": "Invalid authentication",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

لا يمنح مفتاح API صلاحية الوصول إلى قدرة الصوت المطلوبة

application/json

المثال scope_denied

{
  "error": "scope not permitted",
  "code": "AUTH_FORBIDDEN",
  "detail": "scope not permitted",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

الطريقة غير مسموحة

application/json

المثال wrong_method

{
  "error": "method not allowed",
  "code": "METHOD_NOT_ALLOWED",
  "detail": "method not allowed",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

لم يصل أي صوت على شبه الجلسة هذه داخل نافذة سكونها، فأُنهيت الجلسة (RFC 9110 15.5.9). وهي غير قابلة لإعادة المحاولة بمعرّف الجلسة نفسه، الذي صار مسجَّلًا كمنتهٍ ولا يُعاد استخدامه: ابدأ جلسة جديدة بمعرّف جديد ومع is_start.

application/json

المثال session_went_idle

{
  "error": "session idle timeout exceeded; start a new session",
  "code": "SESSION_IDLE_TIMEOUT",
  "detail": "session idle timeout exceeded; start a new session",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 900,
    "observed": 901,
    "unit": "seconds",
    "bound": "session_idle"
  }
}

يتعارض المقطع مع حالة شبه الجلسة التابع لها (RFC 9110 15.5.10): فالمعرّف لم يُبدأ قط، أو أُنهي فعلًا، أو وصل is_start لمعرّف حيّ بالفعل. وإجابة واحدة تغطي كل هذه الحالات، لذلك لا يمكن للتوقيت أن يغيّر العقد. ابدأ جلسة جديدة بمعرّف جديد.

application/json

المثال not_live

{
  "error": "session is not live; start a new session with is_start and a new id",
  "code": "SESSION_EXPIRED",
  "detail": "session is not live; start a new session with is_start and a new id",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z"
}

تجاوز جسم الطلب حد البايتات المضبوط لهذا المسار الصوتي: 64 MiB لرفع Fast، و16 MiB لإطارات ASR الفوري، و16 MiB لإطارات تمييز المتحدثين الفوري. وهو غير قابل لإعادة المحاولة بالحجم نفسه؛ أعد إرسال وحدة أو مقطع أصغر.

ويسمّي data.bound حد البايتات الذي تم بلوغه — fast_audio_bytes أو realtime_asr_frame_bytes أو realtime_diarization_frame_bytes. و data.observed هو حجم الطلب الدقيق عندما يعلن العميل Content-Length، وهو فيما عدا ذلك حد أدنى (الحد زائد بايت واحد)، لأن الجسم الذي لا يعلن طوله يُقطع في أثناء القراءة ولا يُعرف حجمه الحقيقي أبدًا.

ولا تُبلَغ هذه الحالة إلا من عدّ بايتات. أما الطلب المقبولة بايتاته والذي يطول صوته بعد فك الترميز فهو الحالة 422 برمز AUDIO_DURATION_EXCEEDED بدلًا منها.

application/json

أُعلن `Content-Length`، فالقيمة المرصودة دقيقة

{
  "error": "request body too large",
  "code": "PAYLOAD_TOO_LARGE",
  "detail": "request body too large",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 16777216,
    "observed": 20971520,
    "unit": "bytes",
    "bound": "realtime_asr_frame_bytes"
  }
}

لا طول معلن، فالقيمة المرصودة هي الحد زائد بايت واحد

{
  "error": "request body too large",
  "code": "PAYLOAD_TOO_LARGE",
  "detail": "request body too large",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 67108864,
    "observed": 67108865,
    "unit": "bytes",
    "bound": "fast_audio_bytes"
  }
}

حُلِّل الطلب بصورة صحيحة وكانت بايتاته مقبولة، لكن مقدار الصوت الذي يطلب من الخدمة معالجته يتجاوز سقف هذه النقطة (RFC 9110 15.5.21). ورفع مضغوط صغير يُفك إلى ساعات كثيرة هو هذه الحالة بالضبط، ولهذا لا تكون الحالة 413.

ويسمّي data.bound السقف الصوتي الذي تم بلوغه:

  • fast_audio_duration — إرسال Fast واحد فُك إلى أكثر من 1800 ثانية. قسّم التسجيل أو استخدم واجهة النسخ الدفعي.
  • session_audio_duration — أرسلت جلسة فورية الآن محتوى صوتيًا إجماليًا يزيد على حصتها البالغة 14400 ثانية (4 ساعات). وقد أُنهيت الجلسة؛ فابدأ جلسة جديدة.

وdata.observed بالثواني الكاملة، مقرَّبًا إلى الأعلى. وحيث توقفت الخدمة عن فك الترميز عند السقف فإنها لم تعرف الطول الإجمالي الحقيقي، ولذلك تكون القيمة المرصودة حدًا أدنى لا قياسًا دقيقًا.

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

application/json

المثال fast_decoded_audio_too_long

{
  "error": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
  "code": "AUDIO_DURATION_EXCEEDED",
  "detail": "decoded audio duration exceeds the maximum for this endpoint; split the recording or use the batch transcription API",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 1800,
    "observed": 3601,
    "unit": "seconds",
    "bound": "fast_audio_duration"
  }
}

المثال session_audio_allowance_spent

{
  "error": "session maximum audio duration exceeded; start a new session",
  "code": "AUDIO_DURATION_EXCEEDED",
  "detail": "session maximum audio duration exceeded; start a new session",
  "retryable": false,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 14400,
    "observed": 14401,
    "unit": "seconds",
    "bound": "session_audio_duration"
  }
}

تم تحديد معدل طلب فوري. وتشترك ثلاثة مصادر مختلفة في هذه الحالة على هذه المسارات، ويميز بينها حقل code:

  • SESSION_BYTE_RATE_EXCEEDED — الصوت يصل أسرع مما يسمح به المعدل المستدام للجلسة (أربعة أضعاف الزمن الحقيقي، مع اندفاع 16 MiB). التزم بـRetry-After؛ فتنجح الحمولة نفسها بعدها. وتبقى الجلسة حيّة. وdata.bound هو session_audio_rate_burst.
  • CONCURRENCY_LIMIT_EXCEEDED — لدى الحساب القابل للفوترة فعلًا من العمليات المتزامنة من هذا النوع قيد التنفيذ ما تسمح به خطته. وdata.bound هو account_concurrency_<workload>.
  • SESSION_SLOTS_EXHAUSTED — يحتفظ الحساب من أشباه جلسات HTTP المتزامنة بقدر ما تسمح به هذه العملية.

كما يجيب حد معدل الطلبات لكل مفتاح في البوابة بالحالة 429 أيضًا ويبلّغ RATE_LIMIT_EXCEEDED، وشكل جسمه يعتمد على النشر. وكل هذه قابلة لإعادة المحاولة، ولا يستهلك أي منها رصيدًا ولا حصة.

application/json

المثال audio_arriving_too_fast

{
  "error": "audio is arriving faster than this session allows; slow down to real time and retry",
  "code": "SESSION_BYTE_RATE_EXCEEDED",
  "detail": "audio is arriving faster than this session allows; slow down to real time and retry",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 16777216,
    "observed": 33554432,
    "unit": "bytes",
    "bound": "session_audio_rate_burst"
  }
}

المثال account_concurrency_exhausted

{
  "error": "too many concurrent operations for this account",
  "code": "CONCURRENCY_LIMIT_EXCEEDED",
  "detail": "too many concurrent operations for this account",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "limit": 8,
    "observed": 8,
    "unit": "operations",
    "bound": "account_concurrency_realtime_asr"
  }
}

فشل ASR المباشر قبل إصدار سجل نهائي

application/json

المثال transcription_failed

{
  "error": "realtime ASR transcription failed",
  "code": "ASR_TRANSCRIPTION_FAILED",
  "detail": "realtime ASR transcription failed",
  "job_id": "7f51f2c2-e7bc-41c8-a850-f848df2ddfc8",
  "retryable": true,
  "timestamp": "2026-01-15T10:30:00Z"
}

الخطوات التالية

ابنِ دورة الحياة الحية تاليًا: أعد استخدام UUID واحدًا عبر المقاطع المؤطرة، واستبدل حالة العرض الجزئية، وثبّت النتائج النهائية فقط، وأنهِ كل انتظار بموعد نهائي للتطبيق.

في هذه الصفحة