استكشاف الأخطاء وإصلاحها
شخّص إخفاقات الاتصال والوضع والصوت والنهائية والنتائج وTTS وحدود المعدل والتنظيف في SDK 0.18.0.
تستهدف هذه الصفحة @humain-voice/sdk@0.18.0 و
humain-voice==0.18.0. شخّص بالاعتماد على الأدلة: التقط الحالة والحدث
والمعرّف والإشارة النهائية قبل تغيير الإعدادات أو إعادة المحاولة.
شخّص بهذا الترتيب
- تأكد من أن الحزمة المثبتة هي
0.18.0بالضبط. - تأكد من وجود
API_URLوAPI_KEYفي عملية الخادم. - اختر وضع المعالجة وفق الدخل الموجود فعلًا.
- أعد إنتاج المشكلة بدخل واحد صغير ومعروف وطلب واحد. عطّل إعادات المحاولة المتزامنة أثناء عزل الإخفاق.
- سجل حقول الخطأ المنظمة وما إذا اكتمل التنظيف.
شغّل أمر إصدار الحزمة المناسب لتطبيقك فقط. تعرض حلقة الصدفة وجود المتغير من
دون طباعة السر؛ لا تستبدلها بـenv أو أمر آخر يكشف API_KEY.
npm ls @humain-voice/sdk --depth=0
python -c 'from importlib.metadata import version; print(version("humain-voice"))'
for name in API_URL API_KEY; do
if [ -n "$(printenv "$name")" ]; then
printf "%s=set\n" "$name"
else
printf "%s=missing\n" "$name"
fi
doneاختر وضع المعالجة الصحيح
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يتعطل اجتماع طويل أو بودكاست أو ملف أرشيفي في النسخ السريع | استُخدم النسخ السريع لمادة طويلة | كان التسجيل كله موجودًا قبل الطلب وهو طويل | استخدم BatchTranscribeClient واستعلم ضمن مهلة نهائية محدودة |
| يضيف دور محادثة محدود تعقيد بث لا حاجة إليه | استُخدم Realtime رغم وجود الدور كاملًا | لا يصل صوت بعد بدء الطلب | استخدم FastTranscriptionClient للوحدة المكتملة مسبقًا والحساسة لزمن الوصول |
| يُرفع صوت ميكروفون أو مكالمة مرارًا كملفات مكتملة | استُخدم Batch أو الوضع السريع بينما لا يزال الصوت يصل | يجب أن تبدأ المعالجة قبل انتهاء التسجيل | استخدم RealtimeClient أو RealtimeDiarizationClient وأرسل PCM مؤطرًا عند وصوله |
| يُرسل ملف مكتمل كـPCM مباشر أو يُرفع PCM كملف | حدث خلط بين دخل الحاوية ودخل التدفق | قارن بايتات الدخل بعقد العملية المختارة | أرسل ملفًا مشفرًا إلى Batch أو Fast، وأرسل PCM16 LE بلا ترويسة إلى Realtime |
لا يَعِد اختيار الوضع بزمن وصول معين. بل يختار دورة الحياة وعقد الدخل المطابقين للمهمة.
أعراض الاتصال والمصادقة
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
يعيد REST 401 أو 403 | المفتاح مفقود أو غير صالح أو لا يملك وصولًا للعملية | سجل حالة HTTP وcode المنظم، وتأكد فقط من ضبط API_KEY | أرسل القيمة المخصصة كـx-api-key أو api_key؛ وعالج بيانات الاعتماد غير الصالحة أو المرفوضة عبر مسار الوصول المعتمد في مؤسستك |
| يقول مُنشئ Socket.IO إن الرابط أو المفتاح مطلوب | إحدى قيمتي api_url أو api_key فارغة | سجل أسماء الخيارات ووجودها، ولا تسجل قيمة المفتاح | مرر API_URL وAPI_KEY المخصصين؛ ويكون api_path افتراضيًا /socket.io |
يرفع Socket.IO connect_error أو لا يستدعي معالج الاتصال | المضيف أو المسار خاطئ، أو ترقية WebSocket محجوبة، أو المصافحة مرفوضة | قارن API_URL والمسار الفعلي /socket.io بالقيم الصادرة؛ وفي Python أعد الإنتاج مرة مع verbose=True واحتفظ بخطأ المصافحة | استخدم المسار الافتراضي ما لم يوثق نشرك تجاوزًا، وأبقِ نقل WebSocket مفعّلًا، واضبط proxy ليحافظ على الترقية |
| يعمل REST لكن تفشل كل قدرات Socket.IO | مسار Socket.IO أو ترقية WebSocket محجوبان | ينجح طلب REST محمي بينما تفشل مصافحة Socket.IO قبل أي حدث تطبيق | اختبر /socket.io من شبكة الخادم نفسها؛ واضبط API_PATH فقط لتجاوز موثق |
| تُرفض مصافحة Socket.IO قبل أي حدث تطبيق | ترويسة Origin المطلوبة مفقودة أو لا تطابق أصل الخدمة | قارن ترويسات المصافحة المنقحة؛ فقد يكون الجسم صفحة بوابة لا خطأ منصة منظمًا | اضبط Origin على مخطط API_URL ومضيفه. على عميل Socket.IO المباشر ضبطها؛ ويشتقها SDK 0.18.0 من api_url. |
| يتصل عميل Socket.IO المبني يدويًا بشكل مختلف عن SDK | يختلف المسار أو ترويسة مفتاح API أو النقل | افحص المصافحة المنقحة: المسار والنقل ووجود x-api-key | أرسل x-api-key، واختر transports: ["websocket"]، وسجل المعالجات قبل الاتصال |
يستخدم الإصدار 0.18.0 المسار /socket.io افتراضيًا؛ ولا تضبط API_PATH
إلا لتجاوز موثق. وتتطلب نقطة النهاية القديمة sautech.humain.com المسار
/realtime/socket.io. أبقِ الاعتمادات في عملية على الخادم؛ نقل المفتاح إلى
حزمة متصفح أو جوال ليس إصلاحًا للاتصال.
أعراض الصوت والتأطير
افحص المصدر المشفر، ثم أنشئ دخل Realtime الخام الدقيق عند الحاجة:
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,sample_rate,channels,sample_fmt \
-of default=noprint_wrappers=1 input.wav
ffmpeg -i input.wav -ar 16000 -ac 1 -c:a pcm_s16le \
-f s16le realtime.pcm| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
يعيد Batch 422 مع VALIDATION_FILE_CORRUPT | الملف المرفوع تالف أو غير مدعوم | شغّل ffprobe واحتفظ بالحالة وcode وبيانات الملف الوصفية الآمنة | فك الترميز أو حوّله إلى ملف صوت مشفر صالح، ثم أعد المحاولة مرة كرفع جديد |
| يقبل النسخ السريع الرفع من دون نتيجة نهائية مفيدة | تستخدم الحمولة المكتملة حاوية غير مدعومة أو MP4 مشوهًا | تأكد من أنها AAC أو FLAC أو MP3 أو MP4 أو WAV وافحص تخطيط MP4 | أرسل ملفًا مكتملًا مدعومًا واحدًا، وضع ذرة moov في مقدمة MP4 |
| نص Realtime فارغ أو مشوه أو سريع جدًا أو بطيء جدًا | أُرسلت حاوية WAV/MP3 أو عينات big-endian أو تردد أو عدد قنوات خاطئ كـPCM | افحص المصدر بـffprobe وأمر التحويل؛ يجب أن يكون طول حمولة PCM زوجيًا | أرسل بايتات PCM16 little-endian بلا ترويسة، بتردد 16 kHz وأحادية القناة |
| لا يستقبل عميل Realtime مباشر شيئًا | ترويسة التطبيق ذات 18 بايت أو UUID أو الرايات أو بايت اللغة خاطئ | افحص البايتات 0..17، وتأكد من إعادة استخدام UUID واحد وأن الصوت يبدأ في البايت 18 | في audio_stream أرسل الرايات 1 مرة و0 وسطًا و2 مرة في النهاية، واستخدم بايت اللغة الموثق |
| لا يصل التمييز المباشر إلى النهائية | تأطير diarization_stream أو راية النهاية مفقود | تحقق من الترويسة نفسها ذات 18 بايت ومن UUID واحد وبت البداية وبت النهاية | أرسل PCM16 LE بتردد 16 kHz وأحاديًا وإطار نهاية واحدًا بالضبط، وأبقِ بتات الرايات الأخرى صفرًا |
| تصل التحديثات بإيقاع غير منتظم | تختلف أحجام الحمولات كثيرًا عن المساعدات المختبرة | احسب بايتات الصوت بعد الترويسة ذات 18 بايت | ابدأ بـ3,200 بايت صوت لكل إطار Realtime ASR؛ ويوصي SDK بـ15,360 بايت لكل تغذية تمييز مباشر |
أحجام الإطارات إيقاعات مختبرة، وليست ضمانات إنتاجية أو زمن وصول. ينشئ SDK الترويسات؛ افحصها فقط عند بناء تطبيق سلكي مباشر.
أعراض اللغة والنموذج
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| يُتعرف على كلام عربي-إنجليزي كلغة واحدة | لا تصف اللغة والنموذج تبديل اللغتين | سجل قيم التعداد الدقيقة لا تسمياتها فقط | استخدم Language.ArEn مع BatchTranscriptionModel.BayanArEn أو FastTranscriptionModel.BayanArEn |
| يكون النسخ السريع فارغًا مع نموذج اتصالات 8 kHz | فُرض نموذج خاص بـBatch على مسار Fast | لا يوجد NidaArTelephony في FastTranscriptionModel في 0.18.0 | استخدم BatchTranscriptionModel.NidaArTelephony مع Batch، ولا تمرر سلسلته السلكية إلى Fast |
| تتصرف لغة غير متوقعة كالعربية | وصلت سلسلة غير معروفة إلى محول البروتوكول | سجل القيمة الدقيقة الممررة إلى SDK؛ تُحوّل السلاسل المجهولة إلى معرّف البروتوكول 0 في 0.18.0 | مرر Language.Ar أو Language.En أو Language.ArEn بدل تسمية حرة |
| يتضمن إعداد Realtime نموذج ASR خاصًا بـBatch أو Fast | عومل Realtime كمسار ملفات | افحص نوع الاستدعاء؛ يختار RealtimeClient.startStream() / start_stream() اللغة لا نموذج ASR | احذف خيار النموذج ومرر قيمة Language الصحيحة |
| يفشل TTS عبر HTTP المباشر عند عدم تحديد نموذج | يترك المسار المباشر وحده اختيار النموذج للنشر، وقد يختلف الافتراضي المضبوط أو لا يكون متاحًا. أما SDK فيرسل دائمًا nebula عند حذف model، لذا لا يقع هذا عبر TTSClient | سجل حدث error المنظم وحمولة الطلب من دون النص إذا كان حساسًا | أرسل مفتاح النموذج الصريح nebula على المسار المباشر بدل الاعتماد على إعداد النشر |
استخدم الاسم المستعار غير المرقّم BayanArEn لافتراضي تبديل اللغتين في
الإصدار المنشور. اختر BayanArEnV1 أو BayanArEnV2 فقط عندما تحتاج عمدًا
إلى ذلك النموذج المحدد. راجع النماذج واللغات.
أعراض غياب الإشارات النهائية والمهل
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| لا يعود عمل Batch من المساعد | ظل غير نهائي أو أصبح cleared أو تجاوز مهلة المساعد | سجل كل حالة: queued أو processing أو done أو failed أو cleared | استخدم مهلة استعلام محدودة، وتوقف عند done أو failed أو cleared، واستدعِ getResult() / get_result() مباشرة عند الحاجة إلى معالجة cleared فورًا |
| يصل إقرار رفع Fast لكن لا يكتمل الطلب | اعتُبر audio_file_upload_success اكتمالًا للنسخ | طابق id ثم تحقق من transcription_result.is_final === true | انتظر ضمن مهلة تطبيق فقط؛ القيمة الافتراضية لـtimeout_seconds في Python هي 60، بينما لا يملك JavaScript 0.18.0 خيار مهلة لطلب Fast |
يعود RealtimeStream.close() / close() من دون رصد is_final على مستوى البروتوكول | انتهت مهلة انتظار النهاية المحدودة | تتبع is_final الطرفية على السلك؛ انتظار الإغلاق الافتراضي ثانية واحدة | تمثل is_speech_final حد كلام فقط ولا تحقق شرط مساعد SDK. احتفظ بالنص المؤكد ووسم النتيجة غير مكتملة. |
يعيد close() للتمييز خطًا زمنيًا بلا تحديث نهائي | انتهت مهلة إغلاقه ذات خمس ثوانٍ | تتبع isFinal / is_final في آخر تحديث؛ الخط الزمني المعاد أفضل لقطة معروفة | وسمه غير مكتمل ما لم تُرَ النهائية، واحتفظ باللقطة الموفقة وافصل |
| تنتهي مهلة TTS بين المقاطع أو لا يرسل المقطع النهائي | انتهى انتظار خمول كل مقطع أو لم يصل البت 0 في البايت 16 | سجل وقت كل إطار tts_audio وقيمة is_last | افصل بين حد خمول المقطع وحد التوليف كله؛ افتراضي JavaScript لكل مقطع 30 ثانية، بينما لا يضع Python افتراضيًا |
تختلف مهلة SDK عن المهلة النهائية للتطبيق. قد تحد مهلة SDK استعلامًا أو انتظار إغلاق أو المقطع التالي. يجب أن تحد مهلة التطبيق العملية كلها، بما فيها الاتصال والعمل والنهائية وإعادات المحاولة. لا تثبت المهلة مطلقًا إخفاق رفع أو وصول تدفق إلى النهائية.
أعراض نتائج التسميات والتمييز
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| تكرر التسميات المباشرة النص المؤقت | أُلحقت كل transcription_result | سجل id وترتيب الوصول وseq وis_final وis_speech_final | أبقِ سطرًا مؤقتًا واحدًا قابلًا للاستبدال لكل id، وثبّت كلمات الأحداث النهائية أو نهاية الكلام فقط |
يحتفظ RealtimeSubtitles بحدث واحد فقط من عدة أحداث نهائية | يزيل المساعد التكرار حسب id:seq، لكن العقد السلكي الحالي لا يضمن قيم seq متميزة | قارن عدد الأحداث النهائية وقيم seq مع RealtimeSubtitles.words | اجمع كلمات الأحداث النهائية بترتيب الوصول المرصود واعرضها باستخدام Subtitles بعد الإنهاء |
| تتكرر أدوار المتحدثين أو تختفي أو تقفز | جُمعت final_segments وactive_segments الخام بلا توفيق | قارن المصفوفات الخام المتتابعة مع update.segments | اجمع المقاطع النهائية غير المشاهدة، واستبدل الذيل النشط، ورتب حسب البدء، أو استهلك update.segments الموفقة في SDK |
| لا تحمل كلمات Batch متحدثًا رغم وجود التمييز | الخط الزمني للكلمات منفصل عن خط التمييز في شكل الاستجابة | افحص final_word_segments / إزاحات الكلمات وdiarization_segments | وفّق بالتداخل الزمني وحدد قاعدة تطبيق للفجوات أو التداخل الملتبس، ولا تخترع متحدثًا بصمت |
يتجاهل RealtimeSubtitles عمدًا الاستجابات المؤقتة ويلغي تكرار الاستجابات
النهائية حسب id وseq؛ وهذا السلوك نفسه قد يدمج أحداثًا نهائية متميزة بموجب
العقد السلكي الحالي. تظل active_segments في التمييز المباشر قابلة للمراجعة
حتى تنتقل إلى الحالة النهائية.
أعراض أصوات TTS والتشغيل
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
تعيد listVoices() / list_voices() القيمة [] | لا تتوفر نسخة فعلية أو أكثر تحتاجها الهويات المهيأة | سجل طول المصفوفة وأي error منظم، ولا تفهرس العنصر 0 | تعامل مع الحالة الفارغة ولا تخمّن voice_id، وأعد المحاولة ضمن سياسة محدودة فقط |
| ينتظر اكتشاف الأصوات بلا نهاية في Python أو تنتهي مهلته في JavaScript | تختلف قيم المهلة الافتراضية | يفترض JavaScript خمس ثوانٍ، ولا يضع Python افتراضيًا | مرر listVoices({ timeoutSeconds: 5 }) أو list_voices(timeout_seconds=5) صراحة |
| لا يشغل مشغل الوسائط بايتات التوليف | يعيد Socket.IO TTS PCM خامًا لا ملف WAV | تأكد من وصول الاستجابة إلى is_last وافحص عدد البايتات | عامل البايتات كـPCM16 LE بتردد 24 kHz وأحادي، وأضف ترويسة WAV صحيحة باستخدام وصفة TTS إلى WAV المختبرة |
| خرج WAV في JavaScript مبتور أو يحتوي بايتات غير مرتبطة | حُوّل عرض Uint8Array بلا إزاحته وطوله | قارن byteLength مع Buffer.length الناتج | أنشئ Buffer باستخدام byteOffset وbyteLength للعرض |
توقفت الشيفرة التي تطابق label رأيته سابقًا عن إيجاد الصوت | تعرض القائمة تسميات هويات مثل mul_<name> لا تسميات النسخ الفعلية | افحص بيانات profile المعادة | طابق معرّف الهوية id وخزّنه، ولا تطابق label؛ تُرفض معرّفات النسخ الفعلية |
| اختارت هوية متعددة اللغات النسخة الفعلية غير المتوقعة | يتطلب التوجيه العربي حرفًا من محارف الكتابة العربية في text | افحص النص بحثًا عن حرف من محارف الكتابة العربية | يختار أي حرف عربي النسخة العربية؛ وإلا تُختار الإنجليزية |
عند التحليل المباشر لـSocket.IO، تبدأ كل حمولة tts_audio بمعرّف UUID من
16 بايت وبايت ترويسة واحد. ألحق البايتات 17..end فقط؛ البت 0 في البايت
16 هو الإشارة النهائية.
أعراض حدود المعدل وإعادة المحاولة
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
يرفع Batch BatchTranscribeRateLimitError أو يعيد 429 | سعة الصوت غير متاحة مؤقتًا للطلب | افحص retryAfter / retry_after وcapacity وretryable وcode عند وجودها | احترم التأخير المرسل، وأضف تراجعًا أسيًا مع jitter، وضع حدًا للمحاولات والمدة الكلية |
يبدو أن maxRetries / max_retries لا يفعل شيئًا | هو مهمل ومتجاهل في 0.18.0 | يصدر SDK تحذير إهمال عند استخدام قيمة غير صفرية | نفّذ سياسة إعادة المحاولة المحدودة في كود التطبيق |
| يفشل الاتصال بعد إرسال رفع | النتيجة ملتبسة | سجل ما إذا وصل معرّف عمل أو إقرار رفع | لا ترفع مجددًا بلا تمييز؛ لا ينشر API عقد idempotency-key، فطبّق سياسة تطبيق لمنع التكرار أو صعّد بالأدلة |
يقول error في Socket.IO إن retryable: true | صنّف الخادم الحدث قابلًا لإعادة المحاولة، لا مضمون النجاح | التقط id وcode وmessage وretryable وtimestamp من onError / on_error | استخدم الحقل كمدخل واحد في السياسة المحدودة نفسها، ولا تكرر بلا نهاية |
capacity حقل استجابة تشغيلي، لا حصة حساب منشورة أو ضمان توفر. لا تتكرر قراءة
حالة Batch بأمان إلا عندما يحفظ save_result=true الناتج النهائي قبل جلبه؛
وقد تمسحه القراءة الافتراضية. يظل تكرار رفع لا تُعرف نتيجته غير آمن. راجع
الأخطاء وحدود المعدل.
أعراض التنظيف وتسرب الاتصالات
| العَرَض | السبب المرجح | الدليل أو الفحص | الإصلاح |
|---|---|---|---|
| تظل العملية حية بعد اكتمال العمل | ظل عميل Socket.IO أو جلسة HTTP في Python مفتوحًا | سجل إنشاء العميل والإشارة النهائية والتنظيف مرة لكل عملية؛ قد يبلغ Python عن جلسة غير مغلقة | ضع التنظيف في finally، واستدعِ FastTranscriptionClient.close() أو TTSClient.close() أو RealtimeClient.disconnect() أو RealtimeDiarizationClient.disconnect() حسب الحالة |
| يزداد عدد الاتصالات بعد الأخطاء أو المهل | يُنشأ عميل جديد قبل إغلاق العميل المخفق | قارن أعداد استدعاءات الاتصال والانفصال | أعد استخدام عميل سليم واحد حيث يلزم، وأغلق العميل المخفق قبل إعادة المحاولة |
| ينتهي تدفق بلا تنظيف | خرجت حلقة النتائج قبل stream.close() | سجل ما إذا نُفذ الدخل النهائي ومسار الإغلاق | أغلق التدفق داخل finally، ثم افصل العميل إذا وقع الإخفاق خارج تنظيف التدفق المعتاد |
يحذر Python Batch من جلسة aiohttp غير مغلقة | تم تخطي BatchTranscribeClient.close() / close_sync() | أعد إنتاج طلب واحد وراقب إغلاق العملية | استخدم مدير السياق المتزامن أو غير المتزامن، أو استدعِ طريقة الإغلاق المطابقة داخل finally |
تُعد BatchTranscribeClient.close() في JavaScript عملية توافق لا تفعل شيئًا
في 0.18.0؛ إذ تستخدم طلباته fetch. تملك عملاء JavaScript الأخرى اتصالات
Socket.IO وتتطلب مسارات التنظيف الموثقة.
صعّد بأدلة قابلة لإعادة الإنتاج
أعد محاولة دخل واحد معروف فقط عندما تكون النتيجة غير ملتبسة وتسمح السياسة. إذا استمرت المشكلة، فأرسل إلى جهة الاتصال في HUMAIN مثالًا مصغرًا وهذا السجل المنقح:
sdk: "@humain-voice/sdk@0.18.0 | humain-voice==0.18.0"
operation: "batch | fast | realtime | diarization | tts | voice-list"
api_url_host: "host only"
api_path: "Socket.IO path or not-applicable"
started_at_utc: "ISO-8601 timestamp"
request_or_job_id: "UUID if available"
input: "codec, sample_rate, channels, duration, byte_count"
observed: "http_status, event, final_signal"
error: "code, message, retryable, timestamp"
retries: "count and delays"
cleanup: "final frame, stream close, client disconnect"أرفق أصغر مثال كود يعيد إنتاج المشكلة واذكر الإشارة النهائية المتوقعة. لا ترسل مفتاح API، أو رابط Socket.IO كاملًا يحتوي سلسلة الاستعلام، أو صوتًا أو نصًا حساسًا بلا تصريح. عند التباس نتيجة رفع، أرسل نافذته الزمنية بتوقيت UTC وبصمة دخل آمنة وأي معرّف عمل أو طلب بدل إعادة إرساله.
لا تنشر هذه الوثائق رابط حالة انقطاع أو مدة احتفاظ أو حصة أو هدف توفر أو ضمانًا لزمن استجابة الدعم. صعّد إخفاقات الاعتماد ونطاق الوصول إلى مصدر المفتاح، وصعّد إخفاقات البروتوكول أو النهائية القابلة للتكرار بالأدلة أعلاه.