GameSentenceMiner 2.19.0__py3-none-any.whl → 2.19.2.dev0__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.
@@ -260,7 +260,7 @@ async def add_line_to_text_log(line, line_time=None):
260
260
  await add_event_to_texthooker(get_text_log()[-1])
261
261
  if get_config().overlay.websocket_port and overlay_server_thread.has_clients():
262
262
  if get_overlay_processor().ready:
263
- await get_overlay_processor().find_box_and_send_to_overlay(current_line_after_regex)
263
+ asyncio.create_task(get_overlay_processor().find_box_and_send_to_overlay(current_line_after_regex))
264
264
  add_srt_line(line_time, new_line)
265
265
  if 'nostatspls' not in new_line.scene.lower():
266
266
  GameLinesTable.add_line(new_line)
@@ -597,6 +597,16 @@
597
597
  "label": "Capture Interval (Seconds):",
598
598
  "tooltip": "Interval in seconds for periodic screen capture."
599
599
  }
600
+ ,
601
+ "periodic_ratio": {
602
+ "label": "Periodic Match Ratio:",
603
+ "tooltip": "Ratio (0-1) used during periodic scanning to determine how much of the region must match to count as detected. Higher = Less Strict, more Scanning."
604
+ }
605
+ ,
606
+ "number_of_local_scans_per_event": {
607
+ "label": "Local Scans Per Text Event:",
608
+ "tooltip": "How many local scans to perform per text event (agent, textractor, etc.) before stopping or sending results to the OCR engine. .1s delay between scans for now."
609
+ }
600
610
  },
601
611
  "wip": {
602
612
  "title": "WIP",
@@ -596,6 +596,16 @@
596
596
  "label": "キャプチャ間隔(秒):",
597
597
  "tooltip": "定期的な画面キャプチャの間隔(秒単位)。"
598
598
  }
599
+ ,
600
+ "periodic_ratio": {
601
+ "label": "定期一致比率:",
602
+ "tooltip": "定期スキャン中に使用される比率 (0-1)。領域がどれだけ一致すれば検出と見なすかを決定します。"
603
+ }
604
+ ,
605
+ "number_of_local_scans_per_event": {
606
+ "label": "イベントごとのローカルスキャン数:",
607
+ "tooltip": "停止するかOCRエンジンに送信する前に、イベントごとに実行するローカルスキャンの回数。"
608
+ }
599
609
  },
600
610
  "wip": {
601
611
  "title": "WIP",
@@ -585,6 +585,16 @@
585
585
  "label": "捕获间隔(秒):",
586
586
  "tooltip": "定期屏幕捕获的时间间隔(秒)。"
587
587
  }
588
+ ,
589
+ "periodic_ratio": {
590
+ "label": "定期匹配比率:",
591
+ "tooltip": "在定期扫描期间使用的比率(0-1),用于确定区域匹配多少才算检测到。"
592
+ }
593
+ ,
594
+ "number_of_local_scans_per_event": {
595
+ "label": "每次事件本地扫描数:",
596
+ "tooltip": "在停止或将结果发送到OCR引擎之前,每个事件执行的本地扫描次数。"
597
+ }
588
598
  },
589
599
  "wip": {
590
600
  "title": "WIP",
@@ -512,9 +512,11 @@ class ConfigApp:
512
512
  self.overlay_websocket_send_value = tk.BooleanVar(value=self.settings.overlay.monitor_to_capture)
513
513
  self.overlay_engine_value = tk.StringVar(value=self.settings.overlay.engine)
514
514
  self.periodic_value = tk.BooleanVar(value=self.settings.overlay.periodic)
515
+ self.periodic_ratio_value = tk.StringVar(value=str(self.settings.overlay.periodic_ratio))
515
516
  self.periodic_interval_value = tk.StringVar(value=str(self.settings.overlay.periodic_interval))
516
517
  self.scan_delay_value = tk.StringVar(value=str(self.settings.overlay.scan_delay))
517
518
  self.overlay_minimum_character_size_value = tk.StringVar(value=str(self.settings.overlay.minimum_character_size))
519
+ self.number_of_local_scans_per_event_value = tk.StringVar(value=str(getattr(self.settings.overlay, 'number_of_local_scans_per_event', 1)))
518
520
 
519
521
  # Master Config Settings
520
522
  self.switch_to_default_if_not_found_value = tk.BooleanVar(value=self.master_config.switch_to_default_if_not_found)
@@ -616,6 +618,28 @@ class ConfigApp:
616
618
  self.sync_changes_checkbutton.state(['!selected'])
617
619
 
618
620
  # Create a new Config instance
621
+ # Validate and clamp periodic_ratio to [0.0, 1.0]
622
+ try:
623
+ _periodic_ratio = float(self.periodic_ratio_value.get())
624
+ except Exception:
625
+ _periodic_ratio = 0.9
626
+ # clamp
627
+ if _periodic_ratio < 0.0:
628
+ _periodic_ratio = 0.0
629
+ if _periodic_ratio > 1.0:
630
+ _periodic_ratio = 1.0
631
+ # reflect back to UI variable (keep consistent formatting)
632
+ self.periodic_ratio_value.set(str(_periodic_ratio))
633
+
634
+ # Validate and clamp number_of_local_scans_per_event to positive integer
635
+ try:
636
+ _local_scans = int(float(self.number_of_local_scans_per_event_value.get()))
637
+ except Exception:
638
+ _local_scans = int(getattr(self.settings.overlay, 'number_of_local_scans_per_event', 1))
639
+ if _local_scans < 1:
640
+ _local_scans = 1
641
+ self.number_of_local_scans_per_event_value.set(str(_local_scans))
642
+
619
643
  config = ProfileConfig(
620
644
  scenes=self.settings.scenes,
621
645
  general=General(
@@ -754,7 +778,9 @@ class ConfigApp:
754
778
  engine=OverlayEngine(self.overlay_engine_value.get()).value if self.overlay_engine_value.get() else OverlayEngine.LENS.value,
755
779
  scan_delay=float(self.scan_delay_value.get()),
756
780
  periodic=float(self.periodic_value.get()),
781
+ periodic_ratio=_periodic_ratio,
757
782
  periodic_interval=float(self.periodic_interval_value.get()),
783
+ number_of_local_scans_per_event=int(self.number_of_local_scans_per_event_value.get()),
758
784
  minimum_character_size=int(self.overlay_minimum_character_size_value.get()),
759
785
  )
760
786
  # wip=WIP(
@@ -2434,6 +2460,22 @@ class ConfigApp:
2434
2460
  ttk.Entry(overlay_frame, textvariable=self.periodic_interval_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2435
2461
  self.current_row += 1
2436
2462
 
2463
+ # Periodic Ratio (how much of the screen must match to count)
2464
+ periodic_ratio_i18n = overlay_i18n.get('periodic_ratio', {})
2465
+ HoverInfoLabelWidget(overlay_frame, text=periodic_ratio_i18n.get('label', 'Periodic Ratio:'),
2466
+ tooltip=periodic_ratio_i18n.get('tooltip', 'Ratio (0-1) used during periodic scanning to determine matching threshold.'),
2467
+ row=self.current_row, column=0)
2468
+ ttk.Entry(overlay_frame, textvariable=self.periodic_ratio_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2469
+ self.current_row += 1
2470
+
2471
+ # Number of Local Scans Per Event
2472
+ local_scans_i18n = overlay_i18n.get('number_of_local_scans_per_event', {})
2473
+ HoverInfoLabelWidget(overlay_frame, text=local_scans_i18n.get('label', 'Local Scans Per Event:'),
2474
+ tooltip=local_scans_i18n.get('tooltip', 'How many local scans to perform per event before stopping or sending to lens.'),
2475
+ row=self.current_row, column=0)
2476
+ ttk.Entry(overlay_frame, textvariable=self.number_of_local_scans_per_event_value).grid(row=self.current_row, column=1, sticky='EW', pady=2)
2477
+ self.current_row += 1
2478
+
2437
2479
  # Minimum Character Size
2438
2480
  minimum_character_size_i18n = overlay_i18n.get('minimum_character_size', {})
2439
2481
  HoverInfoLabelWidget(overlay_frame, text=minimum_character_size_i18n.get('label', 'Minimum Character Size:'),
@@ -675,8 +675,10 @@ class Overlay:
675
675
  monitor_to_capture: int = 0
676
676
  periodic: bool = False
677
677
  periodic_interval: float = 1.0
678
+ periodic_ratio: float = 0.9
678
679
  scan_delay: float = 0.25
679
680
  minimum_character_size: int = 0
681
+ number_of_local_scans_per_event: int = 1
680
682
 
681
683
  def __post_init__(self):
682
684
  if self.monitor_to_capture == -1:
@@ -330,56 +330,64 @@ class OverlayProcessor:
330
330
  # Check for cancellation after screenshot
331
331
  if asyncio.current_task().cancelled():
332
332
  raise asyncio.CancelledError()
333
-
333
+
334
334
  if self.oneocr:
335
- # 2. Use OneOCR to find general text areas (fast)
336
- res, text, oneocr_results, crop_coords_list = self.oneocr(
337
- full_screenshot,
338
- return_coords=True,
339
- multiple_crop_coords=True,
340
- return_one_box=False,
341
- furigana_filter_sensitivity=get_overlay_config().minimum_character_size,
342
- )
343
-
344
- if not crop_coords_list:
345
- return
346
-
347
- # Check for cancellation after OneOCR
348
- if asyncio.current_task().cancelled():
349
- raise asyncio.CancelledError()
350
-
351
- text_str = "".join([text for text in text if self.regex.match(text)])
352
-
353
- # RapidFuzz fuzzy match 90% to not send the same results repeatedly
354
- if self.last_oneocr_result and check_against_last:
335
+ tries = get_overlay_config().number_of_local_scans_per_event if not check_against_last else 1
336
+ for i in range(tries):
337
+ if i > 0:
338
+ try:
339
+ await asyncio.sleep(0.1)
340
+ except asyncio.CancelledError:
341
+ logger.info("OCR task cancelled during local scan delay")
342
+ raise
343
+ # 2. Use OneOCR to find general text areas (fast)
344
+ res, text, oneocr_results, crop_coords_list = self.oneocr(
345
+ full_screenshot,
346
+ return_coords=True,
347
+ multiple_crop_coords=True,
348
+ return_one_box=False,
349
+ furigana_filter_sensitivity=get_overlay_config().minimum_character_size,
350
+ )
351
+
352
+ if not crop_coords_list:
353
+ return
354
+
355
+ # Check for cancellation after OneOCR
356
+ if asyncio.current_task().cancelled():
357
+ raise asyncio.CancelledError()
355
358
 
356
- score = fuzz.ratio(text_str, self.last_oneocr_result)
357
- if score >= 80:
359
+ text_str = "".join([text for text in text if self.regex.match(text)])
360
+
361
+ # RapidFuzz fuzzy match 90% to not send the same results repeatedly
362
+ if self.last_oneocr_result and check_against_last:
363
+
364
+ score = fuzz.ratio(text_str, self.last_oneocr_result)
365
+ if score >= get_config().overlay.periodic_ratio * 100:
366
+ return
367
+ self.last_oneocr_result = text_str
368
+
369
+ await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
370
+
371
+ # If User Home is beangate
372
+ if is_beangate:
373
+ with open("oneocr_results.json", "w", encoding="utf-8") as f:
374
+ f.write(json.dumps(oneocr_results, ensure_ascii=False, indent=2))
375
+
376
+ if get_config().overlay.engine == OverlayEngine.ONEOCR.value and self.oneocr:
377
+ logger.info("Sent %d text boxes to overlay.", len(oneocr_results))
358
378
  return
359
- self.last_oneocr_result = text_str
360
379
 
361
- await send_word_coordinates_to_overlay(self._convert_oneocr_results_to_percentages(oneocr_results, monitor_width, monitor_height))
362
-
363
- # If User Home is beangate
364
- if is_beangate:
365
- with open("oneocr_results.json", "w", encoding="utf-8") as f:
366
- f.write(json.dumps(oneocr_results, ensure_ascii=False, indent=2))
367
-
368
- if get_config().overlay.engine == OverlayEngine.ONEOCR.value and self.oneocr:
369
- logger.info("Sent %d text boxes to overlay.", len(oneocr_results))
370
- return
380
+ # Check for cancellation before creating composite image
381
+ if asyncio.current_task().cancelled():
382
+ raise asyncio.CancelledError()
371
383
 
372
- # Check for cancellation before creating composite image
373
- if asyncio.current_task().cancelled():
374
- raise asyncio.CancelledError()
375
-
376
- # 3. Create a composite image with only the detected text regions
377
- composite_image = self._create_composite_image(
378
- full_screenshot,
379
- crop_coords_list,
380
- monitor_width,
381
- monitor_height
382
- )
384
+ # 3. Create a composite image with only the detected text regions
385
+ composite_image = self._create_composite_image(
386
+ full_screenshot,
387
+ crop_coords_list,
388
+ monitor_width,
389
+ monitor_height
390
+ )
383
391
  else:
384
392
  composite_image = full_screenshot
385
393
 
@@ -408,7 +416,7 @@ class OverlayProcessor:
408
416
  # RapidFuzz fuzzy match 90% to not send the same results repeatedly
409
417
  if self.last_lens_result and check_against_last:
410
418
  score = fuzz.ratio(text_str, self.last_lens_result)
411
- if score >= 80:
419
+ if score >= get_config().overlay.periodic_ratio * 100:
412
420
  logger.info("Google Lens results are similar to the last results (score: %d). Skipping overlay update.", score)
413
421
  return
414
422
  self.last_lens_result = text_str