تطبيق macOS المرافق

طبقة الصوت

الجمهور: مساهمو تطبيق macOS. الهدف: الحفاظ على طبقة الصوت متوقعة عند تداخل كلمة التنبيه والضغط للتحدث.

النية الحالية

  • إذا كانت الطبقة مرئية بالفعل من كلمة التنبيه وقام المستخدم بالضغط على المفتاح السريع، فإن جلسة المفتاح السريع تتبنى النص الموجود بدلاً من إعادة تعيينه. تبقى الطبقة ظاهرة أثناء استمرار الضغط على المفتاح السريع. عند إفلات المستخدم: أرسل إذا كان هناك نص مقصوص، وإلا أغلق.
  • كلمة التنبيه وحدها لا تزال ترسل تلقائياً عند الصمت؛ الضغط للتحدث يرسل فوراً عند الإفلات.

المنفذ (9 ديسمبر 2025)

  • تحمل جلسات الطبقة الآن رمزاً مميزاً لكل عملية التقاط (كلمة التنبيه أو الضغط للتحدث). يتم تجاهل التحديثات الجزئية/النهائية/الإرسال/الإغلاق/مستوى الصوت عندما لا يتطابق الرمز المميز، مما يتجنب استدعاءات قديمة.
  • يتبنى الضغط للتحدث أي نص مرئي في الطبقة كبادئة (لذا فإن الضغط على المفتاح السريع أثناء ظهور طبقة التنبيه يحافظ على النص ويضيف كلاماً جديداً). ينتظر حتى 1.5 ثانية للحصول على نسخة نهائية قبل التراجع إلى النص الحالي.
  • يتم إصدار سجلات النغمة/الطبقة بمستوى info في الفئات voicewake.overlay، voicewake.ptt، و voicewake.chime (بداية الجلسة، جزئي، نهائي، إرسال، إغلاق، سبب النغمة).

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

  1. VoiceSessionCoordinator (ممثل)
    • يمتلك جلسة VoiceSession واحدة فقط في كل مرة.
    • واجهة برمجة التطبيقات (قائمة على الرموز المميزة): beginWakeCapture، beginPushToTalk، updatePartial، endCapture، cancel، applyCooldown.
    • يتجاهل الاستدعاءات التي تحمل رموزاً مميزة قديمة (يمنع المعالجات القديمة من إعادة فتح الطبقة).
  2. VoiceSession (نموذج)
    • الحقول: token، source (wakeWord|pushToTalk)، نص ثابت/متغير، أعلام النغمة، المؤقتات (إرسال تلقائي، خامل)، overlayMode (عرض|تحرير|إرسال)، موعد انتهاء فترة التهدئة.
  3. ربط الطبقة
    • VoiceSessionPublisher (ObservableObject) يعكس الجلسة النشطة في SwiftUI.
    • VoiceWakeOverlayView يعرض فقط عبر الناشر؛ لا يعدل مباشرةً الكائنات المفردة العامة.
    • إجراءات المستخدم على الطبقة (sendNow، dismiss، edit) تستدعي مرة أخرى إلى المنسق مع رمز الجلسة.
  4. مسار إرسال موحد
    • عند endCapture: إذا كان النص المقصوص فارغاً → أغلق؛ وإلا performSend(session:) (يعزف نغمة الإرسال مرة واحدة، يمرر، يغلق).
    • الضغط للتحدث: لا تأخير؛ كلمة التنبيه: تأخير اختياري للإرسال التلقائي.
    • تطبيق فترة تهدئة قصيرة على وقت تشغيل التنبيه بعد انتهاء الضغط للتحدث حتى لا تعيد كلمة التنبيه التشغيل فوراً.
  5. التسجيل
    • يصدر المنسق سجلات .info في النظام الفرعي ai.openclaw، والفئات voicewake.overlay و voicewake.chime.
    • الأحداث الرئيسية: session_started، adopted_by_push_to_talk، partial، finalized، send، dismiss، cancel، cooldown.

قائمة التحقق للتصحيح

  • بث السجلات أثناء إعادة إنتاج طبقة عالقة:

    نسخ

    sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact
    
  • التحقق من وجود رمز جلسة نشط واحد فقط؛ يجب أن يتجاهل المنسق الاستدعاءات القديمة.

  • التأكد من أن إفلات الضغط للتحدث يستدعي دائماً endCapture مع الرمز النشط؛ إذا كان النص فارغاً، توقع dismiss بدون نغمة أو إرسال.

خطوات الهجرة (مقترحة)

  1. إضافة VoiceSessionCoordinator، و VoiceSession، و VoiceSessionPublisher.
  2. إعادة هيكلة VoiceWakeRuntime لإنشاء/تحديث/إنهاء الجلسات بدلاً من التعديل المباشر على VoiceWakeOverlayController.
  3. إعادة هيكلة VoicePushToTalk لتبني الجلسات الموجودة واستدعاء endCapture عند الإفلات؛ تطبيق فترة تهدئة وقت التشغيل.
  4. توصيل VoiceWakeOverlayController بالناشر؛ إزالة الاستدعاءات المباشرة من وقت التشغيل/الضغط للتحدث.
  5. إضافة اختبارات تكامل لتبني الجلسات، فترة التهدئة، وإغلاق النص الفارغ.

Voice WakeWebChat