Số hóa và hỏi đáp văn bản hành chính tiếng Việt.
Mọi model chạy ngay trên máy, không cần Internet.
Tiếng Việt | English
30 giây cho cả pipeline, trên một văn bản giả lập. Xem bản MP4 1080p.
OCR VBHC là ứng dụng desktop cho Windows. Ứng dụng biến bản quét PDF hoặc ảnh của văn bản hành chính thành văn bản có cấu trúc, cho phép tra cứu toàn văn và hỏi đáp với một trợ lý pháp luật trả lời kèm trích dẫn tới đúng trang. Cả pipeline (OCR, embedding, rerank, sinh câu trả lời) chạy cục bộ bằng llama.cpp và PyTorch. Lúc chạy không có lệnh gọi mạng nào, nên văn bản, chỉ mục và hội thoại luôn nằm trên máy.
|
Đọc |
Hiểu |
Trả lời |
Không gian làm việc gồm kho văn bản, bản PDF và trợ lý pháp luật. Trợ lý đang so sánh một kế hoạch với tờ trình trước đó, và mỗi nhận định đều có nguồn. Mọi văn bản trong ảnh là văn bản giả lập của "tỉnh Mẫu", một tỉnh không có thật.
|
|
Toàn văn và Thông tin: sửa từng trường NĐ30, chọn ngày ban hành bằng lịch, mỗi lần lưu là một phiên bản. |
Trợ lý pháp luật: nguồn hiện thành chip, bấm vào là mở đúng trang PDF. |
Hai giao diện sáng và tối dùng chung một bảng màu xanh ô liu và vàng trên nền giấy trung tính. Biểu tượng lấy từ bộ Fluent UI System Icons, chữ giao diện dùng Be Vietnam Pro, còn nội dung văn bản hiển thị bằng Times New Roman như bản gốc.
- Đầu vào. Nhận một tệp, nhiều tệp hoặc cả thư mục PDF/ảnh. Trang PDF được dựng thành ảnh với DPI thích ứng.
- OCR. Chandra OCR 2 (vision-language model, GGUF Q4_K_M) chạy trên
llama-servercủa llama.cpp. Mỗi worker giữ một KV slot riêng (12 288 ô ngữ cảnh) và tắt chế độ thinking. Kết quả là HTML bố cục cho từng trang. - Cửa kiểm tra trang. Trang bị cắt cụt, lặp vòng, không có HTML hoặc lẫn lời suy luận bị chặn lại và đọc lại tuần tự một lần. Nếu vẫn lỗi, lời suy luận và đoạn lặp bị loại khỏi văn bản, còn trang đó được đánh dấu để người dùng OCR lại.
- Bóc tách trường NĐ30. Gồm 12 trường: số ký hiệu, ngày ban hành, loại văn bản, cơ quan ban hành, trích yếu, người ký, chức vụ, độ khẩn, độ mật, nơi nhận… Người dùng sửa được mọi trường và mỗi lần lưu tạo một phiên bản mới.
- Lưu trữ. Dùng SQLite với chỉ mục toàn văn FTS5 (kèm một chỉ mục bỏ dấu cho câu hỏi
gõ không dấu) và vector
sqlite-vec1024 chiều. Bên cạnh đó là đồ thị quan hệ pháp lý giữa các văn bản. - Truy hồi. Ba danh sách FTS, vector và FTS không dấu được trộn bằng RRF. ViRanker chấm lại các đoạn ứng viên, rồi một ngưỡng liên quan loại những đoạn không đủ khớp.
- Trả lời. Qwen3 nhận câu hỏi cùng các đoạn nguồn đã chọn. Câu trả lời đi qua bước kiểm tra trước khi tới người dùng.
| Vai trò | Model | Chạy bằng | Dung lượng |
|---|---|---|---|
| OCR | Chandra OCR 2, Q4_K_M + mmproj Q8_0 | llama-server, cổng 9999 |
2,9 GB + 349 MB |
| Embedding | AITeamVN/Vietnamese_Embedding (bge-m3, 1024 chiều) | PyTorch | ~2,2 GB |
| Rerank | namdp-ptit/ViRanker (cross-encoder 0,6B) | PyTorch, CPU | ~1,5 GB |
| Trợ lý | Qwen3-8B hoặc Qwen3-4B-Instruct-2507, Q4_K_M | llama-server, cổng 9998 |
5,0 / 2,5 GB |
Ứng dụng tự chọn cấu hình theo phần cứng:
- Model trợ lý. Dùng Qwen3-8B khi GPU còn từ 10 GB VRAM, Qwen3-4B khi còn từ 5 GB. Nếu không có GPU, Qwen3-4B chạy trên CPU với ngữ cảnh 8k.
- Số worker OCR. CPU dùng 1 worker. GPU tới 12 GB dùng 1 worker, từ 16 GB dùng 2, từ 48 GB dùng 4. Chandra chiếm khoảng 3,5 GB VRAM.
- Nhớ hội thoại. Mỗi lượt lưu lại văn bản đang mở và các văn bản đã nhắc tới hoặc đã trích dẫn. Lượt sau nhận một khối "trạng thái hội thoại" gọn. Bộ giải nghĩa tham chiếu hiểu số hiệu đầy đủ hay rút gọn, số hiệu bị OCR đọc sai, và các cách nói như "văn bản trước", "văn bản đầu tiên", "cả hai", "tờ trình đó". Câu hỏi về chính cuộc hội thoại được trả lời từ lịch sử, không cần tìm lại.
- Thống kê tính bằng mã. Các câu như "ai ký nhiều nhất", "bao nhiêu kế hoạch năm 2026" được đếm thẳng từ bảng metadata, không để model tự đếm.
- So sánh nhiều văn bản. Ứng dụng nạp sẵn nguồn của mọi văn bản được nhắc tới. Model còn có các công cụ: tìm kiếm, xem thông tin văn bản, văn bản liên quan, hiệu lực, đọc một mục và liệt kê.
- Kiểm tra câu trả lời. Mọi số hiệu, ngày, con số, số đếm và cặp "loại + số" trong câu trả lời đều được đối chiếu với nguồn. Nếu có sai lệch, model được yêu cầu sửa một lần. Chi tiết nào vẫn không có trong nguồn sẽ bị bỏ hoặc gắn nhãn "(chưa xác minh)".
Mọi con số dưới đây được đo trên máy của người phát triển (RTX 5090 Laptop 24 GB, Qwen3-8B) với các bộ test cục bộ. Các bộ test này chứa văn bản thật nên không được công bố. Trên máy khác, kết quả có thể khác.
|
|
|
| Hạng mục | Trước | Hiện tại |
|---|---|---|
| Trường NĐ30 bóc đúng (50 trang, 165 trường) | 133/165 (80,6%) | |
| Tỉ lệ lỗi ký tự, CER (7 trang có bản chuẩn) | 1,65% | 0,74% |
| Trang bị cắt cụt | 1 | 0 |
| RAM của máy chủ OCR | 15,5 GB | 6,2 GB |
| Hỏi đáp một lượt (41 câu có đáp án) | 13/41 | 36–38/41 |
| Hội thoại nhiều lượt (52 hội thoại, 199 lượt) | 134/199 | 187/199 (94%) |
| Hội thoại đúng trọn vẹn | 16/52 | 40/52 |
| Nhớ văn bản của lượt đầu khi đã tới lượt 4 trở đi | 3/16 | 16/16 |
| Câu hỏi so sánh văn bản | 5/22 | 18/22 |
| Báo nhầm "không tìm thấy" | 25 | 8 |
| Bộ dữ liệu thật (24 hội thoại, 67 lượt, 26 văn bản) | 41/67 | 65/67 |
| Câu trả lời có số liệu không có trong nguồn | 17 | 0 |
Về tốc độ:
- Trợ lý. Trung bình khoảng 5,6 giây mỗi lượt. Câu hỏi về chính cuộc hội thoại mất khoảng 0,8 giây, còn bước kiểm tra câu trả lời chỉ tốn khoảng 2 ms.
- OCR. Khoảng 7,8 giây mỗi trang với 2 worker trên GPU rảnh, 17–25 giây mỗi trang với 1 worker trên GPU dùng chung, và khoảng 90 giây mỗi trang nếu chỉ có CPU.
Kết quả hỏi đáp một lượt dao động ±1 câu giữa các lần chạy.
Bảng cấu hình dạng chữ
| Tối thiểu (CPU) | Đề xuất | Tốt nhất | |
|---|---|---|---|
| Hệ điều hành | Windows 10/11 x64 | Windows 11 x64 | Windows 11 x64 |
| GPU | Không cần. OCR khoảng 90 giây/trang, Qwen3-4B ngữ cảnh 8k | NVIDIA từ 8 GB: Qwen3-4B, 1 worker OCR | NVIDIA 16–24 GB: Qwen3-8B, 2 worker OCR |
| RAM | 16 GB | 32 GB | 32–64 GB |
| Ổ đĩa | Trống khoảng 25 GB | SSD | NVMe SSD |
Tốc độ OCR khoảng 20 giây/trang ở mức đề xuất được đo trên RTX 4070 8 GB (tháng 4/2026, trước các bản sửa tháng 10).
Một bộ cài chạy được gồm ba tầng, và chỉ tầng mã nguồn nằm trong Git:
| Tầng | Nội dung | Dung lượng |
|---|---|---|
| Mã nguồn | Repo này | Nhỏ |
| Runtime | Python 3.9 nhúng cùng PyQt5, PyTorch… (runtime/) |
~5 GB |
| Model và công cụ | gguf/, model_embedding/, model_reranker/, bin/ (llama.cpp), tools/poppler/ |
~16 GB |
- Lấy gói đầy đủ
OCR_VBHC_Portablequa USB hoặc ổ mạng nội bộ. Khi có bản phát hành gắn tagv*, GitHub Releases đăng tầng runtime dưới dạng các tệp.partkèmSHA256SUMSvàBUILD_MANIFEST.json. Tầng model đi riêng thành một gói asset dobuild_asset_bundle.pyđóng gói và kiểm tra. - Chép nguyên thư mục vào ổ SSD. Không chép lẻ từng tệp, vì các đường dẫn tương đối cần đủ cấu trúc thư mục.
- Chạy
verify.batmột lần để kiểm tra gói có đủ tệp và đúng cấu trúc. - Nhấp đúp
start.bat. Script tự tìm Python nhúng, phát hiện GPU và chọnllama-serverbản CUDA hoặc CPU. Lần đầu mất khoảng 30–60 giây để nạp model. - Bắt đầu dùng. Ở trang chủ, chọn Quét một văn bản, Thêm nhiều tệp hoặc Nhập thư mục văn bản, rồi đặt câu hỏi cho Trợ lý pháp luật. Một đợt nhập dài lưu từng văn bản ngay khi xong, nên có thể dừng giữa chừng rồi chạy tiếp.
Muốn cập nhật thì chạy CAP_NHAT.bat "<thư mục bản vá>". Bản vá phải có
BUILD_MANIFEST.json và SHA256SUMS, và chỉ những tệp đã khớp checksum mới được cài.
Hướng dẫn vận hành và xử lý sự cố nằm ở PORTABLE_README.md.
git clone https://github.com/manh2303code/ocr-vbhc.gitChép các thư mục nặng (runtime/, bin/, gguf/, model_embedding/,
model_reranker/, tools/poppler/) từ một gói đầy đủ vào thư mục vừa clone, rồi chạy
start.bat. Muốn dựng lại cả gói portable thì dùng build_portable.py. Xem phần
Dành cho nhà phát triển.
- Cả bốn model chạy cục bộ. Hai máy chủ llama.cpp chỉ lắng nghe trên
127.0.0.1. tools/check_airgap.pykiểm tra mọi kết nối TCP của ứng dụng đang chạy và báo lỗi khi có kết nối nào đi ra ngoài máy. Công cụ này được kiểm thử trongtests/test_airgap.py.- Văn bản, chỉ mục, phiên bản chỉnh sửa và lịch sử hội thoại đều nằm trong SQLite ở
database/. Chuyển máy chỉ cần chép thư mục. - Câu trả lời của trợ lý chỉ để tham khảo, không thay thế ý kiến pháp lý chuyên môn.
Note
Mọi ảnh chụp, video và sơ đồ trong README này đều dựng từ văn bản giả lập
(devtools/demo_corpus/). Không có văn bản thật nào trong repo.
| Thành phần | Phiên bản |
|---|---|
| Python | 3.9 (runtime nhúng trong runtime/) |
| Qt | PyQt5 5.15.11 + PyQtWebEngine 5.15.7 |
| OCR | Chandra OCR 2 Q4_K_M qua llama.cpp (cổng 9999) |
| Trợ lý | Qwen3 4B/8B Q4_K_M qua llama.cpp (cổng 9998) |
| Hệ điều hành | Windows 10/11 x64 |
Khởi động và vỏ ứng dụng
main.py: điểm vào, nạp font, tạoAppControllerstartup_controller.py: điều phối trang chủ nhẹ và workspace nặnglanding_page.py,landing_data.py: trang chủ (WebEngine, có phương án dự phòng bằng Qt thuần)frontend/landing/: HTML/CSS/JS của trang chủ, chỉ nạp tài nguyên cục bộ
Giao diện nghiệp vụ
main_window_1.py: cửa sổ chính, editor, trình xem PDFui_commands.py: danh mục lệnh duy nhất cho toolbar, command palette và bảng phím tắtworkspace_layout.py: quy tắc chia cột viết thành hàm thuần, có test riêngchat_panel.py,analytics_dialog.py,ai_search_dialog.py,settings_dialog.py
Hệ thống thiết kế
theme_tokens.py: bảng màu, spacing, radius, typography cho cả hai giao diệndevtools/theme_template.qss→devtools/build_qss.py→theme.qss/theme_dark.qssui_icons.py+icons/fluent/: nạp SVG Fluent UI System Icons, tô màu và cache thànhQIconfont_loader.py+assets/fonts/: đăng ký Be Vietnam Pro trước khi tạo widget
Xử lý dữ liệu
ocr_pipeline.py,llama_ocr.py,chandra_field_parser.py: OCR, cửa kiểm tra trang, bóc tách trườngdocument_repository.py: SQLite, phiên bản, sao lưuvector_index.py,search_store.py,retrieval.py,reranker.py: tìm kiếm lairag_agent.py,agent_tools.py,llm_client.py: vòng lặp agent trả lời có dẫn nguồndoc_resolver.py,metadata_query.py,answer_check.py: giải tham chiếu, thống kê bằng mã, kiểm tra câu trả lờibackground_workers.py: cácQThreaddùng chung
Runtime nhúng không kèm pytest. Hãy cài vào một thư mục riêng để không làm bẩn gói
portable:
runtime/python.exe -m pip install --target .devtools pytestBản Python nhúng có python39._pth nên bỏ qua biến PYTHONPATH. Vì vậy cần nạp thư mục
trên bằng một script mồi:
runtime/python.exe -c "import sys,os; sys.path.insert(0,'.devtools'); os.environ['QT_QPA_PLATFORM']='offscreen'; import pytest; sys.exit(pytest.console_main())" tests/ -qMột số test tự bỏ qua khi thiếu model GGUF hoặc corpus thật.
Toàn bộ test chạy được trên Linux trong Docker mà không cần model:
docker build -f docker/Dockerfile.ci -t ocr-vbhc-ci . && docker run --rm ocr-vbhc-ciImage chỉ chứa mã nguồn và pin Python 3.9 cùng PyTorch 2.8 CPU, khớp với
build_portable.PYTHON_VERSION và TORCH_VERSION. PyQtWebEngine được bỏ ra có chủ ý,
vì landing_page.py đã chặn lỗi import và tests/test_landing.py chạy nhánh dự phòng.
Image này chỉ dùng để kiểm thử, không dùng để chạy ứng dụng. Workflow
.github/workflows/ci.yml chạy bộ test sau mỗi lần push. Còn release.yml dựng tầng
runtime khi có tag v*.
tests/test_architecture_boundaries.pyngănmain_window_1.pyphình lại thành god-object.tests/test_portable_manifest.pybảo đảm mọi file mới đều đượcbuild_portable.pyđóng gói và đượcverify.batkiểm tra.tests/test_qss_generated.pybảo đảm stylesheet luôn được sinh từ token, không ai sửa tay.
- Thêm file nguồn mới thì khai báo trong
CORE_PY_FILEShoặcSTATIC_FILEScủabuild_portable.py, và bổ sung vàoverify.bat. - Thêm màu thì đặt trong
theme_tokens.py, không hardcode mã hex trong widget. - Thêm lệnh hay phím tắt thì khai báo trong
ui_commands.COMMANDS. - Giữ Python tương thích 3.9: không dùng
match, không dùngX | Ylúc runtime. - Thay đổi lớn phải được đo trước: giữ cấu hình cũ, chạy A/B, và chỉ merge khi kết quả tốt hơn.
| Thư mục | Nội dung | Lệnh |
|---|---|---|
devtools/demo_corpus/ |
10 văn bản giả lập theo NĐ30 và cơ sở dữ liệu demo | runtime\python.exe -X utf8 devtools\demo_corpus\build_demo.py all <demo.db> |
devtools/readme_shots.py |
Ảnh chụp ứng dụng thật trên dữ liệu demo | runtime\python.exe -X utf8 devtools\readme_shots.py <demo.db> docs\media\screens |
docs/readme-src/ |
Sơ đồ và biểu đồ SVG có hoạt ảnh (Node) | node docs/readme-src/build.mjs |
docs/video/ |
Video Remotion (VN/EN) | npm ci && npm run render |
![]() |
Trần Hậu Mạnh (@manh2303code) là người phát triển OCR VBHC, từ pipeline OCR và bộ bóc tách trường NĐ30, tìm kiếm lai, trợ lý pháp luật cùng các bộ đo kiểm, tới giao diện của ứng dụng. |
- llama.cpp chạy Chandra OCR 2 và Qwen3.
- Các model Chandra OCR 2 (Datalab), Qwen3 (Qwen), Vietnamese_Embedding (AITeamVN) và ViRanker tuân theo giấy phép ghi trên trang gốc của từng model.
- Font Be Vietnam Pro (SIL OFL 1.1) và bộ Fluent UI System Icons của Microsoft (MIT): xem THIRD_PARTY_NOTICES.md.
- Video được dựng bằng Remotion. Mã nguồn video nằm trong
docs/video/, kèm ghi chú giấy phép của Remotion.


