GameSentenceMiner 2.11.6__tar.gz → 2.11.8__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.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/gsm.py +1 -1
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/obs.py +2 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/gsm_ocr_config.py +10 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/owocr_area_selector.py +3 -3
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/owocr_helper.py +73 -19
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/ocr.py +29 -19
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/run.py +159 -44
- gamesentenceminer-2.11.8/GameSentenceMiner/util/electron_config.py +256 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/PKG-INFO +7 -12
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/PKG-INFO +7 -12
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/README.md +6 -11
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/pyproject.toml +1 -1
- gamesentenceminer-2.11.6/GameSentenceMiner/util/electron_config.py +0 -315
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ai/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ai/ai_prompting.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/anki.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon128.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon256.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon32.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon512.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/icon64.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/assets/pickaxe.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/config_gui.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/gametext.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/ss_picker.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/config.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/audio_offset_selector.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/communication/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/communication/send.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/communication/websocket.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/configuration.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/downloader/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/ffmpeg.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/gsm_utils.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/model.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/notification.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/package.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/ss_selector.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/text_log.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/util/window_transparency.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/vad.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/service.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/favicon.ico +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/favicon.svg +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/site.webmanifest +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/style.css +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/templates/index.html +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/templates/utility.html +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/web/texthooking_page.py +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/requires.txt +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner.egg-info/top_level.txt +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/LICENSE +0 -0
- {gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/setup.cfg +0 -0
@@ -12,6 +12,7 @@ from GameSentenceMiner.util.communication.send import send_restart_signal
|
|
12
12
|
from GameSentenceMiner.util.downloader.download_tools import download_obs_if_needed, download_ffmpeg_if_needed
|
13
13
|
from GameSentenceMiner.vad import vad_processor
|
14
14
|
from GameSentenceMiner.util.model import VADResult
|
15
|
+
import time
|
15
16
|
|
16
17
|
try:
|
17
18
|
import os.path
|
@@ -45,7 +46,6 @@ try:
|
|
45
46
|
from GameSentenceMiner.web.texthooking_page import run_text_hooker_page
|
46
47
|
except Exception as e:
|
47
48
|
from GameSentenceMiner.util.configuration import logger, is_linux, is_windows
|
48
|
-
import time
|
49
49
|
logger.info("Something bad happened during import/initialization, closing in 5 seconds")
|
50
50
|
logger.exception(e)
|
51
51
|
time.sleep(5)
|
@@ -334,6 +334,7 @@ async def register_scene_change_callback(callback):
|
|
334
334
|
|
335
335
|
logger.info("Scene change callback registered.")
|
336
336
|
|
337
|
+
|
337
338
|
def get_screenshot(compression=-1):
|
338
339
|
try:
|
339
340
|
screenshot = os.path.join(configuration.get_temporary_directory(), make_unique_file_name('screenshot.png'))
|
@@ -377,6 +378,7 @@ def get_screenshot_base64(compression=0, width=None, height=None):
|
|
377
378
|
logger.error(f"Error getting screenshot: {e}")
|
378
379
|
return None
|
379
380
|
|
381
|
+
|
380
382
|
def update_current_game():
|
381
383
|
gsm_state.current_game = get_current_scene()
|
382
384
|
|
{gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/gsm_ocr_config.py
RENAMED
@@ -131,6 +131,16 @@ def set_dpi_awareness():
|
|
131
131
|
ctypes.windll.shcore.SetProcessDpiAwareness(per_monitor_awareness)
|
132
132
|
|
133
133
|
def get_scene_ocr_config(use_window_as_config=False, window=""):
|
134
|
+
path = get_scene_ocr_config_path(use_window_as_config, window)
|
135
|
+
if not os.path.exists(path):
|
136
|
+
return None
|
137
|
+
with open(path, "r", encoding="utf-8") as f:
|
138
|
+
from json import load
|
139
|
+
data = load(f)
|
140
|
+
ocr_config = OCRConfig.from_dict(data)
|
141
|
+
return ocr_config
|
142
|
+
|
143
|
+
def get_scene_ocr_config_path(use_window_as_config=False, window=""):
|
134
144
|
ocr_config_dir = get_ocr_config_path()
|
135
145
|
try:
|
136
146
|
if use_window_as_config:
|
{gamesentenceminer-2.11.6 → gamesentenceminer-2.11.8}/GameSentenceMiner/ocr/owocr_area_selector.py
RENAMED
@@ -11,7 +11,7 @@ from PIL import Image, ImageTk
|
|
11
11
|
|
12
12
|
# Assuming a mock or real obs module exists in this path
|
13
13
|
from GameSentenceMiner import obs
|
14
|
-
from GameSentenceMiner.ocr.gsm_ocr_config import set_dpi_awareness, get_window,
|
14
|
+
from GameSentenceMiner.ocr.gsm_ocr_config import set_dpi_awareness, get_window, get_scene_ocr_config_path
|
15
15
|
from GameSentenceMiner.util.gsm_utils import sanitize_filename
|
16
16
|
|
17
17
|
try:
|
@@ -123,7 +123,7 @@ class ScreenSelector:
|
|
123
123
|
|
124
124
|
def load_existing_rectangles(self):
|
125
125
|
"""Loads rectangles from config, converting from percentage to absolute pixels for use."""
|
126
|
-
config_path =
|
126
|
+
config_path = get_scene_ocr_config_path(self.use_window_as_config, self.window_name)
|
127
127
|
win_geom = self.target_window_geometry # Use current geometry for conversion
|
128
128
|
win_w, win_h, win_l, win_t = win_geom['width'], win_geom['height'], win_geom['left'], win_geom['top']
|
129
129
|
|
@@ -168,7 +168,7 @@ class ScreenSelector:
|
|
168
168
|
|
169
169
|
def save_rects(self, event=None):
|
170
170
|
"""Saves rectangles to config, converting from absolute pixels to percentages."""
|
171
|
-
config_path =
|
171
|
+
config_path = get_scene_ocr_config_path(self.use_window_as_config, self.window_name)
|
172
172
|
win_geom = self.target_window_geometry
|
173
173
|
win_l, win_t, win_w, win_h = win_geom['left'], win_geom['top'], win_geom['width'], win_geom['height']
|
174
174
|
print(f"Saving rectangles to: {config_path} relative to window: {win_geom}")
|
@@ -18,13 +18,15 @@ from PIL import Image
|
|
18
18
|
from rapidfuzz import fuzz
|
19
19
|
|
20
20
|
from GameSentenceMiner import obs
|
21
|
+
from GameSentenceMiner.util.electron_config import *
|
21
22
|
from GameSentenceMiner.ocr.ss_picker import ScreenCropper
|
22
23
|
from GameSentenceMiner.owocr.owocr.run import TextFiltering
|
23
24
|
from GameSentenceMiner.util.configuration import get_config, get_app_directory, get_temporary_directory
|
24
|
-
from GameSentenceMiner.util.electron_config import get_ocr_scan_rate, get_requires_open_window
|
25
25
|
from GameSentenceMiner.ocr.gsm_ocr_config import OCRConfig, set_dpi_awareness, get_window, get_ocr_config_path
|
26
26
|
from GameSentenceMiner.owocr.owocr import screen_coordinate_picker, run
|
27
27
|
from GameSentenceMiner.util.gsm_utils import sanitize_filename, do_text_replacements, OCR_REPLACEMENTS_FILE
|
28
|
+
import threading
|
29
|
+
import time
|
28
30
|
|
29
31
|
CONFIG_FILE = Path("ocr_config.json")
|
30
32
|
DEFAULT_IMAGE_PATH = r"C:\Users\Beangate\Pictures\msedge_acbl8GL7Ax.jpg" # CHANGE THIS
|
@@ -193,17 +195,17 @@ all_cords = None
|
|
193
195
|
rectangles = None
|
194
196
|
last_ocr2_result = []
|
195
197
|
|
196
|
-
def do_second_ocr(ocr1_text, time, img, filtering, ignore_furigana_filter=False, ignore_previous_result=False):
|
198
|
+
def do_second_ocr(ocr1_text, time, img, filtering, pre_crop_image=None, ignore_furigana_filter=False, ignore_previous_result=False):
|
197
199
|
global twopassocr, ocr2, last_ocr2_result
|
198
200
|
try:
|
199
201
|
orig_text, text = run.process_and_write_results(img, None, last_ocr2_result if not ignore_previous_result else None, filtering, None,
|
200
|
-
engine=
|
202
|
+
engine=get_ocr_ocr2(), furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
|
201
203
|
|
202
204
|
if compare_ocr_results(last_ocr2_result, orig_text):
|
203
205
|
if text:
|
204
206
|
logger.info("Seems like Text we already sent, not doing anything.")
|
205
207
|
return
|
206
|
-
save_result_image(img)
|
208
|
+
save_result_image(img, pre_crop_image=pre_crop_image)
|
207
209
|
last_ocr2_result = orig_text
|
208
210
|
asyncio.run(send_result(text, time))
|
209
211
|
except json.JSONDecodeError:
|
@@ -213,19 +215,19 @@ def do_second_ocr(ocr1_text, time, img, filtering, ignore_furigana_filter=False,
|
|
213
215
|
print(f"Error processing message: {e}")
|
214
216
|
|
215
217
|
|
216
|
-
def save_result_image(img):
|
218
|
+
def save_result_image(img, pre_crop_image=None):
|
217
219
|
if isinstance(img, bytes):
|
218
220
|
with open(os.path.join(get_temporary_directory(), "last_successful_ocr.png"), "wb") as f:
|
219
221
|
f.write(img)
|
220
222
|
else:
|
221
223
|
img.save(os.path.join(get_temporary_directory(), "last_successful_ocr.png"))
|
222
|
-
|
224
|
+
run.set_last_image(pre_crop_image if pre_crop_image else img)
|
223
225
|
|
224
226
|
|
225
227
|
async def send_result(text, time):
|
226
228
|
if text:
|
227
229
|
text = do_text_replacements(text, OCR_REPLACEMENTS_FILE)
|
228
|
-
if
|
230
|
+
if get_ocr_send_to_clipboard():
|
229
231
|
import pyperclip
|
230
232
|
pyperclip.copy(text)
|
231
233
|
try:
|
@@ -244,6 +246,50 @@ previous_orig_text = "" # Store original text result
|
|
244
246
|
TEXT_APPEARENCE_DELAY = get_ocr_scan_rate() * 1000 + 500 # Adjust as needed
|
245
247
|
force_stable = False
|
246
248
|
|
249
|
+
class ConfigChangeCheckThread(threading.Thread):
|
250
|
+
def __init__(self):
|
251
|
+
super().__init__(daemon=True)
|
252
|
+
self.last_changes = None
|
253
|
+
self.callbacks = []
|
254
|
+
|
255
|
+
def run(self):
|
256
|
+
global ocr_config
|
257
|
+
while True:
|
258
|
+
try:
|
259
|
+
section_changed, changes = has_ocr_config_changed()
|
260
|
+
if section_changed:
|
261
|
+
reload_electron_config()
|
262
|
+
self.last_changes = changes
|
263
|
+
# Only run this block after a change has occurred and then the section is stable (no change)
|
264
|
+
if self.last_changes is not None and not section_changed:
|
265
|
+
logger.info(f"Detected config changes: {self.last_changes}")
|
266
|
+
for cb in self.callbacks:
|
267
|
+
cb(self.last_changes)
|
268
|
+
if hasattr(run, 'handle_config_change'):
|
269
|
+
run.handle_config_change()
|
270
|
+
if any(c in self.last_changes for c in ('ocr1', 'ocr2', 'language', 'furigana_filter_sensitivity')):
|
271
|
+
reset_callback_vars()
|
272
|
+
self.last_changes = None
|
273
|
+
except Exception as e:
|
274
|
+
logger.debug(f"ConfigChangeCheckThread error: {e}")
|
275
|
+
time.sleep(0.25) # Lowered to 0.25s for more responsiveness
|
276
|
+
|
277
|
+
def add_callback(self, callback):
|
278
|
+
self.callbacks.append(callback)
|
279
|
+
|
280
|
+
def reset_callback_vars():
|
281
|
+
global previous_text, last_oneocr_time, text_stable_start_time, previous_orig_text, previous_img, force_stable, previous_ocr1_result, previous_text_list, last_ocr2_result
|
282
|
+
previous_text = None
|
283
|
+
previous_orig_text = ""
|
284
|
+
previous_img = None
|
285
|
+
text_stable_start_time = None
|
286
|
+
last_oneocr_time = None
|
287
|
+
force_stable = False
|
288
|
+
previous_ocr1_result = ""
|
289
|
+
previous_text_list = []
|
290
|
+
last_ocr2_result = ""
|
291
|
+
run.set_last_image(None)
|
292
|
+
|
247
293
|
def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering=None, crop_coords=None):
|
248
294
|
global twopassocr, ocr2, previous_text, last_oneocr_time, text_stable_start_time, previous_orig_text, previous_img, force_stable, previous_ocr1_result, previous_text_list
|
249
295
|
orig_text_string = ''.join([item for item in orig_text if item is not None]) if orig_text else ""
|
@@ -251,10 +297,13 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
251
297
|
save_result_image(img)
|
252
298
|
asyncio.run(send_result(text, time))
|
253
299
|
return
|
300
|
+
|
301
|
+
if not text:
|
302
|
+
run.set_last_image(img)
|
254
303
|
|
255
304
|
line_start_time = time if time else datetime.now()
|
256
305
|
|
257
|
-
if manual or not
|
306
|
+
if manual or not get_ocr_two_pass_ocr():
|
258
307
|
if compare_ocr_results(previous_orig_text, orig_text_string):
|
259
308
|
if text:
|
260
309
|
logger.info("Seems like Text we already sent, not doing anything.")
|
@@ -274,6 +323,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
274
323
|
if previous_text and text_stable_start_time:
|
275
324
|
stable_time = text_stable_start_time
|
276
325
|
previous_img_local = previous_img
|
326
|
+
pre_crop_image = previous_img_local
|
277
327
|
if compare_ocr_results(previous_orig_text, orig_text_string):
|
278
328
|
if text:
|
279
329
|
logger.info("Seems like Text we already sent, not doing anything.")
|
@@ -281,10 +331,10 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
281
331
|
return
|
282
332
|
previous_orig_text = orig_text_string
|
283
333
|
previous_ocr1_result = previous_text
|
284
|
-
if crop_coords and
|
334
|
+
if crop_coords and get_ocr_optimize_second_scan():
|
285
335
|
previous_img_local.save(os.path.join(get_temporary_directory(), "pre_oneocrcrop.png"))
|
286
336
|
previous_img_local = previous_img_local.crop(crop_coords)
|
287
|
-
second_ocr_queue.put((previous_text, stable_time, previous_img_local, filtering))
|
337
|
+
second_ocr_queue.put((previous_text, stable_time, previous_img_local, filtering, pre_crop_image))
|
288
338
|
# threading.Thread(target=do_second_ocr, args=(previous_text, stable_time, previous_img_local, filtering), daemon=True).start()
|
289
339
|
previous_img = None
|
290
340
|
previous_text = None
|
@@ -294,7 +344,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
|
|
294
344
|
return
|
295
345
|
|
296
346
|
# Make sure it's an actual new line before starting the timer
|
297
|
-
if compare_ocr_results(orig_text_string, previous_orig_text):
|
347
|
+
if text and compare_ocr_results(orig_text_string, previous_orig_text):
|
298
348
|
return
|
299
349
|
|
300
350
|
if not text_stable_start_time:
|
@@ -315,15 +365,15 @@ def process_task_queue():
|
|
315
365
|
task = second_ocr_queue.get()
|
316
366
|
if task is None: # Exit signal
|
317
367
|
break
|
318
|
-
ocr1_text, stable_time, previous_img_local, filtering = task
|
319
|
-
do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering)
|
368
|
+
ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image = task
|
369
|
+
do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image)
|
320
370
|
except Exception as e:
|
321
371
|
logger.exception(f"Error processing task: {e}")
|
322
372
|
finally:
|
323
373
|
second_ocr_queue.task_done()
|
324
374
|
|
325
375
|
|
326
|
-
def run_oneocr(ocr_config: OCRConfig, rectangles):
|
376
|
+
def run_oneocr(ocr_config: OCRConfig, rectangles, config_check_thread):
|
327
377
|
global done
|
328
378
|
print("Running OneOCR")
|
329
379
|
screen_area = None
|
@@ -344,11 +394,9 @@ def run_oneocr(ocr_config: OCRConfig, rectangles):
|
|
344
394
|
screen_capture_area=screen_area,
|
345
395
|
# screen_capture_monitor=monitor_config['index'],
|
346
396
|
screen_capture_window=ocr_config.window if ocr_config and ocr_config.window else None,
|
347
|
-
screen_capture_only_active_windows=get_requires_open_window(),
|
348
397
|
screen_capture_delay_secs=get_ocr_scan_rate(), engine=ocr1,
|
349
398
|
text_callback=text_callback,
|
350
399
|
screen_capture_exclusions=exclusions,
|
351
|
-
language=language,
|
352
400
|
monitor_index=None,
|
353
401
|
ocr1=ocr1,
|
354
402
|
ocr2=ocr2,
|
@@ -356,7 +404,7 @@ def run_oneocr(ocr_config: OCRConfig, rectangles):
|
|
356
404
|
screen_capture_areas=screen_areas,
|
357
405
|
furigana_filter_sensitivity=furigana_filter_sensitivity,
|
358
406
|
screen_capture_combo=manual_ocr_hotkey if manual_ocr_hotkey and manual else None,
|
359
|
-
|
407
|
+
config_check_thread=config_check_thread)
|
360
408
|
except Exception as e:
|
361
409
|
logger.exception(f"Error running OneOCR: {e}")
|
362
410
|
done = True
|
@@ -366,7 +414,7 @@ def run_oneocr(ocr_config: OCRConfig, rectangles):
|
|
366
414
|
def add_ss_hotkey(ss_hotkey="ctrl+shift+g"):
|
367
415
|
import keyboard
|
368
416
|
secret_ss_hotkey = "F14"
|
369
|
-
filtering = TextFiltering(lang=
|
417
|
+
filtering = TextFiltering(lang=get_ocr_language())
|
370
418
|
cropper = ScreenCropper()
|
371
419
|
def capture():
|
372
420
|
print("Taking screenshot...")
|
@@ -462,6 +510,12 @@ if __name__ == "__main__":
|
|
462
510
|
use_window_for_config = args.use_window_for_config
|
463
511
|
keep_newline = args.keep_newline
|
464
512
|
obs_ocr = args.obs_ocr
|
513
|
+
|
514
|
+
# Start config change checker thread
|
515
|
+
config_check_thread = ConfigChangeCheckThread()
|
516
|
+
config_check_thread.start()
|
517
|
+
# Example: add a callback to config_check_thread if needed
|
518
|
+
# config_check_thread.add_callback(lambda: print("Config changed!"))
|
465
519
|
|
466
520
|
window = None
|
467
521
|
logger.info(f"Received arguments: {vars(args)}")
|
@@ -487,7 +541,7 @@ if __name__ == "__main__":
|
|
487
541
|
if manual or ocr_config:
|
488
542
|
rectangles = ocr_config.rectangles if ocr_config and ocr_config.rectangles else []
|
489
543
|
oneocr_threads = []
|
490
|
-
ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config, rectangles), daemon=True)
|
544
|
+
ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config, rectangles, config_check_thread), daemon=True)
|
491
545
|
ocr_thread.start()
|
492
546
|
if not manual:
|
493
547
|
worker_thread = threading.Thread(target=process_task_queue, daemon=True)
|
@@ -17,6 +17,8 @@ from PIL import Image
|
|
17
17
|
from loguru import logger
|
18
18
|
import requests
|
19
19
|
|
20
|
+
from GameSentenceMiner.util.electron_config import get_ocr_language
|
21
|
+
|
20
22
|
# from GameSentenceMiner.util.configuration import get_temporary_directory
|
21
23
|
|
22
24
|
try:
|
@@ -809,25 +811,8 @@ class OneOCR:
|
|
809
811
|
available = False
|
810
812
|
|
811
813
|
def __init__(self, config={}, lang='ja'):
|
812
|
-
|
813
|
-
|
814
|
-
elif lang == "zh":
|
815
|
-
self.regex = re.compile(r'[\u4E00-\u9FFF]')
|
816
|
-
elif lang == "ko":
|
817
|
-
self.regex = re.compile(r'[\uAC00-\uD7AF]')
|
818
|
-
elif lang == "ar":
|
819
|
-
self.regex = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
|
820
|
-
elif lang == "ru":
|
821
|
-
self.regex = re.compile(r'[\u0400-\u04FF\u0500-\u052F\u2DE0-\u2DFF\uA640-\uA69F\u1C80-\u1C8F]')
|
822
|
-
elif lang == "el":
|
823
|
-
self.regex = re.compile(r'[\u0370-\u03FF\u1F00-\u1FFF]')
|
824
|
-
elif lang == "he":
|
825
|
-
self.regex = re.compile(r'[\u0590-\u05FF\uFB1D-\uFB4F]')
|
826
|
-
elif lang == "th":
|
827
|
-
self.regex = re.compile(r'[\u0E00-\u0E7F]')
|
828
|
-
else:
|
829
|
-
self.regex = re.compile(
|
830
|
-
r'[a-zA-Z\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u1D00-\u1D7F\u1D80-\u1DBF\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF\uAB30-\uAB6F]')
|
814
|
+
self.initial_lang = lang
|
815
|
+
self.get_regex(lang)
|
831
816
|
if sys.platform == 'win32':
|
832
817
|
if int(platform.release()) < 10:
|
833
818
|
logger.warning('OneOCR is not supported on Windows older than 10!')
|
@@ -849,7 +834,32 @@ class OneOCR:
|
|
849
834
|
except:
|
850
835
|
logger.warning('Error reading URL from config, OneOCR will not work!')
|
851
836
|
|
837
|
+
def get_regex(self, lang):
|
838
|
+
if lang == "ja":
|
839
|
+
self.regex = re.compile(r'[\u3041-\u3096\u30A1-\u30FA\u4E00-\u9FFF]')
|
840
|
+
elif lang == "zh":
|
841
|
+
self.regex = re.compile(r'[\u4E00-\u9FFF]')
|
842
|
+
elif lang == "ko":
|
843
|
+
self.regex = re.compile(r'[\uAC00-\uD7AF]')
|
844
|
+
elif lang == "ar":
|
845
|
+
self.regex = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
|
846
|
+
elif lang == "ru":
|
847
|
+
self.regex = re.compile(r'[\u0400-\u04FF\u0500-\u052F\u2DE0-\u2DFF\uA640-\uA69F\u1C80-\u1C8F]')
|
848
|
+
elif lang == "el":
|
849
|
+
self.regex = re.compile(r'[\u0370-\u03FF\u1F00-\u1FFF]')
|
850
|
+
elif lang == "he":
|
851
|
+
self.regex = re.compile(r'[\u0590-\u05FF\uFB1D-\uFB4F]')
|
852
|
+
elif lang == "th":
|
853
|
+
self.regex = re.compile(r'[\u0E00-\u0E7F]')
|
854
|
+
else:
|
855
|
+
self.regex = re.compile(
|
856
|
+
r'[a-zA-Z\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u1D00-\u1D7F\u1D80-\u1DBF\u1E00-\u1EFF\u2C60-\u2C7F\uA720-\uA7FF\uAB30-\uAB6F]')
|
857
|
+
|
852
858
|
def __call__(self, img, furigana_filter_sensitivity=0):
|
859
|
+
lang = get_ocr_language()
|
860
|
+
if lang != self.initial_lang:
|
861
|
+
self.initial_lang = lang
|
862
|
+
self.get_regex(lang)
|
853
863
|
img, is_path = input_to_pil_image(img)
|
854
864
|
if img.width < 51 or img.height < 51:
|
855
865
|
new_width = max(img.width, 51)
|