{ nodes, edges } تُرسله إلى مجموعة واحدة من نقاط النهاية. يشغّل التحققُ من صحة المخطط كلَّ عملية إنشاء وكل تعديل قبل الحفظ، وينسخ النشرُ المسودةَ إلى اللقطة الحية، ويتيح لك المحاكي قيادة متصل مبرمج عبر المخطط قبل أن يرنّ أي رقم DID. يشرح هذا الدليل الدورة الكاملة من البداية إلى النهاية.
سنبني تدفقًا صغيرًا بنمط شركات الطيران: تحية المتصل، وتوجيه نوايا الحجز أو الاسترداد إلى طابور ACD، والوقوع في البريد الصوتي عندما لا يطابق أيٌّ منهما. اتبعه خطوة بخطوة، ثم كيّف المخطط مع تفرعاتك الخاصة.
1. أساسيات IVR
تنفّذ بيئة تشغيل الصوت تعريفات التدفق مقابل خط أوامر Jambonz. يتحقق مدقق المخطط — الذي يعمل عند كل إنشاء وتحديث — من وجود عقدة دخول واحدة بالضبط (النوعivrStart)، وعقدة نهائية واحدة على الأقل (hangup, transfer, voicemail, ringGroup, dialByName, offerCallback, offerSmsCallback, scheduleCallback)، ومن أن كل حافة تشير إلى معرفات عقد موجودة، ومن أن كل عقدة يمكن الوصول إليها من الدخول، ومن ألا تكون أي عقدة يمكن الوصول إليها محاصرة في حلقة لا طريق منها إلى نهاية. تحاكي لبنات البناء لغةَ الصوت القابلة للبرمجة — راجع مرجع Programmable Voice DSL لأوامر say / gather / dial / enqueue / transfer / hangup الأساسية التي يصدرها المشغّل.
تكمل نوايا الكلام قوائم DTMF: يطابق نوعا العقد speechInput وdialByName عبارة حرة مع speechIntents لكل عقدة أو مجموعات النوايا لكل مستأجر. تشرح صفحة مفاهيم IVR intents تلك المجموعات — بما في ذلك كيف تصبح قائمة كلام على مستوى العقدة خالية تمامًا من DTMF؛ ويوضح هذا الدليل كيف يدخل الاثنان في تدفق قابل للتشغيل.
2. أنشئ التدفق
أرسل التعريف إلىPOST /api/v1/voice/ivr-flows. يقبل الجسم name ومخطط definition وراية active اختيارية. يعمل المدقق قبل الحفظ، لذلك يعيد المخطط غير السليم 422 IVR_FLOW_GRAPH_INVALID ولا يُخزَّن شيء.
نفس استدعاء الإنشاء من حُزم SDK — يتوافق الجسم مع حقول المخطط ذاتها:
id للتدفق الجديد (معرّف بصيغة ivr_*) — احتفظ به؛ فكل خطوة لاحقة تستخدمه.
تفرّع عقد القائمة حافة واحدة لكل مفتاح DTMF موجود في menuOptions؛ ويرفض المدقق المفاتيح الفارغة أو المكررة أو غير DTMF بالرموز menu_empty_key أو menu_duplicate_key أو menu_invalid_key. تجمع عقد ملء الخانات قيمًا منظمة من الكلام الحر — عرّف عقدة speechInput واحدة بموجّهات لكل كيان، ثم مرّر كل قيمة مجمعة إلى POST /api/v1/voice/ivr-slots/extract، وهي نقطة نهاية عديمة الحالة تقبل utterance ومواصفات slots (الاسم، النوع مثل account_number / order_id / date / amount، الموجّه، required، enumValues) والقيم المجموعة حتى الآن. تعيد filled المحدّث، وnext_prompt لما لا يزال ناقصًا، وراية complete — مرّر خريطة filled عبر الجولات في حالة جلستك الخاصة. راجع تصنيف النوايا في وقت التشغيل (صفحة IVR intents) للمسار الكلامي فقط.
3. تحقق قبل النشر
تحققُ المخطط عند الحفظ سبق أن عمل فيcreate. أعد تشغيله عند كل تعديل — يتحقق PUT /api/v1/voice/ivr-flows/:id من definition المُقدَّم بالطريقة نفسها قبل الحفظ، فلا يصل أي انتقال معطوب إلى الإنتاج أبدًا. إذا فشل الحمل، تعيد واجهة API 422 IVR_FLOW_GRAPH_INVALID مع مدخلات errors مفتاحها الرمز: مشكلات الشكل (no_entry، multiple_entries، no_exit)، والروابط الميتة (orphan_edge_source، orphan_edge_target، unreachable_node)، وفخاخ الحلقات (cycle_without_exit، dead_end_node) حيث يبقى المتصل معلقًا حتى تنهي المنصة المكالمة. خطأ menu_invalid_key في هذا التدفق يعني، مثلًا، أنك كتبت book مفتاحًا فيهبط كل متصل على حافة الاحتياط حتى تصلحه. برمج خطوة CI تضع تدفقًا تجريبيًا بـ PUT بتعريفك المرشح، وتعامل 422 كفشل قبل النشر بدل السماح للبناء.
4. اختبر بالمحاكي
قُد متصلاً مبرمجًا عبر المخطط قبل ربطه برقم DID. يستهلكPOST /api/v1/voice/ivr-flows/:id/simulate القائمةَ turns (كل عنصر فيها يضم digits و/أو speech و/أو intent) ويعيد، لكل خطوة، معرّف العقدة المزارة، والمقبض المطابق المُتّبع، وفئات أوامر verb الصادرة، وtermination_reason. يعيد المشي تشغيل أولوية حواف وقت التشغيل — handle ثم default ثم الحافة الافتراضية الوحيدة — ويتوقف عند العقد التفاعلية (menu, dtmfInput, speechInput, dialByName, offerCallback, offerSmsCallback, scheduleCallback).
reached_nodes: ["start","welcome","menu","bookings"]، وemitted_verbs يشمل gather عند القائمة وenqueue عند الطابور، وtermination_reason: "queue_answered" (الطابور الذي لا يملك overflow تجريبيًا ينتهي كمُجاب). شغّل المسار الاحتياطي أيضًا — أرسل turns: [] فارغة فينتهي المسار عند القائمة بحالة awaiting_input؛ وأرسل ضغطة digits: "9" فيتبع المحاكي حافة default الخاصة بك إلى البريد الصوتي. يلتقط المحاكى الأحمر تراجعات التوجيه قبل أن تحرق دقيقة حية، فعامله بوصفه المكافئ داخل المنتج لأداة اختبارات تراجع IVR. يكون JSON لتعريف DSL مطابقًا بايتيًا أيًّا كان العميل الذي يصدر الطلب — curl أو Node SDK أو Python، كلها ترسل المخطط نفسه بـ POST.
خيارات مفيدة: source: "published" يمشي على اللقطة الحية، وsource: "draft" (الافتراضي) يمشي على المسودة غير المحفوظة؛ أما definition (جسم المخطط الكامل) فيحاكي مرشحًا غير محفوظ ضمنًا.
غلاف القبول — الترويسات والجسم والحالة التي تعود إليك:
Response — 200 OK
422 IVR_FLOW_GRAPH_INVALID (مع تعبئة meta.request_id لفرز الدعم) ويعني أن المخطط فشل في التحقق — يُصلح قبل أن يتقدم أي تشغيل.
5. اربط التدفق برقم DID
يحمل إعداد التوجيه الوارد لكل رقم DID مرجع التدفق. اضبطtype: "ivr" مع config.flowId:
cURL
6. حوّل المكالمة إلى موظف
وجّه فرعsupport إلى طابور ACD عبر عقدة queue (أمر enqueue بلغة DSL) ليتلقى أحد أعضاء الفريق المكالمة من لوحة التحكم، أو وجّه التدفق كله إلى وكيل AI تحتفظ نقطة نهاية handback الموجودة فيه بسياق المحادثة وتصعّد مجددًا إلى الذكاء الاصطناعي بعد أن يحل إنسان الحالة الاستثنائية. كلا المسارين موثق هناك — عقدة queue في هذا التدفق هي نصف التحويل الذي يغذي طابورًا؛ وتغطي صفحة handback عودة حلقة النوايا.
7. المنشئ المرئي — المخطط نفسه دون JSON
كل ما سبق مخطط{ nodes, edges } بالنسبة إلى كودك، لكن المشغلين يعملون عادة في IVR Builder بلوحة التحكم — سطح التصميم من الطراز الأول الذي يظهر فيه المخطط نفسه شجرة مرئية. تُقرأ قائمة DTMF كما تُقرأ الشجرة التي تنتجها: عقدة لكل خيار، وحافة موسومة لكل مفتاح. أسقط عقدة Menu من لوحة المكونات وهي تتفرع أصلًا لكل مفتاح؛ وصِل كل فرع بطابور أو مجموعة رنين أو بريد صوتي أو قائمة أخرى، ويُبقي القماشُ الشجرةَ مقروءة عبر Auto-layout. تُحفظ المسودات تلقائيًا كمسودات (لا يمكن لأي متصل بلوغها)، ويفحص فحص Validate المسبق الفروعَ غير القابلة للوصول والمفاتيح المكررة والطرق المسدودة قبل النشر، ويمشي المحاكي المدمج متصلاً مبرمجًا عبر المسودة دون حرق دقيقة حية. يقلب Publish المخطط إلى اللقطة الحية — إنه published-definition نفسه الذي تكتبه واجهة API.
من أين تفتحه: Voice → IVR Builder في لوحة التحكم. كل أنواع العقد في هذا الدليل موجودة في لوحة المكونات، وربط DID نفسه على بُعد نقرتين من المنشئ: اختر التدفق في تبويب التوجيه الوارد لرقم (Numbers → الرقم → Routing)، أو اربطه من شريط أدوات المنشئ. بعد النشر، افتح لوحة تحليلات عقدة في المنشئ لترى تسرب القمع لكل عقدة — البيانات نفسها التي يعيدها node-analytics — وهي التي تخبرك عادة بما تعدّله بعد ذلك.
أي سطح تختار؟ المنشئ أداة التصميم؛ وواجهة API هي المخطط نفسه لخطوط CI والبنية بوصفها كودًا. الدورة المدفوعة بواجهة API أعلاه هي العقد الكامل؛ ويكتب المنشئ الكائن ذاته في نقاط النهاية ذاتها.
محرر القواعد في لوحة المنشئ
حدد عقدة Speech Input فتتحول اللوحة اليمنى إلى محرر قواعد كلام كامل — كائنspeechIntents نفسه لكل عقدة الذي تقبله واجهة API، يُحرَّر سطرًا بسطر:
- اسم النية — أحرف صغيرة وأرقام وشرطات وشرطات سفلية. يصبح كل اسم مقبض حافة على العقدة؛ وصِله بالطابور أو وكيل AI أو التدفق الفرعي لتلك العبارة. تعلّم اللوحة الأسماء المكررة والمعيبة ضمنًا، والاسم الموصول أصلًا بحافة هو ما تشير إليه الحافة اللاحقة، فأعد التسمية قبل التوصيل.
- Phrases — عبارة في كل سطر. تُسطَّح كل عبارة إلى تلميحات تعرّف Deepgram، وعند وقت المكالمة يطابق النص المنسوخ معها بعد التطبيع (تُتسامح الحالة وعلامات الترتيب وترتيب الكلمات). المطابقة حساب نصوص حتمي بين العبارة والنسخة — لا تعمل أي جولة LLM في الـ gather الحي.
- Keypad digit (optional) — رقم DTMF واحد لكل نية (مثل
1). يطابَق الرقم قبل أي كلام، فيجد المتصل الذي لا يُسمع صوته طريقه أيضًا. يظهر فقط عندما يكون احتياط لوحة المفاتيح مفعلًا. - Keypad fallback toggle — مفتاح تشغيل/إيقاف للأرقام. أطفئه لتجعل القائمة كلامية فقط: لا يجمع الـ gather أرقامًا، وكل عبارة لا يطابقها أحد تسقط إلى مقبض
nomatchالخاص بالعقدة. العقد المحفوظة قبل وجود هذا التحكم تتصرف كما لو كان مفعلًا، فتبقى قوائم الكلام القديمة تقبل الأرقام حتى تطفئها. - STT provider — Deepgram افتراضيًا؛ اختر Google أو Microsoft أو AWS أو افتراضي المجموعة إذا كانت العقدة تحتاج متعرفًا آخر.
- Min confidence — عتبة ثقة من 0 إلى 1 لتحويل الكلام إلى نص. تركه فارغًا يبقي افتراضي المزود؛ وإذا ضبطته، يُرفض النص المتعرف عليه تحت العتبة كعدم مطابقة، فلا تُسقط خطوط مشوشة المتصل على نية خاطئة أبدًا.
speechInput node
bookings بعد التطبيع، ويتبع المشي حافة bookings. العبارة نفسها بثقة 0.41 تحت العتبة، فلا يطابق شيء ويتبع المشي حافة nomatch. وحتى مع الاحتياط مطفأ، يوجّه الرقم 1 إلى bookings — الرقم يكسب دائمًا على الكلام — لكن مع dtmfFallbackEnabled: false لا يجمع الـ gather أي أرقام إطلاقًا وكل إدخال بالمفاتيح أعلاه كلام خالص. (وللنسخة الخالية حقًا من الأرقام، احذف dtmfKey أيضًا.)
تحتفظ اللوحة بمسودة كل نية منفصلة عن المخطط المثبت: تُقرأ عبارات العقدة المحفوظة المخزنة إلى المحرر عند التحميل، وتُكتب التعديلات بصيغة الإرسال عند الحفظ، فلا يعيد فتح عقدة Speech Input محفوظة عرض صفوف فارغة أبدًا.
يقع التوجيه لكل عبارة خارج عبارات الكلمات المفتاحية (أوصاف المجموعات، عتبات الثقة على مستوى المستأجر كله) في صفحة مفاهيم IVR intents — راجع قسم قوائم الكلام الخالية من DTMF.
8. إصدارات وتراجع
يضيف كل نشر صفًا إلى سجل إصدارات التدفق. يدرجGET /api/v1/voice/ivr-flows/:id/versions كل لقطة منشورة (version، definition، published_at)؛ ويقارن GET /:id/versions/:version/compare لقطة بمسودتك الحالية ويبلغ عن معرفات العقد المضافة والمحذوفة والمعدّلة لترى بالضبط ما أدخله تعديل. وللتراجع، يعيد POST /:id/versions/:version/revert تلك اللقطة ويعيد نشرها كرأس جديد — استدعاء واحد بدل جلب التعريف القديم وإعادة ربطه. يستمر رقم DID المرفوع في الإجابة على الرأس المُرجَع.
التدفق أعلاه مكتمل: تم التحقق منه عند الحفظ، وحوكي قبل النشر، ورُبط برقم DID، ويمكن استرجاعه إلى أي إصدار سابق. ابدأ منه وغيّر التفرعات فقط.