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.
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/config_gui.py +1 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/gsm_ocr_config.py +2 -2
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/owocr_helper.py +102 -73
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/ocr.py +127 -53
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/run.py +143 -124
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/configuration.py +1 -1
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/PKG-INFO +1 -1
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/pyproject.toml +1 -1
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ai/ai_prompting.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/anki.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/gametext.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/gsm.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/obs.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/electron_config.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/ffmpeg.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/package.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/ss_selector.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/vad.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/index.html +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/LICENSE +0 -0
- {gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/README.md +0 -0
- {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)
|
{gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/gsm_ocr_config.py
RENAMED
@@ -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
|
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
|
{gamesentenceminer-2.10.11 → gamesentenceminer-2.10.13}/GameSentenceMiner/ocr/owocr_helper.py
RENAMED
@@ -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
|
-
|
191
|
-
|
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
|
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
|
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
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
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)
|