Spaces:
Running
Running
Create pdfk.py
Browse files
pdfk.py
ADDED
@@ -0,0 +1,486 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
import io
|
4 |
+
import zipfile
|
5 |
+
from datetime import datetime
|
6 |
+
import traceback
|
7 |
+
import tempfile
|
8 |
+
import os
|
9 |
+
|
10 |
+
# ติดตั้ง dependencies ที่จำเป็น
|
11 |
+
try:
|
12 |
+
from PyPDF2 import PdfReader, PdfWriter
|
13 |
+
from reportlab.pdfgen import canvas
|
14 |
+
from reportlab.lib.pagesizes import letter
|
15 |
+
from reportlab.pdfbase import pdfmetrics
|
16 |
+
from reportlab.pdfbase.ttfonts import TTFont
|
17 |
+
except ImportError as e:
|
18 |
+
print(f"กำลังติดตั้ง dependencies: {e}")
|
19 |
+
import subprocess
|
20 |
+
import sys
|
21 |
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "PyPDF2", "reportlab", "pandas"])
|
22 |
+
from PyPDF2 import PdfReader, PdfWriter
|
23 |
+
from reportlab.pdfgen import canvas
|
24 |
+
from reportlab.lib.pagesizes import letter
|
25 |
+
|
26 |
+
def analyze_pdf_fields(pdf_path):
|
27 |
+
"""วิเคราะห์ฟิลด์ใน PDF"""
|
28 |
+
try:
|
29 |
+
reader = PdfReader(pdf_path)
|
30 |
+
all_fields = {}
|
31 |
+
|
32 |
+
# ตรวจสอบจาก AcroForm
|
33 |
+
if reader.trailer.get("/Root") and reader.trailer["/Root"].get("/AcroForm"):
|
34 |
+
acro_form = reader.trailer["/Root"]["/AcroForm"]
|
35 |
+
if "/Fields" in acro_form:
|
36 |
+
fields = acro_form["/Fields"]
|
37 |
+
for field in fields:
|
38 |
+
field_obj = field.get_object()
|
39 |
+
if "/T" in field_obj:
|
40 |
+
field_name = str(field_obj["/T"]).strip("()")
|
41 |
+
field_type = str(field_obj.get("/FT", "Unknown"))
|
42 |
+
all_fields[field_name] = {
|
43 |
+
'type': field_type,
|
44 |
+
'method': 'AcroForm'
|
45 |
+
}
|
46 |
+
|
47 |
+
# ตรวจสอบจาก Annotations
|
48 |
+
for page_num, page in enumerate(reader.pages):
|
49 |
+
if "/Annots" in page:
|
50 |
+
try:
|
51 |
+
annotations = page["/Annots"]
|
52 |
+
for annotation in annotations:
|
53 |
+
annot_obj = annotation.get_object()
|
54 |
+
if annot_obj.get("/Subtype") == "/Widget":
|
55 |
+
if "/T" in annot_obj:
|
56 |
+
field_name = str(annot_obj["/T"]).strip("()")
|
57 |
+
field_type = str(annot_obj.get("/FT", "Widget"))
|
58 |
+
all_fields[field_name] = {
|
59 |
+
'type': field_type,
|
60 |
+
'page': page_num + 1,
|
61 |
+
'method': 'Annotation'
|
62 |
+
}
|
63 |
+
except Exception:
|
64 |
+
continue
|
65 |
+
|
66 |
+
return all_fields
|
67 |
+
except Exception as e:
|
68 |
+
return {"error": str(e)}
|
69 |
+
|
70 |
+
def fill_pdf_form(pdf_path, field_data):
|
71 |
+
"""เติมข้อมูลในฟอร์ม PDF"""
|
72 |
+
try:
|
73 |
+
reader = PdfReader(pdf_path)
|
74 |
+
writer = PdfWriter()
|
75 |
+
|
76 |
+
# คัดลอกหน้าทั้งหมด
|
77 |
+
for page in reader.pages:
|
78 |
+
writer.add_page(page)
|
79 |
+
|
80 |
+
# เติมข้อมูลในฟอร์ม
|
81 |
+
if hasattr(writer, 'update_page_form_field_values'):
|
82 |
+
for page_num, page in enumerate(writer.pages):
|
83 |
+
try:
|
84 |
+
writer.update_page_form_field_values(page, field_data)
|
85 |
+
except Exception:
|
86 |
+
pass
|
87 |
+
|
88 |
+
# ลองวิธีอื่น
|
89 |
+
elif "/AcroForm" in reader.trailer.get("/Root", {}):
|
90 |
+
try:
|
91 |
+
acro_form = reader.trailer["/Root"]["/AcroForm"]
|
92 |
+
if "/Fields" in acro_form:
|
93 |
+
fields = acro_form["/Fields"]
|
94 |
+
for field in fields:
|
95 |
+
field_obj = field.get_object()
|
96 |
+
if "/T" in field_obj:
|
97 |
+
field_name = str(field_obj["/T"]).strip("()")
|
98 |
+
if field_name in field_data:
|
99 |
+
try:
|
100 |
+
field_obj.update({"/V": field_data[field_name]})
|
101 |
+
except Exception:
|
102 |
+
pass
|
103 |
+
except Exception:
|
104 |
+
pass
|
105 |
+
|
106 |
+
return writer
|
107 |
+
except Exception as e:
|
108 |
+
raise Exception(f"ไม่สามารถเติมฟอร์มได้: {str(e)}")
|
109 |
+
|
110 |
+
def create_simple_pdf(data_row, filename):
|
111 |
+
"""สร้าง PDF ใหม่แบบง่าย"""
|
112 |
+
buffer = io.BytesIO()
|
113 |
+
p = canvas.Canvas(buffer, pagesize=letter)
|
114 |
+
width, height = letter
|
115 |
+
|
116 |
+
# ตั้งค่า font
|
117 |
+
p.setFont("Helvetica", 12)
|
118 |
+
|
119 |
+
# หัวเรื่อง
|
120 |
+
p.setFont("Helvetica-Bold", 16)
|
121 |
+
title = f"Document: {filename.replace('.pdf', '')}"
|
122 |
+
p.drawString(50, height - 50, title)
|
123 |
+
p.line(50, height - 60, 550, height - 60)
|
124 |
+
|
125 |
+
# เนื้อหา
|
126 |
+
y_position = height - 100
|
127 |
+
p.setFont("Helvetica", 12)
|
128 |
+
|
129 |
+
for column, value in data_row.items():
|
130 |
+
if pd.notna(value) and str(value).strip():
|
131 |
+
clean_column = str(column).strip()
|
132 |
+
clean_value = str(value).strip()
|
133 |
+
|
134 |
+
if len(clean_value) > 80:
|
135 |
+
clean_value = clean_value[:77] + "..."
|
136 |
+
|
137 |
+
text = f"{clean_column}: {clean_value}"
|
138 |
+
|
139 |
+
try:
|
140 |
+
p.drawString(50, y_position, text)
|
141 |
+
except:
|
142 |
+
safe_text = text.encode('ascii', errors='ignore').decode('ascii')
|
143 |
+
p.drawString(50, y_position, safe_text)
|
144 |
+
|
145 |
+
y_position -= 25
|
146 |
+
|
147 |
+
if y_position < 50:
|
148 |
+
p.showPage()
|
149 |
+
p.setFont("Helvetica", 12)
|
150 |
+
y_position = height - 50
|
151 |
+
|
152 |
+
# เวลาที่สร้าง
|
153 |
+
p.setFont("Helvetica", 8)
|
154 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
155 |
+
p.drawString(50, 30, f"Created: {timestamp}")
|
156 |
+
|
157 |
+
p.save()
|
158 |
+
buffer.seek(0)
|
159 |
+
return buffer.getvalue()
|
160 |
+
|
161 |
+
def process_single_row(pdf_path, row_data, filename, use_form=True):
|
162 |
+
"""ประมวลผลแถวเดียว"""
|
163 |
+
try:
|
164 |
+
# เตรียมข้อมูลฟิลด์
|
165 |
+
field_data = {}
|
166 |
+
for column, value in row_data.items():
|
167 |
+
if pd.notna(value) and str(value).strip():
|
168 |
+
clean_value = str(value).strip()
|
169 |
+
clean_column = str(column).strip()
|
170 |
+
|
171 |
+
# ลองหลายรูปแบบของชื่อฟิลด์
|
172 |
+
field_variations = [
|
173 |
+
clean_column,
|
174 |
+
clean_column.lower(),
|
175 |
+
clean_column.upper(),
|
176 |
+
clean_column.replace('_', ' '),
|
177 |
+
clean_column.replace(' ', '_'),
|
178 |
+
clean_column.replace('-', '_'),
|
179 |
+
clean_column.replace('_', '')
|
180 |
+
]
|
181 |
+
|
182 |
+
for variation in field_variations:
|
183 |
+
field_data[variation] = clean_value
|
184 |
+
|
185 |
+
if use_form:
|
186 |
+
try:
|
187 |
+
# ลองเติมฟอร์ม
|
188 |
+
writer = fill_pdf_form(pdf_path, field_data)
|
189 |
+
|
190 |
+
output_buffer = io.BytesIO()
|
191 |
+
writer.write(output_buffer)
|
192 |
+
output_buffer.seek(0)
|
193 |
+
return output_buffer.getvalue(), "form_filled"
|
194 |
+
except Exception as e:
|
195 |
+
# ถ้าไม่ได้ ให้สร้างใหม่
|
196 |
+
pdf_content = create_simple_pdf(row_data, filename)
|
197 |
+
return pdf_content, f"new_pdf_created: {str(e)}"
|
198 |
+
else:
|
199 |
+
# สร้าง PDF ใหม่
|
200 |
+
pdf_content = create_simple_pdf(row_data, filename)
|
201 |
+
return pdf_content, "new_pdf_created"
|
202 |
+
|
203 |
+
except Exception as e:
|
204 |
+
return None, f"error: {str(e)}"
|
205 |
+
|
206 |
+
def read_csv_safe(csv_file):
|
207 |
+
"""อ่าน CSV อย่างปลอดภัย"""
|
208 |
+
encodings = ['utf-8', 'utf-8-sig', 'cp874', 'tis-620', 'iso-8859-1', 'cp1252']
|
209 |
+
separators = [',', ';', '\t', '|']
|
210 |
+
|
211 |
+
for encoding in encodings:
|
212 |
+
for sep in separators:
|
213 |
+
try:
|
214 |
+
df = pd.read_csv(csv_file, encoding=encoding, sep=sep, engine='python')
|
215 |
+
if len(df.columns) > 1 and len(df) > 0:
|
216 |
+
return df, None
|
217 |
+
except Exception:
|
218 |
+
continue
|
219 |
+
|
220 |
+
try:
|
221 |
+
df = pd.read_csv(csv_file)
|
222 |
+
return df, None
|
223 |
+
except Exception as e:
|
224 |
+
return None, str(e)
|
225 |
+
|
226 |
+
def process_pdf_csv(pdf_file, csv_file, filename_column, file_prefix, use_form_fields, progress=gr.Progress()):
|
227 |
+
"""ฟังก์ชันหลักสำหรับประมวลผล PDF และ CSV"""
|
228 |
+
|
229 |
+
if pdf_file is None or csv_file is None:
|
230 |
+
return None, "❌ กรุณาอัพโหลดไฟล์ PDF และ CSV"
|
231 |
+
|
232 |
+
try:
|
233 |
+
# อ่าน CSV
|
234 |
+
df, csv_error = read_csv_safe(csv_file)
|
235 |
+
if df is None:
|
236 |
+
return None, f"❌ ไม่สามารถอ่าน CSV ได้: {csv_error}"
|
237 |
+
|
238 |
+
# วิเคราะห์ PDF
|
239 |
+
pdf_fields = analyze_pdf_fields(pdf_file)
|
240 |
+
has_form_fields = bool(pdf_fields and "error" not in pdf_fields and pdf_fields)
|
241 |
+
|
242 |
+
# เก็บ PDF ที่สร้าง
|
243 |
+
generated_pdfs = {}
|
244 |
+
success_count = 0
|
245 |
+
error_count = 0
|
246 |
+
processing_log = []
|
247 |
+
|
248 |
+
# ประมวลผลแต่ละแถว
|
249 |
+
for index, (_, row) in enumerate(df.iterrows()):
|
250 |
+
progress((index + 1) / len(df), f"ประมวลผล {index + 1}/{len(df)}")
|
251 |
+
|
252 |
+
try:
|
253 |
+
# สร้างชื่อไฟล์
|
254 |
+
if filename_column and filename_column in df.columns and pd.notna(row[filename_column]):
|
255 |
+
safe_name = str(row[filename_column]).strip()
|
256 |
+
safe_name = "".join(c for c in safe_name if c.isalnum() or c in (' ', '-', '_')).strip()
|
257 |
+
filename = f"{file_prefix}_{safe_name}.pdf"
|
258 |
+
else:
|
259 |
+
filename = f"{file_prefix}_{index + 1:03d}.pdf"
|
260 |
+
|
261 |
+
filename = filename.replace(' ', ' ').replace(' ', '_')
|
262 |
+
if not filename.endswith('.pdf'):
|
263 |
+
filename += '.pdf'
|
264 |
+
|
265 |
+
# ประมวลผล
|
266 |
+
pdf_content, status = process_single_row(
|
267 |
+
pdf_file,
|
268 |
+
row,
|
269 |
+
filename,
|
270 |
+
use_form_fields and has_form_fields
|
271 |
+
)
|
272 |
+
|
273 |
+
if pdf_content is not None:
|
274 |
+
generated_pdfs[filename] = pdf_content
|
275 |
+
success_count += 1
|
276 |
+
processing_log.append(f"✅ {filename}: {status}")
|
277 |
+
else:
|
278 |
+
error_count += 1
|
279 |
+
processing_log.append(f"❌ {filename}: {status}")
|
280 |
+
|
281 |
+
except Exception as e:
|
282 |
+
error_count += 1
|
283 |
+
processing_log.append(f"💥 แถว {index + 1}: {str(e)}")
|
284 |
+
|
285 |
+
# สร้าง ZIP
|
286 |
+
if generated_pdfs:
|
287 |
+
zip_buffer = io.BytesIO()
|
288 |
+
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
289 |
+
for filename, pdf_content in generated_pdfs.items():
|
290 |
+
zip_file.writestr(filename, pdf_content)
|
291 |
+
|
292 |
+
zip_buffer.seek(0)
|
293 |
+
|
294 |
+
# สร้างชื่อไฟล์ ZIP
|
295 |
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
296 |
+
zip_filename = f"generated_pdfs_{timestamp}.zip"
|
297 |
+
|
298 |
+
# บันทึกไฟล์ชั่วคราว
|
299 |
+
temp_zip_path = os.path.join(tempfile.gettempdir(), zip_filename)
|
300 |
+
with open(temp_zip_path, 'wb') as f:
|
301 |
+
f.write(zip_buffer.getvalue())
|
302 |
+
|
303 |
+
result_message = f"✅ สร้าง PDF สำเร็จ {success_count} ไฟล์!"
|
304 |
+
if error_count > 0:
|
305 |
+
result_message += f"\n⚠️ มีข้อผิดพลาด {error_count} ไฟล์"
|
306 |
+
|
307 |
+
result_message += f"\n\n📋 รายละเอียด:\n" + "\n".join(processing_log[:10])
|
308 |
+
if len(processing_log) > 10:
|
309 |
+
result_message += f"\n... และอีก {len(processing_log) - 10} รายการ"
|
310 |
+
|
311 |
+
return temp_zip_path, result_message
|
312 |
+
else:
|
313 |
+
return None, "❌ ไม่สามารถสร้าง PDF ได้เลย"
|
314 |
+
|
315 |
+
except Exception as e:
|
316 |
+
return None, f"❌ เกิดข้อผิดพลาด: {str(e)}\n{traceback.format_exc()}"
|
317 |
+
|
318 |
+
def analyze_pdf_info(pdf_file):
|
319 |
+
"""วิเคราะห์ข้อมูล PDF"""
|
320 |
+
if pdf_file is None:
|
321 |
+
return "ไม่มีไฟล์ PDF"
|
322 |
+
|
323 |
+
try:
|
324 |
+
reader = PdfReader(pdf_file)
|
325 |
+
info = f"📄 **ข้อมูล PDF:**\n"
|
326 |
+
info += f"- จำนวนหน้า: {len(reader.pages)}\n"
|
327 |
+
|
328 |
+
# ตรวจสอบฟิลด์
|
329 |
+
pdf_fields = analyze_pdf_fields(pdf_file)
|
330 |
+
|
331 |
+
if pdf_fields and "error" not in pdf_fields and pdf_fields:
|
332 |
+
info += f"- จำนวน Form Fields: {len(pdf_fields)}\n"
|
333 |
+
info += f"\n🏷️ **รายชื่อ Fields:**\n"
|
334 |
+
for name, details in list(pdf_fields.items())[:10]: # แสดงแค่ 10 ตัวแรก
|
335 |
+
info += f" - {name} ({details.get('type', 'Unknown')})\n"
|
336 |
+
if len(pdf_fields) > 10:
|
337 |
+
info += f" - ... และอีก {len(pdf_fields) - 10} fields\n"
|
338 |
+
else:
|
339 |
+
info += "- Form Fields: ไม่พบหรือไม่สามารถอ่านได้\n"
|
340 |
+
info += "- หมายเหตุ: จะสร้าง PDF ใหม่แทน\n"
|
341 |
+
|
342 |
+
return info
|
343 |
+
except Exception as e:
|
344 |
+
return f"❌ ไม่สามารถวิเคราะห์ PDF ได้: {str(e)}"
|
345 |
+
|
346 |
+
def analyze_csv_info(csv_file):
|
347 |
+
"""วิเคราะห์ข้อมูล CSV"""
|
348 |
+
if csv_file is None:
|
349 |
+
return "ไม่มีไฟล์ CSV"
|
350 |
+
|
351 |
+
try:
|
352 |
+
df, error = read_csv_safe(csv_file)
|
353 |
+
if df is None:
|
354 |
+
return f"❌ ไม่สามารถอ่าน CSV ได้: {error}"
|
355 |
+
|
356 |
+
info = f"📋 **ข้อมูล CSV:**\n"
|
357 |
+
info += f"- จำนวนแถว: {len(df)}\n"
|
358 |
+
info += f"- จำนวนคอลัมน์: {len(df.columns)}\n"
|
359 |
+
info += f"\n📝 **รายชื่อคอลัมน์:**\n"
|
360 |
+
|
361 |
+
for col in df.columns[:15]: # แสดงแค่ 15 คอลัมน์แรก
|
362 |
+
info += f" - {col}\n"
|
363 |
+
if len(df.columns) > 15:
|
364 |
+
info += f" - ... และอีก {len(df.columns) - 15} คอลัมน์\n"
|
365 |
+
|
366 |
+
# ตรวจสอบข้อมูลที่ขาด
|
367 |
+
missing_data = df.isnull().sum()
|
368 |
+
if missing_data.any():
|
369 |
+
missing_cols = missing_data[missing_data > 0]
|
370 |
+
if len(missing_cols) > 0:
|
371 |
+
info += f"\n⚠️ **ข้อมูลที่ขาดหาย:**\n"
|
372 |
+
for col, count in missing_cols.head(5).items():
|
373 |
+
info += f" - {col}: {count} แถว\n"
|
374 |
+
|
375 |
+
return info
|
376 |
+
except Exception as e:
|
377 |
+
return f"❌ ไม่สามารถวิเคราะห์ CSV ได้: {str(e)}"
|
378 |
+
|
379 |
+
# สร้าง Gradio Interface
|
380 |
+
def create_interface():
|
381 |
+
with gr.Blocks(title="PDF Form Filler", theme=gr.themes.Soft()) as app:
|
382 |
+
gr.Markdown("""
|
383 |
+
# 📄 เครื่องมือเติมข้อมูล PDF จาก CSV
|
384 |
+
|
385 |
+
**เครื่องมือนี้สามารถ:**
|
386 |
+
- เติมข้อมูลลงในฟอร์ม PDF ที่มี form fields
|
387 |
+
- สร้าง PDF ใหม่หากไม่มี form fields หรือเติมไม่ได้
|
388 |
+
- รองรับ CSV หลาย encoding (UTF-8, TIS-620, CP874, etc.)
|
389 |
+
- ส่งออกเป็นไฟล์ ZIP
|
390 |
+
""")
|
391 |
+
|
392 |
+
with gr.Row():
|
393 |
+
with gr.Column(scale=1):
|
394 |
+
gr.Markdown("## 📁 อัพโหลดไฟล์")
|
395 |
+
|
396 |
+
pdf_file = gr.File(
|
397 |
+
label="PDF Template",
|
398 |
+
file_types=[".pdf"],
|
399 |
+
type="filepath"
|
400 |
+
)
|
401 |
+
|
402 |
+
csv_file = gr.File(
|
403 |
+
label="CSV Data",
|
404 |
+
file_types=[".csv"],
|
405 |
+
type="filepath"
|
406 |
+
)
|
407 |
+
|
408 |
+
gr.Markdown("## ⚙️ ตั้งค่า")
|
409 |
+
|
410 |
+
filename_column = gr.Textbox(
|
411 |
+
label="คอลัมน์สำหรับชื่อไฟล์ (ถ้ามี)",
|
412 |
+
placeholder="เช่น name, id, etc.",
|
413 |
+
value=""
|
414 |
+
)
|
415 |
+
|
416 |
+
file_prefix = gr.Textbox(
|
417 |
+
label="คำนำหน้าชื่อไฟล์",
|
418 |
+
value="document"
|
419 |
+
)
|
420 |
+
|
421 |
+
use_form_fields = gr.Checkbox(
|
422 |
+
label="ใช้ Form Fields (ถ้าพบ)",
|
423 |
+
value=True
|
424 |
+
)
|
425 |
+
|
426 |
+
process_btn = gr.Button(
|
427 |
+
"🚀 สร้าง PDF ทั้งหมด",
|
428 |
+
variant="primary",
|
429 |
+
size="lg"
|
430 |
+
)
|
431 |
+
|
432 |
+
with gr.Column(scale=2):
|
433 |
+
gr.Markdown("## 📊 ข้อมูลไฟล์")
|
434 |
+
|
435 |
+
pdf_info = gr.Markdown("ยังไม่มีไฟล์ PDF")
|
436 |
+
csv_info = gr.Markdown("ยังไม่มีไฟล์ CSV")
|
437 |
+
|
438 |
+
gr.Markdown("## 📥 ผลลัพธ์")
|
439 |
+
|
440 |
+
result_file = gr.File(
|
441 |
+
label="ไฟล์ ZIP ที่สร้าง",
|
442 |
+
visible=False
|
443 |
+
)
|
444 |
+
|
445 |
+
result_message = gr.Markdown("")
|
446 |
+
|
447 |
+
# Event handlers
|
448 |
+
pdf_file.change(
|
449 |
+
fn=analyze_pdf_info,
|
450 |
+
inputs=[pdf_file],
|
451 |
+
outputs=[pdf_info]
|
452 |
+
)
|
453 |
+
|
454 |
+
csv_file.change(
|
455 |
+
fn=analyze_csv_info,
|
456 |
+
inputs=[csv_file],
|
457 |
+
outputs=[csv_info]
|
458 |
+
)
|
459 |
+
|
460 |
+
process_btn.click(
|
461 |
+
fn=process_pdf_csv,
|
462 |
+
inputs=[
|
463 |
+
pdf_file,
|
464 |
+
csv_file,
|
465 |
+
filename_column,
|
466 |
+
file_prefix,
|
467 |
+
use_form_fields
|
468 |
+
],
|
469 |
+
outputs=[result_file, result_message]
|
470 |
+
).then(
|
471 |
+
fn=lambda x: gr.update(visible=x is not None),
|
472 |
+
inputs=[result_file],
|
473 |
+
outputs=[result_file]
|
474 |
+
)
|
475 |
+
|
476 |
+
return app
|
477 |
+
|
478 |
+
# รันแอป
|
479 |
+
if __name__ == "__main__":
|
480 |
+
app = create_interface()
|
481 |
+
app.launch(
|
482 |
+
server_name="0.0.0.0",
|
483 |
+
server_port=7860,
|
484 |
+
share=True, # สร้าง public URL
|
485 |
+
debug=True
|
486 |
+
)
|