GameSentenceMiner 2.10.11__tar.gz → 2.10.13__tar.gz

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.
Files changed (75) hide show
  1. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/config_gui.py +1 -0
  2. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/gsm_ocr_config.py +2 -2
  3. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/owocr_helper.py +102 -73
  4. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/ocr.py +127 -53
  5. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/run.py +143 -124
  6. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/configuration.py +1 -1
  7. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
  8. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/PKG-INFO +1 -1
  9. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/pyproject.toml +1 -1
  10. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/__init__.py +0 -0
  11. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ai/__init__.py +0 -0
  12. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ai/ai_prompting.py +0 -0
  13. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/anki.py +0 -0
  14. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/__init__.py +0 -0
  15. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon.png +0 -0
  16. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon128.png +0 -0
  17. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon256.png +0 -0
  18. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon32.png +0 -0
  19. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon512.png +0 -0
  20. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon64.png +0 -0
  21. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/pickaxe.png +0 -0
  22. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/gametext.py +0 -0
  23. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/gsm.py +0 -0
  24. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/obs.py +0 -0
  25. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/__init__.py +0 -0
  26. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
  27. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
  28. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/ss_picker.py +0 -0
  29. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
  30. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
  31. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/config.py +0 -0
  32. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
  33. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
  34. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/__init__.py +0 -0
  35. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/audio_offset_selector.py +0 -0
  36. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/__init__.py +0 -0
  37. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/send.py +0 -0
  38. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/websocket.py +0 -0
  39. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
  40. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/__init__.py +0 -0
  41. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
  42. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
  43. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/electron_config.py +0 -0
  44. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/ffmpeg.py +0 -0
  45. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/gsm_utils.py +0 -0
  46. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/model.py +0 -0
  47. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/notification.py +0 -0
  48. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/package.py +0 -0
  49. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/ss_selector.py +0 -0
  50. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/text_log.py +0 -0
  51. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/vad.py +0 -0
  52. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/__init__.py +0 -0
  53. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/service.py +0 -0
  54. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/__init__.py +0 -0
  55. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
  56. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
  57. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon.ico +0 -0
  58. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon.svg +0 -0
  59. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/site.webmanifest +0 -0
  60. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/style.css +0 -0
  61. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
  62. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
  63. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/__init__.py +0 -0
  64. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/index.html +0 -0
  65. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
  66. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/utility.html +0 -0
  67. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/texthooking_page.py +0 -0
  68. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
  69. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
  70. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
  71. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/requires.txt +0 -0
  72. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/top_level.txt +0 -0
  73. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/LICENSE +0 -0
  74. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/README.md +0 -0
  75. {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/setup.cfg +0 -0
@@ -80,6 +80,7 @@ class ConfigApp:
80
80
  def __init__(self, root):
81
81
  self.window = root
82
82
  self.on_exit = None
83
+ self.window.tk.call('tk', 'scaling', 1.5) # Set DPI scaling factor
83
84
  # self.window = ttk.Window(themename='darkly')
84
85
  self.window.title('GameSentenceMiner Configuration')
85
86
  self.window.protocol("WM_DELETE_WINDOW", self.hide)
@@ -44,13 +44,13 @@ class WindowGeometry:
44
44
  class OCRConfig:
45
45
  scene: str
46
46
  rectangles: List[Rectangle]
47
- pre_scale_rectangles: List[Rectangle] = None
47
+ pre_scale_rectangles: Optional[List[Rectangle]] = None
48
48
  coordinate_system: str = None
49
49
  window_geometry: Optional[WindowGeometry] = None
50
50
  window: Optional[str] = None
51
51
  language: str = "ja"
52
52
 
53
- def __post_init__(self):
53
+ def scale_coords(self):
54
54
  self.pre_scale_rectangles = deepcopy(self.rectangles)
55
55
  if self.coordinate_system and self.coordinate_system == "percentage" and self.window:
56
56
  import pygetwindow as gw
@@ -178,17 +178,28 @@ class WebsocketServerThread(threading.Thread):
178
178
  asyncio.run(main())
179
179
 
180
180
 
181
+ def compare_ocr_results(prev_text, new_text, threshold=90):
182
+ if not prev_text or not new_text:
183
+ return False
184
+ if isinstance(prev_text, list):
185
+ prev_text = ''.join([item for item in prev_text if item is not None]) if prev_text else ""
186
+ if isinstance(new_text, list):
187
+ new_text = ''.join([item for item in new_text if item is not None]) if new_text else ""
188
+ similarity = fuzz.ratio(prev_text, new_text)
189
+ return similarity >= threshold
190
+
181
191
  all_cords = None
182
192
  rectangles = None
183
- last_ocr2_result = ""
193
+ last_ocr2_result = []
184
194
 
185
195
  def do_second_ocr(ocr1_text, time, img, filtering, ignore_furigana_filter=False):
186
196
  global twopassocr, ocr2, last_ocr2_result
187
197
  try:
188
198
  orig_text, text = run.process_and_write_results(img, None, last_ocr2_result, filtering, None,
189
199
  engine=ocr2, furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
190
- if fuzz.ratio(last_ocr2_result, orig_text) >= 90:
191
- logger.info("Seems like the same text from previous ocr2 result, not sending")
200
+
201
+ if compare_ocr_results(last_ocr2_result, orig_text):
202
+ logger.info("Detected similar text from previous OCR2 result, not sending")
192
203
  return
193
204
  save_result_image(img)
194
205
  last_ocr2_result = orig_text
@@ -242,7 +253,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
242
253
  line_start_time = time if time else datetime.now()
243
254
 
244
255
  if manual or not twopassocr:
245
- if previous_text and fuzz.ratio(orig_text_string, previous_orig_text) >= 90:
256
+ if compare_ocr_results(previous_orig_text, orig_text_string):
246
257
  logger.info("Seems like Text we already sent, not doing anything.")
247
258
  return
248
259
  save_result_image(img)
@@ -260,13 +271,13 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
260
271
  if previous_text and text_stable_start_time:
261
272
  stable_time = text_stable_start_time
262
273
  previous_img_local = previous_img
263
- if previous_text and fuzz.ratio(orig_text_string, previous_orig_text) >= 90:
274
+ if compare_ocr_results(previous_orig_text, orig_text_string):
264
275
  logger.info("Seems like Text we already sent, not doing anything.")
265
276
  previous_text = None
266
277
  return
267
278
  previous_orig_text = orig_text_string
268
279
  previous_ocr1_result = previous_text
269
- if crop_coords:
280
+ if crop_coords and optimize_second_scan:
270
281
  previous_img_local.save(os.path.join(get_temporary_directory(), "pre_oneocrcrop.png"))
271
282
  previous_img_local = previous_img_local.crop(crop_coords)
272
283
  second_ocr_queue.put((previous_text, stable_time, previous_img_local, filtering))
@@ -389,70 +400,88 @@ def set_force_stable_hotkey():
389
400
  print("Press Ctrl+Shift+F to toggle force stable mode.")
390
401
 
391
402
  if __name__ == "__main__":
392
- global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window
393
- import sys
394
-
395
- import argparse
396
-
397
- parser = argparse.ArgumentParser(description="OCR Configuration")
398
- parser.add_argument("--language", type=str, default="ja", help="Language for OCR (default: ja)")
399
- parser.add_argument("--ocr1", type=str, default="oneocr", help="Primary OCR engine (default: oneocr)")
400
- parser.add_argument("--ocr2", type=str, default="glens", help="Secondary OCR engine (default: glens)")
401
- parser.add_argument("--twopassocr", type=int, choices=[0, 1], default=1, help="Enable two-pass OCR (default: 1)")
402
- parser.add_argument("--manual", action="store_true", help="Use screenshot-only mode")
403
- parser.add_argument("--clipboard", action="store_true", help="Use clipboard for input")
404
- parser.add_argument("--clipboard-output", action="store_true", default=False, help="Use clipboard for output")
405
- parser.add_argument("--window", type=str, help="Specify the window name for OCR")
406
- parser.add_argument("--furigana_filter_sensitivity", type=float, default=0, help="Furigana Filter Sensitivity for OCR (default: 0)")
407
- parser.add_argument("--manual_ocr_hotkey", type=str, default=None, help="Hotkey for manual OCR (default: None)")
408
- parser.add_argument("--area_select_ocr_hotkey", type=str, default="ctrl+shift+o", help="Hotkey for area selection OCR (default: ctrl+shift+o)")
409
-
410
- args = parser.parse_args()
411
-
412
- language = args.language
413
- ocr1 = args.ocr1
414
- ocr2 = args.ocr2 if args.ocr2 else None
415
- twopassocr = bool(args.twopassocr)
416
- manual = args.manual
417
- ss_clipboard = args.clipboard
418
- window_name = args.window
419
- furigana_filter_sensitivity = args.furigana_filter_sensitivity
420
- ss_hotkey = args.area_select_ocr_hotkey.lower()
421
- manual_ocr_hotkey = args.manual_ocr_hotkey.lower().replace("ctrl", "<ctrl>").replace("shift", "<shift>").replace("alt", "<alt>") if args.manual_ocr_hotkey else None
422
- clipboard_output = args.clipboard_output
423
-
424
- logger.info(f"Received arguments: {vars(args)}")
425
- # set_force_stable_hotkey()
426
- ocr_config: OCRConfig = get_ocr_config(window=window_name)
427
- if ocr_config:
428
- if ocr_config.window:
429
- start_time = time.time()
430
- while time.time() - start_time < 30:
431
- window = get_window(ocr_config.window)
432
- if window or manual:
433
- break
434
- logger.info(f"Window: {ocr_config.window} Could not be found, retrying in 1 second...")
435
- time.sleep(1)
436
- else:
437
- logger.error(f"Window '{ocr_config.window}' not found within 30 seconds.")
438
- sys.exit(1)
439
- logger.info(f"Starting OCR with configuration: Window: {ocr_config.window}, Rectangles: {ocr_config.rectangles}, Engine 1: {ocr1}, Engine 2: {ocr2}, Two-pass OCR: {twopassocr}")
440
- set_dpi_awareness()
441
- if manual or ocr_config:
442
- rectangles = ocr_config.rectangles if ocr_config and ocr_config.rectangles else []
443
- oneocr_threads = []
444
- ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config,rectangles ), daemon=True)
445
- ocr_thread.start()
446
- if not manual:
447
- worker_thread = threading.Thread(target=process_task_queue, daemon=True)
448
- worker_thread.start()
449
- websocket_server_thread = WebsocketServerThread(read=True)
450
- websocket_server_thread.start()
451
- add_ss_hotkey(ss_hotkey)
452
- try:
453
- while not done:
454
- time.sleep(1)
455
- except KeyboardInterrupt as e:
456
- pass
457
- else:
458
- print("Failed to load OCR configuration. Please check the logs.")
403
+ try:
404
+ global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window, optimize_second_scan
405
+ import sys
406
+
407
+ import argparse
408
+
409
+ parser = argparse.ArgumentParser(description="OCR Configuration")
410
+ parser.add_argument("--language", type=str, default="ja", help="Language for OCR (default: ja)")
411
+ parser.add_argument("--ocr1", type=str, default="oneocr", help="Primary OCR engine (default: oneocr)")
412
+ parser.add_argument("--ocr2", type=str, default="glens", help="Secondary OCR engine (default: glens)")
413
+ parser.add_argument("--twopassocr", type=int, choices=[0, 1], default=1,
414
+ help="Enable two-pass OCR (default: 1)")
415
+ parser.add_argument("--manual", action="store_true", help="Use screenshot-only mode")
416
+ parser.add_argument("--clipboard", action="store_true", help="Use clipboard for input")
417
+ parser.add_argument("--clipboard-output", action="store_true", default=False, help="Use clipboard for output")
418
+ parser.add_argument("--window", type=str, help="Specify the window name for OCR")
419
+ parser.add_argument("--furigana_filter_sensitivity", type=float, default=0,
420
+ help="Furigana Filter Sensitivity for OCR (default: 0)")
421
+ parser.add_argument("--manual_ocr_hotkey", type=str, default=None, help="Hotkey for manual OCR (default: None)")
422
+ parser.add_argument("--area_select_ocr_hotkey", type=str, default="ctrl+shift+o",
423
+ help="Hotkey for area selection OCR (default: ctrl+shift+o)")
424
+ parser.add_argument("--optimize_second_scan", action="store_true",
425
+ help="Optimize second scan by cropping based on first scan results")
426
+
427
+ args = parser.parse_args()
428
+
429
+ language = args.language
430
+ ocr1 = args.ocr1
431
+ ocr2 = args.ocr2 if args.ocr2 else None
432
+ twopassocr = bool(args.twopassocr)
433
+ manual = args.manual
434
+ ss_clipboard = args.clipboard
435
+ window_name = args.window
436
+ furigana_filter_sensitivity = args.furigana_filter_sensitivity
437
+ ss_hotkey = args.area_select_ocr_hotkey.lower()
438
+ manual_ocr_hotkey = args.manual_ocr_hotkey.lower().replace("ctrl", "<ctrl>").replace("shift",
439
+ "<shift>").replace(
440
+ "alt", "<alt>") if args.manual_ocr_hotkey else None
441
+ clipboard_output = args.clipboard_output
442
+ optimize_second_scan = args.optimize_second_scan
443
+
444
+ window = None
445
+ logger.info(f"Received arguments: {vars(args)}")
446
+ # set_force_stable_hotkey()
447
+ ocr_config: OCRConfig = get_ocr_config(window=window_name)
448
+ if ocr_config:
449
+ if ocr_config.window:
450
+ start_time = time.time()
451
+ while time.time() - start_time < 30:
452
+ window = get_window(ocr_config.window)
453
+ if window or manual:
454
+ if window:
455
+ ocr_config.scale_coords()
456
+ break
457
+ logger.info(f"Window: {ocr_config.window} Could not be found, retrying in 1 second...")
458
+ time.sleep(1)
459
+ else:
460
+ logger.error(f"Window '{ocr_config.window}' not found within 30 seconds.")
461
+ sys.exit(1)
462
+ logger.info(
463
+ f"Starting OCR with configuration: Window: {ocr_config.window}, Rectangles: {ocr_config.rectangles}, Engine 1: {ocr1}, Engine 2: {ocr2}, Two-pass OCR: {twopassocr}")
464
+ set_dpi_awareness()
465
+ if manual or ocr_config:
466
+ rectangles = ocr_config.rectangles if ocr_config and ocr_config.rectangles else []
467
+ oneocr_threads = []
468
+ ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config, rectangles), daemon=True)
469
+ ocr_thread.start()
470
+ if not manual:
471
+ worker_thread = threading.Thread(target=process_task_queue, daemon=True)
472
+ worker_thread.start()
473
+ websocket_server_thread = WebsocketServerThread(read=True)
474
+ websocket_server_thread.start()
475
+ add_ss_hotkey(ss_hotkey)
476
+ try:
477
+ while not done:
478
+ time.sleep(1)
479
+ except KeyboardInterrupt as e:
480
+ pass
481
+ else:
482
+ print("Failed to load OCR configuration. Please check the logs.")
483
+ except Exception as e:
484
+ logger.info(e, exc_info=True)
485
+ logger.debug(e, exc_info=True)
486
+ logger.info("Closing in 5 seconds...")
487
+ time.sleep(5)