الإملاء البثّي
Parakeet-EOU-120M هو نموذج ASR بثّي صغير من نوع RNN-T مزوّد برأس صريح لنهاية النطق (EOU)، مبنيّ من أجل الإملاء الفوري على Neural Engine في Apple Silicon. يغطّي هذا الدليل أيضًا DictateDemo، تطبيق macOS المرجعي في شريط القوائم الذي يربط النموذج البثّي بـ Silero VAD لتوفير إملاء بدون استخدام اليدين يلصق النص في أي مكان.
ما هو
- جزئيات حيّة — يتحدّث النص أثناء كلامك، نحو 340 ميلي ثانية بعد كل قطعة
- EOU صريح — يقرّر النموذج وقت انتهاء النطق دون زرّ يدويّ
- إنهاء قسري بقيادة VAD — يضمن دعم Silero الاحتياطي تأكيد النطق حتى حين يتعطّل EOU بسبب ضجيج الخلفية
- 120 ميغابايت INT8 CoreML — يعمل على Neural Engine ويترك وحدة معالجة الرسومات حرّة لنماذج أخرى
- 25 لغة أوروبية — نفس عائلة المفردات لنموذج NeMo Parakeet TDT الأصلي
المعمارية
ثلاثة نماذج CoreML تعمل بالتسلسل لكل قطعة صوتية:
| المكوّن | الوصف |
|---|---|
| المُرمِّز | Conformer واعٍ للذاكرة المؤقتة. يستقبل قطعة mel من 64 إطارًا (640 ميلي ثانية) إضافةً إلى ستة موترّات حالة — ذاكرة KV للانتباه، وذاكرة الالتفاف العمقي (depthwise)، وحلقة استرجاع mel باسم pre_cache تضيف الصوت الماضي القريب أمام القطعة الحالية كي ترى FFT إشارة متواصلة عبر حدود القطع. |
| المُفكِّك | شبكة تنبّؤ LSTM ذات خطوة واحدة. يستهلك التوكن السابق غير الفارغ، وينتج تضمينًا مع حالة (h, c) محدّثة. |
| الوصلة Joint + رأس EOU | يدمج مخرجات المُرمِّز والمُفكِّك في احتمالات على vocab + blank + EOU. صنف EOU هو الإشارة الصارمة من النموذج بأن النطق قد انتهى. |
لماذا توكن EOU مستقلّ
يصدر RNNT العادي قيمًا فارغة blanks أثناء الصمت، فيبتلعها المُفكِّك بكلّ سرور دون الإشارة إلى "انتهاء النطق". يتيح رأس EOU مخصّص للنموذج إجراء قطع صارم لتأكيد الجزئية بوصفها نهائية، وإعادة ضبط حالة الترقيم والكتابة بأحرف كبيرة، وتشغيل إجراءات لاحقة مثل اللصق في التطبيق.
قد تتسبّب نقرات لوحة المفاتيح وحركة الفأرة وضجيج الغرفة أثناء وقفة "صامتة" في أن تُصدر الوصلة Joint من حين لآخر توكنًا غير فارغ، فتُعاد ساعة debounce لـ EOU ويتعطّل التأكيد. تجمع خطوط الإنتاج بين EOU في الوصلة ودعم خارجي بقيادة VAD يستدعي forceEndOfUtterance() — انظر DictateDemo أدناه.
النموذج
| النموذج | الحجم | HuggingFace |
|---|---|---|
| Parakeet-EOU-120M (CoreML INT8) | ~120 ميغابايت | aufklarer/Parakeet-EOU-120M-CoreML-INT8 |
الأداء
| المقياس | القيمة |
|---|---|
| ذاكرة الأوزان | ~120 ميغابايت (INT8) |
| الذاكرة القصوى للاستدلال | ~200 ميغابايت |
| زمن استجابة القطعة (سلسلة M) | ~30 ميلي ثانية حساب / 640 ميلي ثانية صوت (RTF ~0.056) |
| زمن استجابة الجزئيات الكلّي | ~340 ميلي ثانية (قطعة واحدة) |
| زمن استجابة التأكيد (مسار VAD) | ~1 ثانية بعد توقّف الكلام |
| هدف الحساب | Neural Engine (CoreML) |
بداية سريعة — تفريغ دفعي
يلتزم النموذج البثّي أيضًا ببروتوكول SpeechRecognitionModel، فيعمل بديلًا مباشرًا في أي شيفرة تستقبل نموذج STT عامًّا:
import ParakeetStreamingASR
let model = try await ParakeetStreamingASRModel.fromPretrained()
let text = try model.transcribeAudio(audioSamples, sampleRate: 16000)
بداية سريعة — بثّ غير متزامن
for await partial in model.transcribeStream(audio: samples, sampleRate: 16000) {
if partial.isFinal { print("FINAL: \(partial.text)") }
else { print("... \(partial.text)") }
}
يحمل كل PartialTranscript الحقول text وisFinal وconfidence وeouDetected (هل أُطلق من الوصلة Joint أم بإنهاء قسري) ومؤشّر segmentIndex رتيبًا.
واجهة جلسة طويلة العمر (دخل الميكروفون)
للإملاء المباشر، أنشئ جلسة مرّة واحدة ثم زوّدها بالقطع كما تصل من الميكروفون. تخزّن الجلسة العيّنات داخليًا وتشغّل المُرمِّز عند تراكم ما يكفي منها، فيمكنك دفع قطع بأي حجم:
let session = try model.createSession()
// each mic chunk:
let partials = try session.pushAudio(float32Chunk16kHz)
for p in partials {
if p.isFinal { commit(p.text) }
else { showPartial(p.text) }
}
// when the stream ends:
let trailing = try session.finalize()
نمط الإنهاء القسري بـ VAD
حين يكون لديك Silero VAD يعمل أصلًا في خطّ أنابيبك، استخدمه لتشغيل تأكيد احتياطي حتى لا يتمكّن ضجيج الخلفية من تعطيل ساعة debounce لـ EOU:
if hasPendingUtterance && !vadSpeechActive && vadSilentChunks >= 30 {
// ~960 ms of sustained silence per Silero
if let forced = session.forceEndOfUtterance() {
commit(forced.text)
}
hasPendingUtterance = false
}
// guardrail: don't double-commit if joint already fired EOU
if partials.contains(where: { $0.isFinal }) {
hasPendingUtterance = false
}
DictateDemo — تطبيق macOS المرجعي في شريط القوائم
DictateDemo هو وكيل كامل لشريط قوائم macOS مبنيّ فوق الجلسة البثّية. يعمل تطبيقًا في الخلفية، ويفرّغ النص من الميكروفون مع جزئيات حيّة، ويؤكّد النطق تلقائيًا عند EOU أو صمت VAD، ثم يلصق النتائج في التطبيق الأمامي.
- تطبيق في شريط القوائم باختصار عام
Cmd+Shift+D - جزئيات حيّة مع HUD عائم ومؤشّر لمستوى الصوت
- إنهاء قسري محميّ بـ VAD (نمط الإنتاج أعلاه)
- اللصق في التطبيق الأمامي عبر
Cmd+Shift+V - تنزيل تلقائي للنموذج عند الإطلاق الأول (~120 ميغابايت)
cd Examples/DictateDemo
swift build
.build/debug/DictateDemo
يقع التنفيذ الكامل في Examples/DictateDemo/DictateDemo/DictateViewModel.swift: مغرفة صوت خارج المسار الرئيسي ببافر محميّ بقفل، ودقّة مؤقّت كل 300 ميلي ثانية تصرّف ما فيه، وSilero VAD مع تمرير العيّنات المتبقية، وإنهاء قسري محميّ. تغطّي اختبارات الانحدار المماثلة في Examples/DictateDemo/Tests/DictateDemoTests.swift حالات النطق المتعدّد، وعالقية EOU، والصمت الضجيج.
البثّي مقابل Parakeet الدفعي
| Parakeet-EOU-120M (بثّي) | Parakeet TDT 0.6B (دفعي) | |
|---|---|---|
| حالة الاستخدام | إملاء مباشر، ترجمة فورية في الوقت الحقيقي | تفريغ ملفات، مهام دون اتصال |
| المُفكِّك | RNN-T + رأس EOU | Token-and-Duration Transducer |
| حجم القطعة | 640 ميلي ثانية بثّي | دفعة كاملة لملف بأكمله |
| ذاكرة الأوزان | ~120 ميغابايت | 500 ميغابايت |
| الإنتاجية | ~18 ضعفًا من الزمن الحقيقي | ~32 ضعفًا من الزمن الحقيقي |
| زمن الاستجابة | جزئيات ~340 ميلي ثانية | عند نهاية الملف فقط |
…تحتاج إلى جزئيات قبل أن ينتهي المستخدم من الكلام. أمّا للتفريغ الدفعي لملفات الصوت، فإن Parakeet TDT 0.6B الأكبر أسرع كلّيًا وأكثر دقّة. يتقاسم النموذجان نفس مفردات SentencePiece، فيمكن التبديل بينهما دون تغيير في الترميز.