Pure stateless microservice xử lý tài liệu Word.
Không DB. Không storage. Không session.
Nhận file → xử lý → trả file → xoá temp.
Client
│ upload file + params
▼
FastAPI (main.py)
│ gọi service tương ứng
▼
services/document/
├── converter.py # DOC/ODT → DOCX, DOCX → PDF (LibreOffice)
├── reader.py # Đọc text / paragraphs / tables + extract layout (pdfplumber)
├── detector.py # Detect fillable fields (Vietnamese forms)
├── template_builder.py # Apply fields → DOCX có {{placeholders}}
└── renderer.py # Điền data vào {{placeholders}}
│
▼
Trả file response
│
▼
Xoá temp dir (finally block)
pip install -r requirements.txt
uvicorn main:app --reloadHoặc dùng Docker:
docker build -t doc-engine .
docker run -p 8000:8000 doc-engineHoặc dùng docker-compose:
docker-compose up -dSwagger UI: https://plugins.devhub.ai.vn/docs
Convert bất kỳ file nào → DOCX chuẩn.
curl -X POST https://plugins.devhub.ai.vn/document/normalize \
-F "file=@invoice.doc" \
-o invoice.docxĐọc nội dung file → JSON.
curl -X POST https://plugins.devhub.ai.vn/document/read-content \
-F "file=@form.docx"Response:
{
"text": "Toàn bộ text...",
"paragraphs": [
{"text": "Họ tên lái xe: ............", "style": "Normal"}
],
"tables": [
{"rows": [["Cột 1", "Cột 2"], ["Giá trị 1", "Giá trị 2"]]}
]
}Phân tích document layout → trả text blocks với bounding boxes.
Dùng cho UI tool để user highlight và label fields.
curl -X POST https://plugins.devhub.ai.vn/document/read-layout \
-F "file=@bien_ban.docx"Response:
{
"pages": [
{
"page_num": 0,
"width": 612,
"height": 792,
"blocks": [
{
"block_id": "b0_0",
"text": "Họ và tên:",
"bbox": [50, 100, 200, 120],
"type": "text"
},
{
"block_id": "b0_1",
"text": "Nguyễn Văn A",
"bbox": [200, 100, 400, 120],
"type": "text"
}
]
}
],
"total_pages": 1
}Tự động phát hiện các ô cần điền trong Vietnamese forms.
curl -X POST https://plugins.devhub.ai.vn/document/detect-fields \
-F "file=@bien_ban.docx"Response:
{
"count": 5,
"fields": [
{
"id": "field_1",
"label": "Biển kiểm soát xe",
"suggested_name": "bien_kiem_soat_xe",
"placeholder": "{{bien_kiem_soat_xe}}",
"context": "Biển kiểm soát xe: ………",
"type": "text",
"preview": "Biển kiểm soát xe: {{bien_kiem_soat_xe}}"
},
{
"id": "field_2",
"label": "Người thực hiện",
"suggested_name": "nguoi_thuc_hien",
"placeholder": "{{nguoi_thuc_hien}}",
"context": "Người thực hiện: …………………………………………",
"type": "text",
"preview": "Người thực hiện: {{nguoi_thuc_hien}}"
},
{
"id": "field_3",
"label": "Họ tên lái xe",
"suggested_name": "ho_ten_lai_xe",
"placeholder": "{{ho_ten_lai_xe}}",
"context": "Họ tên lái xe:………………………………………",
"type": "text",
"preview": "Họ tên lái xe:{{ho_ten_lai_xe}}"
},
{
"id": "field_4",
"label": "Địa chỉ",
"suggested_name": "dia_chi",
"placeholder": "{{dia_chi}}",
"context": "Địa chỉ: …...........................................................................",
"type": "text",
"preview": "Địa chỉ: {{dia_chi}}"
},
{
"id": "field_5",
"label": "GPLX số",
"suggested_name": "gplx_so",
"placeholder": "{{gplx_so}}",
"context": "GPLX số:…………………………………………",
"type": "text",
"preview": "GPLX số:{{gplx_so}}"
},
]
}Nhận file gốc + danh sách fields → xuất DOCX template có {{placeholders}}.
curl -X POST https://plugins.devhub.ai.vn/document/apply-fields \
-F "file=@bien_ban.docx" \
-F 'fields_json=[{"label":"Họ tên lái xe","name":"driver_name"},{"label":"Địa chỉ","name":"address"}]' \
-o bien_ban_template.docxNhận file gốc + danh sách blocks user đã label → tạo DOCX template.
Đây là bước cuối của labeling workflow.
curl -X POST https://plugins.devhub.ai.vn/document/generate-template-from-labels \
-F "file=@bien_ban.docx" \
-F 'labels_json=[
{
"block_id": "b0_5",
"field": "customer_name",
"block_text": "Nguyễn Văn A"
},
{
"block_id": "b0_10",
"field": "address",
"block_text": "123 Lê Lợi, Q.1"
}
]' \
-o bien_ban_template.docxĐiền data vào DOCX template → DOCX hoàn chỉnh.
curl -X POST https://plugins.devhub.ai.vn/document/render \
-F "file=@bien_ban_template.docx" \
-F 'data_json={"customer_name":"Nguyễn Văn A","address":"123 Lê Lợi, Q.1"}' \
-o bien_ban_filled.docxConvert bất kỳ file nào → PDF.
curl -X POST https://plugins.devhub.ai.vn/document/to-pdf \
-F "file=@bien_ban_filled.docx" \
-o bien_ban.pdf1. document/detect-fields → user xem gợi ý fields
2. document/apply-fields → tạo template DOCX
3. document/render → điền data khi cần
4. document/to-pdf → xuất PDF để in
1. document/read-layout → extract blocks + bbox
2. [UI] User highlight + label blocks
3. document/generate-template-from-labels → tạo template từ labels
4. document/render → điền data khi cần
5. document/to-pdf → xuất PDF để in
- Deploy nhiều container, mỗi request độc lập
- Không cần shared storage
- Thêm load balancer là xong
- LibreOffice chạy headless trong container
Mỗi request tạo dir: /tmp/doc_engine/{uuid}/
Sau khi trả response → shutil.rmtree() trong finally block.
File kết quả được copy ra /tmp/doc_engine/*.docx để FastAPI stream xong rồi client tự clean.
- FastAPI - Web framework
- python-docx - DOCX manipulation
- lxml - XML parsing
- pdfplumber - PDF text extraction with bounding boxes
- LibreOffice - Document conversion (Docker image)