feat: implement dynamic training course tab system and modular PDF data migration scripts
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import pdfplumber
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
|
||||
files = [
|
||||
'/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DaoTao/2.-CHUONG-TRINH-CAN-THIEP-MACH-MAU-THAN-KINH-NANG-CAO-BO-SUNG-FINAL.pdf',
|
||||
'/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DaoTao/CHUONG-TRINH-CAN-THIEP-MACH-MAU-CAC-TANG-VA-MACH-MAU-NGOAI-BIEN-CO-BAN.pdf',
|
||||
'/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DaoTao/CHUONG-TRINH-CHUAN-BI-DUNG-CU-VA-CHAM-SOC-BENH-NHAN-TRONG-PHONG-CHUP-MACH.pdf',
|
||||
'/home/x79/sisvietnamvn_01/sisvietnamvn_Trang chính thức hiện tại/DaoTao/CHUONG-TRINH-DAO-TAO-TIM-MACH-CAN-THIEP-1.pdf'
|
||||
]
|
||||
|
||||
slugs = [
|
||||
"can-thiep-mach-mau-than-kinh-nang-cao",
|
||||
"can-thiep-mach-mau-cac-tang-va-ngoai-bien-co-ban",
|
||||
"chuan-bi-dung-cu-va-cham-soc-benh-nhan-trong-phong-chup-mach",
|
||||
"tim-mach-can-thiep-co-ban"
|
||||
]
|
||||
|
||||
def extract_section(text, start_keywords, end_keywords=None):
|
||||
lines = text.split('\n')
|
||||
started = False
|
||||
content = []
|
||||
|
||||
for line in lines:
|
||||
line_lower = line.lower()
|
||||
if not started:
|
||||
for k in start_keywords:
|
||||
if k in line_lower:
|
||||
started = True
|
||||
split_idx = line_lower.find(k) + len(k)
|
||||
val = line[split_idx:].strip(': ').strip()
|
||||
if val:
|
||||
content.append(val)
|
||||
break
|
||||
else:
|
||||
if end_keywords:
|
||||
for k in end_keywords:
|
||||
if k in line_lower:
|
||||
return '\n'.join(content).strip()
|
||||
# Stop if we hit a new numbered section like "10." or empty lines after some text
|
||||
if re.match(r'^\d+\.', line) or re.match(r'^[A-Z\s]+$', line):
|
||||
return '\n'.join(content).strip()
|
||||
if line.strip():
|
||||
content.append(line.strip())
|
||||
|
||||
return '\n'.join(content).strip()
|
||||
|
||||
def make_text_block(text):
|
||||
return {
|
||||
"type": "paragraph",
|
||||
"data": {
|
||||
"text": text.replace('\n', '<br>')
|
||||
}
|
||||
}
|
||||
|
||||
def make_header_block(text, level=3):
|
||||
return {
|
||||
"type": "header",
|
||||
"data": {
|
||||
"text": text,
|
||||
"level": level
|
||||
}
|
||||
}
|
||||
|
||||
os.makedirs('pdf_json_output', exist_ok=True)
|
||||
|
||||
for f, slug in zip(files, slugs):
|
||||
print(f"--- Rebuilding {slug} ---")
|
||||
blocks = []
|
||||
|
||||
with pdfplumber.open(f) as pdf:
|
||||
text = ''
|
||||
pdf_blocks = []
|
||||
for page in pdf.pages:
|
||||
page_text = page.extract_text()
|
||||
if not page_text:
|
||||
continue
|
||||
text += page_text + '\n'
|
||||
|
||||
# Simple heuristic: split by double newlines or single newlines
|
||||
paragraphs = page_text.split('\n')
|
||||
|
||||
current_p = []
|
||||
for line in paragraphs:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if re.match(r'^(\d+)\.\s+(.*)$', line) or line.isupper():
|
||||
if current_p:
|
||||
pdf_blocks.append(make_text_block(' '.join(current_p)))
|
||||
current_p = []
|
||||
pdf_blocks.append(make_header_block(line, level=3))
|
||||
else:
|
||||
current_p.append(line)
|
||||
|
||||
if current_p:
|
||||
pdf_blocks.append(make_text_block(' '.join(current_p)))
|
||||
|
||||
# Try to extract tables
|
||||
tables = page.extract_tables()
|
||||
for table in tables:
|
||||
if not table: continue
|
||||
html = "<table class='table table-bordered'><tbody>"
|
||||
for row in table:
|
||||
html += "<tr>"
|
||||
for cell in row:
|
||||
cell_text = cell.replace('\n', '<br>') if cell else ''
|
||||
html += f"<td>{cell_text}</td>"
|
||||
html += "</tr>"
|
||||
html += "</tbody></table>"
|
||||
pdf_blocks.append({
|
||||
"type": "raw",
|
||||
"data": {
|
||||
"html": html
|
||||
}
|
||||
})
|
||||
|
||||
# Extraction
|
||||
time = extract_section(text, ['thời gian đào tạo'])
|
||||
audience = extract_section(text, ['đối tượng học viên', 'đối tượng tham dự', 'đối tượng'])
|
||||
classInfo = ""
|
||||
quantity = extract_section(text, ['số lượng học viên:', 'số lượng học viên'])
|
||||
documents = extract_section(text, ['hồ sơ đăng ký tham dự', 'hồ sơ nhập học'])
|
||||
tuitionFee = extract_section(text, ['học phí'])
|
||||
location = extract_section(text, ['địa điểm nhận hồ sơ'])
|
||||
paymentMethod = ""
|
||||
|
||||
# Tab 1: Tổng quan
|
||||
blocks.append({"type": "tabStart", "data": {"title": "Tổng quan"}})
|
||||
|
||||
if time:
|
||||
blocks.append(make_header_block("Thời gian", 4))
|
||||
blocks.append(make_text_block(time))
|
||||
if audience:
|
||||
blocks.append(make_header_block("Đối tượng đăng ký", 4))
|
||||
blocks.append(make_text_block(audience))
|
||||
if quantity:
|
||||
blocks.append(make_header_block("Số lượng", 4))
|
||||
blocks.append(make_text_block(quantity))
|
||||
if documents:
|
||||
blocks.append(make_header_block("Hồ sơ đăng ký tham dự", 4))
|
||||
blocks.append(make_text_block(documents))
|
||||
|
||||
# Tab 2: Thông tin chung
|
||||
blocks.append({"type": "tabStart", "data": {"title": "Thông tin chung"}})
|
||||
|
||||
if tuitionFee:
|
||||
blocks.append(make_header_block("Học phí", 4))
|
||||
blocks.append(make_text_block(tuitionFee))
|
||||
if location:
|
||||
blocks.append(make_header_block("Địa điểm nhận hồ sơ và học phí", 4))
|
||||
blocks.append(make_text_block(location))
|
||||
|
||||
# Tab 3: Chương trình đào tạo
|
||||
blocks.append({"type": "tabStart", "data": {"title": "Chương trình đào tạo"}})
|
||||
|
||||
# Third, add all the extracted text from the PDF
|
||||
blocks.extend(pdf_blocks)
|
||||
|
||||
blocks.append({"type": "tabEnd", "data": {}})
|
||||
|
||||
editor_data = {
|
||||
"time": 1700000000000,
|
||||
"blocks": blocks,
|
||||
"version": "2.29.1"
|
||||
}
|
||||
|
||||
with open(f"pdf_json_output/{slug}.json", 'w', encoding='utf-8') as out:
|
||||
json.dump(editor_data, out, ensure_ascii=False)
|
||||
|
||||
print("All done rebuilding json!")
|
||||
Reference in New Issue
Block a user