GameSentenceMiner 2.17.3__py3-none-any.whl → 2.17.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -199,25 +199,30 @@ rectangles = None
199
199
  last_ocr2_result = []
200
200
  last_sent_result = ""
201
201
 
202
- def do_second_ocr(ocr1_text, time, img, filtering, pre_crop_image=None, ignore_furigana_filter=False, ignore_previous_result=False):
203
- global twopassocr, ocr2, last_ocr2_result, last_sent_result
204
- try:
205
- orig_text, text = run.process_and_write_results(img, None, last_ocr2_result if not ignore_previous_result else None, filtering, None,
206
- engine=get_ocr_ocr2(), furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
207
-
208
- if compare_ocr_results(last_sent_result, text, threshold=80):
209
- if text:
210
- logger.info("Seems like Text we already sent, not doing anything.")
211
- return
212
- save_result_image(img, pre_crop_image=pre_crop_image)
213
- last_ocr2_result = orig_text
214
- last_sent_result = text
215
- asyncio.run(send_result(text, time))
216
- except json.JSONDecodeError:
217
- print("Invalid JSON received.")
218
- except Exception as e:
219
- logger.exception(e)
220
- print(f"Error processing message: {e}")
202
+ class OCRProcessor():
203
+ def __init__(self):
204
+ self.filtering = TextFiltering(lang=get_ocr_language())
205
+ pass
206
+
207
+ def do_second_ocr(self, ocr1_text, time, img, filtering, pre_crop_image=None, ignore_furigana_filter=False, ignore_previous_result=False):
208
+ global twopassocr, ocr2, last_ocr2_result, last_sent_result
209
+ try:
210
+ orig_text, text = run.process_and_write_results(img, None, last_ocr2_result if not ignore_previous_result else None, self.filtering, None,
211
+ engine=get_ocr_ocr2(), furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
212
+
213
+ if compare_ocr_results(last_sent_result, text, threshold=80):
214
+ if text:
215
+ logger.info("Seems like Text we already sent, not doing anything.")
216
+ return
217
+ save_result_image(img, pre_crop_image=pre_crop_image)
218
+ last_ocr2_result = orig_text
219
+ last_sent_result = text
220
+ asyncio.run(send_result(text, time))
221
+ except json.JSONDecodeError:
222
+ print("Invalid JSON received.")
223
+ except Exception as e:
224
+ logger.exception(e)
225
+ print(f"Error processing message: {e}")
221
226
 
222
227
 
223
228
  def save_result_image(img, pre_crop_image=None):
@@ -249,6 +254,7 @@ previous_img = None
249
254
  previous_orig_text = "" # Store original text result
250
255
  TEXT_APPEARENCE_DELAY = get_ocr_scan_rate() * 1000 + 500 # Adjust as needed
251
256
  force_stable = False
257
+ second_ocr_processor = OCRProcessor()
252
258
 
253
259
  class ConfigChangeCheckThread(threading.Thread):
254
260
  def __init__(self):
@@ -461,7 +467,7 @@ def get_ocr2_image(crop_coords, og_image: Image.Image, ocr2_engine=None):
461
467
 
462
468
  # If no crop or optimization, just apply config and return
463
469
  if not crop_coords or not get_ocr_optimize_second_scan():
464
- img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=True)
470
+ img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=False)
465
471
  return img
466
472
 
467
473
  # Calculate scaling ratios
@@ -495,7 +501,7 @@ def process_task_queue():
495
501
  if task is None: # Exit signal
496
502
  break
497
503
  ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image = task
498
- do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image)
504
+ second_ocr_processor.do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image)
499
505
  except Exception as e:
500
506
  logger.exception(f"Error processing task: {e}")
501
507
  finally:
@@ -550,21 +556,21 @@ def add_ss_hotkey(ss_hotkey="ctrl+shift+g"):
550
556
  ocr_config.scale_to_custom_size(img.width, img.height)
551
557
  for rectangle in [rectangle for rectangle in ocr_config.rectangles if rectangle.is_secondary]:
552
558
  new_img = run.apply_ocr_config_to_image(img, ocr_config, is_secondary=True, rectangles=[rectangle])
553
- do_second_ocr("", datetime.now(), new_img, TextFiltering(lang=get_ocr_language()), ignore_furigana_filter=True, ignore_previous_result=True)
559
+ second_ocr_processor.do_second_ocr("", datetime.now(), new_img, TextFiltering(lang=get_ocr_language()), ignore_furigana_filter=True, ignore_previous_result=True)
554
560
 
555
561
  filtering = TextFiltering(lang=get_ocr_language())
556
562
  cropper = ScreenCropper()
557
563
  def capture():
558
564
  print("Taking screenshot...")
559
565
  img = cropper.run()
560
- do_second_ocr("", datetime.now(), img, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
566
+ second_ocr_processor.do_second_ocr("", datetime.now(), img, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
561
567
  def capture_main_monitor():
562
568
  print("Taking screenshot of main monitor...")
563
569
  with mss.mss() as sct:
564
570
  main_monitor = sct.monitors[1] if len(sct.monitors) > 1 else sct.monitors[0]
565
571
  img = sct.grab(main_monitor)
566
572
  img_bytes = mss.tools.to_png(img.rgb, img.size)
567
- do_second_ocr("", datetime.now(), img_bytes, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
573
+ second_ocr_processor.do_second_ocr("", datetime.now(), img_bytes, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
568
574
  hotkey_reg = None
569
575
  secondary_hotkey_reg = None
570
576
  try:
@@ -375,7 +375,7 @@ class GoogleLens:
375
375
  # logger.info(f"Vertical space: {vertical_space}, Average height: {avg_height}")
376
376
  # logger.info(avg_height * 2)
377
377
  if vertical_space > avg_height * 2:
378
- res += 'BLANK_LINE'
378
+ res += 'BLANK_LINE\n'
379
379
  for line in paragraph['lines']:
380
380
  if furigana_filter_sensitivity:
381
381
  line_width = line['geometry']['bounding_box']['width'] * img.width
@@ -320,13 +320,20 @@ class RequestHandler(socketserver.BaseRequestHandler):
320
320
  conn.sendall(b'False')
321
321
 
322
322
 
323
+ class PassthroughSegmenter:
324
+ def segment(self, text):
325
+ return [text]
326
+
323
327
  class TextFiltering:
324
328
  accurate_filtering = False
325
329
 
326
330
  def __init__(self, lang='ja'):
327
- from pysbd import Segmenter
331
+ from pysbd import Segmenter, languages
328
332
  self.initial_lang = get_ocr_language() or lang
329
- self.segmenter = Segmenter(language=get_ocr_language(), clean=True)
333
+ if lang in languages.LANGUAGE_CODES:
334
+ self.segmenter = Segmenter(language=lang, clean=True)
335
+ else:
336
+ self.segmenter = PassthroughSegmenter()
330
337
  self.kana_kanji_regex = re.compile(
331
338
  r'[\u3041-\u3096\u30A1-\u30FA\u4E00-\u9FFF]')
332
339
  self.chinese_common_regex = re.compile(r'[\u4E00-\u9FFF]')
@@ -371,8 +378,11 @@ class TextFiltering:
371
378
  def __call__(self, text, last_result, engine=None, is_second_ocr=False):
372
379
  lang = get_ocr_language()
373
380
  if self.initial_lang != lang:
374
- from pysbd import Segmenter
375
- self.segmenter = Segmenter(language=get_ocr_language(), clean=True)
381
+ from pysbd import Segmenter, languages
382
+ if lang in languages.LANGUAGE_CODES:
383
+ self.segmenter = Segmenter(language=lang, clean=True)
384
+ else:
385
+ self.segmenter = PassthroughSegmenter()
376
386
  self.initial_lang = get_ocr_language()
377
387
 
378
388
  orig_text = self.segmenter.segment(text)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.17.3
3
+ Version: 2.17.5
4
4
  Summary: A tool for mining sentences from games. Update: Overlay?
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -18,7 +18,7 @@ Requires-Dist: DateTime~=5.5
18
18
  Requires-Dist: pyperclip~=1.9.0
19
19
  Requires-Dist: soundfile~=0.12.1
20
20
  Requires-Dist: toml~=0.10.2
21
- Requires-Dist: psutil~=6.0.0
21
+ Requires-Dist: psutil~=7.1.0
22
22
  Requires-Dist: rapidfuzz~=3.9.7
23
23
  Requires-Dist: plyer~=2.1.0
24
24
  Requires-Dist: keyboard~=0.13.5
@@ -22,14 +22,14 @@ GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
22
22
  GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=Ov04c-nKzh3sADxO-5JyZWVe4DlrHM9edM9tc7-97Jo,5970
23
23
  GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
24
24
  GameSentenceMiner/ocr/owocr_area_selector.py,sha256=4MjItlaZ78Smxa3uxMxbjU0n2z_IBTG-iBpDB9COSL8,29270
25
- GameSentenceMiner/ocr/owocr_helper.py,sha256=kuwEiOOyOMHDdsDboyDqB_MI8WL9bsN9XubACfgw1KQ,32036
25
+ GameSentenceMiner/ocr/owocr_helper.py,sha256=BGBiMDziPknCSj2VM4kpVL3iCtIswbisiPuiPOAVqjs,32370
26
26
  GameSentenceMiner/ocr/ss_picker.py,sha256=0IhxUdaKruFpZyBL-8SpxWg7bPrlGpy3lhTcMMZ5rwo,5224
27
27
  GameSentenceMiner/owocr/owocr/__init__.py,sha256=87hfN5u_PbL_onLfMACbc0F5j4KyIK9lKnRCj6oZgR0,49
28
28
  GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
29
29
  GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
30
30
  GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
31
- GameSentenceMiner/owocr/owocr/ocr.py,sha256=vRTMKLzi6GDBFZWCyf0tYi6es3cP1cvQOBjZqaZmnBg,70482
32
- GameSentenceMiner/owocr/owocr/run.py,sha256=bIXC_7PltyVvlA8beCVqdLcKVai8LvVHBRqEueq2GkQ,81545
31
+ GameSentenceMiner/owocr/owocr/ocr.py,sha256=7VCTBl4-8mO9P73olLMihUFtu3idBdyZIWP6XQhCte4,70484
32
+ GameSentenceMiner/owocr/owocr/run.py,sha256=Z7VkoFrsoQbMTHc6CmwpcMzsOROK9A_RJRwhlxw15oA,81871
33
33
  GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
34
34
  GameSentenceMiner/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  GameSentenceMiner/tools/audio_offset_selector.py,sha256=8Stk3BP-XVIuzRv9nl9Eqd2D-1yD3JrgU-CamBywJmY,8542
@@ -90,9 +90,9 @@ GameSentenceMiner/web/templates/utility.html,sha256=KtqnZUMAYs5XsEdC9Tlsd40NKAVi
90
90
  GameSentenceMiner/web/templates/components/navigation.html,sha256=6y9PvM3nh8LY6JWrZb6zVOm0vqkBLDc6d3gB9X5lT_w,1055
91
91
  GameSentenceMiner/web/templates/components/theme-styles.html,sha256=hiq3zdJljpRjQO1iUA7gfFKwXebltG-IWW-gnKS4GHA,3439
92
92
  GameSentenceMiner/wip/__init___.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
- gamesentenceminer-2.17.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
94
- gamesentenceminer-2.17.3.dist-info/METADATA,sha256=Yr9TwKuUOUhU5QWe2dqwq9DPkfpvGZl7OE9D1NLZZe8,7348
95
- gamesentenceminer-2.17.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
- gamesentenceminer-2.17.3.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
97
- gamesentenceminer-2.17.3.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
98
- gamesentenceminer-2.17.3.dist-info/RECORD,,
93
+ gamesentenceminer-2.17.5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
94
+ gamesentenceminer-2.17.5.dist-info/METADATA,sha256=CUChAokaBSIh9jkDR4ICjwvQIdj8MqLAeVlyqHKsZGM,7348
95
+ gamesentenceminer-2.17.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
+ gamesentenceminer-2.17.5.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
97
+ gamesentenceminer-2.17.5.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
98
+ gamesentenceminer-2.17.5.dist-info/RECORD,,