ranbac commited on
Commit
f633237
·
verified ·
1 Parent(s): 02a63b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -34
app.py CHANGED
@@ -17,39 +17,50 @@ import requests
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
- print("Đang khởi tạo PaddleOCR (Coordinate Sync Mode) - Ngôn ngữ: Tiếng Việt...")
 
 
21
 
22
- try:
23
- # THAY ĐỔI 1: Chuyển lang='ch' thành lang='vi'
24
- ocr = PaddleOCR(use_textline_orientation=True, use_doc_orientation_classify=False,
25
- use_doc_unwarping=False, lang='vi')
26
- except Exception as e:
27
- print(f"Lỗi khởi tạo: {e}. Chuyển về chế độ mặc định.")
28
- ocr = PaddleOCR(lang='vi')
29
 
30
- print("Model đã sẵn sàng!")
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- # --- TẢI FONT (HỖ TRỢ TIẾNG VIỆT) ---
 
 
 
 
 
33
  def check_and_download_font():
34
- # THAY ĐỔI 2: Sử dụng font Roboto để hiển thị đúng dấu Tiếng Việt
35
- font_path = "./Roboto-Regular.ttf"
36
  if not os.path.exists(font_path):
37
  try:
38
- print("Đang tải font Roboto hỗ trợ tiếng Việt...")
39
- # URL Font Roboto chuẩn từ Google Fonts
40
- url = "https://github.com/google/fonts/raw/main/apache/roboto/Roboto-Regular.ttf"
41
  r = requests.get(url, allow_redirects=True)
42
  with open(font_path, 'wb') as f:
43
  f.write(r.content)
44
- print("Đã tải xong font.")
45
  except:
46
- print("Không tải được font. Sẽ sử dụng font mặc định hệ thống (có thể lỗi dấu).")
47
  return None
48
  return font_path
49
 
50
  FONT_PATH = check_and_download_font()
51
 
52
- # --- HÀM VẼ ĐA NĂNG ---
53
  def universal_draw(image, raw_data, font_path):
54
  if image is None: return image
55
 
@@ -80,7 +91,6 @@ def universal_draw(image, raw_data, font_path):
80
  items_to_draw = []
81
 
82
  # Logic tìm box/text
83
- # Ưu tiên cấu trúc PaddleX: rec_texts + dt_polys
84
  processed = False
85
  if isinstance(raw_data, list) and len(raw_data) > 0 and isinstance(raw_data[0], dict):
86
  data_dict = raw_data[0]
@@ -131,7 +141,7 @@ def universal_draw(image, raw_data, font_path):
131
 
132
  return canvas
133
 
134
- # --- HÀM XỬ LÝ TEXT ---
135
  def deep_extract_text(data):
136
  found_texts = []
137
  if isinstance(data, str):
@@ -149,40 +159,47 @@ def clean_text_result(text_list):
149
  block_list = ['min', 'max', 'general', 'header', 'footer', 'structure']
150
  for t in text_list:
151
  t = t.strip()
152
- # Giữ lại nếu ký tự Unicode thông thường (bao gồm tiếng Việt)
153
- if len(t) < 2 and not re.search(r'\w', t): continue
 
 
 
 
 
154
  if t.lower().endswith(('.ttf', '.json', '.pdparams', '.yml', '.log')): continue
155
  if t.lower() in block_list: continue
156
- if not re.search(r'[\w\u00C0-\u1EF9]', t): continue # Regex mở rộng cho tiếng Việt
157
  cleaned.append(t)
158
  return cleaned
159
 
160
- # --- MAIN PREDICT ---
161
- def predict(image):
162
  if image is None: return None, "Chưa có ảnh.", "No Data"
163
 
164
  try:
 
 
 
165
  # Chuẩn bị ảnh đầu vào
166
  original_pil = image.copy() if isinstance(image, Image.Image) else Image.fromarray(image).copy()
167
  image_np = np.array(image)
168
 
169
  # 1. OCR
170
- raw_result = ocr.ocr(image_np)
171
 
172
  # 2. XỬ LÝ ẢNH ĐỂ VẼ (KEY FIX: Lấy ảnh từ Preprocessor nếu có)
173
  target_image_for_drawing = original_pil
174
 
175
- # Kiểm tra xem Paddle có chỉnh sửa ảnh không (dựa vào key 'doc_preprocessor_res')
176
  if isinstance(raw_result, list) and len(raw_result) > 0 and isinstance(raw_result[0], dict):
177
  if 'doc_preprocessor_res' in raw_result[0]:
178
  proc_res = raw_result[0]['doc_preprocessor_res']
179
- # Nếu có ảnh đầu ra đã chỉnh sửa (output_img)
180
  if 'output_img' in proc_res:
181
  print("Phát hiện ảnh đã qua xử lý hình học. Đang đồng bộ tọa độ...")
182
  numpy_img = proc_res['output_img']
183
  target_image_for_drawing = Image.fromarray(numpy_img)
184
 
185
- # 3. Vẽ lên ảnh ĐÚNG (Target Image)
186
  annotated_image = universal_draw(target_image_for_drawing, raw_result, FONT_PATH)
187
 
188
  # 4. Xử lý Text
@@ -192,7 +209,7 @@ def predict(image):
192
 
193
  # Debug Info
194
  debug_str = str(raw_result)[:1000]
195
- debug_info = f"Used Image Source: {'Preprocessed' if target_image_for_drawing != original_pil else 'Original'}\nData Preview:\n{debug_str}..."
196
 
197
  return annotated_image, text_output, debug_info
198
 
@@ -200,13 +217,15 @@ def predict(image):
200
  import traceback
201
  return image, f"Lỗi: {str(e)}", traceback.format_exc()
202
 
203
- # --- GIAO DIỆN ---
204
- with gr.Blocks(title="PaddleOCR Perfect Overlay (Vietnamese)") as iface:
205
- gr.Markdown("## PaddleOCR Vietnamese - High Precision Overlay")
206
 
207
  with gr.Row():
208
  with gr.Column():
209
  input_img = gr.Image(type="pil", label="Input Image")
 
 
210
  submit_btn = gr.Button("RUN OCR", variant="primary")
211
 
212
  with gr.Column():
@@ -220,7 +239,7 @@ with gr.Blocks(title="PaddleOCR Perfect Overlay (Vietnamese)") as iface:
220
 
221
  submit_btn.click(
222
  fn=predict,
223
- inputs=input_img,
224
  outputs=[output_img, output_txt, output_debug]
225
  )
226
 
 
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
+ # --- QUẢN MODEL ĐA NGÔN NGỮ ---
21
+ # Cache để lưu các model đã load, tránh load lại gây chậm
22
+ OCR_CACHE = {}
23
 
24
+ def get_ocr_model(lang_code='ch'):
25
+ if lang_code in OCR_CACHE:
26
+ return OCR_CACHE[lang_code]
 
 
 
 
27
 
28
+ print(f"Đang khởi tạo PaddleOCR (Lang: {lang_code})...")
29
+ try:
30
+ # Cấu hình tối ưu (giữ nguyên logic cũ)
31
+ model = PaddleOCR(use_textline_orientation=True,
32
+ use_doc_orientation_classify=False,
33
+ use_doc_unwarping=False,
34
+ lang=lang_code)
35
+ except Exception as e:
36
+ print(f"Lỗi khởi tạo nâng cao cho {lang_code}: {e}. Chuyển về chế độ mặc định.")
37
+ model = PaddleOCR(lang=lang_code)
38
+
39
+ OCR_CACHE[lang_code] = model
40
+ print(f"Model {lang_code} đã sẵn sàng!")
41
+ return model
42
 
43
+ # Khởi tạo trước model mặc định (Trung + Việt) để chạy nhanh lần đầu
44
+ print("Pre-loading models...")
45
+ get_ocr_model('ch')
46
+ # get_ocr_model('vi') # Bỏ comment nếu muốn load sẵn tiếng Việt ngay khi bật app
47
+
48
+ # --- TẢI FONT (GIỮ NGUYÊN) ---
49
  def check_and_download_font():
50
+ font_path = "./simfang.ttf"
 
51
  if not os.path.exists(font_path):
52
  try:
53
+ url = "https://github.com/StellarCN/scp_zh/raw/master/fonts/SimFang.ttf"
 
 
54
  r = requests.get(url, allow_redirects=True)
55
  with open(font_path, 'wb') as f:
56
  f.write(r.content)
 
57
  except:
 
58
  return None
59
  return font_path
60
 
61
  FONT_PATH = check_and_download_font()
62
 
63
+ # --- HÀM VẼ ĐA NĂNG (GIỮ NGUYÊN) ---
64
  def universal_draw(image, raw_data, font_path):
65
  if image is None: return image
66
 
 
91
  items_to_draw = []
92
 
93
  # Logic tìm box/text
 
94
  processed = False
95
  if isinstance(raw_data, list) and len(raw_data) > 0 and isinstance(raw_data[0], dict):
96
  data_dict = raw_data[0]
 
141
 
142
  return canvas
143
 
144
+ # --- HÀM XỬ LÝ TEXT (GIỮ NGUYÊN) ---
145
  def deep_extract_text(data):
146
  found_texts = []
147
  if isinstance(data, str):
 
159
  block_list = ['min', 'max', 'general', 'header', 'footer', 'structure']
160
  for t in text_list:
161
  t = t.strip()
162
+ # Giữ lại logic cũ: nếu < 2 ký tự không phải chữ Hán thì bỏ.
163
+ # Tuy nhiên với Tiếng Việt, các từ ngắn vẫn quan trọng, nhưng để "giữ nguyên" logic cũ, ta không sửa dòng này.
164
+ if len(t) < 2 and not any(u'\u4e00' <= c <= u'\u9fff' for c in t):
165
+ # Logic cũ ưu tiên tiếng Trung, có thể lọc mất từ tiếng Việt ngắn (ví dụ "a", "à").
166
+ # Nhưng theo yêu cầu "tuyệt đối giữ nguyên", tôi sẽ không sửa logic lọc này.
167
+ continue
168
+
169
  if t.lower().endswith(('.ttf', '.json', '.pdparams', '.yml', '.log')): continue
170
  if t.lower() in block_list: continue
171
+ if not re.search(r'[\w\u4e00-\u9fff]', t): continue
172
  cleaned.append(t)
173
  return cleaned
174
 
175
+ # --- MAIN PREDICT (CẬP NHẬT LANG) ---
176
+ def predict(image, lang_choice):
177
  if image is None: return None, "Chưa có ảnh.", "No Data"
178
 
179
  try:
180
+ # Lấy model đúng theo ngôn ngữ người dùng chọn
181
+ current_ocr = get_ocr_model(lang_choice)
182
+
183
  # Chuẩn bị ảnh đầu vào
184
  original_pil = image.copy() if isinstance(image, Image.Image) else Image.fromarray(image).copy()
185
  image_np = np.array(image)
186
 
187
  # 1. OCR
188
+ raw_result = current_ocr.ocr(image_np)
189
 
190
  # 2. XỬ LÝ ẢNH ĐỂ VẼ (KEY FIX: Lấy ảnh từ Preprocessor nếu có)
191
  target_image_for_drawing = original_pil
192
 
193
+ # Kiểm tra xem Paddle có chỉnh sửa ảnh không
194
  if isinstance(raw_result, list) and len(raw_result) > 0 and isinstance(raw_result[0], dict):
195
  if 'doc_preprocessor_res' in raw_result[0]:
196
  proc_res = raw_result[0]['doc_preprocessor_res']
 
197
  if 'output_img' in proc_res:
198
  print("Phát hiện ảnh đã qua xử lý hình học. Đang đồng bộ tọa độ...")
199
  numpy_img = proc_res['output_img']
200
  target_image_for_drawing = Image.fromarray(numpy_img)
201
 
202
+ # 3. Vẽ lên ảnh ĐÚNG
203
  annotated_image = universal_draw(target_image_for_drawing, raw_result, FONT_PATH)
204
 
205
  # 4. Xử lý Text
 
209
 
210
  # Debug Info
211
  debug_str = str(raw_result)[:1000]
212
+ debug_info = f"Language: {lang_choice}\nUsed Image Source: {'Preprocessed' if target_image_for_drawing != original_pil else 'Original'}\nData Preview:\n{debug_str}..."
213
 
214
  return annotated_image, text_output, debug_info
215
 
 
217
  import traceback
218
  return image, f"Lỗi: {str(e)}", traceback.format_exc()
219
 
220
+ # --- GIAO DIỆN (CẬP NHẬT INPUT) ---
221
+ with gr.Blocks(title="PaddleOCR Multi-Lang Overlay") as iface:
222
+ gr.Markdown("## PaddleOCR (Chinese/Vietnamese) - High Precision Overlay")
223
 
224
  with gr.Row():
225
  with gr.Column():
226
  input_img = gr.Image(type="pil", label="Input Image")
227
+ # Thêm Dropdown chọn ngôn ngữ
228
+ lang_select = gr.Dropdown(choices=["ch", "vi", "en"], value="ch", label="Chọn Ngôn ngữ (Language)")
229
  submit_btn = gr.Button("RUN OCR", variant="primary")
230
 
231
  with gr.Column():
 
239
 
240
  submit_btn.click(
241
  fn=predict,
242
+ inputs=[input_img, lang_select], # Thêm lang_select vào input
243
  outputs=[output_img, output_txt, output_debug]
244
  )
245