Traverba: تطبيق Flutter يشغّل 3 نماذج ASR ونموذج LLM محلياً وكاميرا OCR — كل ذلك على الجهاز مباشرةً

بنيتُ Traverba — مترجمًا فوريًا يعمل 100% على هاتفك دون أي APIs سحابية. يتضمن التعرف على الصوت، والترجمة بين 108 لغة، وتعرف الكاميرا على النصوص في 92 لغة مكتوبة، وطبقة ترجمة الشاشة، وترجمة الملفات الصوتية، والدردشة الجماعية بدون إنترنت عبر Bluetooth لما يصل إلى 7 أشخاص.

التطبيق بأكمله مبني بـ Flutter مع كود أصلي لتشغيل العمليات الثقيلة. إليك ما يفعله التطبيق، ولماذا كان Flutter الخيار الصحيح، وأبرز التحديات التي واجهتها في إطلاقه على iOS و Android معًا.

ما الذي يفعله التطبيق

يمتلك Traverba خمس ميزات أساسية، كلها تعمل بدون إنترنت:

الترجمة الصوتية الفورية — تتكلم بلغة فتسمع وتقرأ الترجمة بلغة أخرى. ثلاثة أوضاع: داخل التطبيق، وطبقة عائمة لالتقاط صوت النظام (تترجم صوت Zoom/Teams/Meet)، وميكروفون عائم. مع القراءة التلقائية بصوت عالٍ باللغة الهدف.

ترجمة الكاميرا — وجّه كاميرتك نحو قائمة طعام أو لافتة أو نموذج أو مستند. محركان للتعرف الضوئي على الحروف: وضع Basic (ML Kit) للقراءة الخفيفة، ووضع Professional (PaddleOCR) للكتابات المعقدة كاليابانية والصينية والعربية والسيريلية والديفاناغاري. يدعم 92 لغة. يستبدل التطبيق النص الأجنبي بالنص المترجم مباشرةً فوق الصورة.

ترجمة الشاشة — طبقة عائمة تترجم النص داخل أي تطبيق. تشاهد أنيمي، أو تقرأ أخبارًا كورية، أو تلعب لعبة يابانية، أو تستقبل رسالة WeChat؟ اضغط على زر الطبقة العائمة ويُترجَم النص في مكانه مباشرةً، دون الحاجة للتبديل بين التطبيقات.

ترجمة الملفات — استورد ملفات صوتية أو مرئية (mp3, m4a, wav, mp4) واحصل على نصوص منقحة بطوابع زمنية تعرض المصدر والترجمة جنبًا إلى جنب.

الدردشة الجماعية بدون إنترنت — يتصل حتى 7 أشخاص عبر شبكة Bluetooth. كل شخص يتكلم بلغته، وتُترجَم كل رسالة إلى لغة كل مشارك في الوقت الفعلي. لا إنترنت، لا خادم، كل هاتف يتولى بنفسه عمليات التعرف على الكلام والترجمة.

كل هذا يعمل محليًا على معالج هاتفك. لا مفاتيح API، ولا تكاليف خوادم، ولا بيانات تغادر الجهاز.

لماذا Flutter

قيّمتُ Flutter وReact Native والتطوير الأصلي بالكامل (قاعدتا كود Swift + Kotlin منفصلتان) في البداية.

قاعدة كود واحدة لمنصتين كانت شرطًا لا تنازل عنه. مطوّر منفرد يصون قاعدتَي كود أصليتين لتطبيق بهذا التعقيد كان أمرًا غير واقعي. طبقة Dart للواجهة — الإعدادات، وفقاعات المحادثة، وعروض النصوص المنقحة، وجولة الإعداد، وصفحات التنزيل، ومحددات اللغة — تمثّل نحو 60% من إجمالي الكود. كتابتها مرتين كانت ستضاعف وقت المشروع.

نظام قنوات المنصة في Flutter جعل التكامل الأصلي ممكنًا عمليًا. تعمل المهام الذكية الثقيلة (استنتاج ASR، وترجمة نموذج اللغة الكبير، وOCR، وشبكة Bluetooth، والطبقات العائمة) في كود Swift/Kotlin أصلي عبر قنوات المنصة. Flutter لا يتولى تشغيل نماذج الذكاء الاصطناعي — بل يقوم بدور واجهة المستخدم وطبقة التنسيق التي تربط المحركات الأصلية.

الأداء كان كافيًا. القلق مع Flutter لهذا النوع من التطبيقات هو الحمل الإضافي — كل ميلي ثانية تُحسَب حين تسلسل ASR ← ترجمة ← TTS في المحادثة. في الواقع، تضيف طبقة Flutter زمن استجابة لا يُذكَر لأن الحساب الثقيل يجري في الكود الأصلي. تتولى طبقة Dart إدارة الحالة والتوجيه وتحديثات الواجهة، وتؤدي ذلك بكفاءة.

أسرع التحميل الساخن تكرار الواجهة بشكل ملحوظ. مع خمس واجهات ميزات مختلفة (صوت، كاميرا، شاشة، ملف، دردشة جماعية)، لكل منها حالات وأوضاع متعددة، كانت القدرة على تكرار الواجهة دون إعادة البناء مضاعفًا حقيقيًا للإنتاجية.

المعمارية: Flutter كمنسّق

يتبع التطبيق تقسيمًا واضحًا:

طبقة Flutter/Dart تتولى:

  • كامل الواجهة (Material 3، وتخطيطات تكيّفية للهاتف والجهاز اللوحي)
  • إدارة الحالة وتوجيه الميزات
  • اختيار اللغة والمنطقة وتفضيلات المستخدم
  • إدارة تنزيل النماذج الاختيارية
  • اقتصاد العملات وبوابات الاشتراك
  • جولة الإعداد التفاعلية

الطبقة الأصلية تتولى (عبر قنوات المنصة):

  • استنتاج ASR (sherpa-onnx / whisper.cpp)
  • ترجمة نموذج اللغة الكبير (Gemma عبر بيئة تشغيل على الجهاز)
  • الترجمة التقليدية بالتعلم الآلي (نماذج ONNX NMT)
  • التعرف الضوئي على الحروف بالكاميرا (ML Kit + PaddleOCR)
  • تحويل النص إلى كلام
  • شبكة Bluetooth للدردشة الجماعية
  • الطبقة العائمة (ترجمة الشاشة والتقاط صوت النظام)
  • إدارة ميزانية الذاكرة وتحميل النماذج وإخلاؤها

الجسر بين هاتين الطبقتين عبارة عن مجموعة قنوات منصة بعقود محددة بوضوح. تُرسل طبقة Dart الأوامر ("ابدأ ASR للكانتونية"، "ترجم هذا النص من اليابانية إلى الإنجليزية"، "التقط الشاشة وطبّق OCR"). ترجع الطبقة الأصلية النتائج بشكل غير متزامن.

ثلاثة نماذج ASR، توجيه تلقائي

لا يوجد نموذج واحد للتعرف على الكلام يغطي جميع اللغات بشكل جيد. بدلًا من القبول بجودة رديئة لبعض اللغات، يأتي التطبيق مع ثلاثة نماذج متخصصة:

  • Parakeet محسَّن للإنجليزية. مضمّن في التطبيق لتعرف فوري على الكلام الإنجليزي دون تنزيل.
  • Whisper.cpp تغطية متعددة اللغات واسعة تشمل 30+ لغة.
  • Qwen3-ASR محسَّن للكتابات الصينية/اليابانية/الكورية مع دعم مخصص للكانتونية.

عند اختيار المستخدم للغة المصدر، تختار طبقة توجيه Dart أفضل نموذج وتُخبر الطبقة الأصلية بالمحرك المطلوب تفعيله. المستخدم لا يرى عملية اختيار النموذج ولا يديرها.

الجانب المعقّد هو الذاكرة. تتراوح هذه النماذج بين 500MB و1.9GB من ذاكرة الوصول العشوائي. تحميل الثلاثة في آنٍ واحد سيتسبب في انهيار معظم الهواتف. مخطط ميزانية الذاكرة (مكتوب بـ Dart ويستعلم عن إحصاءات الذاكرة الأصلية) يتتبع ما هو محمّل ويُخلي النموذج الأقل استخدامًا حين يحتاج نموذج جديد إلى التحميل. يتذكر مخزن تفضيلات الواجهة الخلفية أي واجهة حسابية (NPU أو GPU أو CPU) نجحت على كل جهاز بعينه، فتتخطى عمليات التشغيل اللاحقة الواجهات التي فشلت.

108 لغة عبر مستويَين من الترجمة

تسير الترجمة عبر مسارين:

المستوى الأول — نماذج NMT التقليدية (61 لغة): سريعة، قليلة الذاكرة، جودة عالية لأزواج اللغات الرئيسية. نماذج ONNX تعمل عبر sherpa-onnx على كلتا المنصتين.

المستوى الثاني — نموذج Gemma LLM على الجهاز (47 لغة إضافية): للغات التي لا تملك نماذج NMT مخصصة (اليوروبا، الأمهرية، اللاوية، الميانمارية وغيرها)، يتولى نموذج Gemma 2B المضغوط الترجمة محليًا. أبطأ من المستوى الأول، لكنه يوسّع التغطية للغات التي تخدمها النماذج التقليدية بشكل رديء.

تدير طبقة Dart أي مستوى تستخدم استنادًا إلى زوج اللغات. المستخدم يرى تجربة موحّدة.

تعرف الكاميرا: محركان مزدوجان، 92 لغة

تشغّل ترجمة الكاميرا محركين يختار المستخدم بينهما:

وضع Basic يستخدم التعرف على النص على الجهاز من Google ML Kit. سريع، يتعامل جيدًا مع الكتابة اللاتينية والسيريلية والصينية/اليابانية/الكورية. مناسب للاستخدام الفوري في محدد الكاميرا.

وضع Professional يستخدم PaddleOCR على الجهاز. دقة أفضل للتخطيطات المعقدة والنصوص المختلطة والنص المنحني والتباين المنخفض. يستخدم بوابة العملات (5 عملات لكل التقاط) لأنه أكثر كثافةً حسابيًا.

درس مؤلم تعلمتُه: iOS يضم فقط نموذج التعرف على النص اللاتيني بشكل افتراضي. الكتابات الصينية/اليابانية/الكورية والديفاناغاري والعربية تتطلب إضافة pods خاصة بكل كتابة صراحةً في Podfile. الفشل صامت تمامًا — يُرجع ML Kit نتائج فارغة للكتابات غير المدعومة دون أي خطأ. إن كنت تبني تعرفًا متعدد اللغات على iOS مع ML Kit، تحقق من Podfile.

الطبقة العائمة: أصلية لا Flutter

تعمل ميزتا ترجمة الشاشة والتقاط صوت النظام كطبقات عائمة أصلية خارج سطح الرسم الخاص بـ Flutter. على Android، هذه خدمة طبقة نظام مكتوبة بـ Kotlin. على iOS، تستخدم APIs التقاط الشاشة في Swift.

تتواصل هذه الطبقات العائمة مع محرك الترجمة في Flutter عبر قنوات المنصة. التحدي المعماري هو إدارة دورة الحياة — يجب أن تبقى الطبقة العائمة نشطة بينما قد تكون نشاط Flutter الرئيسية في الخلفية.

درس بالغ الأهمية: على iOS، يجب الإبقاء على نسخ الجسر الأصلي بشكل قوي (static أو محتجز بواسطة singleton). إن كان الجسر متغير نسخة لا يحتجزه شيء، سيعيد ARC جمع الذاكرة منه وستصبح جميع إغلاقات المعالج ops-no بصمت. أضعتُ أيامًا في سبب تعثّر مؤشر تقدم التنزيل عند 0% لأن الجسر كان يُجمَع. لا انهيار، لا خطأ، مجرد صمت.

الدردشة الجماعية عبر Bluetooth

تستخدم الدردشة الجماعية بدون إنترنت بروتوكول شبكة Bluetooth. كل هاتف يعمل كمستقبل وموجِّه في آنٍ واحد. الرسائل تُبثّ لجميع الأجهزة المتصلة. كل جهاز يشغّل بنفسه التعرف على الكلام والترجمة — لا يوجد هاتف "مضيف" أو "خادم".

يتولى Flutter واجهة الدردشة وحالة الرسائل وإدارة المشاركين. حزمة Bluetooth أصلية بالكامل (CoreBluetooth على iOS، ومكتبة Android Bluetooth API) مربوطة عبر قنوات المنصة.

إجمالي زمن الاستجابة من بداية إلى النهاية (صوت ← ASR ← ترجمة ← بثّ ← عرض) نحو ثانية واحدة. تستخدم واجهة Dart العرض التفاؤلي (تُظهر "جارٍ الترجمة..." فور الإرسال) لتجعل المحادثة تبدو سلسة.

الأرقام

  • اللغات: 108 إجمالاً (61 تعلم آلة + 47 ذكاء اصطناعي)
  • لغات ASR: 30 لغة للتعرف على الكلام على الجهاز
  • لغات OCR: 92 لغة للتعرف على نص الكاميرا
  • حجم التطبيق الأساسي: ~150MB + نماذج قابلة للتنزيل
  • المنصات: iOS + Android من قاعدة كود Flutter واحدة
  • كود Dart/Flutter: ~60% من إجمالي قاعدة الكود (الواجهة، الحالة، التوجيه، منطق الأعمال)
  • الكود الأصلي: ~40% (ASR، LLM، OCR، Bluetooth، الطبقات العائمة، إدارة الذاكرة)
  • حجم الفريق: 1

ما أصابه Flutter في هذا المشروع

قاعدة كود واحدة لواجهة معقدة. خمس واجهات ميزات، أوضاع متعددة لكل منها، صفحات تنزيل، جولة إعداد، تخطيطات تكيّفية — كتابة هذا مرة واحدة بدلًا من مرتين كان الفارق بين الشحن وعدمه بصفتي مطوّرًا منفردًا.

قنوات المنصة مصمَّمة بإتقان. الجسر بين Dart والكود الأصلي واضح وموثق جيدًا وموثوق. لتطبيق يكون فيه الحساب الثقيل أصليًا وتجربة المستخدم في Flutter، هذه هي المعمارية الصحيحة تمامًا.

إعادة التحميل الساخن للتكرار السريع. ضبط التخطيطات، واختبار الحالات، وتكرار تدفقات تجربة المستخدم — خفّض إعادة التحميل الساخن وقت التكرار من دقائق إلى ثوانٍ عبر مئات من تغييرات الواجهة.

النظام البيئي ناضج. إدارة الحالة (Riverpod)، والتنقل، والتوطين (117 لغة)، والتصميم التكيّفي — يمتلك نظام Flutter البيئي حلولًا بجودة إنتاجية لكل هذه الاحتياجات.

ما كان صعبًا

ضغط الذاكرة هو نقطة عمى Flutter. لا يُتيح Flutter تحكمًا دقيقًا في الذاكرة. حين تُحمّل عدة نماذج تعلم آلة أصلية جانبًا إلى جانب محرك Flutter، تحتاج إلى إدارة الذاكرة على المستوى الأصلي وعكسها إلى Dart. لا توجد Flutter API مدمجة تُخبرك "كم ذاكرة وصول عشوائي يستخدم تطبيقي" أو "ما ضغط ذاكرة النظام".

دورة حياة الطبقة العائمة الأصلية. الطبقات العائمة التي تعمل خارج سطح Flutter معقدة معماريًا. قد تكون نشاط Flutter في الخلفية بينما الطبقة العائمة نشطة. إبقاء الجسر حيًا وإدارة مزامنة الحالة ومعالجة أحداث دورة حياة كل منصة تطلّب كودًا أصليًا كثيفًا لا تستطيع Flutter تجريده.

تعقيد بناء iOS. CocoaPods مع pods نصوص ML Kit، والتراخيص (increased-memory-limit لتحميل ASR + LLM معًا)، وتوقيت App Tracking Transparency، وتوقيع الكود — خط بناء iOS به أجزاء متحركة كثيرة لا تديرها أدوات Flutter بالكامل.

جرّبه

Traverba مجاني على كلتا المنصتين. الترجمة الصوتية وترجمة الكاميرا وترجمة الشاشة والترجمة النصية كلها مجانية وغير محدودة. بريميوم ($1.99/شهر) يفتح الدردشة الجماعية وترجمة الملفات وملخصات الاجتماعات.

متاح على Google Play وApp Store. تعرّف على المزيد في traverba.com.

يسعدني الإجابة على أسئلة حول المعمارية أو أنماط التكامل بين Flutter والكود الأصلي أو الذكاء الاصطناعي على الجهاز بشكل عام.