GameSentenceMiner 2.10.11__py3-none-any.whl → 2.10.12__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.
@@ -80,6 +80,7 @@ class ConfigApp:
80
80
  def __init__(self, root):
81
81
  self.window = root
82
82
  self.on_exit = None
83
+ self.window.tk.call('tk', 'scaling', 1.5) # Set DPI scaling factor
83
84
  # self.window = ttk.Window(themename='darkly')
84
85
  self.window.title('GameSentenceMiner Configuration')
85
86
  self.window.protocol("WM_DELETE_WINDOW", self.hide)
@@ -44,13 +44,13 @@ class WindowGeometry:
44
44
  class OCRConfig:
45
45
  scene: str
46
46
  rectangles: List[Rectangle]
47
- pre_scale_rectangles: List[Rectangle] = None
47
+ pre_scale_rectangles: Optional[List[Rectangle]] = None
48
48
  coordinate_system: str = None
49
49
  window_geometry: Optional[WindowGeometry] = None
50
50
  window: Optional[str] = None
51
51
  language: str = "ja"
52
52
 
53
- def __post_init__(self):
53
+ def scale_coords(self):
54
54
  self.pre_scale_rectangles = deepcopy(self.rectangles)
55
55
  if self.coordinate_system and self.coordinate_system == "percentage" and self.window:
56
56
  import pygetwindow as gw
@@ -178,17 +178,28 @@ class WebsocketServerThread(threading.Thread):
178
178
  asyncio.run(main())
179
179
 
180
180
 
181
+ def compare_ocr_results(prev_text, new_text, threshold=90):
182
+ if not prev_text or not new_text:
183
+ return False
184
+ if isinstance(prev_text, list):
185
+ prev_text = ''.join([item for item in prev_text if item is not None]) if prev_text else ""
186
+ if isinstance(new_text, list):
187
+ new_text = ''.join([item for item in new_text if item is not None]) if new_text else ""
188
+ similarity = fuzz.ratio(prev_text, new_text)
189
+ return similarity >= threshold
190
+
181
191
  all_cords = None
182
192
  rectangles = None
183
- last_ocr2_result = ""
193
+ last_ocr2_result = []
184
194
 
185
195
  def do_second_ocr(ocr1_text, time, img, filtering, ignore_furigana_filter=False):
186
196
  global twopassocr, ocr2, last_ocr2_result
187
197
  try:
188
198
  orig_text, text = run.process_and_write_results(img, None, last_ocr2_result, filtering, None,
189
199
  engine=ocr2, furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
190
- if fuzz.ratio(last_ocr2_result, orig_text) >= 90:
191
- logger.info("Seems like the same text from previous ocr2 result, not sending")
200
+
201
+ if compare_ocr_results(last_ocr2_result, orig_text):
202
+ logger.info("Detected similar text from previous OCR2 result, not sending")
192
203
  return
193
204
  save_result_image(img)
194
205
  last_ocr2_result = orig_text
@@ -242,7 +253,7 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
242
253
  line_start_time = time if time else datetime.now()
243
254
 
244
255
  if manual or not twopassocr:
245
- if previous_text and fuzz.ratio(orig_text_string, previous_orig_text) >= 90:
256
+ if compare_ocr_results(previous_orig_text, orig_text_string):
246
257
  logger.info("Seems like Text we already sent, not doing anything.")
247
258
  return
248
259
  save_result_image(img)
@@ -260,13 +271,13 @@ def text_callback(text, orig_text, time, img=None, came_from_ss=False, filtering
260
271
  if previous_text and text_stable_start_time:
261
272
  stable_time = text_stable_start_time
262
273
  previous_img_local = previous_img
263
- if previous_text and fuzz.ratio(orig_text_string, previous_orig_text) >= 90:
274
+ if compare_ocr_results(previous_orig_text, orig_text_string):
264
275
  logger.info("Seems like Text we already sent, not doing anything.")
265
276
  previous_text = None
266
277
  return
267
278
  previous_orig_text = orig_text_string
268
279
  previous_ocr1_result = previous_text
269
- if crop_coords:
280
+ if crop_coords and optimize_second_scan:
270
281
  previous_img_local.save(os.path.join(get_temporary_directory(), "pre_oneocrcrop.png"))
271
282
  previous_img_local = previous_img_local.crop(crop_coords)
272
283
  second_ocr_queue.put((previous_text, stable_time, previous_img_local, filtering))
@@ -389,70 +400,88 @@ def set_force_stable_hotkey():
389
400
  print("Press Ctrl+Shift+F to toggle force stable mode.")
390
401
 
391
402
  if __name__ == "__main__":
392
- global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window
393
- import sys
394
-
395
- import argparse
396
-
397
- parser = argparse.ArgumentParser(description="OCR Configuration")
398
- parser.add_argument("--language", type=str, default="ja", help="Language for OCR (default: ja)")
399
- parser.add_argument("--ocr1", type=str, default="oneocr", help="Primary OCR engine (default: oneocr)")
400
- parser.add_argument("--ocr2", type=str, default="glens", help="Secondary OCR engine (default: glens)")
401
- parser.add_argument("--twopassocr", type=int, choices=[0, 1], default=1, help="Enable two-pass OCR (default: 1)")
402
- parser.add_argument("--manual", action="store_true", help="Use screenshot-only mode")
403
- parser.add_argument("--clipboard", action="store_true", help="Use clipboard for input")
404
- parser.add_argument("--clipboard-output", action="store_true", default=False, help="Use clipboard for output")
405
- parser.add_argument("--window", type=str, help="Specify the window name for OCR")
406
- parser.add_argument("--furigana_filter_sensitivity", type=float, default=0, help="Furigana Filter Sensitivity for OCR (default: 0)")
407
- parser.add_argument("--manual_ocr_hotkey", type=str, default=None, help="Hotkey for manual OCR (default: None)")
408
- parser.add_argument("--area_select_ocr_hotkey", type=str, default="ctrl+shift+o", help="Hotkey for area selection OCR (default: ctrl+shift+o)")
409
-
410
- args = parser.parse_args()
411
-
412
- language = args.language
413
- ocr1 = args.ocr1
414
- ocr2 = args.ocr2 if args.ocr2 else None
415
- twopassocr = bool(args.twopassocr)
416
- manual = args.manual
417
- ss_clipboard = args.clipboard
418
- window_name = args.window
419
- furigana_filter_sensitivity = args.furigana_filter_sensitivity
420
- ss_hotkey = args.area_select_ocr_hotkey.lower()
421
- manual_ocr_hotkey = args.manual_ocr_hotkey.lower().replace("ctrl", "<ctrl>").replace("shift", "<shift>").replace("alt", "<alt>") if args.manual_ocr_hotkey else None
422
- clipboard_output = args.clipboard_output
423
-
424
- logger.info(f"Received arguments: {vars(args)}")
425
- # set_force_stable_hotkey()
426
- ocr_config: OCRConfig = get_ocr_config(window=window_name)
427
- if ocr_config:
428
- if ocr_config.window:
429
- start_time = time.time()
430
- while time.time() - start_time < 30:
431
- window = get_window(ocr_config.window)
432
- if window or manual:
433
- break
434
- logger.info(f"Window: {ocr_config.window} Could not be found, retrying in 1 second...")
435
- time.sleep(1)
436
- else:
437
- logger.error(f"Window '{ocr_config.window}' not found within 30 seconds.")
438
- sys.exit(1)
439
- logger.info(f"Starting OCR with configuration: Window: {ocr_config.window}, Rectangles: {ocr_config.rectangles}, Engine 1: {ocr1}, Engine 2: {ocr2}, Two-pass OCR: {twopassocr}")
440
- set_dpi_awareness()
441
- if manual or ocr_config:
442
- rectangles = ocr_config.rectangles if ocr_config and ocr_config.rectangles else []
443
- oneocr_threads = []
444
- ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config,rectangles ), daemon=True)
445
- ocr_thread.start()
446
- if not manual:
447
- worker_thread = threading.Thread(target=process_task_queue, daemon=True)
448
- worker_thread.start()
449
- websocket_server_thread = WebsocketServerThread(read=True)
450
- websocket_server_thread.start()
451
- add_ss_hotkey(ss_hotkey)
452
- try:
453
- while not done:
454
- time.sleep(1)
455
- except KeyboardInterrupt as e:
456
- pass
457
- else:
458
- print("Failed to load OCR configuration. Please check the logs.")
403
+ try:
404
+ global ocr1, ocr2, twopassocr, language, ss_clipboard, ss, ocr_config, furigana_filter_sensitivity, area_select_ocr_hotkey, window, optimize_second_scan
405
+ import sys
406
+
407
+ import argparse
408
+
409
+ parser = argparse.ArgumentParser(description="OCR Configuration")
410
+ parser.add_argument("--language", type=str, default="ja", help="Language for OCR (default: ja)")
411
+ parser.add_argument("--ocr1", type=str, default="oneocr", help="Primary OCR engine (default: oneocr)")
412
+ parser.add_argument("--ocr2", type=str, default="glens", help="Secondary OCR engine (default: glens)")
413
+ parser.add_argument("--twopassocr", type=int, choices=[0, 1], default=1,
414
+ help="Enable two-pass OCR (default: 1)")
415
+ parser.add_argument("--manual", action="store_true", help="Use screenshot-only mode")
416
+ parser.add_argument("--clipboard", action="store_true", help="Use clipboard for input")
417
+ parser.add_argument("--clipboard-output", action="store_true", default=False, help="Use clipboard for output")
418
+ parser.add_argument("--window", type=str, help="Specify the window name for OCR")
419
+ parser.add_argument("--furigana_filter_sensitivity", type=float, default=0,
420
+ help="Furigana Filter Sensitivity for OCR (default: 0)")
421
+ parser.add_argument("--manual_ocr_hotkey", type=str, default=None, help="Hotkey for manual OCR (default: None)")
422
+ parser.add_argument("--area_select_ocr_hotkey", type=str, default="ctrl+shift+o",
423
+ help="Hotkey for area selection OCR (default: ctrl+shift+o)")
424
+ parser.add_argument("--optimize_second_scan", action="store_true",
425
+ help="Optimize second scan by cropping based on first scan results")
426
+
427
+ args = parser.parse_args()
428
+
429
+ language = args.language
430
+ ocr1 = args.ocr1
431
+ ocr2 = args.ocr2 if args.ocr2 else None
432
+ twopassocr = bool(args.twopassocr)
433
+ manual = args.manual
434
+ ss_clipboard = args.clipboard
435
+ window_name = args.window
436
+ furigana_filter_sensitivity = args.furigana_filter_sensitivity
437
+ ss_hotkey = args.area_select_ocr_hotkey.lower()
438
+ manual_ocr_hotkey = args.manual_ocr_hotkey.lower().replace("ctrl", "<ctrl>").replace("shift",
439
+ "<shift>").replace(
440
+ "alt", "<alt>") if args.manual_ocr_hotkey else None
441
+ clipboard_output = args.clipboard_output
442
+ optimize_second_scan = args.optimize_second_scan
443
+
444
+ window = None
445
+ logger.info(f"Received arguments: {vars(args)}")
446
+ # set_force_stable_hotkey()
447
+ ocr_config: OCRConfig = get_ocr_config(window=window_name)
448
+ if ocr_config:
449
+ if ocr_config.window:
450
+ start_time = time.time()
451
+ while time.time() - start_time < 30:
452
+ window = get_window(ocr_config.window)
453
+ if window or manual:
454
+ if window:
455
+ ocr_config.scale_coords()
456
+ break
457
+ logger.info(f"Window: {ocr_config.window} Could not be found, retrying in 1 second...")
458
+ time.sleep(1)
459
+ else:
460
+ logger.error(f"Window '{ocr_config.window}' not found within 30 seconds.")
461
+ sys.exit(1)
462
+ logger.info(
463
+ f"Starting OCR with configuration: Window: {ocr_config.window}, Rectangles: {ocr_config.rectangles}, Engine 1: {ocr1}, Engine 2: {ocr2}, Two-pass OCR: {twopassocr}")
464
+ set_dpi_awareness()
465
+ if manual or ocr_config:
466
+ rectangles = ocr_config.rectangles if ocr_config and ocr_config.rectangles else []
467
+ oneocr_threads = []
468
+ ocr_thread = threading.Thread(target=run_oneocr, args=(ocr_config, rectangles), daemon=True)
469
+ ocr_thread.start()
470
+ if not manual:
471
+ worker_thread = threading.Thread(target=process_task_queue, daemon=True)
472
+ worker_thread.start()
473
+ websocket_server_thread = WebsocketServerThread(read=True)
474
+ websocket_server_thread.start()
475
+ add_ss_hotkey(ss_hotkey)
476
+ try:
477
+ while not done:
478
+ time.sleep(1)
479
+ except KeyboardInterrupt as e:
480
+ pass
481
+ else:
482
+ print("Failed to load OCR configuration. Please check the logs.")
483
+ except Exception as e:
484
+ logger.info(e, exc_info=True)
485
+ logger.debug(e, exc_info=True)
486
+ logger.info("Closing in 5 seconds...")
487
+ time.sleep(5)
@@ -1,6 +1,7 @@
1
1
  import re
2
2
  import os
3
3
  import io
4
+ import time
4
5
  from pathlib import Path
5
6
  import sys
6
7
  import platform
@@ -17,8 +18,6 @@ from google.generativeai import GenerationConfig
17
18
  from loguru import logger
18
19
  import requests
19
20
 
20
- from GameSentenceMiner.util.configuration import get_app_directory, get_temporary_directory
21
-
22
21
  try:
23
22
  from manga_ocr import MangaOcr as MOCR
24
23
  except ImportError:
@@ -1247,6 +1246,68 @@ class GroqOCR:
1247
1246
  def _preprocess(self, img):
1248
1247
  return base64.b64encode(pil_image_to_bytes(img, png_compression=1)).decode('utf-8')
1249
1248
 
1249
+ # class QWENOCR:
1250
+ # name = 'qwenvl'
1251
+ # readable_name = 'Qwen2-VL'
1252
+ # key = 'q'
1253
+ # available = False
1254
+ #
1255
+ # def __init__(self, config={}):
1256
+ # try:
1257
+ # import torch
1258
+ # from transformers import Qwen2VLForConditionalGeneration, AutoProcessor
1259
+ # self.model = Qwen2VLForConditionalGeneration.from_pretrained(
1260
+ # "Qwen/Qwen2-VL-2B-Instruct", torch_dtype="auto", device_map="auto"
1261
+ # )
1262
+ # self.processor = AutoProcessor.from_pretrained("Qwen/Qwen2-VL-2B-Instruct", use_fast=True)
1263
+ # self.device = "cuda" if torch.cuda.is_available() else "cpu"
1264
+ # print(self.device)
1265
+ # self.available = True
1266
+ # logger.info('Qwen2-VL ready')
1267
+ # except Exception as e:
1268
+ # logger.warning(f'Qwen2-VL not available: {e}')
1269
+ #
1270
+ # def __call__(self, img, furigana_filter_sensitivity=0):
1271
+ # if not self.available:
1272
+ # return (False, 'Qwen2-VL is not available.')
1273
+ # try:
1274
+ # img = input_to_pil_image(img)
1275
+ # conversation = [
1276
+ # {
1277
+ # "role": "user",
1278
+ # "content": [
1279
+ # {"type": "image"},
1280
+ # {"type": "text", "text": "Analyze the image. Extract text *only* from within dialogue boxes (speech bubbles or panels containing character dialogue). If Text appears to be vertical, read the text from top to bottom, right to left. From the extracted dialogue text, filter out any furigana. Ignore and do not include any text found outside of dialogue boxes, including character names, speaker labels, or sound effects. Return *only* the filtered dialogue text. If no text is found within dialogue boxes after applying filters, return nothing. Do not include any other output, formatting markers, or commentary."},
1281
+ # ],
1282
+ # }
1283
+ # ]
1284
+ # text_prompt = self.processor.apply_chat_template(conversation, add_generation_prompt=True)
1285
+ # inputs = self.processor(
1286
+ # text=[text_prompt], images=[img], padding=True, return_tensors="pt"
1287
+ # )
1288
+ # inputs = inputs.to(self.device)
1289
+ # output_ids = self.model.generate(**inputs, max_new_tokens=128)
1290
+ # generated_ids = [
1291
+ # output_ids[len(input_ids):]
1292
+ # for input_ids, output_ids in zip(inputs.input_ids, output_ids)
1293
+ # ]
1294
+ # output_text = self.processor.batch_decode(
1295
+ # generated_ids, skip_special_tokens=True, clean_up_tokenization_spaces=True
1296
+ # )
1297
+ # return (True, output_text[0] if output_text else "")
1298
+ # except Exception as e:
1299
+ # return (False, f'Qwen2-VL inference failed: {e}')
1300
+
1301
+
1302
+ # qwenocr = QWENOCR()
1303
+ #
1304
+ # for i in range(10):
1305
+ # start_time = time.time()
1306
+ # res, text = qwenocr(Image.open('test_furigana.png'), furigana_filter_sensitivity=0) # Example usage
1307
+ # end_time = time.time()
1308
+ #
1309
+ # print(f"Time taken: {end_time - start_time:.2f} seconds")
1310
+ # print(text)
1250
1311
  # class LocalOCR:
1251
1312
  # name = 'local_ocr'
1252
1313
  # readable_name = 'Local OCR'
@@ -172,7 +172,7 @@ class Screenshot:
172
172
  class Audio:
173
173
  enabled: bool = True
174
174
  extension: str = 'opus'
175
- beginning_offset: float = 0.0
175
+ beginning_offset: float = -0.5
176
176
  end_offset: float = 0.5
177
177
  pre_vad_end_offset: float = 0.0
178
178
  ffmpeg_reencode_options: str = '-c:a libopus -f opus -af \"afade=t=in:d=0.10\"' if is_windows() else ''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.10.11
3
+ Version: 2.10.12
4
4
  Summary: A tool for mining sentences from games. Update: Full UI Re-design
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  GameSentenceMiner/anki.py,sha256=kWw3PV_Jj5-lHcttCB3lRXejHlaAbiJ2Ag_NAGX-RI8,16632
3
- GameSentenceMiner/config_gui.py,sha256=h-vDxpFCC347iK_mDJAjwKm7Qubeu-NWaxvd9SvzqzY,90942
3
+ GameSentenceMiner/config_gui.py,sha256=Xa_a-sdQzht3kzR-Z9gkLy4qnaPyP1bdVadYTHp5lUQ,91018
4
4
  GameSentenceMiner/gametext.py,sha256=6VkjmBeiuZfPk8T6PHFdIAElBH2Y_oLVYvmcafqN7RM,6747
5
5
  GameSentenceMiner/gsm.py,sha256=p4DVa_Jx1EOsgUxAAdC7st7VXLKWnP2BLDGT78ToO8w,24864
6
6
  GameSentenceMiner/obs.py,sha256=ZV9Vk39hrsJLT-AlIxa3qgncKxXaL3Myl33vVJEDEoA,14670
@@ -16,21 +16,21 @@ GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB
16
16
  GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
17
17
  GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
18
18
  GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=0hZmNIvZmlAEcy_NaTukG_ALUORULUT7sQ8q5VlDJU4,4047
19
+ GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=jtTzAWtMAx8GuA1XIJ_BmyNn3aYaO3u_c5Q7m5D4gS8,4056
20
20
  GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
21
21
  GameSentenceMiner/ocr/owocr_area_selector.py,sha256=boAqarX17jvFscu-7s6C9rqesjQ54s-kfuW0bjCru-M,19834
22
- GameSentenceMiner/ocr/owocr_helper.py,sha256=wkrobbrBugzzRBnUO9zBnxIwMEHWVTwxfutDn2HY17c,20205
22
+ GameSentenceMiner/ocr/owocr_helper.py,sha256=VDcuBfyZ1B7TN6yImJVuNxqWY7pr95R2cRM9jgD5Rk8,21670
23
23
  GameSentenceMiner/ocr/ss_picker.py,sha256=0IhxUdaKruFpZyBL-8SpxWg7bPrlGpy3lhTcMMZ5rwo,5224
24
24
  GameSentenceMiner/owocr/owocr/__init__.py,sha256=87hfN5u_PbL_onLfMACbc0F5j4KyIK9lKnRCj6oZgR0,49
25
25
  GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
26
26
  GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
27
27
  GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
28
- GameSentenceMiner/owocr/owocr/ocr.py,sha256=fWrbKomSrdkSdlEiMGTKb6-F7wCgfaZZNBUo2gCqmuA,52247
28
+ GameSentenceMiner/owocr/owocr/ocr.py,sha256=Mri_zB_COk7x9GmolyhYCINJ-lQlD45GuJ4m4M0IBFM,55328
29
29
  GameSentenceMiner/owocr/owocr/run.py,sha256=mZIGDm3fGYrYbSNuFOk7Sbslfgi36YN0YqfC1xYh_eY,55286
30
30
  GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
31
31
  GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  GameSentenceMiner/util/audio_offset_selector.py,sha256=8Stk3BP-XVIuzRv9nl9Eqd2D-1yD3JrgU-CamBywJmY,8542
33
- GameSentenceMiner/util/configuration.py,sha256=wuuM39xhXahswx7EhhWXURDQ_KIPbo4RhmQ_wPEbezo,28816
33
+ GameSentenceMiner/util/configuration.py,sha256=8PZk4IhtWFimfRy7biREcfG1NGkFNzKzFjlOjxNEFd0,28817
34
34
  GameSentenceMiner/util/electron_config.py,sha256=3VmIrcXhC-wIMMc4uqV85NrNenRl4ZUbnQfSjWEwuig,9852
35
35
  GameSentenceMiner/util/ffmpeg.py,sha256=t0tflxq170n8PZKkdw8fTZIUQfXD0p_qARa9JTdhBTc,21530
36
36
  GameSentenceMiner/util/gsm_utils.py,sha256=_279Fu9CU6FEh4cP6h40TWOt_BrqmPgytfumi8y53Ew,11491
@@ -62,9 +62,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
62
62
  GameSentenceMiner/web/templates/index.html,sha256=n0J-dV8eksj8JXUuaCTIh0fIxIjfgm2EvxGBdQ6gWoM,214113
63
63
  GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
64
64
  GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
65
- gamesentenceminer-2.10.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
66
- gamesentenceminer-2.10.11.dist-info/METADATA,sha256=pEHEHL90MhO8afUJ3yQTLDjdGvcYz5slrezzJ6biWfk,7355
67
- gamesentenceminer-2.10.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
- gamesentenceminer-2.10.11.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
69
- gamesentenceminer-2.10.11.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
70
- gamesentenceminer-2.10.11.dist-info/RECORD,,
65
+ gamesentenceminer-2.10.12.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
66
+ gamesentenceminer-2.10.12.dist-info/METADATA,sha256=YzGn0pkP-I00xGsRHt-5GK8x9pCKpoKR5lHBYL_z8Ho,7355
67
+ gamesentenceminer-2.10.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
68
+ gamesentenceminer-2.10.12.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
69
+ gamesentenceminer-2.10.12.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
70
+ gamesentenceminer-2.10.12.dist-info/RECORD,,