Antharee commited on
Commit
0d1f6bf
·
verified ·
1 Parent(s): e964fb0

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -415
app.py DELETED
@@ -1,415 +0,0 @@
1
- from flask import Flask, request, render_template, jsonify
2
- import easyocr
3
- import google.generativeai as genai
4
- import os
5
- import re
6
-
7
- app = Flask(__name__)
8
-
9
- # ตั้งค่า Gemini API Key
10
- genai.configure(api_key="AIzaSyCK_4YXWSEaZf6_E0RS_kNIsvHRBbAz8rQ") # เปลี่ยนตรงนี้ให้เป็น API Key ของคุณ
11
-
12
- # โหลดโมเดล OCR
13
- reader = easyocr.Reader(['th', 'en'])
14
-
15
- # โหลดโมเดล Gemini
16
- model = genai.GenerativeModel("gemini-2.0-flash")
17
-
18
- # สร้างโฟลเดอร์สำหรับเก็บไฟล์อัปโหลด
19
- if not os.path.exists('static'):
20
- os.makedirs('static')
21
-
22
- # ฟังก์ชันให้ Gemini ช่วยแก้ข้อความ OCR
23
- def refine_text_with_gemini(text):
24
- try:
25
- prompt = f"""
26
- ด้านล่างนี้คือข้อความดิบที่ได้จาก OCR ซึ่งอาจมีคำผิดหรือรูปแบบไม่ถูกต้อง:
27
- {text}
28
-
29
- กรุณาช่วยแก้ไขให้ข้อความถูกต้องตามความเป็นจริงของบัตรประชาชนไทย:
30
- - แก้คำสะกดผิด
31
- - หากข้อความหายไปหรือผิดพลาดจาก OCR กรุณาเติมให้สมบูรณ์ โดยอิงจากบริบทของข้อความที่เหลือ
32
- - ข้อมูลใดไม่ทราบข้อมูลได้ไม่ต้องแสดง
33
- - ไม่ต้องอธิบายการทำงานเเค่ถอดข้อความออกมาให้อ่านเข้าใจ
34
- - ไม่ต้องเเปลภาษา
35
- """
36
- response = model.generate_content(prompt)
37
- return response.text
38
- except Exception as e:
39
- print(f"Error in Gemini processing: {e}")
40
- return text # Return original text if Gemini fails
41
-
42
- # ฟังก์ชันแยกข้อมูลจากการตอบของ Gemini
43
- def parse_gemini_response(text):
44
- """
45
- แยกข้อมูลสำคัญจากข้อความที่ Gemini แก้ไขแล้ว
46
- """
47
- data = {
48
- 'fullname': '',
49
- 'idnumber': '',
50
- 'birthdate': '',
51
- 'religion': '',
52
- 'address': '',
53
- 'issuedate': '',
54
- 'expiredate': ''
55
- }
56
-
57
- try:
58
- # ใช้ regex patterns หาข้อมูล
59
- lines = text.split('\n')
60
-
61
- for line in lines:
62
- line = line.strip()
63
- # หาชื่อ-นามสกุล (มักจะเป็นบรรทัดที่มีคำว่า "นาย" "นาง" "นางสาว" หรือเป็นชื่อภาษาไทย)
64
- if re.search(r'(นาย|นาง|นางสาว|Mr\.|Mrs\.|Miss)', line):
65
- data['fullname'] = line
66
-
67
- # หาเลขประจำตัวประชาชน (13 หลัก)
68
- id_match = re.search(r'(\d{1}\s*\d{4}\s*\d{5}\s*\d{2}\s*\d{1}|\d{13})', line)
69
- if id_match:
70
- data['idnumber'] = id_match.group().replace(' ', '')
71
-
72
- # หาวันเกิด
73
- if re.search(r'(เกิด|born)', line.lower()):
74
- date_match = re.search(r'(\d{1,2}[\s/.-]\d{1,2}[\s/.-]\d{4})', line)
75
- if date_match:
76
- data['birthdate'] = date_match.group()
77
-
78
- # หาศาสนา
79
- if re.search(r'(ศาสนา|religion)', line.lower()):
80
- religion_match = re.search(r'(พุทธ|คริสต์|อิสลาม|ฮินดู|ซิกข์)', line)
81
- if religion_match:
82
- data['religion'] = religion_match.group()
83
-
84
- # หาที่อยู่ (บรรทัดที่มีเลขที่ หมู่ ถนน)
85
- if re.search(r'(เลขที่|หมู่|ถนน|ตำบล|อำเภอ|จังหวัด)', line):
86
- if not data['address']: # เก็บที่อยู่บรรทัดแรกที่เจอ
87
- data['address'] = line
88
- else:
89
- data['address'] += ' ' + line
90
-
91
- # หาวันออกบัตร
92
- if re.search(r'(ออกบัตร|issued)', line.lower()):
93
- date_match = re.search(r'(\d{1,2}[\s/.-]\d{1,2}[\s/.-]\d{4})', line)
94
- if date_match:
95
- data['issuedate'] = date_match.group()
96
-
97
- # หาวันหมดอายุ
98
- if re.search(r'(หมดอายุ|expire)', line.lower()):
99
- date_match = re.search(r'(\d{1,2}[\s/.-]\d{1,2}[\s/.-]\d{4})', line)
100
- if date_match:
101
- data['expiredate'] = date_match.group()
102
-
103
- except Exception as e:
104
- print(f"Error parsing Gemini response: {e}")
105
-
106
- return data
107
-
108
- # หน้าเริ่มต้น
109
- @app.route("/", methods=["GET"])
110
- def index():
111
- return render_template("index.html")
112
-
113
- # เมื่อมีการอัปโหลดภาพ
114
- @app.route("/upload", methods=["POST"])
115
- def upload():
116
- try:
117
- if "image" not in request.files:
118
- return jsonify({"error": "ไม่พบไฟล์"}), 400
119
-
120
- file = request.files["image"]
121
-
122
- if file.filename == '':
123
- return jsonify({"error": "ไม่ได้เลือกไฟล์"}), 400
124
-
125
- # ตรวจสอบว่ามีนามสกุลไฟล์หรือไม่
126
- if '.' not in file.filename:
127
- return jsonify({"error": "ไฟล์ต้องมีนามสกุล"}), 400
128
-
129
- file_extension = file.filename.rsplit('.', 1)[1].lower()
130
-
131
- # ไฟล์ที่อันตรายที่ไม่ควรอนุญาต (blacklist)
132
- dangerous_extensions = {
133
- 'exe', 'bat', 'cmd', 'scr', 'vbs', 'jar', 'com', 'pif',
134
- 'application', 'gadget', 'msi', 'msp', 'hta', 'cpl', 'msc',
135
- 'wsf', 'wsh', 'ps1', 'ps1xml', 'ps2', 'ps2xml', 'psc1', 'psc2'
136
- }
137
-
138
- # ป้องกันไฟล์อันตราย
139
- if file_extension in dangerous_extensions:
140
- return jsonify({"error": f"ไฟล์ประเภท .{file_extension} อาจเป็นอันตราย"}), 400
141
-
142
- # ตรวจสอบขนาดไฟล์ (10MB = 10 * 1024 * 1024 bytes)
143
- file.seek(0, 2) # ไปที่ท้ายไฟล์
144
- file_size = file.tell() # ได้ขนาดไฟล์
145
- file.seek(0) # กลับไปต้นไฟล์
146
-
147
- if file_size > 10 * 1024 * 1024: # 10MB
148
- return jsonify({"error": "ไฟล์ใหญ่เกินไป (สูงสุด 10MB)"}), 400
149
-
150
- # สร้างชื่อไฟล์ใหม่เพื่อป้องกันชื่อซ้ำ
151
- import time
152
- timestamp = str(int(time.time()))
153
- safe_filename = f"{timestamp}_{file.filename}"
154
- file_path = os.path.join("static", safe_filename)
155
-
156
- # บันทึกไฟล์
157
- file.save(file_path)
158
-
159
- # ตรวจสอบว่าไฟล์เป็นรูปภาพหรือ PDF ก่อนทำ OCR
160
- image_extensions = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'webp'}
161
- pdf_extensions = {'pdf'}
162
-
163
- raw_text = ""
164
- refined_text = ""
165
- data = {}
166
-
167
- if file_extension in image_extensions or file_extension in pdf_extensions:
168
- # OCR อ่านข้อความจากภาพหรือ PDF
169
- try:
170
- results = reader.readtext(file_path, detail=0)
171
- raw_text = "\n".join(results)
172
-
173
- if not raw_text.strip():
174
- return render_template("index.html",
175
- error="ไม่สามารถอ่านข้อความจากไฟล์ได้ กรุณาลองใหม่ด้วยไฟล์ที่ชัดขึ้น",
176
- file_info={"name": file.filename, "size": file_size, "type": file_extension})
177
-
178
- except Exception as e:
179
- print(f"OCR Error: {e}")
180
- return render_template("index.html",
181
- error="เกิดข้อผิดพลาดในการอ่านไฟล์ กรุณาลองใหม่อีกครั้ง",
182
- file_info={"name": file.filename, "size": file_size, "type": file_extension})
183
-
184
- # แก้ไขปัญหาการอ่านเลข 1 เป็น /
185
- def fix_common_ocr_errors(text):
186
- # แก้เฉพาะ / ที่น่าจะเป็นเลข 1 เช่น 2/3 → 213
187
- return re.sub(r'(?<=\d)/(?=\d)', '1', text)
188
-
189
- raw_text = fix_common_ocr_errors(raw_text)
190
-
191
- # ส่งข้อความดิบให้ Gemini แก้ไข
192
- try:
193
- refined_text = refine_text_with_gemini(raw_text)
194
- except Exception as e:
195
- print(f"Gemini Error: {e}")
196
- refined_text = raw_text # ใช้ข้อความต้นฉบับถ้า Gemini ล้มเหลว
197
-
198
- # แยกข้อมูลที่สำคัญออกมา
199
- try:
200
- data = parse_gemini_response(refined_text)
201
- except Exception as e:
202
- print(f"Parse Error: {e}")
203
- data = {}
204
- else:
205
- # ไฟล์ประเภทอื่นที่ไม่ใช่รูปภาพหรือ PDF
206
- raw_text = f"อัปโหลดไฟล์ {file.filename} สำเร็จ"
207
- refined_text = f"ไฟล์ประเภท .{file_extension} ได้รับการอัปโหลดเรียบร้อยแล้ว"
208
- data = {
209
- "filename": file.filename,
210
- "file_type": file_extension,
211
- "file_size": f"{file_size / 1024:.2f} KB"
212
- }
213
-
214
- # ลบไฟล์ที่อัปโหลดเพื่อประหยัดพื้นที่ (ถ้าไม่ต้องการเก็บไว้)
215
- try:
216
- os.remove(file_path)
217
- except:
218
- pass
219
-
220
- # ส่งข้อมูลไปหน้าเว็บ
221
- return render_template("index.html",
222
- raw_text=raw_text,
223
- refined_text=refined_text,
224
- data=data,
225
- file_info={
226
- "name": file.filename,
227
- "size": f"{file_size / 1024:.2f} KB",
228
- "type": file_extension
229
- })
230
-
231
- except Exception as e:
232
- print(f"Unexpected error: {e}")
233
- return render_template("index.html",
234
- error="เกิดข้อผิดพลาดที่ไม่คาดคิด กรุณาลองใหม่อีกครั้ง")
235
-
236
-
237
- @app.route("/api/lucky-draw", methods=["POST"])
238
- def lucky_draw():
239
- try:
240
- if "image" not in request.files:
241
- return jsonify({"success": False, "message": "ไม่พบไฟล์"}), 400
242
-
243
- file = request.files["image"]
244
-
245
- if file.filename == '':
246
- return jsonify({"success": False, "message": "ไม่ได้เลือกไฟล์"}), 400
247
-
248
- if '.' not in file.filename:
249
- return jsonify({"success": False, "message": "ไฟล์ต้องมีนามสกุล"}), 400
250
-
251
- file_extension = file.filename.rsplit('.', 1)[1].lower()
252
- allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'webp', 'pdf'}
253
- if file_extension not in allowed_extensions:
254
- return jsonify({"success": False, "message": "รองรับเฉพาะไฟล์รูปภาพและ PDF เท่านั้น"}), 400
255
-
256
- file.seek(0, 2)
257
- file_size = file.tell()
258
- file.seek(0)
259
- if file_size > 10 * 1024 * 1024:
260
- return jsonify({"success": False, "message": "ไฟล์ใหญ่เกินไป (สูงสุด 10MB)"}), 400
261
-
262
- # บันทึกไฟล์ชั่วคราว
263
- import time
264
- timestamp = str(int(time.time()))
265
- safe_filename = f"{timestamp}_{file.filename}"
266
- file_path = os.path.join("static", safe_filename)
267
- file.save(file_path)
268
-
269
- # OCR อ่านข้อความ
270
- results = []
271
- try:
272
- if file_extension == 'pdf':
273
- # ถ้า PDF อาจต้องแปลงเป็นรูปก่อน (ง่ายๆ ใช้ pdf2image หรือ library อื่น)
274
- # แต่ถ้าอยากง่าย ให้บอกว่ารองรับเฉพาะรูปภาพก่อน
275
- return jsonify({"success": False, "message": "ยังไม่รองรับ PDF สำหรับฟังก์ชันสุ่มชื่อ"}), 400
276
- else:
277
- results = reader.readtext(file_path, detail=0)
278
- except Exception as e:
279
- print(f"OCR Error: {e}")
280
- return jsonify({"success": False, "message": "เกิดข้อผิดพลาดในการอ่านไฟล์"}), 500
281
-
282
- raw_text = "\n".join(results)
283
-
284
- # ฟังก์ชันช่วยแก้ปัญหาการอ่านเลข 1 ผิดเป็น /
285
- def fix_common_ocr_errors(text):
286
- return re.sub(r'(?<=\d)/(?=\d)', '1', text)
287
- raw_text = fix_common_ocr_errors(raw_text)
288
-
289
- # สร้าง prompt สำหรับให้ Gemini สุ่มชื่อผู้โชคดี 3 ราย
290
- prompt = f"""
291
- ข้อความด้านล่างเป็นรายชื่อผู้เข้าร่วมกิจกรรม (อาจมีหลายบรรทัด):
292
- {raw_text}
293
-
294
- กรุณาสุ่มเลือกชื่อผู้โชคดีจำนวน 3 คน และตอบกลับเป็นรายการชื่อแยกบรรทัดใหม่โดยไม่ต้องมีข้อความอื่น
295
- """
296
-
297
- # เรียก Gemini เพื่อสุ่มชื่อ
298
- response = model.generate_content(prompt)
299
- lucky_names_text = response.text.strip()
300
-
301
- # แปลงข้อความชื่อผู้โชคดีเป็น list
302
- lucky_names = [line.strip() for line in lucky_names_text.split('\n') if line.strip()]
303
-
304
- # ลบไฟล์หลังใช้งาน
305
- try:
306
- os.remove(file_path)
307
- except:
308
- pass
309
-
310
- return jsonify({
311
- "success": True,
312
- "lucky_names": lucky_names,
313
- "raw_text": raw_text
314
- })
315
-
316
- except Exception as e:
317
- print(f"Unexpected error in lucky_draw: {e}")
318
- return jsonify({"success": False, "message": "เกิดข้อผิดพลาดที่ไม่คาดคิด"}), 500
319
-
320
-
321
- # ===== ทางเลือกอื่น: รองรับทุกไฟล์โดยไม่มีข้อจำกัด =====
322
-
323
- @app.route("/upload_no_limit", methods=["POST"])
324
- def upload_no_limit():
325
- """เวอร์ชันที่รองรับทุกประเภทไฟล์โดยไม่มีข้อจำกัด"""
326
- try:
327
- if "image" not in request.files:
328
- return jsonify({"error": "ไม่พบไฟล์"}), 400
329
-
330
- file = request.files["image"]
331
-
332
- if file.filename == '':
333
- return jsonify({"error": "ไม่ได้เลือกไฟล์"}), 400
334
-
335
- # ตรวจสอบขนาดไฟล์เท่านั้น (50MB)
336
- file.seek(0, 2)
337
- file_size = file.tell()
338
- file.seek(0)
339
-
340
- if file_size > 50 * 1024 * 1024: # 50MB
341
- return jsonify({"error": "ไฟล์ใหญ่เกินไป (สูงสุด 50MB)"}), 400
342
-
343
- # สร้างชื่อไฟล์ใหม่
344
- import time
345
- timestamp = str(int(time.time()))
346
- safe_filename = f"{timestamp}_{file.filename}"
347
- file_path = os.path.join("static", safe_filename)
348
-
349
- # บันทึกไฟล์
350
- file.save(file_path)
351
-
352
- # ได้นามสกุลไฟล์ (ถ้ามี)
353
- file_extension = ""
354
- if '.' in file.filename:
355
- file_extension = file.filename.rsplit('.', 1)[1].lower()
356
-
357
- # ลบไฟล์หลังอัปโหลด
358
- try:
359
- os.remove(file_path)
360
- except:
361
- pass
362
-
363
- # ส่งข้อมูลกลับ
364
- return render_template("index.html",
365
- raw_text=f"อัปโหลด {file.filename} สำเร็จ",
366
- refined_text=f"ไฟล์ {file.filename} ได้รับการอัปโหลดเรียบร้อย",
367
- data={
368
- "filename": file.filename,
369
- "file_type": file_extension if file_extension else "ไม่มีนามสกุล",
370
- "file_size": f"{file_size / 1024:.2f} KB"
371
- },
372
- file_info={
373
- "name": file.filename,
374
- "size": f"{file_size / 1024:.2f} KB",
375
- "type": file_extension if file_extension else "unknown"
376
- })
377
-
378
- except Exception as e:
379
- print(f"Unexpected error: {e}")
380
- return render_template("index.html",
381
- error="เกิดข้อผิดพลาดที่ไม่คาดคิด กรุณาลองใหม่อีกครั้ง")
382
-
383
- # API สำหรับบันทึกข้อมูล
384
- @app.route("/save", methods=["POST"])
385
- def save_data():
386
- try:
387
- data = request.get_json()
388
-
389
- # ที่นี่คุณสามารถบันทึกข้อมูลลงฐานข้อมูลได้
390
- # เช่น บันทึกลง SQLite, MySQL, MongoDB เป็นต้น
391
-
392
- print("Saving data:", data)
393
-
394
- return jsonify({"success": True, "message": "บันทึกข้อมูลสำเร็จ"})
395
-
396
- except Exception as e:
397
- print(f"Save error: {e}")
398
- return jsonify({"success": False, "error": "ไม่สามารถบันทึกข้อมูลได้"}), 500
399
-
400
- # Error handlers
401
- @app.errorhandler(404)
402
- def not_found(error):
403
- return render_template("index.html", error="ไม่พบหน้าที่ต้องการ"), 404
404
-
405
- @app.errorhandler(500)
406
- def internal_error(error):
407
- return render_template("index.html", error="เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์"), 500
408
-
409
- @app.errorhandler(413)
410
- def too_large(error):
411
- return render_template("index.html", error="ไฟล์ใหญ่เกินไป (สูงสุด 10MB)"), 413
412
-
413
- # รัน Flask app
414
- if __name__ == "__main__":
415
- app.run(debug=True, host="0.0.0.0", port=7860)