Traverba: Ứng Dụng Flutter Chạy 3 Mô Hình ASR, LLM Nội Thiết Bị và OCR Camera — Hoàn Toàn Trên Thiết Bị

Tôi đã xây dựng Traverba — một ứng dụng dịch thuật thời gian thực chạy 100% trên điện thoại của bạn, không cần bất kỳ API đám mây nào. Nhận diện giọng nói, dịch thuật qua 108 ngôn ngữ, OCR camera với 92 bộ chữ viết, overlay dịch màn hình, phiên âm tệp và trò chuyện nhóm ngoại tuyến qua Bluetooth cho tối đa 7 người.

Toàn bộ ứng dụng được xây dựng bằng Flutter kết hợp với code native cho các tác vụ nặng. Dưới đây là những gì ứng dụng làm được, lý do Flutter là lựa chọn phù hợp, và những thách thức lớn nhất tôi gặp phải khi phát hành lên cả iOS và Android.

Ứng Dụng Làm Được Gì

Traverba có năm tính năng cốt lõi, tất cả đều hoạt động ngoại tuyến:

Dịch Giọng Nói Trực Tiếp — Nói bằng một ngôn ngữ, nghe và đọc bản dịch bằng ngôn ngữ khác. Ba chế độ: trong ứng dụng, chụp âm thanh hệ thống dạng overlay nổi (dịch âm thanh từ Zoom/Teams/Meet), và micro overlay nổi. Tự động đọc to kết quả dịch bằng ngôn ngữ đích.

Dịch Camera — Hướng camera vào thực đơn, biển hiệu, biểu mẫu hoặc tài liệu. Hai công cụ OCR: chế độ Basic (ML Kit) để đọc mau, chế độ Professional (PaddleOCR) cho các bộ chữ phức tạp như CJK, tiếng Ả Rập, Cyrillic và Devanagari. Hỗ trợ 92 ngôn ngữ. Ứng dụng thay thế văn bản nước ngoài bằng bản dịch trực tiếp trên ảnh.

Dịch Màn Hình — Một overlay nổi dịch văn bản bên trong bất kỳ ứng dụng nào. Đang xem anime, đọc tin tức tiếng Hàn, chơi game Nhật Bản, hay nhận tin nhắn WeChat? Chỉ cần nhấn nút overlay và văn bản được dịch ngay tại chỗ. Không cần chuyển đổi ứng dụng.

Phiên Âm Tệp — Nhập tệp âm thanh hoặc video (mp3, m4a, wav, mp4) và nhận bản phiên âm có dấu thời gian, song song gốc và dịch.

Trò Chuyện Nhóm Ngoại Tuyến — Tối đa 7 người kết nối qua mạng lưới Bluetooth. Mỗi người nói ngôn ngữ của mình. Mỗi tin nhắn được dịch sang ngôn ngữ của tất cả người tham gia theo thời gian thực. Không cần internet, không cần máy chủ. Mỗi điện thoại tự xử lý ASR và dịch thuật độc lập.

Tất cả điều này chạy cục bộ trên bộ xử lý của điện thoại. Không cần API key, không tốn chi phí máy chủ, không có dữ liệu nào rời khỏi thiết bị.

Tại Sao Chọn Flutter

Tôi đã đánh giá Flutter, React Native và hoàn toàn native (hai codebase riêng biệt Swift + Kotlin) từ đầu.

Đa nền tảng từ một codebase duy nhất là yêu cầu không thể thiếu. Một lập trình viên solo duy trì hai codebase native cho một ứng dụng phức tạp như vậy là không thực tế. Lớp UI Dart — cài đặt, bong bóng trò chuyện, màn hình phiên âm, tour giới thiệu, màn hình tải xuống, bộ chọn ngôn ngữ — chiếm khoảng 60% tổng lượng code. Viết những thứ đó hai lần sẽ tăng gấp đôi thời gian dự án.

Hệ thống platform channel của Flutter giúp tích hợp native trở nên khả thi. Phần nặng về AI (suy luận ASR, dịch LLM, OCR, mạng lưới Bluetooth, overlay nổi) chạy trong native Swift/Kotlin thông qua platform channel và method channel. Flutter không cố trở thành môi trường chạy AI — nó là lớp UI và điều phối kết nối các engine native.

Hiệu năng đủ tốt. Mối lo ngại với Flutter cho loại ứng dụng này là overhead — mỗi mili giây đều quan trọng khi bạn đang kết nối chuỗi ASR → dịch → TTS trong một cuộc trò chuyện. Trong thực tế, lớp Flutter thêm độ trễ không đáng kể vì tính toán nặng xảy ra trong code native. Lớp Dart xử lý quản lý trạng thái, routing và cập nhật UI, và nó làm điều đó tốt.

Hot reload tăng tốc đáng kể quá trình lặp lại UI. Với năm bề mặt tính năng riêng biệt (giọng nói, camera, màn hình, tệp, trò chuyện nhóm), mỗi cái có nhiều trạng thái và chế độ, khả năng lặp lại UI mà không cần rebuild là bộ nhân năng suất đáng kể.

Kiến Trúc: Flutter Là Bộ Điều Phối

Ứng dụng tuân theo sự phân tách rõ ràng:

Lớp Flutter/Dart xử lý:

  • Toàn bộ UI (Material 3, layout thích ứng cho điện thoại và máy tính bảng)
  • Quản lý trạng thái và routing tính năng
  • Chọn ngôn ngữ/vùng miền và tùy chọn người dùng
  • Quản lý tải xuống cho các mô hình tùy chọn
  • Kinh tế xu và kiểm soát gói đăng ký
  • Tour giới thiệu hướng dẫn

Lớp Native xử lý (qua platform channel):

  • Suy luận ASR (sherpa-onnx / whisper.cpp)
  • Dịch LLM (Gemma qua runtime nội thiết bị)
  • Dịch ML truyền thống (mô hình ONNX NMT)
  • OCR camera (ML Kit + PaddleOCR)
  • Chuyển văn bản thành giọng nói
  • Mạng lưới Bluetooth cho trò chuyện nhóm
  • Overlay nổi (dịch màn hình + chụp âm thanh hệ thống)
  • Quản lý ngân sách bộ nhớ và tải/giải phóng mô hình

Cầu nối giữa các lớp này là một tập hợp platform channel với các hợp đồng được định nghĩa rõ ràng. Phía Dart gửi lệnh ("bắt đầu ASR cho tiếng Quảng Đông," "dịch văn bản này từ tiếng Nhật sang tiếng Anh," "chụp màn hình và OCR"). Phía native trả về kết quả bất đồng bộ.

Ba Mô Hình ASR, Routing Tự Động

Không có mô hình nhận diện giọng nói nào bao phủ tốt tất cả các ngôn ngữ. Thay vì chấp nhận chất lượng kém cho một số ngôn ngữ, ứng dụng đi kèm ba mô hình chuyên biệt:

  • Parakeet Tối ưu cho tiếng Anh. Đi kèm ứng dụng để ASR tiếng Anh tức thì mà không cần tải xuống.
  • Whisper.cpp Bao phủ đa ngôn ngữ rộng trên 30+ ngôn ngữ.
  • Qwen3-ASR Tối ưu cho CJK với hỗ trợ tiếng Quảng Đông chuyên dụng.

Khi người dùng chọn ngôn ngữ nguồn, lớp routing Dart chọn mô hình tốt nhất và báo cho phía native engine nào cần kích hoạt. Người dùng không bao giờ thấy hoặc quản lý việc chọn mô hình.

Phần phức tạp là bộ nhớ. Các mô hình này dao động từ 500MB đến 1.9GB trong RAM. Tải cả ba đồng thời sẽ làm hỏng hầu hết điện thoại. Một bộ lập kế hoạch ngân sách bộ nhớ (viết bằng Dart, truy vấn số liệu bộ nhớ native) theo dõi những gì đã tải và giải phóng mô hình ít được dùng gần nhất khi cần tải một mô hình mới. Một cửa hàng ưu tiên backend ghi nhớ backend tính toán nào (NPU, GPU, CPU) hoạt động trên mỗi thiết bị cụ thể, để các lần chạy tiếp theo bỏ qua các backend thất bại.

108 Ngôn Ngữ qua Hai Tầng Dịch Thuật

Dịch thuật xảy ra qua hai con đường:

Tầng 1 — Mô hình NMT truyền thống (61 ngôn ngữ): Nhanh, ít bộ nhớ, chất lượng tốt cho các cặp ngôn ngữ có tài nguyên phong phú. Các mô hình ONNX chạy qua sherpa-onnx trên cả hai nền tảng.

Tầng 2 — LLM Gemma nội thiết bị (47 ngôn ngữ bổ sung): Đối với các ngôn ngữ không có mô hình NMT chuyên dụng (Yoruba, Amharic, Lao, Myanmar và các ngôn ngữ khác), một mô hình Gemma 2B lượng tử hóa xử lý dịch thuật cục bộ. Chậm hơn Tầng 1, nhưng mở rộng phạm vi sang các ngôn ngữ mà mô hình truyền thống phục vụ kém.

Lớp Dart quản lý tầng nào cần sử dụng dựa trên cặp ngôn ngữ. Người dùng thấy một trải nghiệm thống nhất.

OCR Camera: Hai Engine, 92 Ngôn Ngữ

Dịch camera chạy hai engine mà người dùng có thể chọn:

Chế độ Basic sử dụng nhận diện văn bản nội thiết bị của Google ML Kit. Nhanh, xử lý tốt Latin, Cyrillic và CJK. Phù hợp để dùng với màn hình ngắm thời gian thực.

Chế độ Professional sử dụng PaddleOCR chạy nội thiết bị. Độ chính xác tốt hơn cho bố cục phức tạp, chữ viết hỗn hợp, văn bản cong và độ tương phản thấp. Sử dụng cổng xu (5 xu mỗi lần chụp) vì tốn nhiều tài nguyên tính toán hơn.

Một bài học học được theo cách khó khăn: iOS chỉ đi kèm mô hình script OCR Latin theo mặc định. CJK, Devanagari và tiếng Ả Rập yêu cầu phải thêm các pod dành riêng cho script vào Podfile một cách tường minh. Lỗi này hoàn toàn im lặng — ML Kit trả về kết quả rỗng cho các script không được hỗ trợ mà không có thông báo lỗi. Nếu bạn đang xây dựng OCR đa ngôn ngữ trên iOS với ML Kit, hãy kiểm tra Podfile của bạn.

Overlay Nổi: Native, Không Phải Flutter

Các tính năng dịch màn hình và âm thanh hệ thống chạy dưới dạng overlay native bên ngoài bề mặt render của Flutter. Trên Android, đây là dịch vụ overlay hệ thống viết bằng Kotlin. Trên iOS, nó sử dụng API chụp màn hình trong Swift.

Các overlay này giao tiếp trở lại với engine dịch thuật Flutter qua platform channel. Thách thức kiến trúc là quản lý vòng đời — overlay phải tồn tại trong khi activity Flutter chính có thể đang ở nền.

Một bài học quan trọng: trên iOS, các instance bridge native phải được giữ lại mạnh mẽ (static hoặc được giữ bởi singleton). Nếu bridge là biến instance mà không có gì giữ lại, ARC sẽ thu gom rác nó và tất cả các closure handler sẽ âm thầm trở thành no-op. Tôi đã mất nhiều ngày vì chỉ báo tiến trình tải xuống bị kẹt ở 0% vì bridge đang bị thu gom. Không có crash, không có lỗi, chỉ là thất bại im lặng.

Trò Chuyện Nhóm Bluetooth

Trò chuyện nhóm ngoại tuyến sử dụng giao thức mạng lưới Bluetooth. Mỗi điện thoại hoạt động vừa là bộ nhận vừa là bộ tiếp sóng. Tin nhắn phát sóng đến tất cả thiết bị đã kết nối. Mỗi thiết bị chạy ASR và dịch thuật của riêng mình độc lập — không có điện thoại "chủ" hay "máy chủ".

Flutter xử lý UI trò chuyện, trạng thái tin nhắn và quản lý người tham gia. Ngăn xếp Bluetooth hoàn toàn native (CoreBluetooth trên iOS, Android Bluetooth API) được kết nối qua platform channel.

Độ trễ pipeline tổng cộng (giọng nói → ASR → dịch → phát sóng → hiển thị) khoảng 1 giây. UI Dart sử dụng hiển thị lạc quan (hiện "đang dịch..." ngay lập tức khi gửi) để cuộc trò chuyện có cảm giác phản hồi nhanh.

Số Liệu

  • Ngôn ngữ: 108 tổng cộng (61 ML + 47 AI)
  • Ngôn ngữ ASR: 30 ngôn ngữ nhận diện giọng nói nội thiết bị
  • Ngôn ngữ OCR: 92 ngôn ngữ nhận diện văn bản camera
  • Kích thước ứng dụng cơ bản: ~150MB + các mô hình có thể tải xuống
  • Nền tảng: iOS + Android từ một codebase Flutter duy nhất
  • Code Dart/Flutter: ~60% tổng codebase (UI, trạng thái, routing, business logic)
  • Code native: ~40% (ASR, LLM, OCR, Bluetooth, overlay, quản lý bộ nhớ)
  • Quy mô nhóm: 1

Flutter Làm Đúng Điều Gì Cho Dự Án Này

Codebase duy nhất cho UI phức tạp. Năm bề mặt tính năng, mỗi cái nhiều chế độ, màn hình tải xuống, tour giới thiệu, layout thích ứng — viết một lần thay vì hai lần là sự khác biệt giữa việc phát hành được và không, khi là lập trình viên solo.

Platform channel được thiết kế tốt. Cầu nối giữa Dart và code native sạch sẽ, tài liệu tốt và đáng tin cậy. Đối với ứng dụng mà tính toán nặng là native nhưng trải nghiệm người dùng là Flutter, đây chính xác là kiến trúc phù hợp.

Hot reload để lặp lại nhanh. Tinh chỉnh layout, kiểm tra trạng thái, lặp lại luồng UX — hot reload cắt giảm thời gian lặp lại từ vài phút xuống vài giây qua hàng trăm thay đổi UI.

Hệ sinh thái đã trưởng thành. Quản lý trạng thái (Riverpod), điều hướng, bản địa hóa (117 vùng miền), thiết kế thích ứng — hệ sinh thái Flutter có giải pháp chất lượng sản xuất cho tất cả những điều này.

Những Gì Khó Khăn

Áp lực bộ nhớ là điểm mù của Flutter. Flutter không cung cấp kiểm soát bộ nhớ chi tiết. Khi bạn đang tải đồng thời nhiều mô hình ML native cùng với engine Flutter, bạn cần quản lý bộ nhớ ở cấp độ native và đưa nó trở lại Dart. Không có Flutter API tích hợp nào cho "ứng dụng của tôi đang sử dụng bao nhiêu RAM" hoặc "áp lực bộ nhớ hệ thống là bao nhiêu."

Vòng đời overlay native. Các overlay nổi hoạt động bên ngoài bề mặt Flutter có kiến trúc phức tạp. Activity Flutter có thể ở nền trong khi overlay đang hoạt động. Giữ cho bridge còn sống, quản lý đồng bộ hóa trạng thái và xử lý các sự kiện vòng đời dành riêng cho nền tảng đòi hỏi code native đáng kể mà Flutter không thể trừu tượng hóa.

Độ phức tạp build iOS. CocoaPods với các pod script ML Kit, entitlement (increased-memory-limit để tải đồng thời ASR + LLM), thời điểm App Tracking Transparency, ký code — quy trình build iOS có nhiều thành phần chuyển động mà tooling của Flutter không quản lý hoàn toàn.

Dùng Thử

Traverba miễn phí trên cả hai nền tảng. Dịch giọng nói, camera, màn hình và văn bản đều miễn phí và không giới hạn. Premium ($1.99/tháng) mở khóa trò chuyện nhóm, phiên âm tệp và tóm tắt cuộc họp.

Có sẵn trên Google PlayApp Store. Tìm hiểu thêm tại traverba.com.

Tôi rất vui được trả lời các câu hỏi về kiến trúc, các mẫu tích hợp Flutter + native, hoặc AI nội thiết bị nói chung.