macOS companion app

โอเวอร์เลย์เสียง

วงจรชีวิตของโอเวอร์เลย์เสียง (macOS)

กลุ่มเป้าหมาย: ผู้มีส่วนร่วมของแอป macOS เป้าหมาย: ทำให้โอเวอร์เลย์เสียงคาดการณ์ได้เมื่อคำปลุกและกดเพื่อพูดทำงานทับซ้อนกัน

เจตนาปัจจุบัน

  • หากโอเวอร์เลย์แสดงอยู่แล้วจากคำปลุกและผู้ใช้กดปุ่มลัด เซสชันจากปุ่มลัดจะ รับช่วง ข้อความที่มีอยู่แทนการรีเซ็ต โอเวอร์เลย์จะยังคงแสดงอยู่ขณะกดปุ่มลัดค้างไว้ เมื่อผู้ใช้ปล่อยปุ่ม: ส่งหากมีข้อความหลังตัดช่องว่างแล้ว มิฉะนั้นให้ปิด
  • คำปลุกเพียงอย่างเดียวยังคงส่งอัตโนมัติเมื่อเงียบ ส่วนกดเพื่อพูดจะส่งทันทีเมื่อปล่อยปุ่ม

ดำเนินการแล้ว (9 ธ.ค. 2025)

  • ตอนนี้เซสชันโอเวอร์เลย์มีโทเค็นต่อการจับเสียงแต่ละครั้ง (คำปลุกหรือกดเพื่อพูด) การอัปเดตข้อความบางส่วน/สุดท้าย/ส่ง/ปิด/ระดับจะถูกทิ้งเมื่อโทเค็นไม่ตรงกัน เพื่อหลีกเลี่ยงคอลแบ็กเก่า
  • กดเพื่อพูดจะรับช่วงข้อความโอเวอร์เลย์ที่มองเห็นอยู่เป็นคำนำหน้า (ดังนั้นการกดปุ่มลัดขณะโอเวอร์เลย์คำปลุกแสดงอยู่จะคงข้อความไว้และต่อท้ายคำพูดใหม่) ระบบจะรอทรานสคริปต์สุดท้ายนานสูงสุด 1.5 วินาทีก่อนถอยกลับไปใช้ข้อความปัจจุบัน
  • บันทึก chime/overlay ถูกปล่อยที่ระดับ info ในหมวดหมู่ voicewake.overlay, voicewake.ptt และ voicewake.chime (เริ่มเซสชัน, บางส่วน, สุดท้าย, ส่ง, ปิด, เหตุผล chime)

ขั้นตอนถัดไป

  1. VoiceSessionCoordinator (แอกเตอร์)
    • ถือครอง VoiceSession เพียงหนึ่งรายการในแต่ละครั้ง
    • API (อิงโทเค็น): beginWakeCapture, beginPushToTalk, updatePartial, endCapture, cancel, applyCooldown
    • ทิ้งคอลแบ็กที่มีโทเค็นเก่า (ป้องกันไม่ให้ตัวรู้จำเก่าเปิดโอเวอร์เลย์อีกครั้ง)
  2. VoiceSession (โมเดล)
    • ฟิลด์: token, source (wakeWord|pushToTalk), ข้อความที่ยืนยันแล้ว/ชั่วคราว, แฟล็ก chime, ตัวจับเวลา (ส่งอัตโนมัติ, ว่าง), overlayMode (display|editing|sending), เส้นตาย cooldown
  3. การผูกโอเวอร์เลย์
    • VoiceSessionPublisher (ObservableObject) สะท้อนเซสชันที่ทำงานอยู่เข้าไปยัง SwiftUI
    • VoiceWakeOverlayView เรนเดอร์ผ่าน publisher เท่านั้น และไม่แก้ไข singleton ส่วนกลางโดยตรง
    • การกระทำของผู้ใช้บนโอเวอร์เลย์ (sendNow, dismiss, edit) เรียกกลับเข้า coordinator พร้อมโทเค็นเซสชัน
  4. เส้นทางการส่งแบบรวม
    • เมื่อ endCapture: หากข้อความหลังตัดช่องว่างว่างเปล่า → ปิด; มิฉะนั้น performSend(session:) (เล่น chime สำหรับการส่งหนึ่งครั้ง, ส่งต่อ, ปิด)
    • กดเพื่อพูด: ไม่มีการหน่วงเวลา; คำปลุก: หน่วงเวลาได้สำหรับการส่งอัตโนมัติ
    • ใช้ cooldown สั้น ๆ กับรันไทม์คำปลุกหลังจากกดเพื่อพูดเสร็จ เพื่อไม่ให้คำปลุกถูกทริกเกอร์ซ้ำทันที
  5. การบันทึก
    • Coordinator ปล่อยบันทึก .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
    
  • ตรวจสอบว่ามีโทเค็นเซสชันที่ทำงานอยู่เพียงหนึ่งรายการ คอลแบ็กเก่าควรถูกทิ้งโดย coordinator

  • ตรวจให้แน่ใจว่าการปล่อยปุ่มกดเพื่อพูดเรียก endCapture พร้อมโทเค็นที่ทำงานอยู่เสมอ หากข้อความว่างเปล่า ควรเห็น dismiss โดยไม่มี chime หรือการส่ง

ขั้นตอนการย้าย (แนะนำ)

  1. เพิ่ม VoiceSessionCoordinator, VoiceSession และ VoiceSessionPublisher
  2. รีแฟกเตอร์ VoiceWakeRuntime ให้สร้าง/อัปเดต/สิ้นสุดเซสชันแทนการแตะ VoiceWakeOverlayController โดยตรง
  3. รีแฟกเตอร์ VoicePushToTalk ให้รับช่วงเซสชันที่มีอยู่และเรียก endCapture เมื่อปล่อยปุ่ม; ใช้ runtime cooldown
  4. เชื่อม VoiceWakeOverlayController เข้ากับ publisher; ลบการเรียกโดยตรงจาก runtime/PTT
  5. เพิ่มการทดสอบอินทิเกรชันสำหรับการรับช่วงเซสชัน, cooldown และการปิดเมื่อข้อความว่างเปล่า

ที่เกี่ยวข้อง