GameSentenceMiner 2.14.19__tar.gz → 2.14.21__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.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/gsm.py +92 -81
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/obs.py +4 -5
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/ocr.py +16 -15
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/run.py +1 -1
- gamesentenceminer-2.14.21/GameSentenceMiner/tools/furigana_filter_preview.py +330 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/vad.py +8 -8
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/SOURCES.txt +1 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/PKG-INFO +1 -1
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/pyproject.toml +1 -1
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ai/ai_prompting.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/anki.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/config_gui.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/gametext.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/en_us.json +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/ja_jp.json +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/zh_cn.json +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/owocr_helper.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/tools/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/tools/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/tools/ss_selector.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/tools/window_transparency.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/configuration.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/db.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/electron_config.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/ffmpeg.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/get_overlay_coords.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/win10toast/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/win10toast/__main__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/index.html +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/wip/__init___.py +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/LICENSE +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/README.md +0 -0
- {gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/setup.cfg +0 -0
@@ -123,8 +123,6 @@ if is_windows():
|
|
123
123
|
procs_to_close = []
|
124
124
|
settings_window: config_gui.ConfigApp = None
|
125
125
|
obs_paused = False
|
126
|
-
icon: Icon
|
127
|
-
menu: Menu
|
128
126
|
root = None
|
129
127
|
warnings.simplefilter("ignore", DeprecationWarning)
|
130
128
|
|
@@ -401,83 +399,94 @@ def open_log():
|
|
401
399
|
logger.info("Log opened.")
|
402
400
|
|
403
401
|
|
404
|
-
def
|
405
|
-
|
406
|
-
if not passed_icon:
|
407
|
-
passed_icon = icon
|
408
|
-
logger.info("Exiting...")
|
409
|
-
passed_icon.stop()
|
410
|
-
cleanup()
|
402
|
+
def open_multimine(icon, item):
|
403
|
+
texthooking_page.open_texthooker()
|
411
404
|
|
412
405
|
|
413
|
-
def
|
414
|
-
|
415
|
-
|
416
|
-
|
406
|
+
def exit_program(passed_icon, item):
|
407
|
+
"""Exit the application."""
|
408
|
+
if not passed_icon:
|
409
|
+
passed_icon = icon
|
410
|
+
logger.info("Exiting...")
|
411
|
+
passed_icon.stop()
|
412
|
+
cleanup()
|
417
413
|
|
414
|
+
class GSMTray(threading.Thread):
|
415
|
+
def __init__(self):
|
416
|
+
super().__init__()
|
417
|
+
self.daemon = True
|
418
|
+
self.menu = None
|
419
|
+
self.icon = None
|
420
|
+
|
421
|
+
def run(self):
|
422
|
+
self.run_tray()
|
423
|
+
|
424
|
+
|
425
|
+
def run_tray(self):
|
426
|
+
self.profile_menu = Menu(
|
427
|
+
*[MenuItem(("Active: " if profile == get_master_config().current_profile else "") + profile, self.switch_profile) for
|
428
|
+
profile in
|
429
|
+
get_master_config().get_all_profile_names()]
|
430
|
+
)
|
431
|
+
|
432
|
+
menu = Menu(
|
433
|
+
MenuItem("Open Settings", open_settings, default=True),
|
434
|
+
MenuItem("Open Texthooker", texthooking_page.open_texthooker),
|
435
|
+
MenuItem("Open Log", open_log),
|
436
|
+
MenuItem("Toggle Replay Buffer", self.play_pause),
|
437
|
+
MenuItem("Restart OBS", restart_obs),
|
438
|
+
MenuItem("Switch Profile", self.profile_menu),
|
439
|
+
MenuItem("Exit", exit_program)
|
440
|
+
)
|
441
|
+
|
442
|
+
self.icon = Icon("TrayApp", create_image(), "GameSentenceMiner", menu)
|
443
|
+
self.icon.run()
|
444
|
+
|
445
|
+
def update_icon(self, profile=None):
|
446
|
+
global menu, icon
|
447
|
+
# Recreate the menu with the updated button text
|
448
|
+
profile_menu = Menu(
|
449
|
+
*[MenuItem(("Active: " if profile == get_master_config().current_profile else "") + profile, self.switch_profile) for
|
450
|
+
profile in
|
451
|
+
get_master_config().get_all_profile_names()]
|
452
|
+
)
|
453
|
+
|
454
|
+
menu = Menu(
|
455
|
+
MenuItem("Open Settings", open_settings, default=True),
|
456
|
+
MenuItem("Open Multi-Mine GUI", open_multimine),
|
457
|
+
MenuItem("Open Log", open_log),
|
458
|
+
MenuItem("Toggle Replay Buffer", self.play_pause),
|
459
|
+
MenuItem("Restart OBS", restart_obs),
|
460
|
+
MenuItem("Switch Profile", profile_menu),
|
461
|
+
MenuItem("Exit", exit_program)
|
462
|
+
)
|
463
|
+
|
464
|
+
self.icon.menu = menu
|
465
|
+
self.icon.update_menu()
|
466
|
+
|
467
|
+
def switch_profile(self, icon, item):
|
468
|
+
if "Active:" in item.text:
|
469
|
+
logger.error("You cannot switch to the currently active profile!")
|
470
|
+
return
|
471
|
+
logger.info(f"Switching to profile: {item.text}")
|
472
|
+
prev_config = get_config()
|
473
|
+
get_master_config().current_profile = item.text
|
474
|
+
switch_profile_and_save(item.text)
|
475
|
+
settings_window.reload_settings()
|
476
|
+
self.update_icon()
|
477
|
+
if get_config().restart_required(prev_config):
|
478
|
+
send_restart_signal()
|
418
479
|
|
419
|
-
def
|
420
|
-
|
480
|
+
def play_pause(self, icon, item):
|
481
|
+
global obs_paused, menu
|
482
|
+
obs.toggle_replay_buffer()
|
483
|
+
self.update_icon()
|
421
484
|
|
485
|
+
def stop(self):
|
486
|
+
if self.icon:
|
487
|
+
self.icon.stop()
|
422
488
|
|
423
|
-
|
424
|
-
global menu, icon
|
425
|
-
# Recreate the menu with the updated button text
|
426
|
-
profile_menu = Menu(
|
427
|
-
*[MenuItem(("Active: " if profile == get_master_config().current_profile else "") + profile, switch_profile) for
|
428
|
-
profile in
|
429
|
-
get_master_config().get_all_profile_names()]
|
430
|
-
)
|
431
|
-
|
432
|
-
menu = Menu(
|
433
|
-
MenuItem("Open Settings", open_settings, default=True),
|
434
|
-
MenuItem("Open Multi-Mine GUI", open_multimine),
|
435
|
-
MenuItem("Open Log", open_log),
|
436
|
-
MenuItem("Toggle Replay Buffer", play_pause),
|
437
|
-
MenuItem("Restart OBS", restart_obs),
|
438
|
-
MenuItem("Switch Profile", profile_menu),
|
439
|
-
MenuItem("Exit", exit_program)
|
440
|
-
)
|
441
|
-
|
442
|
-
icon.menu = menu
|
443
|
-
icon.update_menu()
|
444
|
-
|
445
|
-
|
446
|
-
def switch_profile(icon, item):
|
447
|
-
if "Active:" in item.text:
|
448
|
-
logger.error("You cannot switch to the currently active profile!")
|
449
|
-
return
|
450
|
-
logger.info(f"Switching to profile: {item.text}")
|
451
|
-
prev_config = get_config()
|
452
|
-
get_master_config().current_profile = item.text
|
453
|
-
switch_profile_and_save(item.text)
|
454
|
-
settings_window.reload_settings()
|
455
|
-
update_icon()
|
456
|
-
if get_config().restart_required(prev_config):
|
457
|
-
send_restart_signal()
|
458
|
-
|
459
|
-
|
460
|
-
def run_tray():
|
461
|
-
global menu, icon
|
462
|
-
|
463
|
-
profile_menu = Menu(
|
464
|
-
*[MenuItem(("Active: " if profile == get_master_config().current_profile else "") + profile, switch_profile) for
|
465
|
-
profile in
|
466
|
-
get_master_config().get_all_profile_names()]
|
467
|
-
)
|
468
|
-
|
469
|
-
menu = Menu(
|
470
|
-
MenuItem("Open Settings", open_settings, default=True),
|
471
|
-
MenuItem("Open Texthooker", texthooking_page.open_texthooker),
|
472
|
-
MenuItem("Open Log", open_log),
|
473
|
-
MenuItem("Toggle Replay Buffer", play_pause),
|
474
|
-
MenuItem("Restart OBS", restart_obs),
|
475
|
-
MenuItem("Switch Profile", profile_menu),
|
476
|
-
MenuItem("Exit", exit_program)
|
477
|
-
)
|
478
|
-
|
479
|
-
icon = Icon("TrayApp", create_image(), "GameSentenceMiner", menu)
|
480
|
-
icon.run()
|
489
|
+
gsm_tray = GSMTray()
|
481
490
|
|
482
491
|
|
483
492
|
# def close_obs():
|
@@ -551,8 +560,8 @@ def cleanup():
|
|
551
560
|
proc.kill()
|
552
561
|
logger.error(f"Error terminating process {proc}: {e}")
|
553
562
|
|
554
|
-
if
|
555
|
-
|
563
|
+
if gsm_tray:
|
564
|
+
gsm_tray.stop()
|
556
565
|
|
557
566
|
for video in gsm_state.videos_to_remove:
|
558
567
|
try:
|
@@ -608,7 +617,7 @@ def initialize(reloading=False):
|
|
608
617
|
|
609
618
|
|
610
619
|
def initialize_async():
|
611
|
-
tasks = [connect_websocket
|
620
|
+
tasks = [connect_websocket]
|
612
621
|
threads = []
|
613
622
|
tasks.append(anki.start_monitoring_anki)
|
614
623
|
for task in tasks:
|
@@ -633,11 +642,12 @@ def handle_websocket_message(message: Message):
|
|
633
642
|
case FunctionName.OPEN_LOG:
|
634
643
|
open_log()
|
635
644
|
case FunctionName.TOGGLE_REPLAY_BUFFER:
|
636
|
-
|
645
|
+
obs.toggle_replay_buffer()
|
637
646
|
case FunctionName.RESTART_OBS:
|
638
647
|
restart_obs()
|
639
648
|
case FunctionName.EXIT:
|
640
|
-
|
649
|
+
cleanup()
|
650
|
+
sys.exit(0)
|
641
651
|
case FunctionName.CONNECT:
|
642
652
|
logger.debug("Electron WSS connected")
|
643
653
|
case _:
|
@@ -671,7 +681,7 @@ async def register_scene_switcher_callback():
|
|
671
681
|
all_configured_scenes = [
|
672
682
|
config.scenes for config in get_master_config().configs.values()]
|
673
683
|
print(all_configured_scenes)
|
674
|
-
matching_configs = [name.strip() for name, config in
|
684
|
+
matching_configs = [name.strip() for name, config in get_master_config().configs.items(
|
675
685
|
) if scene.strip() in config.scenes]
|
676
686
|
switch_to = None
|
677
687
|
|
@@ -692,7 +702,7 @@ async def register_scene_switcher_callback():
|
|
692
702
|
get_master_config().current_profile = switch_to
|
693
703
|
switch_profile_and_save(switch_to)
|
694
704
|
settings_window.reload_settings()
|
695
|
-
update_icon()
|
705
|
+
gsm_tray.update_icon()
|
696
706
|
|
697
707
|
await obs.register_scene_change_callback(scene_switcher_callback)
|
698
708
|
|
@@ -763,7 +773,8 @@ async def async_main(reloading=False):
|
|
763
773
|
try:
|
764
774
|
if get_config().general.open_config_on_startup:
|
765
775
|
root.after(50, settings_window.show)
|
766
|
-
|
776
|
+
root.after(50, gsm_tray.start)
|
777
|
+
settings_window.add_save_hook(gsm_tray.update_icon)
|
767
778
|
settings_window.on_exit = exit_program
|
768
779
|
root.mainloop()
|
769
780
|
except KeyboardInterrupt:
|
@@ -1,16 +1,17 @@
|
|
1
1
|
import asyncio
|
2
|
+
import json
|
2
3
|
import os.path
|
3
4
|
import subprocess
|
4
5
|
import threading
|
5
6
|
import time
|
6
|
-
|
7
|
+
import logging
|
7
8
|
|
8
9
|
import psutil
|
9
10
|
|
10
11
|
import obsws_python as obs
|
11
12
|
|
12
13
|
from GameSentenceMiner.util import configuration
|
13
|
-
from GameSentenceMiner.util.configuration import
|
14
|
+
from GameSentenceMiner.util.configuration import get_app_directory, get_config, get_master_config, is_windows, save_full_config, reload_config, logger, gsm_status, gsm_state
|
14
15
|
from GameSentenceMiner.util.gsm_utils import sanitize_filename, make_unique_file_name
|
15
16
|
import tkinter as tk
|
16
17
|
from tkinter import messagebox
|
@@ -54,7 +55,7 @@ class OBSConnectionManager(threading.Thread):
|
|
54
55
|
if gsm_status.obs_connected and not replay_buffer_status and not self.said_no_to_replay_buffer:
|
55
56
|
try:
|
56
57
|
self.check_output()
|
57
|
-
except Exception
|
58
|
+
except Exception:
|
58
59
|
pass
|
59
60
|
except Exception as e:
|
60
61
|
logger.error(f"Error when running Extra Utils in OBS Health Check, Keeping ConnectionManager Alive: {e}")
|
@@ -251,7 +252,6 @@ def connect_to_obs_sync(retry=2, check_output=True):
|
|
251
252
|
logger.error(f"Failed to connect to OBS WebSocket: {e}")
|
252
253
|
client = None
|
253
254
|
event_client = None
|
254
|
-
connecting = False
|
255
255
|
break
|
256
256
|
time.sleep(1)
|
257
257
|
retry -= 1
|
@@ -559,7 +559,6 @@ def main():
|
|
559
559
|
disconnect_from_obs()
|
560
560
|
|
561
561
|
if __name__ == '__main__':
|
562
|
-
from mss import mss
|
563
562
|
logging.basicConfig(level=logging.INFO)
|
564
563
|
connect_to_obs_sync()
|
565
564
|
set_fit_to_screen_for_scene_items(get_current_scene())
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/ocr.py
RENAMED
@@ -377,16 +377,13 @@ class GoogleLens:
|
|
377
377
|
res += 'BLANK_LINE'
|
378
378
|
for line in paragraph['lines']:
|
379
379
|
if furigana_filter_sensitivity:
|
380
|
+
line_width = line['geometry']['bounding_box']['width'] * img.width
|
381
|
+
line_height = line['geometry']['bounding_box']['height'] * img.height
|
380
382
|
for word in line['words']:
|
381
383
|
if self.punctuation_regex.findall(word['plain_text']):
|
382
384
|
res += word['plain_text'] + word['text_separator']
|
383
385
|
continue
|
384
|
-
if
|
385
|
-
res += word['plain_text'] + word['text_separator']
|
386
|
-
continue
|
387
|
-
word_width = word['geometry']['bounding_box']['width'] * img.width
|
388
|
-
word_height = word['geometry']['bounding_box']['height'] * img.height
|
389
|
-
if word_width > furigana_filter_sensitivity and word_height > furigana_filter_sensitivity:
|
386
|
+
if line_width > furigana_filter_sensitivity and line_height > furigana_filter_sensitivity:
|
390
387
|
res += word['plain_text'] + word['text_separator']
|
391
388
|
else:
|
392
389
|
skipped.extend(word['plain_text'])
|
@@ -394,7 +391,8 @@ class GoogleLens:
|
|
394
391
|
else:
|
395
392
|
for word in line['words']:
|
396
393
|
res += word['plain_text'] + word['text_separator']
|
397
|
-
|
394
|
+
res += '\n'
|
395
|
+
|
398
396
|
previous_line = paragraph
|
399
397
|
res += '\n'
|
400
398
|
# logger.info(
|
@@ -920,7 +918,7 @@ class OneOCR:
|
|
920
918
|
self.regex = re.compile(
|
921
919
|
r'[a-zA-Z\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u1D00-\u1D7F\u1D80-\u1DBF\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF\uAB30-\uAB6F]')
|
922
920
|
|
923
|
-
def __call__(self, img, furigana_filter_sensitivity=0, return_coords=False, multiple_crop_coords=False, return_one_box=True):
|
921
|
+
def __call__(self, img, furigana_filter_sensitivity=0, return_coords=False, multiple_crop_coords=False, return_one_box=True, return_dict=False):
|
924
922
|
lang = get_ocr_language()
|
925
923
|
if furigana_filter_sensitivity != None:
|
926
924
|
furigana_filter_sensitivity = get_furigana_filter_sensitivity()
|
@@ -940,6 +938,7 @@ class OneOCR:
|
|
940
938
|
return (False, 'Invalid image provided')
|
941
939
|
crop_coords = None
|
942
940
|
crop_coords_list = []
|
941
|
+
ocr_resp = ''
|
943
942
|
if sys.platform == 'win32':
|
944
943
|
try:
|
945
944
|
ocr_resp = self.model.recognize_pil(img)
|
@@ -959,17 +958,17 @@ class OneOCR:
|
|
959
958
|
boxes = []
|
960
959
|
if furigana_filter_sensitivity > 0:
|
961
960
|
for line in filtered_lines:
|
961
|
+
line_x1, line_x2, line_x3, line_x4 = line['bounding_rect']['x1'], line['bounding_rect']['x2'], \
|
962
|
+
line['bounding_rect']['x3'], line['bounding_rect']['x4']
|
963
|
+
line_y1, line_y2, line_y3, line_y4 = line['bounding_rect']['y1'], line['bounding_rect']['y2'], \
|
964
|
+
line['bounding_rect']['y3'], line['bounding_rect']['y4']
|
965
|
+
line_width = max(line_x2 - line_x1, line_x3 - line_x4)
|
966
|
+
line_height = max(line_y3 - line_y1, line_y4 - line_y2)
|
962
967
|
for char in line['words']:
|
963
968
|
if self.punctuation_regex.findall(char['text']):
|
964
969
|
res += char['text']
|
965
970
|
continue
|
966
|
-
|
967
|
-
char['bounding_rect']['x3'], char['bounding_rect']['x4']
|
968
|
-
y1, y2, y3, y4 = char['bounding_rect']['y1'], char['bounding_rect']['y2'], \
|
969
|
-
char['bounding_rect']['y3'], char['bounding_rect']['y4']
|
970
|
-
width = max(x2 - x1, x3 - x4)
|
971
|
-
height = max(y3 - y1, y4 - y2)
|
972
|
-
if width > furigana_filter_sensitivity and height > furigana_filter_sensitivity:
|
971
|
+
if line_width > furigana_filter_sensitivity and line_height > furigana_filter_sensitivity:
|
973
972
|
res += char['text']
|
974
973
|
else:
|
975
974
|
skipped.extend(char for char in line['text'])
|
@@ -1042,6 +1041,8 @@ class OneOCR:
|
|
1042
1041
|
x.append(crop_coords_list)
|
1043
1042
|
if return_one_box:
|
1044
1043
|
x.append(crop_coords)
|
1044
|
+
if return_dict:
|
1045
|
+
x.append(ocr_resp)
|
1045
1046
|
if is_path:
|
1046
1047
|
img.close()
|
1047
1048
|
return x
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/run.py
RENAMED
@@ -1785,7 +1785,7 @@ def run(read_from=None,
|
|
1785
1785
|
continue
|
1786
1786
|
|
1787
1787
|
res, text = process_and_write_results(img, write_to, last_result, filtering, notify,
|
1788
|
-
ocr_start_time=ocr_start_time, furigana_filter_sensitivity=
|
1788
|
+
ocr_start_time=ocr_start_time, furigana_filter_sensitivity=None if get_ocr_two_pass_ocr() else get_furigana_filter_sensitivity())
|
1789
1789
|
if not text and not previous_text and time.time() - last_result_time > 10:
|
1790
1790
|
sleep_time_to_add += .005
|
1791
1791
|
logger.info(f"No text detected again, sleeping.")
|
@@ -0,0 +1,330 @@
|
|
1
|
+
import tkinter as tk
|
2
|
+
from tkinter import ttk
|
3
|
+
from PIL import Image, ImageTk
|
4
|
+
import threading
|
5
|
+
|
6
|
+
import regex
|
7
|
+
|
8
|
+
from GameSentenceMiner import obs
|
9
|
+
from GameSentenceMiner.util.configuration import logger
|
10
|
+
from GameSentenceMiner.owocr.owocr.ocr import GoogleLens, OneOCR
|
11
|
+
|
12
|
+
def get_ocr_results_from_image(image_obj: Image.Image) -> tuple:
|
13
|
+
"""
|
14
|
+
This is the function where you will plug in your OCR logic.
|
15
|
+
|
16
|
+
Args:
|
17
|
+
image_obj: A PIL Image object of the screenshot (used by your actual OCR call).
|
18
|
+
|
19
|
+
Returns:
|
20
|
+
A tuple containing the OCR results from both engines.
|
21
|
+
"""
|
22
|
+
lens = GoogleLens()
|
23
|
+
oneocr = OneOCR()
|
24
|
+
oneocr_res = oneocr(image_obj, return_dict=True)
|
25
|
+
res = lens(image_obj, return_coords=True)
|
26
|
+
|
27
|
+
return res[2], oneocr_res[3]
|
28
|
+
|
29
|
+
|
30
|
+
class FuriganaFilterVisualizer:
|
31
|
+
def __init__(self, master, image: Image.Image, current_furigana_sensitivity: int = 0):
|
32
|
+
self.master = master
|
33
|
+
self.image = image
|
34
|
+
self.ocr1_result = None
|
35
|
+
self.ocr2_result = None
|
36
|
+
self.current_ocr = 1
|
37
|
+
self.master.title("Furigana Filter Visualizer - Lens")
|
38
|
+
|
39
|
+
self.words_data = []
|
40
|
+
self.lines_data = []
|
41
|
+
self.drawn_rects = []
|
42
|
+
|
43
|
+
main_frame = tk.Frame(master)
|
44
|
+
main_frame.pack(fill=tk.BOTH, expand=True)
|
45
|
+
|
46
|
+
self.photo_image = ImageTk.PhotoImage(self.image)
|
47
|
+
self.canvas = tk.Canvas(main_frame, width=self.image.width, height=self.image.height)
|
48
|
+
self.canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
|
49
|
+
self.canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)
|
50
|
+
|
51
|
+
self.loading_bg = self.canvas.create_rectangle(
|
52
|
+
self.image.width/2 - 100, self.image.height/2 - 25,
|
53
|
+
self.image.width/2 + 100, self.image.height/2 + 25,
|
54
|
+
fill="black", outline="white", width=2
|
55
|
+
)
|
56
|
+
self.loading_text = self.canvas.create_text(
|
57
|
+
self.image.width / 2, self.image.height / 2,
|
58
|
+
text="Loading OCR data...", fill="white", font=("Helvetica", 16)
|
59
|
+
)
|
60
|
+
|
61
|
+
self.control_frame = tk.Frame(main_frame, padx=10, pady=10)
|
62
|
+
self.control_frame.pack(side=tk.BOTTOM, fill=tk.X)
|
63
|
+
|
64
|
+
ttk.Label(self.control_frame, text="Furigana Filter Sensitivity:").pack(side=tk.LEFT, padx=(0, 10))
|
65
|
+
|
66
|
+
self.slider = ttk.Scale(
|
67
|
+
self.control_frame, from_=0, to=100, orient=tk.HORIZONTAL, command=self.update_filter_visualization
|
68
|
+
)
|
69
|
+
self.slider.set(current_furigana_sensitivity)
|
70
|
+
self.slider.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
71
|
+
|
72
|
+
self.slider_value_label = ttk.Label(self.control_frame, text=f"{self.slider.get():.0f} px", width=6)
|
73
|
+
self.slider_value_label.pack(side=tk.LEFT, padx=(10, 0))
|
74
|
+
|
75
|
+
self.swap_button = ttk.Button(self.control_frame, text="Switch to OneOCR", command=self.swap_ocr)
|
76
|
+
self.swap_button.pack(side=tk.LEFT, padx=(10, 0))
|
77
|
+
|
78
|
+
self.ok_button = ttk.Button(self.control_frame, text="OK", command=self.on_ok)
|
79
|
+
self.ok_button.pack(side=tk.LEFT, padx=(10, 0))
|
80
|
+
|
81
|
+
self.slider.config(state=tk.DISABLED)
|
82
|
+
self.swap_button.config(state=tk.DISABLED)
|
83
|
+
self.ok_button.config(state=tk.DISABLED)
|
84
|
+
|
85
|
+
self.punctuation_regex = regex.compile(r'[\p{P}\p{S}]')
|
86
|
+
self.master.protocol("WM_DELETE_WINDOW", self.on_ok)
|
87
|
+
|
88
|
+
def update_with_ocr_data(self, ocr1_result, ocr2_result):
|
89
|
+
"""Called by the background thread to populate the GUI with OCR data."""
|
90
|
+
self.ocr1_result = ocr1_result
|
91
|
+
self.ocr2_result = ocr2_result
|
92
|
+
|
93
|
+
# Remove loading message
|
94
|
+
self.canvas.delete(self.loading_bg)
|
95
|
+
self.canvas.delete(self.loading_text)
|
96
|
+
|
97
|
+
if not self.ocr1_result:
|
98
|
+
logger.error("OCR processing failed or returned no data.")
|
99
|
+
self.canvas.create_text(
|
100
|
+
self.image.width / 2, self.image.height / 2,
|
101
|
+
text="OCR Failed!", fill="red", font=("Helvetica", 16)
|
102
|
+
)
|
103
|
+
# Still enable OK button to allow closing
|
104
|
+
self.ok_button.config(state=tk.NORMAL)
|
105
|
+
return
|
106
|
+
|
107
|
+
# Enable controls
|
108
|
+
self.slider.config(state=tk.NORMAL)
|
109
|
+
self.ok_button.config(state=tk.NORMAL)
|
110
|
+
if self.ocr2_result:
|
111
|
+
self.swap_button.config(state=tk.NORMAL)
|
112
|
+
|
113
|
+
# Process and display initial data
|
114
|
+
self.pre_process_word_geometries()
|
115
|
+
self.update_filter_visualization(self.slider.get())
|
116
|
+
|
117
|
+
def on_ok(self):
|
118
|
+
print(f"RESULT:[{self.slider.get():.0f}]")
|
119
|
+
self.master.destroy()
|
120
|
+
|
121
|
+
def swap_ocr(self):
|
122
|
+
self.current_ocr = 2 if self.current_ocr == 1 else 1
|
123
|
+
# Change to oneocr or lens, in title too
|
124
|
+
if self.current_ocr == 1:
|
125
|
+
self.swap_button.config(text="Switch to OneOCR")
|
126
|
+
self.master.title("Furigana Filter Visualizer - Lens")
|
127
|
+
else:
|
128
|
+
self.swap_button.config(text="Switch to Lens")
|
129
|
+
self.master.title("Furigana Filter Visualizer - OneOCR")
|
130
|
+
self.pre_process_word_geometries()
|
131
|
+
self.update_filter_visualization(self.slider.get())
|
132
|
+
|
133
|
+
def pre_process_word_geometries(self):
|
134
|
+
"""
|
135
|
+
Parses the OCR result structure (supports both original and new JSON formats),
|
136
|
+
calculates absolute pixel values, and stores them for high-performance updates.
|
137
|
+
"""
|
138
|
+
img_w, img_h = self.image.size
|
139
|
+
logger.info(f"Processing word geometries for image size {img_w}x{img_h}...")
|
140
|
+
|
141
|
+
# Select the current OCR result
|
142
|
+
ocr_result = self.ocr1_result if self.current_ocr == 1 else self.ocr2_result
|
143
|
+
if not ocr_result:
|
144
|
+
return
|
145
|
+
self.words_data.clear()
|
146
|
+
self.lines_data.clear()
|
147
|
+
|
148
|
+
# Try to detect the format: oneocr has 'lines' as a top-level key
|
149
|
+
if 'lines' in ocr_result:
|
150
|
+
for line in ocr_result.get('lines', []):
|
151
|
+
for word in line.get('words', []):
|
152
|
+
try:
|
153
|
+
bbox = word['bounding_rect']
|
154
|
+
x1 = bbox['x1']
|
155
|
+
y1 = bbox['y1']
|
156
|
+
x2 = bbox['x3']
|
157
|
+
y2 = bbox['y3']
|
158
|
+
px_w = abs(x2 - x1)
|
159
|
+
px_h = abs(y2 - y1)
|
160
|
+
self.words_data.append({
|
161
|
+
'text': word.get('text', ''),
|
162
|
+
'px_w': px_w,
|
163
|
+
'px_h': px_h,
|
164
|
+
'coords': (x1, y1, x2, y2)
|
165
|
+
})
|
166
|
+
except Exception as e:
|
167
|
+
logger.warning(f"Skipping malformed word data (new format): {e}. Data: {word}")
|
168
|
+
continue
|
169
|
+
try:
|
170
|
+
bbox = line['bounding_rect']
|
171
|
+
x1 = bbox['x1']
|
172
|
+
y1 = bbox['y1']
|
173
|
+
x2 = bbox['x3']
|
174
|
+
y2 = bbox['y3']
|
175
|
+
px_w = abs(x2 - x1)
|
176
|
+
px_h = abs(y2 - y1)
|
177
|
+
self.lines_data.append({
|
178
|
+
'text': line.get('text', ''),
|
179
|
+
'px_w': px_w,
|
180
|
+
'px_h': px_h,
|
181
|
+
'coords': (x1, y1, x2, y2)
|
182
|
+
})
|
183
|
+
except Exception as e:
|
184
|
+
logger.warning(f"Skipping malformed line data (new format): {e}. Data: {line}")
|
185
|
+
continue
|
186
|
+
else:
|
187
|
+
# Lens format (nested paragraphs/lines/words)
|
188
|
+
text_layout = ocr_result.get('objects_response', {}).get('text', {}).get('text_layout', {})
|
189
|
+
if not text_layout:
|
190
|
+
logger.error("Could not find 'text_layout' in the OCR response.")
|
191
|
+
return
|
192
|
+
for paragraph in text_layout.get('paragraphs', []):
|
193
|
+
for line in paragraph.get('lines', []):
|
194
|
+
for word in line.get('words', []):
|
195
|
+
try:
|
196
|
+
bbox_pct = word['geometry']['bounding_box']
|
197
|
+
width_pct = bbox_pct['width']
|
198
|
+
height_pct = bbox_pct['height']
|
199
|
+
top_left_x_pct = bbox_pct['center_x'] - (width_pct / 2)
|
200
|
+
top_left_y_pct = bbox_pct['center_y'] - (height_pct / 2)
|
201
|
+
px_w = width_pct * img_w
|
202
|
+
px_h = height_pct * img_h
|
203
|
+
x1 = top_left_x_pct * img_w
|
204
|
+
y1 = top_left_y_pct * img_h
|
205
|
+
x2 = x1 + px_w
|
206
|
+
y2 = y1 + px_h
|
207
|
+
self.words_data.append({
|
208
|
+
'text': word.get('plain_text', ''),
|
209
|
+
'px_w': px_w,
|
210
|
+
'px_h': px_h,
|
211
|
+
'coords': (x1, y1, x2, y2)
|
212
|
+
})
|
213
|
+
except (KeyError, TypeError) as e:
|
214
|
+
logger.warning(f"Skipping malformed word data (orig format): {e}. Data: {word}")
|
215
|
+
continue
|
216
|
+
try:
|
217
|
+
line_bbox = line['geometry']['bounding_box']
|
218
|
+
width_pct = line_bbox['width']
|
219
|
+
height_pct = line_bbox['height']
|
220
|
+
top_left_x_pct = line_bbox['center_x'] - (width_pct / 2)
|
221
|
+
top_left_y_pct = line_bbox['center_y'] - (height_pct / 2)
|
222
|
+
px_w = width_pct * img_w
|
223
|
+
px_h = height_pct * img_h
|
224
|
+
x1 = top_left_x_pct * img_w
|
225
|
+
y1 = top_left_y_pct * img_h
|
226
|
+
x2 = x1 + px_w
|
227
|
+
y2 = y1 + px_h
|
228
|
+
self.lines_data.append({
|
229
|
+
'text': ''.join([w.get('plain_text', '') for w in line.get('words', [])]),
|
230
|
+
'px_w': px_w,
|
231
|
+
'px_h': px_h,
|
232
|
+
'coords': (x1, y1, x2, y2)
|
233
|
+
})
|
234
|
+
except (KeyError, TypeError) as e:
|
235
|
+
logger.warning(f"Skipping malformed line data (orig format): {e}. Data: {line}")
|
236
|
+
continue
|
237
|
+
logger.info(f"Successfully pre-processed {len(self.lines_data)} lines.")
|
238
|
+
|
239
|
+
|
240
|
+
def update_filter_visualization(self, slider_value):
|
241
|
+
"""
|
242
|
+
Called on every slider move. Clears old rectangles and draws new ones
|
243
|
+
for words that pass the sensitivity filter.
|
244
|
+
"""
|
245
|
+
sensitivity = float(slider_value)
|
246
|
+
self.slider_value_label.config(text=f"{sensitivity:.0f} px")
|
247
|
+
|
248
|
+
for rect_id in self.drawn_rects:
|
249
|
+
self.canvas.delete(rect_id)
|
250
|
+
self.drawn_rects.clear()
|
251
|
+
|
252
|
+
for line_data in self.lines_data:
|
253
|
+
if line_data['px_w'] > sensitivity and line_data['px_h'] > sensitivity:
|
254
|
+
x1, y1, x2, y2 = line_data['coords']
|
255
|
+
rect_id = self.canvas.create_rectangle(
|
256
|
+
x1, y1, x2, y2, outline='blue', width=2
|
257
|
+
)
|
258
|
+
self.drawn_rects.append(rect_id)
|
259
|
+
|
260
|
+
def scale_down_width_height(width, height):
|
261
|
+
if width == 0 or height == 0:
|
262
|
+
return width, height
|
263
|
+
aspect_ratio = width / height
|
264
|
+
if aspect_ratio > 2.66:
|
265
|
+
# Ultra-wide (32:9) - use 1920x540
|
266
|
+
return 1920, 540
|
267
|
+
elif aspect_ratio > 2.33:
|
268
|
+
# 21:9 - use 1920x800
|
269
|
+
return 1920, 800
|
270
|
+
elif aspect_ratio > 1.77:
|
271
|
+
# 16:9 - use 1280x720
|
272
|
+
return 1280, 720
|
273
|
+
elif aspect_ratio > 1.6:
|
274
|
+
# 16:10 - use 1280x800
|
275
|
+
return 1280, 800
|
276
|
+
elif aspect_ratio > 1.33:
|
277
|
+
# 4:3 - use 960x720
|
278
|
+
return 960, 720
|
279
|
+
elif aspect_ratio > 1.25:
|
280
|
+
# 5:4 - use 900x720
|
281
|
+
return 900, 720
|
282
|
+
elif aspect_ratio > 1.5:
|
283
|
+
# 3:2 - use 1080x720
|
284
|
+
return 1080, 720
|
285
|
+
else:
|
286
|
+
# Default/fallback - use original resolution
|
287
|
+
print(f"Unrecognized aspect ratio {aspect_ratio}. Using original resolution.")
|
288
|
+
return width, height
|
289
|
+
|
290
|
+
def main():
|
291
|
+
import sys
|
292
|
+
current_furigana_sensitivity = int(sys.argv[1]) if len(sys.argv) > 1 else 0
|
293
|
+
|
294
|
+
"""Main execution function."""
|
295
|
+
try:
|
296
|
+
logger.info("Connecting to OBS...")
|
297
|
+
obs.connect_to_obs_sync()
|
298
|
+
except Exception as e:
|
299
|
+
logger.error(f"Failed to connect to OBS. Please ensure OBS is running and the WebSocket server is enabled. Error: {e}")
|
300
|
+
return
|
301
|
+
|
302
|
+
logger.info("Taking OBS screenshot...")
|
303
|
+
screenshot_img = obs.get_screenshot_PIL(compression=90, img_format='jpg')
|
304
|
+
|
305
|
+
screenshot_img = screenshot_img.resize(scale_down_width_height(screenshot_img.width, screenshot_img.height), Image.LANCZOS)
|
306
|
+
|
307
|
+
if not screenshot_img:
|
308
|
+
logger.error("Failed to get screenshot from OBS.")
|
309
|
+
return
|
310
|
+
|
311
|
+
logger.info(f"Screenshot received ({screenshot_img.width}x{screenshot_img.height}).")
|
312
|
+
|
313
|
+
root = tk.Tk()
|
314
|
+
app = FuriganaFilterVisualizer(root, screenshot_img, current_furigana_sensitivity)
|
315
|
+
|
316
|
+
def ocr_worker():
|
317
|
+
logger.info("Starting OCR process in background thread...")
|
318
|
+
try:
|
319
|
+
ocr1_data, ocr2_data = get_ocr_results_from_image(screenshot_img)
|
320
|
+
root.after(0, app.update_with_ocr_data, ocr1_data, ocr2_data)
|
321
|
+
except Exception as e:
|
322
|
+
logger.error(f"Error in OCR background thread: {e}")
|
323
|
+
root.after(0, app.update_with_ocr_data, None, None)
|
324
|
+
|
325
|
+
threading.Thread(target=ocr_worker, daemon=True).start()
|
326
|
+
|
327
|
+
root.mainloop()
|
328
|
+
|
329
|
+
if __name__ == "__main__":
|
330
|
+
main()
|
@@ -150,9 +150,9 @@ class SileroVADProcessor(VADProcessor):
|
|
150
150
|
|
151
151
|
def _detect_voice_activity(self, input_audio):
|
152
152
|
from silero_vad import read_audio, get_speech_timestamps
|
153
|
-
|
154
|
-
|
155
|
-
wav = read_audio(
|
153
|
+
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
154
|
+
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
155
|
+
wav = read_audio(temp_wav)
|
156
156
|
speech_timestamps = get_speech_timestamps(wav, self.vad_model, return_seconds=True, threshold=0.2)
|
157
157
|
logger.debug(speech_timestamps)
|
158
158
|
return speech_timestamps
|
@@ -173,15 +173,15 @@ class WhisperVADProcessor(VADProcessor):
|
|
173
173
|
|
174
174
|
def _detect_voice_activity(self, input_audio):
|
175
175
|
from stable_whisper import WhisperResult
|
176
|
-
# Convert the audio to 16kHz mono WAV
|
177
|
-
|
178
|
-
|
176
|
+
# Convert the audio to 16kHz mono WAV, evidence https://discord.com/channels/1286409772383342664/1286518821913362445/1407017127529152533
|
177
|
+
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
178
|
+
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
179
179
|
|
180
180
|
logger.info('transcribing audio...')
|
181
181
|
|
182
182
|
# Transcribe the audio using Whisper
|
183
183
|
with warnings.catch_warnings():
|
184
|
-
result: WhisperResult = self.vad_model.transcribe(
|
184
|
+
result: WhisperResult = self.vad_model.transcribe(temp_wav, vad=True, language=get_config().vad.language,
|
185
185
|
temperature=0.0)
|
186
186
|
voice_activity = []
|
187
187
|
|
@@ -376,7 +376,7 @@ vad_processor = VADSystem()
|
|
376
376
|
# Test cases for all VADProcessors
|
377
377
|
def test_vad_processors():
|
378
378
|
logger.setLevel(logging.DEBUG)
|
379
|
-
test_audio = r"C:\Users\Beangate\GSM\GameSentenceMiner\GameSentenceMiner\test\
|
379
|
+
test_audio = r"C:\Users\Beangate\GSM\GameSentenceMiner\GameSentenceMiner\test\NEKOPARAvol.1_2025-08-18-17-20-43-614.opus"
|
380
380
|
output_dir = r"C:\Users\Beangate\GSM\GameSentenceMiner\GameSentenceMiner\test\output"
|
381
381
|
os.makedirs(output_dir, exist_ok=True)
|
382
382
|
processors = [
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/SOURCES.txt
RENAMED
@@ -42,6 +42,7 @@ GameSentenceMiner/owocr/owocr/run.py
|
|
42
42
|
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py
|
43
43
|
GameSentenceMiner/tools/__init__.py
|
44
44
|
GameSentenceMiner/tools/audio_offset_selector.py
|
45
|
+
GameSentenceMiner/tools/furigana_filter_preview.py
|
45
46
|
GameSentenceMiner/tools/ss_selector.py
|
46
47
|
GameSentenceMiner/tools/window_transparency.py
|
47
48
|
GameSentenceMiner/util/__init__.py
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ai/ai_prompting.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/__init__.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon128.png
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon256.png
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/icon512.png
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/assets/pickaxe.png
RENAMED
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/en_us.json
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/ja_jp.json
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/locales/zh_cn.json
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/gsm_ocr_config.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/owocr_area_selector.py
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/ocr/owocr_helper.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/__init__.py
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/__main__.py
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/owocr/owocr/config.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/tools/ss_selector.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/communication/send.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/configuration.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/electron_config.py
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/get_overlay_coords.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/util/notification.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/favicon.ico
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/favicon.svg
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/static/style.css
RENAMED
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/__init__.py
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/index.html
RENAMED
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/templates/utility.html
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner/web/texthooking_page.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/entry_points.txt
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/requires.txt
RENAMED
File without changes
|
{gamesentenceminer-2.14.19 → gamesentenceminer-2.14.21}/GameSentenceMiner.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|