Spaces:
Runtime error
Runtime error
import gradio as gr | |
import sqlite3 | |
import json | |
from huggingface_hub import hf_hub_download, upload_file | |
import os | |
from pathlib import Path | |
from reportlab.lib.pagesizes import A4 | |
from reportlab.lib.units import cm | |
from reportlab.pdfgen import canvas | |
from reportlab.pdfbase import pdfmetrics | |
from reportlab.pdfbase.ttfonts import TTFont | |
import qrcode | |
import zipfile | |
import io | |
from dotenv import load_dotenv | |
import time | |
# อ่าน .env (ถ้ามี) | |
load_dotenv() | |
REPO_ID = os.getenv("REPO_ID", "protae5544/WorkerManagement") | |
ORIGINAL_REPO_ID = os.getenv("ORIGINAL_REPO_ID", None) | |
# ตั้งค่าฟอนต์ | |
try: | |
pdfmetrics.registerFont(TTFont('THSarabun', 'THSarabunNew.ttf')) | |
pdfmetrics.registerFont(TTFont('THSarabunBold', 'THSarabunNew-Bold.ttf')) | |
except Exception as e: | |
print(f"Warning: Could not load fonts: {e}") | |
# ฟังก์ชันแปลงวันที่เป็นภาษาไทย | |
def thai_date_time(timestamp): | |
months = { | |
1: "มกราคม", 2: "กุมภาพันธ์", 3: "มีนาคม", 4: "เมษายน", | |
5: "พฤษภาคม", 6: "มิถุนายน", 7: "กรกฎาคม", 8: "สิงหาคม", | |
9: "กันยายน", 10: "ตุลาคม", 11: "พฤศจิกายน", 12: "ธันวาคม" | |
} | |
dt = time.localtime(timestamp) | |
day = dt.tm_mday | |
month = months[dt.tm_mon] | |
year = dt.tm_year + 543 | |
hour = dt.tm_hour | |
minute = dt.tm_min | |
return f"{day:02d} {month} {year} {hour:02d}:{minute:02d} น." | |
# เริ่มต้นฐานข้อมูล | |
def init_db(): | |
conn = sqlite3.connect("workers.db") | |
c = conn.cursor() | |
c.execute('''CREATE TABLE IF NOT EXISTS workers ( | |
request_number TEXT PRIMARY KEY, | |
english_name TEXT, | |
foreign_reference_number TEXT, | |
id_number TEXT, | |
nationality TEXT, | |
receipt_number TEXT, | |
payment_number TEXT, | |
created_at TEXT | |
)''') | |
c.execute('''CREATE TABLE IF NOT EXISTS attachments ( | |
request_number TEXT, | |
file_url TEXT, | |
FOREIGN KEY(request_number) REFERENCES workers(request_number) | |
)''') | |
c.execute('''CREATE TABLE IF NOT EXISTS pdfs ( | |
request_number TEXT, | |
pdf_url TEXT, | |
FOREIGN KEY(request_number) REFERENCES workers(request_number) | |
)''') | |
conn.commit() | |
conn.close() | |
# สำรองฐานข้อมูล | |
def backup_db(): | |
try: | |
upload_file( | |
path_or_fileobj="workers.db", | |
path_in_repo="workers.db", | |
repo_id=REPO_ID, | |
repo_type="space" | |
) | |
except Exception as e: | |
print(f"Error backing up database: {e}") | |
# ดึงเลขคำขอถัดไป | |
def get_next_request_number(): | |
conn = sqlite3.connect("workers.db") | |
c = conn.cursor() | |
c.execute("SELECT request_number FROM workers") | |
request_numbers = c.fetchall() | |
conn.close() | |
if not request_numbers: | |
return "WP-68-366-150" | |
try: | |
max_num = max([int(num[0].split('-')[-1]) for num in request_numbers if num[0].startswith('WP-68-366-')]) | |
return f"WP-68-366-{max_num + 1:03d}" | |
except: | |
return "WP-68-366-150" | |
# สร้าง PDF | |
def create_receipt_pdf(request_number, english_name, foreign_reference_number, id_number, nationality, receipt_number, payment_number): | |
filename = f"pdfs/receipt_{request_number}.pdf" | |
local_path = f"temp_{request_number}.pdf" | |
# สร้างโฟลเดอร์ pdfs ถ้าไม่มี | |
os.makedirs("pdfs", exist_ok=True) | |
c = canvas.Canvas(local_path, pagesize=A4) | |
# ใช้ฟอนต์ไทยถ้ามี ไม่งั้นใช้ Helvetica | |
try: | |
c.setFont("THSarabunBold", 18) | |
font_available = True | |
except: | |
c.setFont("Helvetica-Bold", 16) | |
font_available = False | |
# Header | |
c.drawString(2*cm, 28*cm, "กระทรวงแรงงาน" if font_available else "Ministry of Labour") | |
try: | |
c.setFont("THSarabun", 14) if font_available else c.setFont("Helvetica", 12) | |
except: | |
c.setFont("Helvetica", 12) | |
c.drawString(2*cm, 27.5*cm, "ใบเสร็จรับเงิน (ต้นฉบับ)" if font_available else "Receipt (Original)") | |
c.drawString(2*cm, 26*cm, f"เลขที่: {receipt_number}" if font_available else f"Number: {receipt_number}") | |
c.drawString(2*cm, 25.5*cm, "ที่ทำการ: สำนักบริหารแรงงานต่างด้าว" if font_available else "Office: Bureau of Foreign Workers Administration") | |
c.drawString(2*cm, 25*cm, "วันที่: 01 เมษายน 2568" if font_available else "Date: 01 April 2025") | |
c.drawString(2*cm, 24.5*cm, f"เลขที่ใบชำระเงิน: {payment_number}" if font_available else f"Payment Number: {payment_number}") | |
c.drawString(2*cm, 24*cm, f"เลขรับคำขอที่: {request_number}" if font_available else f"Request Number: {request_number}") | |
c.drawString(2*cm, 23.5*cm, f"ชื่อผู้ชำระเงิน: {english_name}" if font_available else f"Payer Name: {english_name}") | |
c.drawString(2*cm, 23*cm, f"สัญชาติ: {nationality}" if font_available else f"Nationality: {nationality}") | |
c.drawString(2*cm, 22.5*cm, f"เลขอ้างอิงคนต่างด้าว: {foreign_reference_number}" if font_available else f"Foreign Reference: {foreign_reference_number}") | |
c.drawString(2*cm, 22*cm, f"หมายเลขประจำตัวคนต่างด้าว: {id_number}" if font_available else f"Foreign Worker ID: {id_number}") | |
c.drawString(2*cm, 21.5*cm, "ชื่อนายจ้าง/สถานประกอบการ: บริษัท บาน กง เอ็นจิเนียริ่ง จำกัด" if font_available else "Employer: Ban Kong Engineering Co., Ltd.") | |
c.drawString(2*cm, 21*cm, "เลขประจำตัวนายจ้าง: 0415567000061" if font_available else "Employer ID: 0415567000061") | |
# รายการ | |
try: | |
c.setFont("THSarabunBold", 14) if font_available else c.setFont("Helvetica-Bold", 12) | |
except: | |
c.setFont("Helvetica-Bold", 12) | |
c.drawString(2*cm, 20*cm, "รายการ" if font_available else "Items") | |
try: | |
c.setFont("THSarabun", 12) if font_available else c.setFont("Helvetica", 10) | |
except: | |
c.setFont("Helvetica", 10) | |
c.drawString(2*cm, 19.5*cm, "1. ค่าธรรมเนียมในการยื่นคำขอ ฉบับละ 100 บาท: 100.00" if font_available else "1. Application fee 100 Baht each: 100.00") | |
c.drawString(2*cm, 19*cm, "2. ค่าธรรมเนียม: 900.00" if font_available else "2. Service fee: 900.00") | |
c.drawString(2*cm, 18.5*cm, "รวมเป็นเงินทั้งสิ้น (บาท): (หนึ่งพันบาทถ้วน) 1,000.00" if font_available else "Total (Baht): (One thousand Baht) 1,000.00") | |
c.drawString(2*cm, 18*cm, "ได้รับเงินไว้เป็นการถูกต้องแล้ว" if font_available else "Payment received correctly") | |
c.drawString(2*cm, 17.5*cm, "(ลงชื่อ) นางสาวอารีวรรณ โพธิ์นิ่มแดง (ผู้รับเงิน)" if font_available else "(Signature) Ms. Areewan Pho Nim Daeng") | |
c.drawString(2*cm, 17*cm, "ตำแหน่ง: นักวิชาการแรงงานชำนาญการ" if font_available else "Position: Senior Labor Academic") | |
# QR Code | |
pdf_url = f"https://huggingface.co/spaces/{REPO_ID}/resolve/main/{filename}" | |
try: | |
qr = qrcode.QRCode(version=1, box_size=10, border=5) | |
qr.add_data(pdf_url) | |
qr.make(fit=True) | |
qr_img = qr.make_image(fill_color="black", back_color="white") | |
qr_img.save("temp_qr.png") | |
c.drawImage("temp_qr.png", 15*cm, 15*cm, width=3*cm, height=3*cm) | |
except Exception as e: | |
print(f"Error creating QR code: {e}") | |
# Timestamp | |
try: | |
c.setFont("THSarabun", 8) if font_available else c.setFont("Helvetica", 8) | |
except: | |
c.setFont("Helvetica", 8) | |
print_time = thai_date_time(time.time()) | |
c.drawString(2*cm, 2*cm, f"พิมพ์เมื่อ: {print_time}" if font_available else f"Printed: {print_time}") | |
c.showPage() | |
c.save() | |
# อัพโหลด PDF | |
try: | |
upload_file( | |
path_or_fileobj=local_path, | |
path_in_repo=filename, | |
repo_id=REPO_ID, | |
repo_type="space" | |
) | |
print(f"PDF uploaded successfully: {filename}") | |
except Exception as e: | |
print(f"Error uploading PDF: {e}") | |
return None | |
# บันทึกข้อมูล PDF ในฐานข้อมูล | |
conn = sqlite3.connect("workers.db") | |
cursor = conn.cursor() | |
cursor.execute("INSERT OR REPLACE INTO pdfs (request_number, pdf_url) VALUES (?, ?)", | |
(request_number, pdf_url)) | |
conn.commit() | |
conn.close() | |
return pdf_url | |
# ตรวจสอบข้อมูล | |
def validate_input(english_name, foreign_reference_number, id_number, nationality, receipt_number, payment_number): | |
if not english_name or not english_name.strip(): | |
return "กรุณากรอกชื่อภาษาอังกฤษ" | |
if not foreign_reference_number or not foreign_reference_number.strip(): | |
return "กรุณากรอกหมายเลขอ้างอิงคนต่างด้าว" | |
if not id_number or not id_number.isdigit() or len(id_number) != 13: | |
return "หมายเลขประจำตัวต้องเป็นตัวเลข 13 หลัก" | |
if not nationality or not nationality.strip(): | |
return "กรุณากรอกสัญชาติ" | |
if not receipt_number or not receipt_number.strip(): | |
return "กรุณากรอกเลขที่ใบเสร็จ" | |
if not payment_number or not payment_number.strip(): | |
return "กรุณากรอกหมายเลขชำระเงิน" | |
return None | |
# เพิ่มข้อมูลพนักงาน | |
def add_worker(english_name, foreign_reference_number, id_number, nationality, receipt_number, payment_number, attachments): | |
# ตรวจสอบข้อมูล | |
error = validate_input(english_name, foreign_reference_number, id_number, nationality, receipt_number, payment_number) | |
if error: | |
return f"❌ {error}" | |
try: | |
request_number = get_next_request_number() | |
# บันทึกข้อมูลในฐานข้อมูล | |
conn = sqlite3.connect("workers.db") | |
c = conn.cursor() | |
c.execute('''INSERT INTO workers ( | |
request_number, english_name, foreign_reference_number, id_number, | |
nationality, receipt_number, payment_number, created_at | |
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)''', ( | |
request_number, english_name, foreign_reference_number, id_number, | |
nationality, receipt_number, payment_number, time.time() | |
)) | |
# จัดการไฟล์แนบ | |
attachment_urls = [] | |
if attachments: | |
for i, file_data in enumerate(attachments): | |
if file_data is not None: | |
try: | |
filename = f"attachments/file_{request_number}_{i}_{os.path.basename(file_data.name)}" | |
upload_file( | |
path_or_fileobj=file_data.name, | |
path_in_repo=filename, | |
repo_id=REPO_ID, | |
repo_type="space" | |
) | |
url = f"https://huggingface.co/spaces/{REPO_ID}/resolve/main/{filename}" | |
c.execute("INSERT INTO attachments (request_number, file_url) VALUES (?, ?)", | |
(request_number, url)) | |
attachment_urls.append(url) | |
except Exception as e: | |
print(f"Error uploading attachment: {e}") | |
conn.commit() | |
conn.close() | |
# สร้าง PDF | |
pdf_url = create_receipt_pdf(request_number, english_name, foreign_reference_number, | |
id_number, nationality, receipt_number, payment_number) | |
if pdf_url: | |
# สำรองฐานข้อมูล | |
backup_db() | |
result = f"✅ เพิ่มข้อมูลพนักงานสำเร็จ!\n" | |
result += f"📋 เลขคำขอ: {request_number}\n" | |
result += f"📄 PDF: {pdf_url}\n" | |
if attachment_urls: | |
result += f"📎 ไฟล์แนบ: {len(attachment_urls)} ไฟล์" | |
else: | |
result += f"📎 ไฟล์แนบ: ไม่มี" | |
return result | |
else: | |
return f"❌ เกิดข้อผิดพลาดในการสร้าง PDF สำหรับเลขคำขอ: {request_number}" | |
except Exception as e: | |
return f"❌ เกิดข้อผิดพลาด: {str(e)}" | |
# ดาวน์โหลด PDF ทั้งหมด | |
def download_all_pdfs(): | |
try: | |
conn = sqlite3.connect("workers.db") | |
c = conn.cursor() | |
c.execute("SELECT request_number, pdf_url FROM pdfs") | |
pdfs = c.fetchall() | |
conn.close() | |
if not pdfs: | |
return "❌ ไม่มี PDF ในระบบ" | |
zip_buffer = io.BytesIO() | |
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: | |
for request_number, pdf_url in pdfs: | |
try: | |
# ดาวน์โหลด PDF จาก Space | |
local_path = hf_hub_download( | |
repo_id=REPO_ID, | |
filename=f"pdfs/receipt_{request_number}.pdf", | |
repo_type="space" | |
) | |
zip_file.write(local_path, f"receipt_{request_number}.pdf") | |
except Exception as e: | |
print(f"Error downloading PDF {request_number}: {e}") | |
continue | |
zip_path = "all_receipts.zip" | |
with open(zip_path, 'wb') as f: | |
f.write(zip_buffer.getvalue()) | |
# อัพโหลด ZIP file | |
upload_file( | |
path_or_fileobj=zip_path, | |
path_in_repo="downloads/all_receipts.zip", | |
repo_id=REPO_ID, | |
repo_type="space" | |
) | |
download_url = f"https://huggingface.co/spaces/{REPO_ID}/resolve/main/downloads/all_receipts.zip" | |
return f"✅ สร้างไฟล์ ZIP สำเร็จ!\n📥 ดาวน์โหลด: {download_url}\n📊 จำนวน PDF: {len(pdfs)} ไฟล์" | |
except Exception as e: | |
return f"❌ เกิดข้อผิดพลาด: {str(e)}" | |
# ดูรายการพนักงาน | |
def get_worker_list(): | |
try: | |
conn = sqlite3.connect("workers.db") | |
c = conn.cursor() | |
c.execute("""SELECT request_number, english_name, nationality, id_number, | |
receipt_number, payment_number FROM workers ORDER BY request_number DESC""") | |
workers = c.fetchall() | |
conn.close() | |
if not workers: | |
return "ไม่มีข้อมูลพนักงานในระบบ" | |
result = f"📋 รายการพนักงานทั้งหมด ({len(workers)} คน)\n" + "="*50 + "\n" | |
for worker in workers: | |
result += f"🆔 {worker[0]} | {worker[1]} | {worker[2]} | {worker[3]}\n" | |
return result | |
except Exception as e: | |
return f"❌ เกิดข้อผิดพลาด: {str(e)}" | |
# เริ่มต้นฐานข้อมูล | |
init_db() | |
# UI Gradio | |
with gr.Blocks( | |
theme=gr.themes.Soft(), | |
title="ระบบจัดการข้อมูลพนักงานต่างด้าว", | |
css=""" | |
.gradio-container { | |
max-width: 1200px !important; | |
margin: auto !important; | |
} | |
.form-container { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
border-radius: 15px; | |
padding: 20px; | |
margin: 10px 0; | |
} | |
""" | |
) as demo: | |
gr.Markdown(""" | |
# 🏢 ระบบจัดการข้อมูลพนักงานต่างด้าว | |
### Worker Management System - Ban Kong Engineering Co., Ltd. | |
""") | |
with gr.Tab("📝 เพิ่มข้อมูลพนักงานใหม่"): | |
gr.Markdown("### กรอกข้อมูลพนักงานใหม่") | |
with gr.Row(): | |
english_name = gr.Textbox( | |
label="🏷️ ชื่อภาษาอังกฤษ", | |
placeholder="เช่น MR. AUNG KYAW", | |
lines=1 | |
) | |
foreign_reference_number = gr.Textbox( | |
label="🔢 หมายเลขอ้างอิงคนต่างด้าว", | |
placeholder="เช่น 2492102076212", | |
lines=1 | |
) | |
with gr.Row(): | |
id_number = gr.Textbox( | |
label="🆔 หมายเลขประจำตัว (13 หลัก)", | |
placeholder="เช่น 6685490000472", | |
lines=1 | |
) | |
nationality = gr.Dropdown( | |
label="🌍 สัญชาติ", | |
choices=["เมียนมา", "กัมพูชา", "ลาว", "เวียดนาม"], | |
value="เมียนมา" | |
) | |
with gr.Row(): | |
receipt_number = gr.Textbox( | |
label="🧾 เลขที่บนขวาใบเสร็จ", | |
placeholder="เช่น 2100680001130", | |
lines=1 | |
) | |
payment_number = gr.Textbox( | |
label="💳 หมายเลขชำระเงิน", | |
placeholder="เช่น IV680210/002350", | |
lines=1 | |
) | |
attachments = gr.File( | |
label="📎 แนบไฟล์ (สูงสุด 5MB ต่อไฟล์)", | |
file_count="multiple", | |
file_types=[".jpg", ".png", ".pdf", ".jpeg"], | |
max_file_size="5MB" | |
) | |
submit_btn = gr.Button( | |
"💾 บันทึกข้อมูลและสร้าง PDF", | |
variant="primary", | |
size="lg" | |
) | |
output = gr.Textbox( | |
label="📋 ผลลัพธ์", | |
lines=6, | |
interactive=False | |
) | |
with gr.Tab("📊 จัดการข้อมูล"): | |
gr.Markdown("### ดูและจัดการข้อมูลพนักงาน") | |
with gr.Row(): | |
view_workers_btn = gr.Button("👥 ดูรายการพนักงานทั้งหมด", variant="secondary") | |
download_all_btn = gr.Button("📥 ดาวน์โหลด PDF ทั้งหมด", variant="primary") | |
management_output = gr.Textbox( | |
label="📋 ผลลัพธ์", | |
lines=10, | |
interactive=False | |
) | |
with gr.Tab("ℹ️ คำแนะนำ"): | |
gr.Markdown(""" | |
## 📖 วิธีการใช้งาน | |
### 1. เพิ่มข้อมูลพนักงานใหม่ | |
- กรอกข้อมูลในฟอร์มให้ครบถ้วน | |
- หมายเลขประจำตัวต้องเป็นตัวเลข 13 หลัก | |
- สามารถแนบไฟล์เอกสารได้ (JPG, PNG, PDF) | |
- ระบบจะสร้าง PDF ใบเสร็จพร้อม QR Code อัตโนมัติ | |
### 2. ดาวน์โหลด PDF | |
- ใช้ QR Code ในใบเสร็จเพื่อดาวน์โหลด PDF แต่ละไฟล์ | |
- หรือดาวน์โหลด PDF ทั้งหมดเป็นไฟล์ ZIP | |
### 3. ข้อมูลที่เก็บ | |
- ข้อมูลพนักงาน | |
- ไฟล์ PDF ใบเสร็จ | |
- ไฟล์แนบเอกสาร | |
- ประวัติการทำรายการ | |
### 4. คุณสมบัติ | |
- 🔒 ข้อมูลปลอดภัย บันทึกใน Hugging Face Space | |
- 📱 QR Code สำหรับดาวน์โหลดใบเสร็จ | |
- 📊 รายงานและสถิติ | |
- 💾 สำรองข้อมูลอัตโนมัติ | |
--- | |
**🏢 พัฒนาโดย: Ban Kong Engineering Co., Ltd.** | |
""") | |
# Event handlers | |
submit_btn.click( | |
fn=add_worker, | |
inputs=[english_name, foreign_reference_number, id_number, nationality, | |
receipt_number, payment_number, attachments], | |
outputs=output | |
) | |
view_workers_btn.click( | |
fn=get_worker_list, | |
outputs=management_output | |
) | |
download_all_btn.click( | |
fn=download_all_pdfs, | |
outputs=management_output | |
) | |
if __name__ == "__main__": | |
demo.launch() |