يعرض Bruno Capuano، بصفته Cloud Advocate، طريقة بناء تطبيق لتحويل الكلام إلى نص مباشرة باستخدام C# وFoundry Local ونموذج nemotron-speech-streaming-en-0.6b. يلتقط التطبيق الصوت من الميكروفون، ويرسل البيانات الصوتية الخام إلى جلسة بث مفتوحة، ثم يعرض النتائج المرحلية أثناء حديث المستخدم والنتائج النهائية عند اكتمال كل مقطع صوتي.
المثال الكامل متاح في مستودع Generative-AI-for-beginners-dotnet ضمن المسار الخاص بعينة Foundry Local للتفريغ الحي. أما المقاطع البرمجية في المقال فتركز على واجهات Foundry Local، وتحذف بعض تفاصيل مستوى التطبيق لتبسيط الشرح، مثل معالجة الأخطاء والتنظيف الكامل للموارد.
إدارة النموذج عبر Foundry Local
تبدأ العملية بإنشاء مدير Foundry Local، ثم تسجيل موفري التنفيذ المتوافقين مع العتاد المكتشف. بعد ذلك يستخرج التطبيق الكتالوج ويطلب النموذج باستخدام الاسم المستعار، قبل تنزيله وتحميله:
يتولى Foundry Local تنزيل ملفات النموذج وموفري التنفيذ المطلوبين للعتاد المتاح. وفي التشغيل الأول يُنزّل نموذج Nemotron speech وتُخزّن الملفات مؤقتاً، بينما يمكن للتشغيلات اللاحقة إعادة استخدام النسخة الموجودة في ذاكرة Foundry Local المؤقتة بدلاً من تنزيلها من جديد.
يشدد المقال على ضرورة الحصول على النموذج من كتالوج Foundry Local وتنزيله عبر model.DownloadAsync()، بدلاً من تنزيل ملفاته منفصلة من Hugging Face. كما يستطيع Foundry Local اختيار نسخة النموذج وموفر التنفيذ المناسبين للعتاد المتاح، ما يتيح تشغيل هذا النوع من أحمال الذكاء الاصطناعي محلياً من دون الاعتماد بالضرورة على وحدة معالجة رسومات.
إنشاء جلسة تحويل صوتي مباشرة
بعد تحميل النموذج، يحصل التطبيق على AudioClient وينشئ جلسة للتحويل الحي. يضبط المثال معدل أخذ العينات عند 16 كيلوهرتز، وقناة صوتية واحدة، واللغة على en، لأن نسخة Nemotron المستخدمة مخصصة للإنجليزية فقط.
لا تتعامل الجلسة مع ملف صوتي مكتمل كما يحدث في التحويل الدفعي، بل تبقى مفتوحة وتستقبل بيانات PCM الخام بينما يتحدث المستخدم. ويستخدم المثال مكتبة NAudio عبر WaveInEvent لالتقاط الصوت بمعدل 16 كيلوهرتز، وعمق 16 بت، وقناة واحدة.
وبما أن رد نداء NAudio متزامن، في حين أن session.AppendAsync() غير متزامنة، يضع التطبيق مقاطع الصوت في قناة محدودة السعة، ثم يرسلها إلى الجلسة من مهمة مستقلة. وتستخدم القناة سياسة DropOldest عند امتلائها، بما يساعد على احترام آلية الضغط العكسي وتجنب إنشاء عدد غير محدود من العمليات غير المتزامنة التي تعمل في الخلفية.
قراءة النتائج المرحلية والنهائية
تصل نتائج التحويل عبر تدفق غير متزامن. ويقترح المثال استهلاك هذا التدفق في مهمة مختلفة عن المهمة التي تستدعي AppendAsync()، حتى لا تؤدي قراءة النتائج إلى تعطيل التقاط الصوت.
تُعرض النتيجة المرحلية فور توفرها أثناء حديث المستخدم، بينما تُرسل النتيجة النهائية عند اكتمال العبارة. ويضع التطبيق السابقة [FINAL] أمام النص النهائي، مع عرض النتائج المرحلية بشكل مستمر. ويمكن لهذا النمط أن يخدم التعليقات الحية، وتدوين ملاحظات الاجتماعات، وتطبيقات سطح المكتب التي تعمل بالأوامر الصوتية، وأدوات إمكانية الوصول، والحلول الطرفية ذات الاتصال المحدود.
دورة حياة الموارد ومتى يناسب التشغيل المحلي
يتضمن المثال مساراً للتنظيف يوقف جلسة التحويل ويفرغ النموذج حتى عند وقوع استثناء. كما يستخدم المفتاح Enter للإيقاف المنظم. أما تطبيقات سطر الأوامر التي تدعم Ctrl+C، فينبغي أن تتعامل مع Console.CancelKeyPress، وتلغي العمل النشط، ثم تسمح بإكمال مسار التنظيف نفسه.
يوضح المثال أيضاً إمكانية استخدام RemoveFromCacheAsync() لإزالة النموذج الذي جرى تنزيله عند عدم الحاجة إلى الاحتفاظ به. وفي التطبيق المعتاد، يساعد إبقاء النموذج في الذاكرة المؤقتة على تجنب تنزيله مرة أخرى عند التشغيل التالي.
وفق العرض، يظل الصوت الملتقط من الميكروفون على الجهاز، ولا يحتاج التطبيق إلى مورد ذكاء اصطناعي سحابي أو مفتاح API. وبعد تنزيل النموذج للمرة الأولى، يمكن للاستدلال أن يعمل من دون رحلة ذهاب وإياب عبر الشبكة، كما يمكن لنموذج البث العمل عبر نسخة وحدة المعالجة المركزية التي يحددها Foundry Local.
في المقابل، لا يقدم المقال التشغيل المحلي بديلاً لكل أحمال الذكاء الاصطناعي السحابية؛ فالنماذج الأكبر، والإدارة المركزية، والتوسع المرن، وغيرها من الخدمات السحابية تظل مهمة. لكنه يراه خياراً عملياً لمطوري .NET في حالات الصوت الحساس للخصوصية، والتجارب التي تعمل دون اتصال، والنماذج الأولية، والتطبيقات التي تتطلب معالجة على الجهاز.