HSB3119-22080292-daothivananh commited on
Commit
dc003ba
·
1 Parent(s): b599a7e
Files changed (1) hide show
  1. controllers/main.py +25 -49
controllers/main.py CHANGED
@@ -1,6 +1,5 @@
1
  import os
2
  import sys
3
- import threading # <-- Đã thêm thư viện threading
4
  from pathlib import Path
5
 
6
  # ─── 1. CẤU HÌNH ĐƯỜNG DẪN TUYỆT ĐỐI (TRÁNH LẠC ĐƯỜNG) ──────────────────────
@@ -49,52 +48,34 @@ logging.basicConfig(level=logging.INFO)
49
  logger = logging.getLogger(__name__)
50
 
51
 
52
- # ─── KHỞI TẠO AI CHẠY NGẦM ───────────────────────────────────────────────────
53
- ocr_predictor = None
54
- read_info = None
55
- is_ai_ready = False
56
 
57
- def load_ai_background():
58
- global ocr_predictor, read_info, is_ai_ready
59
- try:
60
- logger.info("[AI_LOADER] Bắt đầu nạp mô hình AI chạy ngầm (Chống sập Render)...")
61
-
62
- # Nạp VietOCR
63
- vocr_config_path = os.path.join(current_dir, 'Vocr', 'config', 'vgg-seq2seq.yml')
64
- config_vietocr = Cfg_vietocr.load_config_from_file(vocr_config_path)
65
- config_vietocr['weights'] = os.path.join(current_dir, 'Models', 'seq2seqocr.pth')
66
- config_vietocr['device'] = 'cpu'
67
- ocr_predictor = Predictor(config_vietocr)
68
-
69
- # Nạp YOLOv7
70
- get_dictionary = Detect(opt)
71
- scan_weight = os.path.join(current_dir, 'Models', 'cccdYoloV7.pt')
72
- imgsz, stride, device, half, model, names = get_dictionary.load_model(scan_weight)
73
-
74
- read_info = ReadInfo(imgsz, stride, device, half, model, names, ocr_predictor)
75
-
76
- is_ai_ready = True
77
- logger.info("[AI_LOADER] HOÀN TẤT! Hệ thống YOLO + VietOCR đã sẵn sàng nhận diện.")
78
- except Exception as e:
79
- logger.error(f"[AI_LOADER] Lỗi khi nạp AI: {e}")
80
 
81
 
82
- # ─── Startup (Vượt qua vòng kiểm duyệt của Render) ────────────────────────────
83
  @asynccontextmanager
84
  async def lifespan(app: FastAPI):
85
  logger.info("[Startup] Khởi tạo cấu trúc Database (nếu chưa có)...")
86
  init_database()
87
-
88
  logger.info("[Startup] Nạp embedding vào RAM...")
89
  _load_embeddings_to_ram()
90
  logger.info(f"[Startup] {face_memory_store.count} khuôn mặt trên RAM")
91
-
92
- # BẬT LUỒNG CHẠY NGẦM: Server mở cổng ngay lập tức, AI từ từ nạp
93
- threading.Thread(target=load_ai_background, daemon=True).start()
94
-
95
  yield
96
  logger.info("[Shutdown] Bye!")
97
-
98
  def _load_embeddings_to_ram():
99
  conn = None
100
  cursor = None
@@ -122,11 +103,10 @@ def _load_embeddings_to_ram():
122
  })
123
  except Exception as e:
124
  logger.warning(f"[Startup] Bỏ qua khuôn mặt lỗi: {e}")
125
-
126
- face_memory_store.load_all(parsed)
127
 
128
  except Exception as e:
129
- logger.error(f"[Startup] Lỗi kết nối DB khi nạp dữ liệu: {e}")
130
  face_memory_store.load_all([])
131
 
132
  finally:
@@ -147,11 +127,13 @@ app.add_middleware(
147
 
148
  app.mount("/uploads", StaticFiles(directory=UPLOAD_DIR), name="uploads")
149
 
 
150
  class PersonUpdate(BaseModel):
151
  name: str
152
  role: str
153
  department: str
154
 
 
155
  def save_log_to_db(log_queries: list) -> None:
156
  if not log_queries:
157
  return
@@ -171,10 +153,6 @@ def save_log_to_db(log_queries: list) -> None:
171
 
172
  @app.post("/api/face/ocr")
173
  async def extract_ocr_local(file: UploadFile = File(...), side: str = Form(...)):
174
- # BẢO VỆ: Chặn request nếu AI chưa nạp xong
175
- if not is_ai_ready:
176
- return {"success": False, "message": "Hệ thống AI đang khởi động, vui lòng thử lại sau 1-2 phút!"}
177
-
178
  temp_path = ""
179
  try:
180
  temp_filename = f"temp_cccd_{uuid.uuid4().hex}.jpg"
@@ -199,7 +177,7 @@ async def extract_ocr_local(file: UploadFile = File(...), side: str = Form(...))
199
  "expiry_date": raw.get("date_of_expiry", ""),
200
  }
201
 
202
- else: # back
203
  raw = read_info.get_back_info(temp_path)
204
  logger.info(f"[OCR] Mặt sau raw: {raw}")
205
  mapped_data = {
@@ -218,7 +196,7 @@ async def extract_ocr_local(file: UploadFile = File(...), side: str = Form(...))
218
  logger.error(f"[OCR] Lỗi: {e}", exc_info=True)
219
  if os.path.exists(temp_path):
220
  os.remove(temp_path)
221
- return {"success": False, "message": str(e), "data": {}}
222
 
223
 
224
  # ═════════════════════════════════════════════════════════════════════════════
@@ -307,7 +285,6 @@ async def register(
307
  new_encodings: list[tuple] = []
308
  avatar_path = ""
309
  saved_files = [] # Lưu danh sách file đã tạo để xóa nếu có lỗi
310
- COSINE_THRESHOLD = 0.5 # Bổ sung biến ngưỡng vì thấy bạn nhắc tới trong code
311
 
312
  try:
313
  cccd = json.loads(cccd_info) if cccd_info else {}
@@ -345,8 +322,8 @@ async def register(
345
  avatar_path = saved_path
346
  cursor.execute(
347
  """INSERT INTO persons
348
- (id, name, role, department, status, img_path, work_expiry_date)
349
- VALUES (%s, %s, %s, %s, 'active', %s, %s)""",
350
  (person_id, name, role, department, avatar_path, expiry_val),
351
  )
352
 
@@ -431,7 +408,6 @@ async def register(
431
  finally:
432
  cursor.close()
433
  conn.close()
434
-
435
  # ═════════════════════════════════════════════════════════════════════════════
436
  # DANH SÁCH NGƯỜI DÙNG
437
  # ═════════════════════════════════════════════════════════════════════════════
@@ -467,7 +443,7 @@ async def get_persons():
467
 
468
 
469
  # ═════════════════════════════════════════════════════════════════════════════
470
- # CẬP NHẬT & XÓA & LOGS & THỐNG KÊ
471
  # ═════════════════════════════════════════════════════════════════════════════
472
  @app.put("/api/face/persons/{id}")
473
  async def update_person(id: str, person_data: PersonUpdate):
 
1
  import os
2
  import sys
 
3
  from pathlib import Path
4
 
5
  # ─── 1. CẤU HÌNH ĐƯỜNG DẪN TUYỆT ĐỐI (TRÁNH LẠC ĐƯỜNG) ──────────────────────
 
48
  logger = logging.getLogger(__name__)
49
 
50
 
51
+ # ─── KHỞI TẠO AI: YOLOv7 + VietOCR ────────────────────────────────────────────
52
+ logger.info("[Startup] Nạp mô hình VietOCR (VGG-seq2seq)...")
53
+ vocr_config_path = os.path.join(current_dir, 'Vocr', 'config', 'vgg-seq2seq.yml')
54
+ config_vietocr = Cfg_vietocr.load_config_from_file(vocr_config_path)
55
 
56
+ config_vietocr['weights'] = os.path.join(current_dir, 'Models', 'seq2seqocr.pth')
57
+ config_vietocr['device'] = 'cpu' # Đổi thành 'cuda:0' nếu máy có Card rời NVIDIA
58
+ ocr_predictor = Predictor(config_vietocr)
59
+
60
+ logger.info("[Startup] Nạp mô hình YOLOv7 (Phát hiện vùng thông tin)...")
61
+ get_dictionary = Detect(opt)
62
+ scan_weight = os.path.join(current_dir, 'Models', 'cccdYoloV7.pt')
63
+ imgsz, stride, device, half, model, names = get_dictionary.load_model(scan_weight)
64
+
65
+ read_info = ReadInfo(imgsz, stride, device, half, model, names, ocr_predictor)
66
+ logger.info("[Startup] Hệ thống YOLO + VietOCR đã sẵn sàng!")
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
 
69
+ # ─── Startup ──────────────────────────────────────────────────────────────────
70
  @asynccontextmanager
71
  async def lifespan(app: FastAPI):
72
  logger.info("[Startup] Khởi tạo cấu trúc Database (nếu chưa có)...")
73
  init_database()
 
74
  logger.info("[Startup] Nạp embedding vào RAM...")
75
  _load_embeddings_to_ram()
76
  logger.info(f"[Startup] {face_memory_store.count} khuôn mặt trên RAM")
 
 
 
 
77
  yield
78
  logger.info("[Shutdown] Bye!")
 
79
  def _load_embeddings_to_ram():
80
  conn = None
81
  cursor = None
 
103
  })
104
  except Exception as e:
105
  logger.warning(f"[Startup] Bỏ qua khuôn mặt lỗi: {e}")
106
+ face_memory_store.load_all(parsed)
 
107
 
108
  except Exception as e:
109
+ logger.error(f"[Startup] Lỗi kết nối DB khi nạp dữ liệu: {e}")
110
  face_memory_store.load_all([])
111
 
112
  finally:
 
127
 
128
  app.mount("/uploads", StaticFiles(directory=UPLOAD_DIR), name="uploads")
129
 
130
+
131
  class PersonUpdate(BaseModel):
132
  name: str
133
  role: str
134
  department: str
135
 
136
+
137
  def save_log_to_db(log_queries: list) -> None:
138
  if not log_queries:
139
  return
 
153
 
154
  @app.post("/api/face/ocr")
155
  async def extract_ocr_local(file: UploadFile = File(...), side: str = Form(...)):
 
 
 
 
156
  temp_path = ""
157
  try:
158
  temp_filename = f"temp_cccd_{uuid.uuid4().hex}.jpg"
 
177
  "expiry_date": raw.get("date_of_expiry", ""),
178
  }
179
 
180
+ else: # back — ĐÃ NÂNG CẤP: dùng get_back_info như mặt trước
181
  raw = read_info.get_back_info(temp_path)
182
  logger.info(f"[OCR] Mặt sau raw: {raw}")
183
  mapped_data = {
 
196
  logger.error(f"[OCR] Lỗi: {e}", exc_info=True)
197
  if os.path.exists(temp_path):
198
  os.remove(temp_path)
199
+ return {"success": True, "data": {}}
200
 
201
 
202
  # ═════════════════════════════════════════════════════════════════════════════
 
285
  new_encodings: list[tuple] = []
286
  avatar_path = ""
287
  saved_files = [] # Lưu danh sách file đã tạo để xóa nếu có lỗi
 
288
 
289
  try:
290
  cccd = json.loads(cccd_info) if cccd_info else {}
 
322
  avatar_path = saved_path
323
  cursor.execute(
324
  """INSERT INTO persons
325
+ (id, name, role, department, status, img_path, work_expiry_date)
326
+ VALUES (%s, %s, %s, %s, 'active', %s, %s)""",
327
  (person_id, name, role, department, avatar_path, expiry_val),
328
  )
329
 
 
408
  finally:
409
  cursor.close()
410
  conn.close()
 
411
  # ═════════════════════════════════════════════════════════════════════════════
412
  # DANH SÁCH NGƯỜI DÙNG
413
  # ═════════════════════════════════════════════════════════════════════════════
 
443
 
444
 
445
  # ═════════════════════════════════════════════════════════════════════════════
446
+ # CẬP NHẬT & XÓA & LOGS & THỐNG KÊ (Giữ nguyên)
447
  # ═════════════════════════════════════════════════════════════════════════════
448
  @app.put("/api/face/persons/{id}")
449
  async def update_person(id: str, person_data: PersonUpdate):