ranbac commited on
Commit
d72652a
·
verified ·
1 Parent(s): f082006

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -57
app.py CHANGED
@@ -17,52 +17,64 @@ import requests
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
- # --- QUẢN MODEL ĐA NGÔN NGỮ (THAY ĐỔI ĐỂ HỖ TRỢ THÊM NGÔN NGỮ) ---
21
- print("Đang khởi tạo hệ thống quản lý Model...")
22
 
23
- # Cache để lưu các model đã tải, tránh load lại gây chậm
24
- OCR_ENGINES = {}
25
 
26
- def get_ocr_model(lang_code):
27
- # Nếu model ngôn ngữ này đã load rồi thì dùng luôn
28
- if lang_code in OCR_ENGINES:
29
- return OCR_ENGINES[lang_code]
30
-
31
- print(f"Đang tải model ngôn ngữ: {lang_code}...")
32
- try:
33
- # Khởi tạo PaddleOCR với ngôn ngữ được chọn
34
- # 'vi' hỗ trợ tốt Tiếng Việt Latin. 'en' hỗ trợ chung Latin. 'ch' là Tiếng Trung.
35
- engine = PaddleOCR(
36
- use_textline_orientation=True,
37
- use_doc_orientation_classify=False,
38
- use_doc_unwarping=False,
39
- lang=lang_code
40
- )
41
- OCR_ENGINES[lang_code] = engine
42
- return engine
43
- except Exception as e:
44
- print(f"Lỗi khởi tạo ngôn ngữ {lang_code}: {e}. Thử khởi tạo lại chế độ cơ bản.")
45
- # Fallback nếu tham số lỗi
46
- engine = PaddleOCR(lang='en')
47
- OCR_ENGINES[lang_code] = engine
48
- return engine
49
-
50
- # --- TẢI FONT (GIỮ NGUYÊN) ---
51
- def check_and_download_font():
52
- font_path = "./simfang.ttf"
53
  if not os.path.exists(font_path):
54
  try:
55
- url = "https://github.com/StellarCN/scp_zh/raw/master/fonts/SimFang.ttf"
56
  r = requests.get(url, allow_redirects=True)
57
  with open(font_path, 'wb') as f:
58
  f.write(r.content)
 
59
  except:
 
60
  return None
61
  return font_path
62
 
63
- FONT_PATH = check_and_download_font()
 
 
 
 
64
 
65
- # --- HÀM VẼ ĐA NĂNG (GIỮ NGUYÊN) ---
 
 
 
 
 
 
 
 
 
 
 
 
66
  def universal_draw(image, raw_data, font_path):
67
  if image is None: return image
68
 
@@ -76,6 +88,7 @@ def universal_draw(image, raw_data, font_path):
76
 
77
  try:
78
  font_size = 24
 
79
  font = ImageFont.truetype(font_path, font_size) if font_path else ImageFont.load_default()
80
  except:
81
  font = ImageFont.load_default()
@@ -93,7 +106,6 @@ def universal_draw(image, raw_data, font_path):
93
  items_to_draw = []
94
 
95
  # Logic tìm box/text
96
- # Ưu tiên cấu trúc PaddleX: rec_texts + dt_polys
97
  processed = False
98
  if isinstance(raw_data, list) and len(raw_data) > 0 and isinstance(raw_data[0], dict):
99
  data_dict = raw_data[0]
@@ -162,32 +174,36 @@ def clean_text_result(text_list):
162
  block_list = ['min', 'max', 'general', 'header', 'footer', 'structure']
163
  for t in text_list:
164
  t = t.strip()
165
- if len(t) < 2 and not any(u'\u4e00' <= c <= u'\u9fff' for c in t): continue
 
166
  if t.lower().endswith(('.ttf', '.json', '.pdparams', '.yml', '.log')): continue
167
  if t.lower() in block_list: continue
168
- if not re.search(r'[\w\u4e00-\u9fff]', t): continue
169
  cleaned.append(t)
170
  return cleaned
171
 
172
- # --- MAIN PREDICT (CẬP NHẬT THAM SỐ LANG) ---
173
  def predict(image, lang_code):
174
  if image is None: return None, "Chưa có ảnh.", "No Data"
175
 
176
- try:
177
- # Lấy model tương ứng với ngôn ngữ đã chọn
178
- current_ocr = get_ocr_model(lang_code)
 
 
 
 
179
 
 
180
  # Chuẩn bị ảnh đầu vào
181
  original_pil = image.copy() if isinstance(image, Image.Image) else Image.fromarray(image).copy()
182
  image_np = np.array(image)
183
 
184
- # 1. OCR (Sử dụng model đã chọn)
185
  raw_result = current_ocr.ocr(image_np)
186
 
187
  # 2. XỬ LÝ ẢNH ĐỂ VẼ
188
  target_image_for_drawing = original_pil
189
 
190
- # Kiểm tra xem Paddle có chỉnh sửa ảnh không
191
  if isinstance(raw_result, list) and len(raw_result) > 0 and isinstance(raw_result[0], dict):
192
  if 'doc_preprocessor_res' in raw_result[0]:
193
  proc_res = raw_result[0]['doc_preprocessor_res']
@@ -196,8 +212,8 @@ def predict(image, lang_code):
196
  numpy_img = proc_res['output_img']
197
  target_image_for_drawing = Image.fromarray(numpy_img)
198
 
199
- # 3. Vẽ lên ảnh ĐÚNG (Target Image)
200
- annotated_image = universal_draw(target_image_for_drawing, raw_result, FONT_PATH)
201
 
202
  # 4. Xử lý Text
203
  all_texts = deep_extract_text(raw_result)
@@ -206,7 +222,7 @@ def predict(image, lang_code):
206
 
207
  # Debug Info
208
  debug_str = str(raw_result)[:1000]
209
- debug_info = f"Language Mode: {lang_code}\nUsed Image Source: {'Preprocessed' if target_image_for_drawing != original_pil else 'Original'}\nData Preview:\n{debug_str}..."
210
 
211
  return annotated_image, text_output, debug_info
212
 
@@ -214,23 +230,20 @@ def predict(image, lang_code):
214
  import traceback
215
  return image, f"Lỗi: {str(e)}", traceback.format_exc()
216
 
217
- # --- GIAO DIỆN (CẬP NHẬT DROPDOWN) ---
218
  with gr.Blocks(title="PaddleOCR Multi-Language Overlay") as iface:
219
- gr.Markdown("## PaddleOCR Multi-Language - High Precision Overlay")
220
 
221
  with gr.Row():
222
  with gr.Column():
223
  input_img = gr.Image(type="pil", label="Input Image")
224
 
225
- # Thêm Dropdown chọn ngôn ngữ
226
- # 'vi' bao phủ hầu hết các ngôn ngữ Latin + Tiếng Việt
227
- # 'ch' cho tiếng Trung
228
- # 'en', 'fr', 'de' cho các model chuyên biệt nếu cần
229
  lang_dropdown = gr.Dropdown(
230
- choices=["vi", "ch", "en", "fr", "de", "es", "it", "pt", "ru", "ja", "ko"],
231
- value="vi",
232
- label="Chọn Ngôn Ngữ (Language)",
233
- info="Chọn 'vi' cho Tiếng Việt & hầu hết ngôn ngữ Latin (Anh, Pháp, Đức...)."
234
  )
235
 
236
  submit_btn = gr.Button("RUN OCR", variant="primary")
@@ -246,7 +259,7 @@ with gr.Blocks(title="PaddleOCR Multi-Language Overlay") as iface:
246
 
247
  submit_btn.click(
248
  fn=predict,
249
- inputs=[input_img, lang_dropdown], # Truyền thêm lang_dropdown
250
  outputs=[output_img, output_txt, output_debug]
251
  )
252
 
 
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
+ # --- KHỞI TẠO PADDLEOCR ĐA NGÔN NGỮ ---
21
+ print("Đang khởi tạo các Model OCR...")
22
 
23
+ ocr_engines = {}
 
24
 
25
+ # 1. Model Trung Quốc (Mặc định cũ)
26
+ try:
27
+ print(" - Loading Chinese Model...")
28
+ ocr_engines['ch'] = PaddleOCR(use_textline_orientation=True, use_doc_orientation_classify=False,
29
+ use_doc_unwarping=False, lang='ch', show_log=False)
30
+ except Exception as e:
31
+ print(f"Lỗi khởi tạo Chinese Model: {e}")
32
+
33
+ # 2. Model Latin (Mới - Hỗ trợ list ngôn ngữ Châu Âu, Việt Nam, v.v.)
34
+ try:
35
+ print(" - Loading Latin/European/Vietnamese Model...")
36
+ # lang='latin' hỗ trợ chung cho các ngôn ngữ ký tự Latin bao gồm cả tiếng Việt, Pháp, Đức...
37
+ ocr_engines['latin'] = PaddleOCR(use_textline_orientation=True, use_doc_orientation_classify=False,
38
+ use_doc_unwarping=False, lang='latin', show_log=False)
39
+ except Exception as e:
40
+ print(f"Lỗi khởi tạo Latin Model: {e}")
41
+
42
+ print("Các Model đã sẵn sàng!")
43
+
44
+ # --- TẢI FONT (CẬP NHẬT) ---
45
+ def check_and_download_font(font_name, url):
46
+ font_path = f"./{font_name}"
 
 
 
 
 
47
  if not os.path.exists(font_path):
48
  try:
49
+ print(f"Đang tải font {font_name}...")
50
  r = requests.get(url, allow_redirects=True)
51
  with open(font_path, 'wb') as f:
52
  f.write(r.content)
53
+ print(f"Đã tải xong {font_name}.")
54
  except:
55
+ print(f"Không thể tải {font_name}.")
56
  return None
57
  return font_path
58
 
59
+ # Font cho tiếng Trung ()
60
+ FONT_CH_PATH = check_and_download_font(
61
+ "simfang.ttf",
62
+ "https://github.com/StellarCN/scp_zh/raw/master/fonts/SimFang.ttf"
63
+ )
64
 
65
+ # Font cho tiếng Latin/Việt (Mới - Dùng Roboto để hiển thị tốt dấu)
66
+ FONT_LATIN_PATH = check_and_download_font(
67
+ "Roboto-Regular.ttf",
68
+ "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab-Regular.ttf"
69
+ )
70
+
71
+ # Map ngôn ngữ với Font
72
+ FONT_MAP = {
73
+ 'ch': FONT_CH_PATH,
74
+ 'latin': FONT_LATIN_PATH
75
+ }
76
+
77
+ # --- HÀM VẼ ĐA NĂNG (GIỮ NGUYÊN LOGIC, CHỈ THÊM THAM SỐ FONT) ---
78
  def universal_draw(image, raw_data, font_path):
79
  if image is None: return image
80
 
 
88
 
89
  try:
90
  font_size = 24
91
+ # Sử dụng font_path được truyền vào
92
  font = ImageFont.truetype(font_path, font_size) if font_path else ImageFont.load_default()
93
  except:
94
  font = ImageFont.load_default()
 
106
  items_to_draw = []
107
 
108
  # Logic tìm box/text
 
109
  processed = False
110
  if isinstance(raw_data, list) and len(raw_data) > 0 and isinstance(raw_data[0], dict):
111
  data_dict = raw_data[0]
 
174
  block_list = ['min', 'max', 'general', 'header', 'footer', 'structure']
175
  for t in text_list:
176
  t = t.strip()
177
+ # Chỉnh sửa nhẹ điều kiện lọc để không bỏ qua các từ ngắn Latin
178
+ if len(t) < 1: continue
179
  if t.lower().endswith(('.ttf', '.json', '.pdparams', '.yml', '.log')): continue
180
  if t.lower() in block_list: continue
 
181
  cleaned.append(t)
182
  return cleaned
183
 
184
+ # --- MAIN PREDICT (CẬP NHẬT) ---
185
  def predict(image, lang_code):
186
  if image is None: return None, "Chưa có ảnh.", "No Data"
187
 
188
+ # Chọn OCR Engine
189
+ current_ocr = ocr_engines.get(lang_code)
190
+ if not current_ocr:
191
+ return image, "Lỗi: Model ngôn ngữ chưa được tải hoặc không tồn tại.", ""
192
+
193
+ # Chọn Font tương ứng
194
+ current_font = FONT_MAP.get(lang_code, FONT_LATIN_PATH)
195
 
196
+ try:
197
  # Chuẩn bị ảnh đầu vào
198
  original_pil = image.copy() if isinstance(image, Image.Image) else Image.fromarray(image).copy()
199
  image_np = np.array(image)
200
 
201
+ # 1. OCR (Dùng engine đã chọn)
202
  raw_result = current_ocr.ocr(image_np)
203
 
204
  # 2. XỬ LÝ ẢNH ĐỂ VẼ
205
  target_image_for_drawing = original_pil
206
 
 
207
  if isinstance(raw_result, list) and len(raw_result) > 0 and isinstance(raw_result[0], dict):
208
  if 'doc_preprocessor_res' in raw_result[0]:
209
  proc_res = raw_result[0]['doc_preprocessor_res']
 
212
  numpy_img = proc_res['output_img']
213
  target_image_for_drawing = Image.fromarray(numpy_img)
214
 
215
+ # 3. Vẽ lên ảnh (Truyền đúng font)
216
+ annotated_image = universal_draw(target_image_for_drawing, raw_result, current_font)
217
 
218
  # 4. Xử lý Text
219
  all_texts = deep_extract_text(raw_result)
 
222
 
223
  # Debug Info
224
  debug_str = str(raw_result)[:1000]
225
+ debug_info = f"Language: {lang_code}\nFont Used: {current_font}\nUsed Image Source: {'Preprocessed' if target_image_for_drawing != original_pil else 'Original'}\nData Preview:\n{debug_str}..."
226
 
227
  return annotated_image, text_output, debug_info
228
 
 
230
  import traceback
231
  return image, f"Lỗi: {str(e)}", traceback.format_exc()
232
 
233
+ # --- GIAO DIỆN (CẬP NHẬT) ---
234
  with gr.Blocks(title="PaddleOCR Multi-Language Overlay") as iface:
235
+ gr.Markdown("## PaddleOCR - High Precision Overlay (Multi-Language)")
236
 
237
  with gr.Row():
238
  with gr.Column():
239
  input_img = gr.Image(type="pil", label="Input Image")
240
 
241
+ # Dropdown chọn ngôn ngữ
 
 
 
242
  lang_dropdown = gr.Dropdown(
243
+ choices=["ch", "latin"],
244
+ value="ch",
245
+ label="Language / Ngôn ngữ",
246
+ info="ch: Tiếng Trung | latin: Anh, Việt, Pháp, Đức, Tây Ban Nha..."
247
  )
248
 
249
  submit_btn = gr.Button("RUN OCR", variant="primary")
 
259
 
260
  submit_btn.click(
261
  fn=predict,
262
+ inputs=[input_img, lang_dropdown],
263
  outputs=[output_img, output_txt, output_debug]
264
  )
265