GameSentenceMiner 2.9.0__py3-none-any.whl → 2.9.1__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/anki.py +1 -1
- GameSentenceMiner/communication/websocket.py +7 -0
- GameSentenceMiner/config_gui.py +54 -19
- GameSentenceMiner/configuration.py +67 -3
- GameSentenceMiner/ffmpeg.py +2 -2
- GameSentenceMiner/gametext.py +71 -62
- GameSentenceMiner/gsm.py +103 -51
- GameSentenceMiner/obs.py +2 -2
- GameSentenceMiner/ocr/owocr_helper.py +17 -25
- GameSentenceMiner/owocr/owocr/ocr.py +4 -3
- GameSentenceMiner/text_log.py +1 -1
- GameSentenceMiner/vad/groq_trim.py +82 -0
- GameSentenceMiner/vad/result.py +15 -2
- GameSentenceMiner/vad/silero_trim.py +14 -10
- GameSentenceMiner/vad/vosk_helper.py +2 -2
- GameSentenceMiner/vad/whisper_helper.py +8 -7
- GameSentenceMiner/web/texthooking_page.py +41 -26
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/METADATA +4 -1
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/RECORD +23 -22
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/WHEEL +1 -1
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.9.0.dist-info → gamesentenceminer-2.9.1.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@ import tempfile
|
|
2
2
|
import warnings
|
3
3
|
|
4
4
|
import stable_whisper as whisper
|
5
|
+
import torch
|
5
6
|
from stable_whisper import WhisperResult
|
6
7
|
|
7
8
|
from GameSentenceMiner import configuration, ffmpeg
|
@@ -16,10 +17,9 @@ whisper_model = None
|
|
16
17
|
def load_whisper_model():
|
17
18
|
global whisper_model
|
18
19
|
if whisper_model is None:
|
19
|
-
logger.info(f"Loading Whisper model '{get_config().vad.whisper_model}'... This may take a while.")
|
20
20
|
with warnings.catch_warnings(action="ignore"):
|
21
21
|
whisper_model = whisper.load_model(get_config().vad.whisper_model)
|
22
|
-
logger.info("Whisper model loaded.")
|
22
|
+
logger.info(f"Whisper model '{get_config().vad.whisper_model}' loaded.")
|
23
23
|
|
24
24
|
|
25
25
|
# Use Whisper to detect voice activity with timestamps in the audio
|
@@ -35,8 +35,7 @@ def detect_voice_with_whisper(input_audio):
|
|
35
35
|
|
36
36
|
# Transcribe the audio using Whisper
|
37
37
|
with warnings.catch_warnings(action="ignore"):
|
38
|
-
result: WhisperResult = whisper_model.transcribe(temp_wav, vad=True, language=
|
39
|
-
|
38
|
+
result: WhisperResult = whisper_model.transcribe(temp_wav, vad=True, language=get_config().vad.language, temperature=0.0)
|
40
39
|
voice_activity = []
|
41
40
|
|
42
41
|
logger.debug(result.to_dict())
|
@@ -75,7 +74,7 @@ def process_audio_with_whisper(input_audio, output_audio, game_line):
|
|
75
74
|
|
76
75
|
if not voice_activity:
|
77
76
|
logger.info("No voice activity detected in the audio.")
|
78
|
-
return VADResult(False, 0, 0)
|
77
|
+
return VADResult(False, 0, 0, WHISPER)
|
79
78
|
|
80
79
|
# Trim based on the first and last speech detected
|
81
80
|
start_time = voice_activity[0]['start'] if voice_activity else 0
|
@@ -95,10 +94,12 @@ def process_audio_with_whisper(input_audio, output_audio, game_line):
|
|
95
94
|
|
96
95
|
# Trim the audio using FFmpeg
|
97
96
|
ffmpeg.trim_audio(input_audio, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, output_audio)
|
98
|
-
return VADResult(True, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset)
|
97
|
+
return VADResult(True, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, WHISPER)
|
99
98
|
|
100
99
|
|
101
100
|
# Load Whisper model initially
|
102
101
|
def initialize_whisper_model():
|
103
102
|
load_whisper_model()
|
104
|
-
|
103
|
+
|
104
|
+
# initialize_whisper_model()
|
105
|
+
# process_audio_with_whisper("tmp6x81cy27.opus", "tmp6x81cy27_trimmed.opus", None)
|
@@ -14,7 +14,7 @@ from GameSentenceMiner.text_log import GameLine, get_line_by_id, initial_time, g
|
|
14
14
|
from flask import request, jsonify, send_from_directory
|
15
15
|
import webbrowser
|
16
16
|
from GameSentenceMiner import obs
|
17
|
-
from GameSentenceMiner.configuration import logger, get_config, DB_PATH
|
17
|
+
from GameSentenceMiner.configuration import logger, get_config, DB_PATH, gsm_state
|
18
18
|
from GameSentenceMiner.util import TEXT_REPLACEMENTS_FILE
|
19
19
|
|
20
20
|
port = get_config().general.texthooker_port
|
@@ -52,8 +52,6 @@ class EventItem:
|
|
52
52
|
class EventManager:
|
53
53
|
events: list[EventItem]
|
54
54
|
events_dict: dict[str, EventItem] = {}
|
55
|
-
line_for_audio: GameLine = None
|
56
|
-
line_for_screenshot: GameLine = None
|
57
55
|
|
58
56
|
def __init__(self):
|
59
57
|
self.events = []
|
@@ -100,7 +98,7 @@ class EventManager:
|
|
100
98
|
self.events_dict[line.id] = new_event
|
101
99
|
self.events.append(new_event)
|
102
100
|
# self.store_to_db(new_event)
|
103
|
-
event_queue.put(new_event)
|
101
|
+
# event_queue.put(new_event)
|
104
102
|
return new_event
|
105
103
|
|
106
104
|
def reset_checked_lines(self):
|
@@ -271,14 +269,14 @@ def update_event():
|
|
271
269
|
def get_screenshot():
|
272
270
|
"""Endpoint to get a screenshot of the current game screen."""
|
273
271
|
data = request.get_json()
|
274
|
-
print(data)
|
275
272
|
event_id = data.get('id')
|
276
273
|
if event_id is None:
|
277
274
|
return jsonify({'error': 'Missing id'}), 400
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
275
|
+
gsm_state.line_for_screenshot = get_line_by_id(event_id)
|
276
|
+
if gsm_state.previous_line_for_screenshot and gsm_state.line_for_screenshot.id == gsm_state.previous_line_for_screenshot.id:
|
277
|
+
open(os.path.join(get_config().paths.folder_to_watch, "previous.mkv"), 'a').close()
|
278
|
+
else:
|
279
|
+
obs.save_replay_buffer()
|
282
280
|
return jsonify({}), 200
|
283
281
|
|
284
282
|
@app.route('/play-audio', methods=['POST'])
|
@@ -288,8 +286,11 @@ def play_audio():
|
|
288
286
|
event_id = data.get('id')
|
289
287
|
if event_id is None:
|
290
288
|
return jsonify({'error': 'Missing id'}), 400
|
291
|
-
|
292
|
-
|
289
|
+
gsm_state.line_for_audio = get_line_by_id(event_id)
|
290
|
+
if gsm_state.previous_line_for_audio and gsm_state.line_for_audio == gsm_state.previous_line_for_audio:
|
291
|
+
open(os.path.join(get_config().paths.folder_to_watch, "previous.mkv"), 'a').close()
|
292
|
+
else:
|
293
|
+
obs.save_replay_buffer()
|
293
294
|
return jsonify({}), 200
|
294
295
|
|
295
296
|
|
@@ -321,8 +322,8 @@ async def websocket_handler(websocket):
|
|
321
322
|
|
322
323
|
async def broadcast_message(message):
|
323
324
|
if connected_clients:
|
324
|
-
|
325
|
-
|
325
|
+
for client in connected_clients:
|
326
|
+
await client.send(json.dumps(message))
|
326
327
|
|
327
328
|
# async def main():
|
328
329
|
# async with websockets.serve(websocket_handler, "localhost", 8765): # Choose a port for WebSocket
|
@@ -380,19 +381,30 @@ def start_web_server():
|
|
380
381
|
|
381
382
|
app.run(port=port, debug=False) # debug=True provides helpful error messages during development
|
382
383
|
|
383
|
-
|
384
|
-
global websocket_port
|
385
|
-
while True:
|
386
|
-
websocket_port = port
|
387
|
-
try:
|
388
|
-
async with websockets.serve(websocket_handler, host, port):
|
389
|
-
logger.debug(f"WebSocket server started at ws://{host}:{port}/")
|
390
|
-
await asyncio.Future() # Keep the WebSocket server running
|
391
|
-
except OSError as e:
|
392
|
-
logger.debug(f"Port {port} is in use. Trying the next port...")
|
393
|
-
port += 1
|
384
|
+
import signal
|
394
385
|
|
386
|
+
async def run_websocket_server(host="0.0.0.0"):
|
387
|
+
global websocket_port
|
388
|
+
websocket = None
|
389
|
+
try:
|
390
|
+
websocket_port = get_config().advanced.texthooker_communication_websocket_port
|
391
|
+
websocket = await websockets.serve(websocket_handler, host, websocket_port)
|
392
|
+
logger.debug(f"WebSocket server started at ws://{host}:{websocket_port}/")
|
393
|
+
await asyncio.Future() # Keep the server running
|
394
|
+
except asyncio.CancelledError:
|
395
|
+
logger.info("WebSocket server shutting down...")
|
396
|
+
except OSError as e:
|
397
|
+
logger.error(f"TextHooker WebSocket server failed to start on port {websocket_port}: {e}")
|
398
|
+
logger.info("You may need to try a different port in GSM's advanced config, and then update that in the Texthooker's settings.")
|
399
|
+
finally:
|
400
|
+
if websocket:
|
401
|
+
websocket.close()
|
402
|
+
await asyncio.sleep(1) # Wait before retrying
|
395
403
|
|
404
|
+
def handle_exit_signal(loop):
|
405
|
+
logger.info("Received exit signal. Shutting down...")
|
406
|
+
for task in asyncio.all_tasks(loop):
|
407
|
+
task.cancel()
|
396
408
|
|
397
409
|
async def texthooker_page_coro():
|
398
410
|
# Run the WebSocket server in the asyncio event loop
|
@@ -404,7 +416,10 @@ async def texthooker_page_coro():
|
|
404
416
|
await run_websocket_server()
|
405
417
|
|
406
418
|
def run_text_hooker_page():
|
407
|
-
|
419
|
+
try:
|
420
|
+
asyncio.run(texthooker_page_coro())
|
421
|
+
except KeyboardInterrupt:
|
422
|
+
logger.info("Shutting down due to KeyboardInterrupt.")
|
408
423
|
|
409
424
|
if __name__ == '__main__':
|
410
|
-
asyncio.run(
|
425
|
+
asyncio.run(texthooker_page_coro())
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GameSentenceMiner
|
3
|
-
Version: 2.9.
|
3
|
+
Version: 2.9.1
|
4
4
|
Summary: A tool for mining sentences from games. Update: Multi-Line Mining! Fixed!
|
5
5
|
Author-email: Beangate <bpwhelan95@gmail.com>
|
6
6
|
License: MIT License
|
@@ -38,6 +38,7 @@ Requires-Dist: pygetwindow; sys_platform == "win32"
|
|
38
38
|
Requires-Dist: flask
|
39
39
|
Requires-Dist: groq
|
40
40
|
Requires-Dist: obsws-python
|
41
|
+
Requires-Dist: Flask-SocketIO
|
41
42
|
Dynamic: license-file
|
42
43
|
|
43
44
|
# GameSentenceMiner (GSM)
|
@@ -152,6 +153,8 @@ If you encounter issues, please ask for help in my [Discord](https://discord.gg/
|
|
152
153
|
|
153
154
|
* [OBS](https://obsproject.com/) and [FFMPEG](https://ffmpeg.org/), without which GSM would not be possible.
|
154
155
|
|
156
|
+
* [Renji's Texthooker](https://github.com/Renji-XD/texthooker-ui)
|
157
|
+
|
155
158
|
## Donations
|
156
159
|
|
157
160
|
If you've found this or any of my other projects helpful, please consider supporting my work through [GitHub Sponsors](https://github.com/sponsors/bpwhelan) or [Ko-fi](https://ko-fi.com/beangate).
|
@@ -1,24 +1,24 @@
|
|
1
1
|
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=
|
4
|
-
GameSentenceMiner/configuration.py,sha256=
|
2
|
+
GameSentenceMiner/anki.py,sha256=JnVfFkLpEfWaPfOLngU0PSQq4vrgWuhd_VLYZEBqNTY,14608
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=h4zz85gfhxSphaJ-IZSu9D4jR70mDlKecZ9JRCO5Noc,80927
|
4
|
+
GameSentenceMiner/configuration.py,sha256=8CfdTJ0ROJrxyzNg3NaElAVS1bwchg1ih6XfhfDZy1g,25492
|
5
5
|
GameSentenceMiner/electron_config.py,sha256=dGcPYCISPehXubYSzsDuI2Gl092MYK0u3bTnkL9Jh1Y,9787
|
6
|
-
GameSentenceMiner/ffmpeg.py,sha256=
|
7
|
-
GameSentenceMiner/gametext.py,sha256=
|
8
|
-
GameSentenceMiner/gsm.py,sha256=
|
6
|
+
GameSentenceMiner/ffmpeg.py,sha256=zVmLJOsXpy71zKb0cLBPrXJ6YpjPVRJmH0uRfd5O30k,18299
|
7
|
+
GameSentenceMiner/gametext.py,sha256=32e7w0qGXYNRRNpLzj9XIwtuto-E6ogEcyl6DC_MPbw,6200
|
8
|
+
GameSentenceMiner/gsm.py,sha256=_Mp_gZFomeFz9FTZqYEXIgqxbICYcAB06KUlFkClX5Q,29831
|
9
9
|
GameSentenceMiner/model.py,sha256=1lRyJFf_LND_4O16h8CWVqDfosLgr0ZS6ufBZ3qJHpY,5699
|
10
10
|
GameSentenceMiner/notification.py,sha256=pXKoLfmRQLH55IQ5G6uxdMuczqX7D6l3ubVEY1e6hXg,2859
|
11
|
-
GameSentenceMiner/obs.py,sha256=
|
11
|
+
GameSentenceMiner/obs.py,sha256=DoUJk00Gk0Idley7CEldfIobqJ9na2UBlCv7nclZO4s,14793
|
12
12
|
GameSentenceMiner/obs_back.py,sha256=_N_UV7Nh5cyy3mnH5lOUOzhgZwHMACeFEuBo1Z-bNzg,10894
|
13
13
|
GameSentenceMiner/package.py,sha256=YlS6QRMuVlm6mdXx0rlXv9_3erTGS21jaP3PNNWfAH0,1250
|
14
14
|
GameSentenceMiner/ss_selector.py,sha256=csey9H3561-guRJcT6gQN6hXxvylP0CBI0dp2-kwo2Q,4446
|
15
|
-
GameSentenceMiner/text_log.py,sha256=
|
15
|
+
GameSentenceMiner/text_log.py,sha256=U2_g8THAYeexRiE2bLk_bCt_2ShiA8SQ9VdJsi4riHs,5181
|
16
16
|
GameSentenceMiner/util.py,sha256=PrDNnxWiJZh1lGuwnp3DjWIlwbkVxweRTYWLtQk94Ao,9122
|
17
17
|
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
GameSentenceMiner/ai/ai_prompting.py,sha256=xw8et6XNwQiDXOXZnw8iIntVSg8lni4YYZbgWsK7qDE,10013
|
19
19
|
GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
|
20
20
|
GameSentenceMiner/communication/send.py,sha256=X0MytGv5hY-uUvkfvdCqQA_ljZFmV6UkJ6in1TA1bUE,217
|
21
|
-
GameSentenceMiner/communication/websocket.py,sha256=
|
21
|
+
GameSentenceMiner/communication/websocket.py,sha256=8eFZaTtoFggEPdqw2Jl4zqHC2I7J3-Gk27CxVX7SyBo,3277
|
22
22
|
GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
|
23
23
|
GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
24
|
GameSentenceMiner/downloader/download_tools.py,sha256=aRfpCqEmKUFRVsGipwY-7PhY6AeWiFJanW4ZCB9e2iE,8124
|
@@ -27,22 +27,23 @@ GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
27
27
|
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=fEQ2o2NXksGRHpueO8c4TfAp75GEdAtAr1ngTFOsdpg,2257
|
28
28
|
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
29
29
|
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=Q8ETMHL7BKMA1mbtjrntDLyqCQB0lZ5T4RCZsodjH7Y,47186
|
30
|
-
GameSentenceMiner/ocr/owocr_helper.py,sha256=
|
30
|
+
GameSentenceMiner/ocr/owocr_helper.py,sha256=M4Is-Ki5O3r4ixYhILibfjrVGD6xDlOcR3YvVGmETQ4,17363
|
31
31
|
GameSentenceMiner/owocr/owocr/__init__.py,sha256=opjBOyGGyEqZCE6YdZPnyt7nVfiwyELHsXA0jAsjm14,25
|
32
32
|
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
33
33
|
GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
|
34
34
|
GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
|
35
|
-
GameSentenceMiner/owocr/owocr/ocr.py,sha256=
|
35
|
+
GameSentenceMiner/owocr/owocr/ocr.py,sha256=V0HqVRQlaE1-12IH480IupfSv1BlDdEcwNPejhQZfS0,42292
|
36
36
|
GameSentenceMiner/owocr/owocr/run.py,sha256=0UyjOKEP0MqSdCaagCUMGdqO-BMexPxCl7ZabGlic4E,54749
|
37
37
|
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
38
38
|
GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
GameSentenceMiner/vad/
|
40
|
-
GameSentenceMiner/vad/
|
39
|
+
GameSentenceMiner/vad/groq_trim.py,sha256=MDYiApduwF7oDx3r0TXL3xQrTkbUC1RinMwNKSbF5gw,3764
|
40
|
+
GameSentenceMiner/vad/result.py,sha256=aFlr2px90fn3qXj49dwF9BDXA5m4yXD_HYH01CVvP1U,799
|
41
|
+
GameSentenceMiner/vad/silero_trim.py,sha256=ACvIdfjeCku6XWeUdi1zThBDvynJ01gjMFpSPWQALjg,2240
|
41
42
|
GameSentenceMiner/vad/vad_utils.py,sha256=_YC6rW2eXSBeLnYbVl_F3na1KCRL90VrnOzKYJ9RhUE,391
|
42
|
-
GameSentenceMiner/vad/vosk_helper.py,sha256=
|
43
|
-
GameSentenceMiner/vad/whisper_helper.py,sha256=
|
43
|
+
GameSentenceMiner/vad/vosk_helper.py,sha256=h7yNHrzrzT-J74UniA0T2ZX8cHqhflCzwyDjoIdKLO4,6479
|
44
|
+
GameSentenceMiner/vad/whisper_helper.py,sha256=B64-Eq_ZMCIyQX_A8uvYz-c48hSXJAyz6tSXNRaLjtA,4020
|
44
45
|
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
|
-
GameSentenceMiner/web/texthooking_page.py,sha256=
|
46
|
+
GameSentenceMiner/web/texthooking_page.py,sha256=alXNkpm2Kl-ewYIm_aw24_8RdcYedLB59y6YTkp_mrE,14789
|
46
47
|
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
48
|
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
48
49
|
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
@@ -56,9 +57,9 @@ GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
56
57
|
GameSentenceMiner/web/templates/index.html,sha256=HZKiIjiGJV8PGQ9T2aLDUNSfJn71qOwbYCjbRuSIjpY,213583
|
57
58
|
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
58
59
|
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
59
|
-
gamesentenceminer-2.9.
|
60
|
-
gamesentenceminer-2.9.
|
61
|
-
gamesentenceminer-2.9.
|
62
|
-
gamesentenceminer-2.9.
|
63
|
-
gamesentenceminer-2.9.
|
64
|
-
gamesentenceminer-2.9.
|
60
|
+
gamesentenceminer-2.9.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
61
|
+
gamesentenceminer-2.9.1.dist-info/METADATA,sha256=3SHKdq8q35tQXbi0x_4zQAekXgVPf-le5kKpSmdfSHY,7314
|
62
|
+
gamesentenceminer-2.9.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
63
|
+
gamesentenceminer-2.9.1.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
64
|
+
gamesentenceminer-2.9.1.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
65
|
+
gamesentenceminer-2.9.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|