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.
- GameSentenceMiner/config_gui.py +1 -0
- GameSentenceMiner/ocr/gsm_ocr_config.py +2 -2
- GameSentenceMiner/ocr/owocr_helper.py +102 -73
- GameSentenceMiner/owocr/owocr/ocr.py +63 -2
- GameSentenceMiner/util/configuration.py +1 -1
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/RECORD +11 -11
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/top_level.txt +0 -0
GameSentenceMiner/config_gui.py
CHANGED
@@ -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
|
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
|
-
|
191
|
-
|
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
|
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
|
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
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
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.
|
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
|
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=
|
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=
|
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=
|
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=
|
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=
|
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.
|
66
|
-
gamesentenceminer-2.10.
|
67
|
-
gamesentenceminer-2.10.
|
68
|
-
gamesentenceminer-2.10.
|
69
|
-
gamesentenceminer-2.10.
|
70
|
-
gamesentenceminer-2.10.
|
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,,
|
File without changes
|
{gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/entry_points.txt
RENAMED
File without changes
|
{gamesentenceminer-2.10.11.dist-info → gamesentenceminer-2.10.12.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|