GameSentenceMiner 2.16.12__py3-none-any.whl → 2.16.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- GameSentenceMiner/config_gui.py +1 -1
- GameSentenceMiner/util/get_overlay_coords.py +78 -11
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/RECORD +8 -8
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/top_level.txt +0 -0
GameSentenceMiner/config_gui.py
CHANGED
|
@@ -417,10 +417,10 @@ class ConfigApp:
|
|
|
417
417
|
self.create_screenshot_tab()
|
|
418
418
|
self.create_audio_tab()
|
|
419
419
|
self.create_obs_tab()
|
|
420
|
-
self.create_profiles_tab()
|
|
421
420
|
self.create_ai_tab()
|
|
422
421
|
self.create_advanced_tab()
|
|
423
422
|
self.create_overlay_tab()
|
|
423
|
+
self.create_profiles_tab()
|
|
424
424
|
# self.create_wip_tab()
|
|
425
425
|
|
|
426
426
|
def add_reset_button(self, frame, category, row, column=0, recreate_tab=None):
|
|
@@ -9,11 +9,11 @@ import time
|
|
|
9
9
|
from PIL import Image
|
|
10
10
|
from typing import Dict, Any, List, Tuple
|
|
11
11
|
import json
|
|
12
|
-
from rapidfuzz
|
|
12
|
+
from rapidfuzz import fuzz
|
|
13
13
|
|
|
14
14
|
# Local application imports
|
|
15
15
|
from GameSentenceMiner.ocr.gsm_ocr_config import set_dpi_awareness
|
|
16
|
-
from GameSentenceMiner.util.configuration import OverlayEngine, get_config, is_windows, is_beangate, logger
|
|
16
|
+
from GameSentenceMiner.util.configuration import OverlayEngine, get_config, get_temporary_directory, is_windows, is_beangate, logger
|
|
17
17
|
from GameSentenceMiner.util.electron_config import get_ocr_language
|
|
18
18
|
from GameSentenceMiner.obs import get_screenshot_PIL
|
|
19
19
|
from GameSentenceMiner.web.texthooking_page import send_word_coordinates_to_overlay
|
|
@@ -93,7 +93,8 @@ class OverlayThread(threading.Thread):
|
|
|
93
93
|
super().__init__()
|
|
94
94
|
self.overlay_processor = OverlayProcessor()
|
|
95
95
|
self.loop = asyncio.new_event_loop()
|
|
96
|
-
self.daemon = True
|
|
96
|
+
self.daemon = True
|
|
97
|
+
self.first_time_run = True
|
|
97
98
|
|
|
98
99
|
def run(self):
|
|
99
100
|
"""Runs the overlay processing loop."""
|
|
@@ -103,11 +104,18 @@ class OverlayThread(threading.Thread):
|
|
|
103
104
|
async def overlay_loop(self):
|
|
104
105
|
"""Main loop to periodically process and send overlay data."""
|
|
105
106
|
while True:
|
|
106
|
-
if
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
if overlay_server_thread.has_clients():
|
|
108
|
+
if get_config().overlay.periodic:
|
|
109
|
+
await self.overlay_processor.find_box_and_send_to_overlay('')
|
|
110
|
+
await asyncio.sleep(get_config().overlay.periodic_interval)
|
|
111
|
+
elif self.first_time_run:
|
|
112
|
+
await self.overlay_processor.find_box_and_send_to_overlay('')
|
|
113
|
+
self.first_time_run = False
|
|
114
|
+
else:
|
|
115
|
+
await asyncio.sleep(3)
|
|
109
116
|
else:
|
|
110
|
-
|
|
117
|
+
self.first_time_run = True
|
|
118
|
+
await asyncio.sleep(3)
|
|
111
119
|
|
|
112
120
|
class OverlayProcessor:
|
|
113
121
|
"""
|
|
@@ -125,6 +133,8 @@ class OverlayProcessor:
|
|
|
125
133
|
self.lens = None
|
|
126
134
|
self.regex = None
|
|
127
135
|
self.ready = False
|
|
136
|
+
self.last_oneocr_result = None
|
|
137
|
+
self.last_lens_result = None
|
|
128
138
|
|
|
129
139
|
try:
|
|
130
140
|
if self.config.overlay.websocket_port and all([GoogleLens, get_regex]):
|
|
@@ -221,6 +231,8 @@ class OverlayProcessor:
|
|
|
221
231
|
monitor = self.get_monitor_workarea(0) # Get primary monitor work area
|
|
222
232
|
sct_img = sct.grab(monitor)
|
|
223
233
|
img = Image.frombytes('RGB', sct_img.size, sct_img.bgra, 'raw', 'BGRX')
|
|
234
|
+
|
|
235
|
+
img.save(os.path.join(get_temporary_directory(), "latest_overlay_screenshot.png"))
|
|
224
236
|
|
|
225
237
|
return img, monitor['width'], monitor['height']
|
|
226
238
|
|
|
@@ -261,6 +273,8 @@ class OverlayProcessor:
|
|
|
261
273
|
paste_x = math.floor(x1)
|
|
262
274
|
paste_y = math.floor(y1)
|
|
263
275
|
composite_img.paste(cropped_image, (paste_x, paste_y))
|
|
276
|
+
|
|
277
|
+
composite_img.save(os.path.join(get_temporary_directory(), "latest_overlay_screenshot_trimmed.png"))
|
|
264
278
|
|
|
265
279
|
return composite_img
|
|
266
280
|
|
|
@@ -277,7 +291,7 @@ class OverlayProcessor:
|
|
|
277
291
|
return []
|
|
278
292
|
if self.oneocr:
|
|
279
293
|
# 2. Use OneOCR to find general text areas (fast)
|
|
280
|
-
|
|
294
|
+
res, text, oneocr_results, crop_coords_list = self.oneocr(
|
|
281
295
|
full_screenshot,
|
|
282
296
|
return_coords=True,
|
|
283
297
|
multiple_crop_coords=True,
|
|
@@ -285,8 +299,19 @@ class OverlayProcessor:
|
|
|
285
299
|
furigana_filter_sensitivity=None, # Disable furigana filtering
|
|
286
300
|
)
|
|
287
301
|
|
|
302
|
+
text_str = "".join([text for text in text if self.regex.match(text)])
|
|
303
|
+
|
|
304
|
+
# RapidFuzz fuzzy match 90% to not send the same results repeatedly
|
|
305
|
+
if self.last_oneocr_result:
|
|
306
|
+
|
|
307
|
+
score = fuzz.ratio(text_str, self.last_oneocr_result)
|
|
308
|
+
if score >= 80:
|
|
309
|
+
logger.info("OneOCR results are similar to the last results (score: %d). Skipping overlay update.", score)
|
|
310
|
+
return
|
|
311
|
+
self.last_oneocr_result = text_str
|
|
312
|
+
|
|
288
313
|
logger.info("Sending OneOCR results to overlay.")
|
|
289
|
-
await send_word_coordinates_to_overlay(oneocr_results)
|
|
314
|
+
await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
|
|
290
315
|
|
|
291
316
|
# If User Home is beangate
|
|
292
317
|
if is_beangate:
|
|
@@ -317,9 +342,19 @@ class OverlayProcessor:
|
|
|
317
342
|
if len(res) != 3:
|
|
318
343
|
return
|
|
319
344
|
|
|
320
|
-
|
|
345
|
+
success, text_list, coords = res
|
|
346
|
+
|
|
347
|
+
text_str = "".join([text for text in text_list if self.regex.match(text)])
|
|
348
|
+
|
|
349
|
+
# RapidFuzz fuzzy match 90% to not send the same results repeatedly
|
|
350
|
+
if self.last_lens_result:
|
|
351
|
+
score = fuzz.ratio(text_str, self.last_lens_result)
|
|
352
|
+
if score >= 80:
|
|
353
|
+
logger.info("Google Lens results are similar to the last results (score: %d). Skipping overlay update.", score)
|
|
354
|
+
return
|
|
355
|
+
self.last_lens_result = text_str
|
|
321
356
|
|
|
322
|
-
if not
|
|
357
|
+
if not success or not coords:
|
|
323
358
|
return
|
|
324
359
|
|
|
325
360
|
# 5. Process the high-accuracy results into the desired format
|
|
@@ -433,6 +468,38 @@ class OverlayProcessor:
|
|
|
433
468
|
"x3": center_x + half_w, "y3": center_y + half_h,
|
|
434
469
|
"x4": center_x - half_w, "y4": center_y + half_h,
|
|
435
470
|
}
|
|
471
|
+
|
|
472
|
+
def _convert_oneocr_results_to_percentages(
|
|
473
|
+
self,
|
|
474
|
+
oneocr_results: List[Dict[str, Any]],
|
|
475
|
+
monitor_width: int,
|
|
476
|
+
monitor_height: int
|
|
477
|
+
) -> List[Dict[str, Any]]:
|
|
478
|
+
"""
|
|
479
|
+
Converts OneOCR results with pixel coordinates to percentages relative to the monitor size.
|
|
480
|
+
"""
|
|
481
|
+
converted_results = []
|
|
482
|
+
for item in oneocr_results:
|
|
483
|
+
bbox = item.get("bounding_rect", {})
|
|
484
|
+
if not bbox:
|
|
485
|
+
continue
|
|
486
|
+
# Convert each coordinate to a percentage of the monitor dimensions
|
|
487
|
+
converted_bbox = {
|
|
488
|
+
key: (value / monitor_width if "x" in key else value / monitor_height)
|
|
489
|
+
for key, value in bbox.items()
|
|
490
|
+
}
|
|
491
|
+
converted_item = item.copy()
|
|
492
|
+
converted_item["bounding_rect"] = converted_bbox
|
|
493
|
+
converted_results.append(converted_item)
|
|
494
|
+
for word in converted_item.get("words", []):
|
|
495
|
+
word_bbox = word.get("bounding_rect", {})
|
|
496
|
+
if word_bbox:
|
|
497
|
+
word["bounding_rect"] = {
|
|
498
|
+
key: (value / monitor_width if "x" in key else value / monitor_height)
|
|
499
|
+
for key, value in word_bbox.items()
|
|
500
|
+
}
|
|
501
|
+
# logger.info(f"Converted OneOCR results to percentages: {converted_results}")
|
|
502
|
+
return converted_results
|
|
436
503
|
|
|
437
504
|
async def main_test_screenshot():
|
|
438
505
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
GameSentenceMiner/anki.py,sha256=Qq03nxYCA0bXS8IR1vnEB9cv2vxo6Ruy-UuiojC4ad0,26518
|
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=
|
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=kyAK3s1tkYmjO_zdJDYWR0rubAsS0vHiT46HdMTxJGk,146121
|
|
4
4
|
GameSentenceMiner/gametext.py,sha256=fgBgLchezpauWELE9Y5G3kVCLfAneD0X4lJFoI3FYbs,10351
|
|
5
5
|
GameSentenceMiner/gsm.py,sha256=1eq5nkYulfm85749g8g2s_WkqqiQWDopUXyimJLIy6M,33814
|
|
6
6
|
GameSentenceMiner/obs.py,sha256=EyAYhaLvMjoeC-3j7fuvkqZN5logFFanPfb8Wn1C6m0,27296
|
|
@@ -41,7 +41,7 @@ GameSentenceMiner/util/configuration.py,sha256=qATOwZahVQNP8-ZnWiAKuR7UJLW25QNDm
|
|
|
41
41
|
GameSentenceMiner/util/db.py,sha256=B2Qwg7i0Qn_yxov-NhcT9QdFkF218Cqea_V7ZPzYBzM,21365
|
|
42
42
|
GameSentenceMiner/util/electron_config.py,sha256=KfeJToeFFVw0IR5MKa-gBzpzaGrU-lyJbR9z-sDEHYU,8767
|
|
43
43
|
GameSentenceMiner/util/ffmpeg.py,sha256=g3v1aJnv3qWekDnO0FdYozB-MG9di4WUvPA3NyXY9Ws,28998
|
|
44
|
-
GameSentenceMiner/util/get_overlay_coords.py,sha256=
|
|
44
|
+
GameSentenceMiner/util/get_overlay_coords.py,sha256=lUD2YU4iVoXRHvQzkCN0Re3IQkYKemU2NV81MtQ94Uk,22028
|
|
45
45
|
GameSentenceMiner/util/gsm_utils.py,sha256=Piwv88Q9av2LBeN7M6QDi0Mp0_R2lNbkcI6ekK5hd2o,11851
|
|
46
46
|
GameSentenceMiner/util/model.py,sha256=R-_RYTYLSDNgBoVTPuPBcIHeOznIqi_vBzQ7VQ20WYk,6727
|
|
47
47
|
GameSentenceMiner/util/notification.py,sha256=YBhf_mSo_i3cjBz-pmeTPx3wchKiG9BK2VBdZSa2prQ,4597
|
|
@@ -90,9 +90,9 @@ GameSentenceMiner/web/templates/utility.html,sha256=KtqnZUMAYs5XsEdC9Tlsd40NKAVi
|
|
|
90
90
|
GameSentenceMiner/web/templates/components/navigation.html,sha256=6y9PvM3nh8LY6JWrZb6zVOm0vqkBLDc6d3gB9X5lT_w,1055
|
|
91
91
|
GameSentenceMiner/web/templates/components/theme-styles.html,sha256=hiq3zdJljpRjQO1iUA7gfFKwXebltG-IWW-gnKS4GHA,3439
|
|
92
92
|
GameSentenceMiner/wip/__init___.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
|
-
gamesentenceminer-2.16.
|
|
94
|
-
gamesentenceminer-2.16.
|
|
95
|
-
gamesentenceminer-2.16.
|
|
96
|
-
gamesentenceminer-2.16.
|
|
97
|
-
gamesentenceminer-2.16.
|
|
98
|
-
gamesentenceminer-2.16.
|
|
93
|
+
gamesentenceminer-2.16.13.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
94
|
+
gamesentenceminer-2.16.13.dist-info/METADATA,sha256=Y5s0ewCxQEPwTEo4MTRyUqaDrfWOiiVfL1qtWDmo-ew,7349
|
|
95
|
+
gamesentenceminer-2.16.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
96
|
+
gamesentenceminer-2.16.13.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
|
97
|
+
gamesentenceminer-2.16.13.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
|
98
|
+
gamesentenceminer-2.16.13.dist-info/RECORD,,
|
|
File without changes
|
{gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{gamesentenceminer-2.16.12.dist-info → gamesentenceminer-2.16.13.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|