GameSentenceMiner 2.15.9__py3-none-any.whl → 2.15.10__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.
@@ -83,7 +83,7 @@ class OCRConfig:
83
83
  ]
84
84
 
85
85
  def scale_to_custom_size(self, width, height):
86
- self.rectangles = self.pre_scale_rectangles.copy()
86
+ self.rectangles = deepcopy(self.pre_scale_rectangles)
87
87
  if self.coordinate_system and self.coordinate_system == "percentage":
88
88
  for rectangle in self.rectangles:
89
89
  rectangle.coordinates = [
@@ -424,13 +424,14 @@ def get_ocr2_image(crop_coords, og_image, ocr2_engine=None):
424
424
  if not crop_coords or not get_ocr_optimize_second_scan():
425
425
  return og_image
426
426
  x1, y1, x2, y2 = crop_coords
427
- x1 = max(0, min(x1, og_image.width))
428
- y1 = max(0, min(y1, og_image.height))
429
- x2 = max(x1, min(x2, og_image.width))
430
- y2 = max(y1, min(y2, og_image.height))
427
+ x1 = min(max(0, x1), img.width)
428
+ y1 = min(max(0, y1), img.height)
429
+ x2 = min(max(0, x2), img.width)
430
+ y2 = min(max(0, y2), img.height)
431
431
  og_image.save(os.path.join(get_temporary_directory(), "pre_oneocrcrop.png"))
432
432
  return og_image.crop((x1, y1, x2, y2))
433
433
 
434
+ # TODO Get rid of this check, and just always convert to full res
434
435
  LOCAL_OCR_ENGINES = ['easyocr', 'oneocr', 'rapidocr', 'mangaocr', 'winrtocr']
435
436
  local_ocr = ocr2_engine in LOCAL_OCR_ENGINES
436
437
  ocr_config_local = copy(ocr_config)
@@ -444,10 +445,17 @@ def get_ocr2_image(crop_coords, og_image, ocr2_engine=None):
444
445
  obs_height = getattr(run.obs_screenshot_thread, 'height', None)
445
446
  if not obs_width or not obs_height:
446
447
  return return_original_image()
448
+
447
449
  logger.debug(f"Getting OCR2 image with OBS dimensions: {obs_width}x{obs_height}")
448
450
 
449
451
  img = obs.get_screenshot_PIL(compression=100, img_format="jpg")
452
+
450
453
  ocr_config_local.scale_to_custom_size(img.width, img.height)
454
+
455
+ # If img.width and height is the same as obs, no need to scale coords, tolerance of .1%
456
+ if abs(img.width - obs_width) <= 0.1 * obs_width and abs(img.height - obs_height) <= 0.1 * obs_height:
457
+ logger.info("Image size matches OBS size, no need to scale coordinates.")
458
+ return return_original_image()
451
459
 
452
460
  # If no crop or optimization, just apply config and return
453
461
  if not crop_coords or not get_ocr_optimize_second_scan():
@@ -464,18 +472,19 @@ def get_ocr2_image(crop_coords, og_image, ocr2_engine=None):
464
472
  y1 = int(crop_coords[1] * height_ratio)
465
473
  x2 = int(crop_coords[2] * width_ratio)
466
474
  y2 = int(crop_coords[3] * height_ratio)
467
- logger.debug(f"Scaled crop coordinates: {(x1, y1, x2, y2)}")
468
475
 
469
476
  # Clamp coordinates to image bounds
470
- x1 = max(0, min(x1, img.width))
471
- y1 = max(0, min(y1, img.height))
472
- x2 = max(x1, min(x2, img.width))
473
- y2 = max(y1, min(y2, img.height))
474
-
475
- img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=False)
477
+ x1 = min(max(0, x1), img.width)
478
+ y1 = min(max(0, y1), img.height)
479
+ x2 = min(max(0, x2), img.width)
480
+ y2 = min(max(0, y2), img.height)
476
481
 
482
+ logger.debug(f"Scaled crop coordinates: {(x1, y1, x2, y2)}")
483
+
484
+ img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=False)
477
485
 
478
- return img.crop((x1, y1, x2, y2))
486
+ ret = img.crop((x1, y1, x2, y2))
487
+ return ret
479
488
 
480
489
  def process_task_queue():
481
490
  while True:
@@ -1029,11 +1029,11 @@ class OBSScreenshotThread(threading.Thread):
1029
1029
  "sceneItemTransform").get("sourceWidth") or self.width
1030
1030
  self.source_height = self.current_source.get(
1031
1031
  "sceneItemTransform").get("sourceHeight") or self.height
1032
- if self.source_width and self.source_height and not self.is_manual_ocr and not get_ocr_two_pass_ocr():
1032
+ if self.source_width and self.source_height and not self.is_manual_ocr and get_ocr_two_pass_ocr():
1033
1033
  self.width, self.height = scale_down_width_height(
1034
1034
  self.source_width, self.source_height)
1035
1035
  logger.info(
1036
- f"Using OBS source dimensions: {self.source_width}x{self.source_height}")
1036
+ f"Using OBS source dimensions: {self.width}x{self.height}")
1037
1037
  else:
1038
1038
  self.width = self.source_width or 1280
1039
1039
  self.height = self.source_height or 720
@@ -585,6 +585,9 @@ class Advanced:
585
585
  multi_line_sentence_storage_field: str = ''
586
586
  ocr_websocket_port: int = 9002
587
587
  texthooker_communication_websocket_port: int = 55001
588
+ afk_timer_seconds: int = 120
589
+ session_gap_seconds: int = 3600
590
+ streak_requirement_hours: float = 0.01 # 1 second required per day to keep your streak by default
588
591
 
589
592
  def __post_init__(self):
590
593
  if self.plaintext_websocket_port == -1:
@@ -119,7 +119,7 @@ def strip_whitespace_and_punctuation(text: str) -> str:
119
119
  return re.sub(r'[\s 、。「」【】《》., ]', '', text).strip()
120
120
 
121
121
 
122
- def lines_match(texthooker_sentence, anki_sentence):
122
+ def lines_match(texthooker_sentence, anki_sentence, similarity_threshold=80) -> bool:
123
123
  # Replace newlines, spaces, other whitespace characters, AND japanese punctuation
124
124
  texthooker_sentence = strip_whitespace_and_punctuation(texthooker_sentence)
125
125
  anki_sentence = strip_whitespace_and_punctuation(anki_sentence)
@@ -129,7 +129,7 @@ def lines_match(texthooker_sentence, anki_sentence):
129
129
  logger.debug(f"One contains the other: {texthooker_sentence} in {anki_sentence} - Similarity: {similarity}")
130
130
  elif anki_sentence in texthooker_sentence:
131
131
  logger.debug(f"One contains the other: {anki_sentence} in {texthooker_sentence} - Similarity: {similarity}")
132
- return (anki_sentence in texthooker_sentence) or (texthooker_sentence in anki_sentence) or (similarity >= 80)
132
+ return (anki_sentence in texthooker_sentence) or (texthooker_sentence in anki_sentence) or (similarity >= similarity_threshold)
133
133
 
134
134
 
135
135
  def get_text_event(last_note) -> GameLine: