ranbac commited on
Commit
0396510
·
verified ·
1 Parent(s): e5634f6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -60
app.py CHANGED
@@ -1,6 +1,6 @@
1
  import os
2
 
3
- # --- CẤU HÌNH HỆ THỐNG ---
4
  os.environ["FLAGS_use_mkldnn"] = "0"
5
  os.environ["FLAGS_enable_mkldnn"] = "0"
6
  os.environ["DN_ENABLE_MKLDNN"] = "0"
@@ -17,56 +17,52 @@ import requests
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
- print("Đang khởi tạo hệ thống...")
 
21
 
22
- # --- QUẢN MODEL (CACHE) ---
23
- # Dictionary để lưu các model đã load, tránh load lại gây chậm
24
  OCR_ENGINES = {}
25
 
26
- def get_ocr_engine(lang_code):
27
- """
28
- Hàm lấy model từ bộ nhớ đệm, nếu chưa có thì tải mới.
29
- """
30
  if lang_code in OCR_ENGINES:
31
  return OCR_ENGINES[lang_code]
32
 
33
- print(f"🔄 Đang nạp model ngôn ngữ: {lang_code} ...")
34
  try:
35
- # Cấu hình chung cho các model
36
- ocr = PaddleOCR(
 
37
  use_textline_orientation=True,
38
  use_doc_orientation_classify=False,
39
  use_doc_unwarping=False,
40
- lang=lang_code, # Ngôn ngữ được chọn
41
  )
42
- OCR_ENGINES[lang_code] = ocr
43
- print(f"✅ Đã nạp xong model: {lang_code}")
44
- return ocr
45
  except Exception as e:
46
- print(f"Lỗi khởi tạo model {lang_code}: {e}")
47
- return None
 
 
 
48
 
49
- # Pre-load model mặc định (Tiếng Trung) để khởi động nhanh
50
- get_ocr_engine('ch')
51
-
52
- # --- TẢI FONT ---
53
  def check_and_download_font():
54
  font_path = "./simfang.ttf"
55
  if not os.path.exists(font_path):
56
  try:
57
  url = "https://github.com/StellarCN/scp_zh/raw/master/fonts/SimFang.ttf"
58
- print("Đang tải font SimFang...")
59
  r = requests.get(url, allow_redirects=True)
60
  with open(font_path, 'wb') as f:
61
  f.write(r.content)
62
- print("Đã tải font xong.")
63
  except:
64
  return None
65
  return font_path
66
 
67
  FONT_PATH = check_and_download_font()
68
 
69
- # --- HÀM VẼ ĐA NĂNG ---
70
  def universal_draw(image, raw_data, font_path):
71
  if image is None: return image
72
 
@@ -97,6 +93,7 @@ def universal_draw(image, raw_data, font_path):
97
  items_to_draw = []
98
 
99
  # Logic tìm box/text
 
100
  processed = False
101
  if isinstance(raw_data, list) and len(raw_data) > 0 and isinstance(raw_data[0], dict):
102
  data_dict = raw_data[0]
@@ -110,18 +107,23 @@ def universal_draw(image, raw_data, font_path):
110
  if box and txt: items_to_draw.append((box, txt))
111
  processed = True
112
 
113
- # Fallback Logic (Dành cho output chuẩn của PaddleOCR)
114
  if not processed:
115
  def hunt(data):
116
- if isinstance(data, (list, tuple)):
117
- # Cấu trúc [[box, [text, conf]], ...]
 
 
 
 
 
 
 
118
  if len(data) == 2 and isinstance(data[0], list) and len(data[0]) == 4:
119
  box = parse_box(data[0])
120
  txt_obj = data[1]
121
  text = txt_obj[0] if isinstance(txt_obj, (list, tuple)) else txt_obj
122
- if box and isinstance(text, str):
123
- items_to_draw.append((box, text))
124
- return
125
  for item in data: hunt(item)
126
  hunt(raw_data)
127
 
@@ -142,54 +144,59 @@ def universal_draw(image, raw_data, font_path):
142
 
143
  return canvas
144
 
145
- # --- HÀM XỬ LÝ TEXT ---
146
  def deep_extract_text(data):
147
  found_texts = []
148
  if isinstance(data, str):
149
  if len(data.strip()) > 0: return [data]
150
  return []
151
  if isinstance(data, (list, tuple)):
152
- # Bỏ qua con số confidence (float)
153
- if len(data) == 2 and isinstance(data[1], (int, float)):
154
- return deep_extract_text(data[0])
155
  for item in data: found_texts.extend(deep_extract_text(item))
156
  elif isinstance(data, dict):
157
  for val in data.values(): found_texts.extend(deep_extract_text(val))
 
158
  return found_texts
159
 
160
  def clean_text_result(text_list):
161
  cleaned = []
162
  block_list = ['min', 'max', 'general', 'header', 'footer', 'structure']
163
  for t in text_list:
164
- if not isinstance(t, str): continue
165
  t = t.strip()
166
- if len(t) < 1: continue
167
- # Giữ lại text nếu ký tự chữ hoặc số
 
168
  if not re.search(r'[\w\u4e00-\u9fff]', t): continue
169
  cleaned.append(t)
170
  return cleaned
171
 
172
- # --- MAIN PREDICT ---
173
- def predict(image, lang_choice):
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ữ user chọn
178
- ocr_model = get_ocr_engine(lang_choice)
179
- if ocr_model is None:
180
- return image, "Lỗi khởi tạo model.", "Error loading model"
181
 
182
  # Chuẩn bị ảnh đầu vào
183
  original_pil = image.copy() if isinstance(image, Image.Image) else Image.fromarray(image).copy()
184
  image_np = np.array(image)
185
 
186
- # 1. OCR
187
- raw_result = ocr_model.ocr(image_np)
188
 
189
  # 2. XỬ LÝ ẢNH ĐỂ VẼ
190
  target_image_for_drawing = original_pil
191
 
192
- # 3. Vẽ lên ảnh
 
 
 
 
 
 
 
 
 
193
  annotated_image = universal_draw(target_image_for_drawing, raw_result, FONT_PATH)
194
 
195
  # 4. Xử lý Text
@@ -199,7 +206,7 @@ def predict(image, lang_choice):
199
 
200
  # Debug Info
201
  debug_str = str(raw_result)[:1000]
202
- debug_info = f"Model Used: {lang_choice}\nRaw Output Preview:\n{debug_str}..."
203
 
204
  return annotated_image, text_output, debug_info
205
 
@@ -207,36 +214,39 @@ def predict(image, lang_choice):
207
  import traceback
208
  return image, f"Lỗi: {str(e)}", traceback.format_exc()
209
 
210
- # --- GIAO DIỆN ---
211
- with gr.Blocks(title="Multi-Language OCR") as iface:
212
- gr.Markdown("## PaddleOCR Multi-Language (Latin/Vietnamese/Chinese)")
213
 
214
  with gr.Row():
215
- with gr.Column(scale=1):
216
  input_img = gr.Image(type="pil", label="Input Image")
217
 
218
- # --- DROPDOWN CHỌN NGÔN NGỮ ---
 
 
 
219
  lang_dropdown = gr.Dropdown(
220
- choices=["ch", "en", "vi"],
221
- value="ch",
222
- label="Chọn Ngôn Ngữ / Language",
223
- info="ch: Chinese | en: Latin/Euro (Anh, Pháp, Đức...) | vi: Vietnamese"
224
  )
225
 
226
  submit_btn = gr.Button("RUN OCR", variant="primary")
227
 
228
- with gr.Column(scale=2):
229
  with gr.Tabs():
230
- with gr.TabItem("🖼️ Kết quả / Result"):
231
  output_img = gr.Image(type="pil", label="Overlay Result")
232
- with gr.TabItem("📝 Văn bản / Text"):
233
  output_txt = gr.Textbox(label="Text Content", lines=15)
234
  with gr.TabItem("🐞 Debug"):
235
  output_debug = gr.Textbox(label="Debug Info", lines=15)
236
 
237
  submit_btn.click(
238
  fn=predict,
239
- inputs=[input_img, lang_dropdown], # Truyền thêm lựa chọn ngôn ngữ
240
  outputs=[output_img, output_txt, output_debug]
241
  )
242
 
 
1
  import os
2
 
3
+ # --- CẤU HÌNH HỆ THỐNG (GIỮ NGUYÊN) ---
4
  os.environ["FLAGS_use_mkldnn"] = "0"
5
  os.environ["FLAGS_enable_mkldnn"] = "0"
6
  os.environ["DN_ENABLE_MKLDNN"] = "0"
 
17
  # Tắt log thừa
18
  logging.getLogger("ppocr").setLevel(logging.WARNING)
19
 
20
+ # --- QUẢN LÝ 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 và 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
 
 
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]
 
107
  if box and txt: items_to_draw.append((box, txt))
108
  processed = True
109
 
110
+ # Fallback Logic
111
  if not processed:
112
  def hunt(data):
113
+ if isinstance(data, dict):
114
+ box = None; text = None
115
+ for k in ['points', 'box', 'dt_boxes', 'poly']:
116
+ if k in data: box = parse_box(data[k]); break
117
+ for k in ['transcription', 'text', 'rec_text', 'label']:
118
+ if k in data: text = data[k]; break
119
+ if box and text: items_to_draw.append((box, text)); return
120
+ for v in data.values(): hunt(v)
121
+ elif isinstance(data, (list, tuple)):
122
  if len(data) == 2 and isinstance(data[0], list) and len(data[0]) == 4:
123
  box = parse_box(data[0])
124
  txt_obj = data[1]
125
  text = txt_obj[0] if isinstance(txt_obj, (list, tuple)) else txt_obj
126
+ if box and isinstance(text, str): items_to_draw.append((box, text)); return
 
 
127
  for item in data: hunt(item)
128
  hunt(raw_data)
129
 
 
144
 
145
  return canvas
146
 
147
+ # --- HÀM XỬ LÝ TEXT (GIỮ NGUYÊN) ---
148
  def deep_extract_text(data):
149
  found_texts = []
150
  if isinstance(data, str):
151
  if len(data.strip()) > 0: return [data]
152
  return []
153
  if isinstance(data, (list, tuple)):
 
 
 
154
  for item in data: found_texts.extend(deep_extract_text(item))
155
  elif isinstance(data, dict):
156
  for val in data.values(): found_texts.extend(deep_extract_text(val))
157
+ elif hasattr(data, '__dict__'): found_texts.extend(deep_extract_text(data.__dict__))
158
  return found_texts
159
 
160
  def clean_text_result(text_list):
161
  cleaned = []
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']
194
+ if 'output_img' in proc_res:
195
+ print("Phát hiện ảnh đã qua xử lý hình học. Đang đồng bộ tọa độ...")
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
 
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
  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")
237
 
238
+ with gr.Column():
239
  with gr.Tabs():
240
+ with gr.TabItem("🖼️ Kết quả Khớp Tọa Độ"):
241
  output_img = gr.Image(type="pil", label="Overlay Result")
242
+ with gr.TabItem("📝 Văn bản"):
243
  output_txt = gr.Textbox(label="Text Content", lines=15)
244
  with gr.TabItem("🐞 Debug"):
245
  output_debug = gr.Textbox(label="Debug Info", lines=15)
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