GameSentenceMiner 2.9.4__py3-none-any.whl → 2.9.6__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/ai/ai_prompting.py +3 -3
- GameSentenceMiner/anki.py +16 -14
- GameSentenceMiner/config_gui.py +22 -7
- GameSentenceMiner/gametext.py +5 -5
- GameSentenceMiner/gsm.py +25 -67
- GameSentenceMiner/obs.py +7 -8
- GameSentenceMiner/ocr/owocr_area_selector.py +1 -1
- GameSentenceMiner/ocr/owocr_helper.py +30 -13
- GameSentenceMiner/owocr/owocr/ocr.py +0 -2
- GameSentenceMiner/owocr/owocr/run.py +1 -1
- GameSentenceMiner/{communication → util/communication}/__init__.py +1 -1
- GameSentenceMiner/{communication → util/communication}/send.py +1 -1
- GameSentenceMiner/{communication → util/communication}/websocket.py +2 -2
- GameSentenceMiner/{configuration.py → util/configuration.py} +6 -0
- GameSentenceMiner/{downloader → util/downloader}/download_tools.py +3 -3
- GameSentenceMiner/{electron_config.py → util/electron_config.py} +1 -1
- GameSentenceMiner/{ffmpeg.py → util/ffmpeg.py} +18 -10
- GameSentenceMiner/{util.py → util/gsm_utils.py} +4 -31
- GameSentenceMiner/{model.py → util/model.py} +1 -1
- GameSentenceMiner/{notification.py → util/notification.py} +3 -5
- GameSentenceMiner/{package.py → util/package.py} +1 -2
- GameSentenceMiner/{ss_selector.py → util/ss_selector.py} +5 -4
- GameSentenceMiner/{text_log.py → util/text_log.py} +3 -3
- GameSentenceMiner/vad.py +344 -0
- GameSentenceMiner/web/texthooking_page.py +15 -10
- {gamesentenceminer-2.9.4.dist-info → gamesentenceminer-2.9.6.dist-info}/METADATA +2 -3
- gamesentenceminer-2.9.6.dist-info/RECORD +67 -0
- GameSentenceMiner/vad/groq_trim.py +0 -82
- GameSentenceMiner/vad/result.py +0 -21
- GameSentenceMiner/vad/silero_trim.py +0 -52
- GameSentenceMiner/vad/vad_utils.py +0 -13
- GameSentenceMiner/vad/vosk_helper.py +0 -158
- GameSentenceMiner/vad/whisper_helper.py +0 -105
- gamesentenceminer-2.9.4.dist-info/RECORD +0 -72
- /GameSentenceMiner/{downloader → util}/__init__.py +0 -0
- /GameSentenceMiner/{downloader → util/downloader}/Untitled_json.py +0 -0
- /GameSentenceMiner/{vad → util/downloader}/__init__.py +0 -0
- /GameSentenceMiner/{downloader → util/downloader}/oneocr_dl.py +0 -0
- {gamesentenceminer-2.9.4.dist-info → gamesentenceminer-2.9.6.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.9.4.dist-info → gamesentenceminer-2.9.6.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.9.4.dist-info → gamesentenceminer-2.9.6.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.9.4.dist-info → gamesentenceminer-2.9.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
GameSentenceMiner/anki.py,sha256=CuzVqzuFtZnbMbU2Zk-sxNGwSgyCpv5RLL7lOOX0Meg,14972
|
3
|
+
GameSentenceMiner/config_gui.py,sha256=r-ASCXVNS4Io6Ej3svwC8aJEWc9Rc7u-pzfsAwD4ru8,82079
|
4
|
+
GameSentenceMiner/gametext.py,sha256=mM-gw1d7c2EEvMUznaAevTQFLswNZavCuxMXhA9pV4g,6251
|
5
|
+
GameSentenceMiner/gsm.py,sha256=SHvT3JZlYpZgKeJnVXrtk8ve4ubiM7YPv-9FDF7rVM4,27724
|
6
|
+
GameSentenceMiner/obs.py,sha256=jdAKQFnXlviMupRUKBuK68Q1u8yEZNKBgFnvIq1hhnc,14810
|
7
|
+
GameSentenceMiner/vad.py,sha256=Gk_VthD7mDp3-wM_S6bEv8ykGmqzCDbbcRiaEBzAE_o,14835
|
8
|
+
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
GameSentenceMiner/ai/ai_prompting.py,sha256=tPDiTHlrfZul0hlvEFgZS4V_6oaHkVb-4v79Sd4gtlM,10018
|
10
|
+
GameSentenceMiner/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
GameSentenceMiner/assets/icon.png,sha256=9GRL8uXUAgkUSlvbm9Pv9o2poFVRGdW6s2ub_DeUD9M,937624
|
12
|
+
GameSentenceMiner/assets/icon128.png,sha256=l90j7biwdz5ahwOd5wZ-406ryEV9Pan93dquJQ3e1CI,18395
|
13
|
+
GameSentenceMiner/assets/icon256.png,sha256=JEW46wOrG1KR-907rvFaEdNbPtj5gu0HJmG7qUnIHxQ,51874
|
14
|
+
GameSentenceMiner/assets/icon32.png,sha256=Kww0hU_qke9_22wBuO_Nq0Dv2SfnOLwMhCyGgbgXdg8,6089
|
15
|
+
GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB_7W4sqs,192487
|
16
|
+
GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
|
17
|
+
GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
|
18
|
+
GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=fEQ2o2NXksGRHpueO8c4TfAp75GEdAtAr1ngTFOsdpg,2257
|
20
|
+
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
21
|
+
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=71trzwz9Isyy-kN9mLS8vIX-giC8Lkin4slLXaxudac,47162
|
22
|
+
GameSentenceMiner/ocr/owocr_helper.py,sha256=FQXk5PSCS9gWtcgoIFsPxjVELUwA4Dg1hEX83902K0Q,18114
|
23
|
+
GameSentenceMiner/owocr/owocr/__init__.py,sha256=opjBOyGGyEqZCE6YdZPnyt7nVfiwyELHsXA0jAsjm14,25
|
24
|
+
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
25
|
+
GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
|
26
|
+
GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
|
27
|
+
GameSentenceMiner/owocr/owocr/ocr.py,sha256=y8RHHaJw8M4BG4CbbtIw0DrV8KP9RjbJNJxjM5v91oU,42236
|
28
|
+
GameSentenceMiner/owocr/owocr/run.py,sha256=jFN7gYYriHgfqORJiBTz8mPkQsDJ6ZugA0_ATWUxk-U,54750
|
29
|
+
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
30
|
+
GameSentenceMiner/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
+
GameSentenceMiner/util/configuration.py,sha256=Qk5V4HA2FJbdMTa9jYZfNVQ_4rzvjbUtJgPejwQ3vwk,25856
|
32
|
+
GameSentenceMiner/util/electron_config.py,sha256=ZZf54QifdNHbII-JDsMZmdT8nTyrq-7gVvalyLRecfw,9792
|
33
|
+
GameSentenceMiner/util/ffmpeg.py,sha256=qaCXkfK2fd-1NRqbm7burrdBYgnGx07kBuyenee8Mtk,18697
|
34
|
+
GameSentenceMiner/util/gsm_utils.py,sha256=RoOTvWCVpmfYA7fLDdIPcgH1c6TZK4jDZq98BectPhg,8272
|
35
|
+
GameSentenceMiner/util/model.py,sha256=iDtLTfR6D-ZC0gCiDqYno6-gA6Z07PZTM4B5MAA6xZI,5704
|
36
|
+
GameSentenceMiner/util/notification.py,sha256=euTnnNDJm0izr0Z5AhZGV2wrrioCASeKUtm5aZFO5zU,3462
|
37
|
+
GameSentenceMiner/util/package.py,sha256=u1ym5z869lw5EHvIviC9h9uH97bzUXSXXA8KIn8rUvk,1157
|
38
|
+
GameSentenceMiner/util/ss_selector.py,sha256=ATgwDXi4-TLv0hB21NV79FZnXgidiM0z7TgvO7eBnhw,4472
|
39
|
+
GameSentenceMiner/util/text_log.py,sha256=XOq8tpJUpNa-mKJPui40P5aUTX2yzMHPnHgJ2obagw0,5201
|
40
|
+
GameSentenceMiner/util/communication/__init__.py,sha256=xh__yn2MhzXi9eLi89PeZWlJPn-cbBSjskhi1BRraXg,643
|
41
|
+
GameSentenceMiner/util/communication/send.py,sha256=Wki9qIY2CgYnuHbmnyKVIYkcKAN_oYS4up93XMikBaI,222
|
42
|
+
GameSentenceMiner/util/communication/websocket.py,sha256=gPgxA2R2U6QZJjPqbUgODC87gtacPhmuC8lCprIkSmA,3287
|
43
|
+
GameSentenceMiner/util/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
|
44
|
+
GameSentenceMiner/util/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
|
+
GameSentenceMiner/util/downloader/download_tools.py,sha256=mvnOjDHFlV1AbjHaNI7mdnC5_CH5k3N4n1ezqzzbzGA,8139
|
46
|
+
GameSentenceMiner/util/downloader/oneocr_dl.py,sha256=o3ANp5IodEQoQ8GPcJdg9Y8JzA_lictwnebFPwwUZVk,10144
|
47
|
+
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
|
+
GameSentenceMiner/web/texthooking_page.py,sha256=RR70Vgde3wNHarQHbB-LBbEP-z95vRD5rtlW0GgdjmQ,15037
|
49
|
+
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
|
+
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
51
|
+
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
52
|
+
GameSentenceMiner/web/static/favicon.ico,sha256=7d25r_FBqRSNsAoEHpSzNoT7zyVt2DJRLNDNq_HYoX8,15086
|
53
|
+
GameSentenceMiner/web/static/favicon.svg,sha256=x305AP6WlXGtrXIZlaQspdLmwteoFYUoe5FyJ9MYlJ8,11517
|
54
|
+
GameSentenceMiner/web/static/site.webmanifest,sha256=kaeNT-FjFt-T7JGzOhXH7YSqsrDeiplZ2kDxCN_CFU4,436
|
55
|
+
GameSentenceMiner/web/static/style.css,sha256=bPZK0NVMuyRl5NNDuT7ZTzVLKlvSsdmeVHmAW4y5FM0,7001
|
56
|
+
GameSentenceMiner/web/static/web-app-manifest-192x192.png,sha256=EfSNnBmsSaLfESbkGfYwbKzcjKOdzuWo18ABADfN974,51117
|
57
|
+
GameSentenceMiner/web/static/web-app-manifest-512x512.png,sha256=wyqgCWCrLEUxSRXmaA3iJEESd-vM-ZmlTtZFBY4V8Pk,230819
|
58
|
+
GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
|
+
GameSentenceMiner/web/templates/index.html,sha256=HZKiIjiGJV8PGQ9T2aLDUNSfJn71qOwbYCjbRuSIjpY,213583
|
60
|
+
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
61
|
+
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
62
|
+
gamesentenceminer-2.9.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
63
|
+
gamesentenceminer-2.9.6.dist-info/METADATA,sha256=dXyoIXRhD6Qg7iCyRhGgoWjgR9PbS40yCmltnqTJZAA,7250
|
64
|
+
gamesentenceminer-2.9.6.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
65
|
+
gamesentenceminer-2.9.6.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
66
|
+
gamesentenceminer-2.9.6.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
67
|
+
gamesentenceminer-2.9.6.dist-info/RECORD,,
|
@@ -1,82 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import tempfile
|
3
|
-
import time
|
4
|
-
|
5
|
-
from groq import Groq
|
6
|
-
|
7
|
-
# Assuming these are available from GameSentenceMiner
|
8
|
-
from GameSentenceMiner import configuration, ffmpeg
|
9
|
-
from GameSentenceMiner.configuration import get_config, logger, GROQ # Import specific functions/objects
|
10
|
-
from GameSentenceMiner.vad.result import VADResult
|
11
|
-
from GameSentenceMiner.vad.vad_utils import get_audio_length
|
12
|
-
|
13
|
-
# Initialize Groq Client
|
14
|
-
client = Groq(api_key=get_config().ai.groq_api_key)
|
15
|
-
|
16
|
-
def detect_voice_with_groq(input_audio_path):
|
17
|
-
"""
|
18
|
-
Detects voice activity and extracts speech timestamps using the Groq Whisper API.
|
19
|
-
"""
|
20
|
-
try:
|
21
|
-
with open(input_audio_path, "rb") as file:
|
22
|
-
transcription = client.audio.transcriptions.create(
|
23
|
-
file=(os.path.basename(input_audio_path), file.read()),
|
24
|
-
model="whisper-large-v3-turbo",
|
25
|
-
response_format="verbose_json",
|
26
|
-
language=get_config().vad.language,
|
27
|
-
temperature=0.0,
|
28
|
-
timestamp_granularities=["segment"],
|
29
|
-
prompt=f"Start detecting speech from the first spoken word. If there is music or background noise, ignore it completely. Be very careful to not hallucinate on silence. If the transcription is anything but language:{get_config().vad.language}, ignore it completely. If the end of the audio seems like the start of a new sentence, ignore it completely.",
|
30
|
-
)
|
31
|
-
|
32
|
-
logger.debug(transcription)
|
33
|
-
|
34
|
-
# print(transcription)
|
35
|
-
|
36
|
-
speech_segments = transcription.segments if hasattr(transcription, 'segments') else []
|
37
|
-
# print(f"Groq speech segments: {speech_segments}")
|
38
|
-
|
39
|
-
audio_length = get_audio_length(input_audio_path)
|
40
|
-
# print(f"FFPROBE Length of input audio: {audio_length}")
|
41
|
-
|
42
|
-
return speech_segments, audio_length
|
43
|
-
except Exception as e:
|
44
|
-
logger.error(f"Error detecting voice with Groq: {e}")
|
45
|
-
return [], 0.0
|
46
|
-
|
47
|
-
def process_audio_with_groq(input_audio, output_audio, game_line):
|
48
|
-
"""
|
49
|
-
Processes an audio file by detecting voice activity using Groq Whisper API,
|
50
|
-
trimming the audio based on detected speech timestamps, and saving the trimmed audio.
|
51
|
-
"""
|
52
|
-
start = time.time()
|
53
|
-
voice_activity, audio_length = detect_voice_with_groq(input_audio)
|
54
|
-
logger.info(f"Processing time for Groq: {time.time() - start:.2f} seconds")
|
55
|
-
|
56
|
-
if not voice_activity:
|
57
|
-
logger.info(f"No voice activity detected in {input_audio}")
|
58
|
-
return VADResult(False, 0, 0, GROQ)
|
59
|
-
|
60
|
-
start_time = voice_activity[0]['start']
|
61
|
-
end_time = voice_activity[-1]['end']
|
62
|
-
|
63
|
-
# Logic to potentially use the second-to-last timestamp if a next game line is expected
|
64
|
-
# and there's a significant pause before the very last segment.
|
65
|
-
if (game_line and hasattr(game_line, 'next') and game_line.next and
|
66
|
-
len(voice_activity) > 1 and
|
67
|
-
(voice_activity[-1]['start'] - voice_activity[-2]['end']) > 3.0):
|
68
|
-
end_time = voice_activity[-2]['end']
|
69
|
-
logger.info("Using the second last timestamp for trimming due to game_line.next and significant pause.")
|
70
|
-
|
71
|
-
# Apply offsets from configuration, ensuring times are within valid bounds
|
72
|
-
final_start_time = max(0, start_time + get_config().vad.beginning_offset)
|
73
|
-
final_end_time = min(audio_length, end_time + get_config().audio.end_offset)
|
74
|
-
|
75
|
-
logger.debug(f"Trimming {input_audio} from {final_start_time:.2f}s to {final_end_time:.2f}s into {output_audio}")
|
76
|
-
|
77
|
-
ffmpeg.trim_audio(input_audio, final_start_time, final_end_time, output_audio)
|
78
|
-
|
79
|
-
return VADResult(True, final_start_time, final_end_time, GROQ)
|
80
|
-
|
81
|
-
# Example usage (uncomment and modify with your actual file paths for testing)
|
82
|
-
# process_audio_with_groq("tmp6x81cy27.opus", "tmp6x81cy27_trimmed_groq.opus", None)
|
GameSentenceMiner/vad/result.py
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
from GameSentenceMiner.configuration import get_config
|
2
|
-
|
3
|
-
|
4
|
-
class VADResult:
|
5
|
-
def __init__(self, success: bool, start: float, end: float, model: str):
|
6
|
-
self.success = success
|
7
|
-
self.start = start
|
8
|
-
self.end = end
|
9
|
-
self.model = model
|
10
|
-
|
11
|
-
def __repr__(self):
|
12
|
-
return f"VADResult(success={self.success}, start={self.start}, end={self.end}, model={self.model})"
|
13
|
-
|
14
|
-
def trim_successful_string(self):
|
15
|
-
if self.success:
|
16
|
-
if get_config().vad.trim_beginning:
|
17
|
-
return f"Trimmed audio from {self.start:.2f} to {self.end:.2f} seconds using {self.model}."
|
18
|
-
else:
|
19
|
-
return f"Trimmed end of audio to {self.end:.2f} seconds using {self.model}."
|
20
|
-
else:
|
21
|
-
return f"Failed to trim audio using {self.model}."
|
@@ -1,52 +0,0 @@
|
|
1
|
-
import tempfile
|
2
|
-
|
3
|
-
from silero_vad import load_silero_vad, read_audio, get_speech_timestamps
|
4
|
-
|
5
|
-
from GameSentenceMiner import configuration, ffmpeg
|
6
|
-
from GameSentenceMiner.configuration import *
|
7
|
-
from GameSentenceMiner.vad.result import VADResult
|
8
|
-
from GameSentenceMiner.vad.vad_utils import get_audio_length
|
9
|
-
|
10
|
-
# Silero VAD setup
|
11
|
-
vad_model = load_silero_vad()
|
12
|
-
|
13
|
-
|
14
|
-
# Use Silero to detect voice activity with timestamps in the audio
|
15
|
-
def detect_voice_with_silero(input_audio):
|
16
|
-
# Convert the audio to 16kHz mono WAV
|
17
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
18
|
-
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
19
|
-
|
20
|
-
# Load the audio and detect speech timestamps
|
21
|
-
wav = read_audio(temp_wav)
|
22
|
-
speech_timestamps = get_speech_timestamps(wav, vad_model, return_seconds=True)
|
23
|
-
|
24
|
-
logger.debug(speech_timestamps)
|
25
|
-
|
26
|
-
# Return the speech timestamps (start and end in seconds)
|
27
|
-
return speech_timestamps, len(wav) / 16000
|
28
|
-
|
29
|
-
|
30
|
-
# Example usage of Silero with trimming
|
31
|
-
def process_audio_with_silero(input_audio, output_audio, game_line):
|
32
|
-
voice_activity, audio_length = detect_voice_with_silero(input_audio)
|
33
|
-
|
34
|
-
if not voice_activity:
|
35
|
-
return VADResult(False, 0, 0, SILERO)
|
36
|
-
|
37
|
-
# Trim based on the first and last speech detected
|
38
|
-
start_time = voice_activity[0]['start'] if voice_activity else 0
|
39
|
-
if game_line and game_line.next and len(voice_activity) > 1 and 0 > audio_length - voice_activity[-1]['start'] + get_config().audio.beginning_offset:
|
40
|
-
# and (voice_activity[-1]['start'] - voice_activity[-2]['end']) > 3.0):
|
41
|
-
end_time = voice_activity[-2]['end']
|
42
|
-
logger.info("Using the second last timestamp for trimming")
|
43
|
-
else:
|
44
|
-
end_time = voice_activity[-1]['end'] if voice_activity else 0
|
45
|
-
|
46
|
-
# Trim the audio using FFmpeg
|
47
|
-
ffmpeg.trim_audio(input_audio, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, output_audio)
|
48
|
-
return VADResult(True, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, SILERO)
|
49
|
-
|
50
|
-
|
51
|
-
# process_audio_with_silero("tmp6x81cy27.opus", "tmp6x81cy27_trimmed.opus", None)
|
52
|
-
# print(detect_voice_with_silero("tmp6x81cy27.opus"))
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import subprocess
|
2
|
-
|
3
|
-
from GameSentenceMiner.ffmpeg import get_ffprobe_path
|
4
|
-
|
5
|
-
|
6
|
-
def get_audio_length(path):
|
7
|
-
result = subprocess.run(
|
8
|
-
[get_ffprobe_path(), "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", path],
|
9
|
-
stdout=subprocess.PIPE,
|
10
|
-
stderr=subprocess.PIPE,
|
11
|
-
text=True
|
12
|
-
)
|
13
|
-
return float(result.stdout.strip())
|
@@ -1,158 +0,0 @@
|
|
1
|
-
import tarfile
|
2
|
-
import tempfile
|
3
|
-
import zipfile
|
4
|
-
|
5
|
-
import numpy as np
|
6
|
-
import requests
|
7
|
-
import soundfile as sf
|
8
|
-
import vosk
|
9
|
-
|
10
|
-
from GameSentenceMiner import configuration, ffmpeg
|
11
|
-
from GameSentenceMiner.configuration import *
|
12
|
-
from GameSentenceMiner.vad.result import VADResult
|
13
|
-
|
14
|
-
ffmpeg_base_command_list = ["ffmpeg", "-hide_banner", "-loglevel", "error"]
|
15
|
-
vosk.SetLogLevel(-1)
|
16
|
-
vosk_model_path = ''
|
17
|
-
vosk_model = None
|
18
|
-
|
19
|
-
|
20
|
-
# Function to download and cache the Vosk model
|
21
|
-
def download_and_cache_vosk_model(model_dir="vosk_model_cache"):
|
22
|
-
# Ensure the cache directory exists
|
23
|
-
if not os.path.exists(os.path.join(get_app_directory(), model_dir)):
|
24
|
-
os.makedirs(os.path.join(get_app_directory(), model_dir))
|
25
|
-
|
26
|
-
# Extract the model name from the URL
|
27
|
-
model_filename = get_config().vad.vosk_url.split("/")[-1]
|
28
|
-
model_path = os.path.join(get_app_directory(), model_dir, model_filename)
|
29
|
-
|
30
|
-
# If the model is already downloaded, skip the download
|
31
|
-
if not os.path.exists(model_path):
|
32
|
-
logger.info(
|
33
|
-
f"Downloading the Vosk model from {get_config().vad.vosk_url}... This will take a while if using large model, ~1G")
|
34
|
-
response = requests.get(get_config().vad.vosk_url, stream=True)
|
35
|
-
with open(model_path, "wb") as file:
|
36
|
-
for chunk in response.iter_content(chunk_size=8192):
|
37
|
-
if chunk:
|
38
|
-
file.write(chunk)
|
39
|
-
logger.info("Download complete.")
|
40
|
-
|
41
|
-
# Extract the model if it's a zip or tar file
|
42
|
-
model_extract_path = os.path.join(get_app_directory(), model_dir, "vosk_model")
|
43
|
-
if not os.path.exists(model_extract_path):
|
44
|
-
logger.info("Extracting the Vosk model...")
|
45
|
-
if model_filename.endswith(".zip"):
|
46
|
-
with zipfile.ZipFile(model_path, "r") as zip_ref:
|
47
|
-
zip_ref.extractall(model_extract_path)
|
48
|
-
elif model_filename.endswith(".tar.gz"):
|
49
|
-
with tarfile.open(model_path, "r:gz") as tar_ref:
|
50
|
-
tar_ref.extractall(model_extract_path)
|
51
|
-
else:
|
52
|
-
logger.info("Unknown archive format. Model extraction skipped.")
|
53
|
-
logger.info(f"Model extracted to {model_extract_path}.")
|
54
|
-
else:
|
55
|
-
logger.info(f"Model already extracted at {model_extract_path}.")
|
56
|
-
|
57
|
-
# Return the path to the actual model folder inside the extraction directory
|
58
|
-
extracted_folders = os.listdir(model_extract_path)
|
59
|
-
if extracted_folders:
|
60
|
-
actual_model_folder = os.path.join(model_extract_path,
|
61
|
-
extracted_folders[0]) # Assuming the first folder is the model
|
62
|
-
return actual_model_folder
|
63
|
-
else:
|
64
|
-
return model_extract_path # In case there's no subfolder, return the extraction path directly
|
65
|
-
|
66
|
-
|
67
|
-
# Use Vosk to detect voice activity with timestamps in the audio
|
68
|
-
def detect_voice_with_vosk(input_audio):
|
69
|
-
global vosk_model_path, vosk_model
|
70
|
-
# Convert the audio to 16kHz mono WAV
|
71
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
72
|
-
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
73
|
-
|
74
|
-
if not vosk_model_path or not vosk_model:
|
75
|
-
vosk_model_path = download_and_cache_vosk_model()
|
76
|
-
vosk_model = vosk.Model(vosk_model_path)
|
77
|
-
|
78
|
-
# Open the audio file
|
79
|
-
with sf.SoundFile(temp_wav) as audio_file:
|
80
|
-
recognizer = vosk.KaldiRecognizer(vosk_model, audio_file.samplerate)
|
81
|
-
voice_activity = []
|
82
|
-
total_duration = len(audio_file) / audio_file.samplerate # Get total duration in seconds
|
83
|
-
|
84
|
-
recognizer.SetWords(True)
|
85
|
-
# recognizer.SetPartialWords(True)
|
86
|
-
|
87
|
-
# Process audio in chunks
|
88
|
-
while True:
|
89
|
-
data = audio_file.buffer_read(4000, dtype='int16')
|
90
|
-
if len(data) == 0:
|
91
|
-
break
|
92
|
-
|
93
|
-
# Convert buffer to bytes using NumPy
|
94
|
-
data_bytes = np.frombuffer(data, dtype='int16').tobytes()
|
95
|
-
|
96
|
-
if recognizer.AcceptWaveform(data_bytes):
|
97
|
-
pass
|
98
|
-
|
99
|
-
final_result = json.loads(recognizer.FinalResult())
|
100
|
-
if 'result' in final_result:
|
101
|
-
should_use = False
|
102
|
-
unique_words = set()
|
103
|
-
for word in final_result['result']:
|
104
|
-
if word['conf'] >= .90:
|
105
|
-
logger.debug(word)
|
106
|
-
should_use = True
|
107
|
-
unique_words.add(word['word'])
|
108
|
-
if len(unique_words) == 1 or all(item in ['えー', 'ん'] for item in unique_words):
|
109
|
-
should_use = False
|
110
|
-
|
111
|
-
if not should_use:
|
112
|
-
return None, 0
|
113
|
-
|
114
|
-
for word in final_result['result']:
|
115
|
-
voice_activity.append({
|
116
|
-
'text': word['word'],
|
117
|
-
'start': word['start'],
|
118
|
-
'end': word['end']
|
119
|
-
})
|
120
|
-
|
121
|
-
# Return the detected voice activity and the total duration
|
122
|
-
return voice_activity, total_duration
|
123
|
-
|
124
|
-
|
125
|
-
# Example usage of Vosk with trimming
|
126
|
-
def process_audio_with_vosk(input_audio, output_audio, game_line):
|
127
|
-
voice_activity, total_duration = detect_voice_with_vosk(input_audio)
|
128
|
-
|
129
|
-
if not voice_activity:
|
130
|
-
logger.info("No voice activity detected in the audio.")
|
131
|
-
return VADResult(False, 0, 0, VOSK)
|
132
|
-
|
133
|
-
# Trim based on the first and last speech detected
|
134
|
-
start_time = voice_activity[0]['start'] if voice_activity else 0
|
135
|
-
# if (game_line.next and len(voice_activity) > 1
|
136
|
-
# and voice_activity[-1]['start'] - get_config().audio.beginning_offset > len(input_audio) / 16000
|
137
|
-
# and (voice_activity[-1]['start'] - voice_activity[-2]['end']) > 5.0):
|
138
|
-
# end_time = voice_activity[-2]['end']
|
139
|
-
# logger.info("Using the second last timestamp for trimming")
|
140
|
-
# else:
|
141
|
-
end_time = voice_activity[-1]['end'] if voice_activity else 0
|
142
|
-
|
143
|
-
if get_config().vad.trim_beginning:
|
144
|
-
logger.info(f"VAD Trimmed Beginning of Audio to {start_time}")
|
145
|
-
|
146
|
-
# Print detected speech details with timestamps
|
147
|
-
logger.info(f"VAD Trimmed End of Audio to {end_time} seconds:")
|
148
|
-
|
149
|
-
# Trim the audio using FFmpeg
|
150
|
-
ffmpeg.trim_audio(input_audio, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, output_audio)
|
151
|
-
return VADResult(True, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, VOSK)
|
152
|
-
|
153
|
-
|
154
|
-
def get_vosk_model():
|
155
|
-
global vosk_model_path, vosk_model
|
156
|
-
vosk_model_path = download_and_cache_vosk_model()
|
157
|
-
vosk_model = vosk.Model(vosk_model_path)
|
158
|
-
logger.info(f"Using Vosk model from {vosk_model_path}")
|
@@ -1,105 +0,0 @@
|
|
1
|
-
import tempfile
|
2
|
-
import warnings
|
3
|
-
|
4
|
-
import stable_whisper as whisper
|
5
|
-
import torch
|
6
|
-
from stable_whisper import WhisperResult
|
7
|
-
|
8
|
-
from GameSentenceMiner import configuration, ffmpeg
|
9
|
-
from GameSentenceMiner.configuration import *
|
10
|
-
from GameSentenceMiner.vad.result import VADResult
|
11
|
-
|
12
|
-
ffmpeg_base_command_list = ["ffmpeg", "-hide_banner", "-loglevel", "error"]
|
13
|
-
whisper_model = None
|
14
|
-
|
15
|
-
|
16
|
-
# Function to download and load the Whisper model
|
17
|
-
def load_whisper_model():
|
18
|
-
global whisper_model
|
19
|
-
if whisper_model is None:
|
20
|
-
with warnings.catch_warnings(action="ignore"):
|
21
|
-
whisper_model = whisper.load_model(get_config().vad.whisper_model)
|
22
|
-
logger.info(f"Whisper model '{get_config().vad.whisper_model}' loaded.")
|
23
|
-
|
24
|
-
|
25
|
-
# Use Whisper to detect voice activity with timestamps in the audio
|
26
|
-
def detect_voice_with_whisper(input_audio):
|
27
|
-
# Convert the audio to 16kHz mono WAV
|
28
|
-
temp_wav = tempfile.NamedTemporaryFile(dir=configuration.get_temporary_directory(), suffix='.wav').name
|
29
|
-
ffmpeg.convert_audio_to_wav(input_audio, temp_wav)
|
30
|
-
|
31
|
-
# Make sure Whisper is loaded
|
32
|
-
load_whisper_model()
|
33
|
-
|
34
|
-
logger.info('transcribing audio...')
|
35
|
-
|
36
|
-
# Transcribe the audio using Whisper
|
37
|
-
with warnings.catch_warnings(action="ignore"):
|
38
|
-
result: WhisperResult = whisper_model.transcribe(temp_wav, vad=True, language=get_config().vad.language, temperature=0.0)
|
39
|
-
voice_activity = []
|
40
|
-
|
41
|
-
logger.debug(result.to_dict())
|
42
|
-
|
43
|
-
# Process the segments to extract tokens, timestamps, and confidence
|
44
|
-
for segment in result.segments:
|
45
|
-
logger.debug(segment.to_dict())
|
46
|
-
for word in segment.words:
|
47
|
-
logger.debug(word.to_dict())
|
48
|
-
confidence = word.probability
|
49
|
-
if confidence > .1:
|
50
|
-
logger.debug(word)
|
51
|
-
voice_activity.append({
|
52
|
-
'text': word.word,
|
53
|
-
'start': word.start,
|
54
|
-
'end': word.end,
|
55
|
-
'confidence': word.probability
|
56
|
-
})
|
57
|
-
|
58
|
-
# Analyze the detected words to decide whether to use the audio
|
59
|
-
should_use = False
|
60
|
-
unique_words = set(word['text'] for word in voice_activity)
|
61
|
-
if len(unique_words) > 1 or not all(item in ['えー', 'ん'] for item in unique_words):
|
62
|
-
should_use = True
|
63
|
-
|
64
|
-
if not should_use:
|
65
|
-
return None
|
66
|
-
|
67
|
-
# Return the detected voice activity and the total duration
|
68
|
-
return voice_activity
|
69
|
-
|
70
|
-
|
71
|
-
# Example usage of Whisper with trimming
|
72
|
-
def process_audio_with_whisper(input_audio, output_audio, game_line):
|
73
|
-
voice_activity = detect_voice_with_whisper(input_audio)
|
74
|
-
|
75
|
-
if not voice_activity:
|
76
|
-
logger.info("No voice activity detected in the audio.")
|
77
|
-
return VADResult(False, 0, 0, WHISPER)
|
78
|
-
|
79
|
-
# Trim based on the first and last speech detected
|
80
|
-
start_time = voice_activity[0]['start'] if voice_activity else 0
|
81
|
-
# if (game_line.next and len(voice_activity) > 1
|
82
|
-
# and voice_activity[-1]['start'] - get_config().audio.beginning_offset > len(input_audio) / 16000
|
83
|
-
# and (voice_activity[-1]['start'] - voice_activity[-2]['end']) > 5.0):
|
84
|
-
# end_time = voice_activity[-2]['end']
|
85
|
-
# logger.info("Using the second last timestamp for trimming")
|
86
|
-
# else:
|
87
|
-
end_time = voice_activity[-1]['end'] if voice_activity else 0
|
88
|
-
|
89
|
-
if get_config().vad.trim_beginning:
|
90
|
-
logger.info(f"VAD Trimmed Beginning of Audio to {start_time}")
|
91
|
-
|
92
|
-
# Print detected speech details with timestamps
|
93
|
-
logger.info(f"VAD Trimmed End of Audio to {end_time} seconds:")
|
94
|
-
|
95
|
-
# Trim the audio using FFmpeg
|
96
|
-
ffmpeg.trim_audio(input_audio, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, output_audio)
|
97
|
-
return VADResult(True, start_time + get_config().vad.beginning_offset, end_time + get_config().audio.end_offset, WHISPER)
|
98
|
-
|
99
|
-
|
100
|
-
# Load Whisper model initially
|
101
|
-
def initialize_whisper_model():
|
102
|
-
load_whisper_model()
|
103
|
-
|
104
|
-
# initialize_whisper_model()
|
105
|
-
# process_audio_with_whisper("tmp6x81cy27.opus", "tmp6x81cy27_trimmed.opus", None)
|
@@ -1,72 +0,0 @@
|
|
1
|
-
GameSentenceMiner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
GameSentenceMiner/anki.py,sha256=HAYblBjkth5p0tx9Z0LNQn6zuQC8_54RIB2BMzN8-LE,14705
|
3
|
-
GameSentenceMiner/config_gui.py,sha256=h4zz85gfhxSphaJ-IZSu9D4jR70mDlKecZ9JRCO5Noc,80927
|
4
|
-
GameSentenceMiner/configuration.py,sha256=KKW6fmpxya4dmXx9cERFVrzsKCTw0vmZrF2HAJDURBU,25667
|
5
|
-
GameSentenceMiner/electron_config.py,sha256=dGcPYCISPehXubYSzsDuI2Gl092MYK0u3bTnkL9Jh1Y,9787
|
6
|
-
GameSentenceMiner/ffmpeg.py,sha256=APa2vNdAgxYdG96_Z3Xdh1WqOiWaK6gTLJqzEvCMMeU,18323
|
7
|
-
GameSentenceMiner/gametext.py,sha256=sll-6Pficd4ZXYy8yL8hBrEOSpfa53TOye7vtHHKFN4,6218
|
8
|
-
GameSentenceMiner/gsm.py,sha256=olG3BIWjbVHWTsRKmeDVE5X8XrgppWke73Fy1J15dxA,29868
|
9
|
-
GameSentenceMiner/model.py,sha256=1lRyJFf_LND_4O16h8CWVqDfosLgr0ZS6ufBZ3qJHpY,5699
|
10
|
-
GameSentenceMiner/notification.py,sha256=e6TOzZJD7RTvMgxaY-V01r5OiocHhdqEIVdAnj4MGSw,3437
|
11
|
-
GameSentenceMiner/obs.py,sha256=JiydRMpfSpNZ0nDAzH8OOECbYbsxMNSGz46lO8lZbvA,14871
|
12
|
-
GameSentenceMiner/package.py,sha256=uu3Yb3pqu8vN5ISzP87YCHlFNR9wxMMf5hPRncTr7ws,1181
|
13
|
-
GameSentenceMiner/ss_selector.py,sha256=csey9H3561-guRJcT6gQN6hXxvylP0CBI0dp2-kwo2Q,4446
|
14
|
-
GameSentenceMiner/text_log.py,sha256=U2_g8THAYeexRiE2bLk_bCt_2ShiA8SQ9VdJsi4riHs,5181
|
15
|
-
GameSentenceMiner/util.py,sha256=ZbK7i1UeOzKyc5WtCcttiGljR_stfu7qpnEpgqFBwro,8976
|
16
|
-
GameSentenceMiner/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
-
GameSentenceMiner/ai/ai_prompting.py,sha256=xw8et6XNwQiDXOXZnw8iIntVSg8lni4YYZbgWsK7qDE,10013
|
18
|
-
GameSentenceMiner/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
-
GameSentenceMiner/assets/icon.png,sha256=9GRL8uXUAgkUSlvbm9Pv9o2poFVRGdW6s2ub_DeUD9M,937624
|
20
|
-
GameSentenceMiner/assets/icon128.png,sha256=l90j7biwdz5ahwOd5wZ-406ryEV9Pan93dquJQ3e1CI,18395
|
21
|
-
GameSentenceMiner/assets/icon256.png,sha256=JEW46wOrG1KR-907rvFaEdNbPtj5gu0HJmG7qUnIHxQ,51874
|
22
|
-
GameSentenceMiner/assets/icon32.png,sha256=Kww0hU_qke9_22wBuO_Nq0Dv2SfnOLwMhCyGgbgXdg8,6089
|
23
|
-
GameSentenceMiner/assets/icon512.png,sha256=HxUj2GHjyQsk8NV433256UxU9phPhtjCY-YB_7W4sqs,192487
|
24
|
-
GameSentenceMiner/assets/icon64.png,sha256=N8xgdZXvhqVQP9QUK3wX5iqxX9LxHljD7c-Bmgim6tM,9301
|
25
|
-
GameSentenceMiner/assets/pickaxe.png,sha256=VfIGyXyIZdzEnVcc4PmG3wszPMO1W4KCT7Q_nFK6eSE,1403829
|
26
|
-
GameSentenceMiner/communication/__init__.py,sha256=_jGn9PJxtOAOPtJ2rI-Qu9hEHVZVpIvWlxKvqk91_zI,638
|
27
|
-
GameSentenceMiner/communication/send.py,sha256=X0MytGv5hY-uUvkfvdCqQA_ljZFmV6UkJ6in1TA1bUE,217
|
28
|
-
GameSentenceMiner/communication/websocket.py,sha256=8eFZaTtoFggEPdqw2Jl4zqHC2I7J3-Gk27CxVX7SyBo,3277
|
29
|
-
GameSentenceMiner/downloader/Untitled_json.py,sha256=RUUl2bbbCpUDUUS0fP0tdvf5FngZ7ILdA_J5TFYAXUQ,15272
|
30
|
-
GameSentenceMiner/downloader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
-
GameSentenceMiner/downloader/download_tools.py,sha256=aRfpCqEmKUFRVsGipwY-7PhY6AeWiFJanW4ZCB9e2iE,8124
|
32
|
-
GameSentenceMiner/downloader/oneocr_dl.py,sha256=o3ANp5IodEQoQ8GPcJdg9Y8JzA_lictwnebFPwwUZVk,10144
|
33
|
-
GameSentenceMiner/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
-
GameSentenceMiner/ocr/gsm_ocr_config.py,sha256=fEQ2o2NXksGRHpueO8c4TfAp75GEdAtAr1ngTFOsdpg,2257
|
35
|
-
GameSentenceMiner/ocr/ocrconfig.py,sha256=_tY8mjnzHMJrLS8E5pHqYXZjMuLoGKYgJwdhYgN-ny4,6466
|
36
|
-
GameSentenceMiner/ocr/owocr_area_selector.py,sha256=Q8ETMHL7BKMA1mbtjrntDLyqCQB0lZ5T4RCZsodjH7Y,47186
|
37
|
-
GameSentenceMiner/ocr/owocr_helper.py,sha256=M4Is-Ki5O3r4ixYhILibfjrVGD6xDlOcR3YvVGmETQ4,17363
|
38
|
-
GameSentenceMiner/owocr/owocr/__init__.py,sha256=opjBOyGGyEqZCE6YdZPnyt7nVfiwyELHsXA0jAsjm14,25
|
39
|
-
GameSentenceMiner/owocr/owocr/__main__.py,sha256=XQaqZY99EKoCpU-gWQjNbTs7Kg17HvBVE7JY8LqIE0o,157
|
40
|
-
GameSentenceMiner/owocr/owocr/config.py,sha256=qM7kISHdUhuygGXOxmgU6Ef2nwBShrZtdqu4InDCViE,8103
|
41
|
-
GameSentenceMiner/owocr/owocr/lens_betterproto.py,sha256=oNoISsPilVVRBBPVDtb4-roJtAhp8ZAuFTci3TGXtMc,39141
|
42
|
-
GameSentenceMiner/owocr/owocr/ocr.py,sha256=V0HqVRQlaE1-12IH480IupfSv1BlDdEcwNPejhQZfS0,42292
|
43
|
-
GameSentenceMiner/owocr/owocr/run.py,sha256=0UyjOKEP0MqSdCaagCUMGdqO-BMexPxCl7ZabGlic4E,54749
|
44
|
-
GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py,sha256=Na6XStbQBtpQUSdbN3QhEswtKuU1JjReFk_K8t5ezQE,3395
|
45
|
-
GameSentenceMiner/vad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
46
|
-
GameSentenceMiner/vad/groq_trim.py,sha256=MDYiApduwF7oDx3r0TXL3xQrTkbUC1RinMwNKSbF5gw,3764
|
47
|
-
GameSentenceMiner/vad/result.py,sha256=aFlr2px90fn3qXj49dwF9BDXA5m4yXD_HYH01CVvP1U,799
|
48
|
-
GameSentenceMiner/vad/silero_trim.py,sha256=u4BC93LieJW0CZ7HToz51FneojqW_SNjSKmJmHMKwUA,2240
|
49
|
-
GameSentenceMiner/vad/vad_utils.py,sha256=_YC6rW2eXSBeLnYbVl_F3na1KCRL90VrnOzKYJ9RhUE,391
|
50
|
-
GameSentenceMiner/vad/vosk_helper.py,sha256=h7yNHrzrzT-J74UniA0T2ZX8cHqhflCzwyDjoIdKLO4,6479
|
51
|
-
GameSentenceMiner/vad/whisper_helper.py,sha256=B64-Eq_ZMCIyQX_A8uvYz-c48hSXJAyz6tSXNRaLjtA,4020
|
52
|
-
GameSentenceMiner/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
-
GameSentenceMiner/web/texthooking_page.py,sha256=7Z7TGDcnj-94Y9ws7bQph4oIXrqf8Q9qVKowKimHWxM,14749
|
54
|
-
GameSentenceMiner/web/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
GameSentenceMiner/web/static/apple-touch-icon.png,sha256=OcMI8af_68DA_tweOsQ5LytTyMwm7-hPW07IfrOVgEs,46132
|
56
|
-
GameSentenceMiner/web/static/favicon-96x96.png,sha256=lOePzjiKl1JY2J1kT_PMdyEnrlJmi5GWbmXJunM12B4,16502
|
57
|
-
GameSentenceMiner/web/static/favicon.ico,sha256=7d25r_FBqRSNsAoEHpSzNoT7zyVt2DJRLNDNq_HYoX8,15086
|
58
|
-
GameSentenceMiner/web/static/favicon.svg,sha256=x305AP6WlXGtrXIZlaQspdLmwteoFYUoe5FyJ9MYlJ8,11517
|
59
|
-
GameSentenceMiner/web/static/site.webmanifest,sha256=kaeNT-FjFt-T7JGzOhXH7YSqsrDeiplZ2kDxCN_CFU4,436
|
60
|
-
GameSentenceMiner/web/static/style.css,sha256=bPZK0NVMuyRl5NNDuT7ZTzVLKlvSsdmeVHmAW4y5FM0,7001
|
61
|
-
GameSentenceMiner/web/static/web-app-manifest-192x192.png,sha256=EfSNnBmsSaLfESbkGfYwbKzcjKOdzuWo18ABADfN974,51117
|
62
|
-
GameSentenceMiner/web/static/web-app-manifest-512x512.png,sha256=wyqgCWCrLEUxSRXmaA3iJEESd-vM-ZmlTtZFBY4V8Pk,230819
|
63
|
-
GameSentenceMiner/web/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
64
|
-
GameSentenceMiner/web/templates/index.html,sha256=HZKiIjiGJV8PGQ9T2aLDUNSfJn71qOwbYCjbRuSIjpY,213583
|
65
|
-
GameSentenceMiner/web/templates/text_replacements.html,sha256=tV5c8mCaWSt_vKuUpbdbLAzXZ3ATZeDvQ9PnnAfqY0M,8598
|
66
|
-
GameSentenceMiner/web/templates/utility.html,sha256=3flZinKNqUJ7pvrZk6xu__v67z44rXnaK7UTZ303R-8,16946
|
67
|
-
gamesentenceminer-2.9.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
68
|
-
gamesentenceminer-2.9.4.dist-info/METADATA,sha256=jNhOj4IaiTEJqGlm4-VCtviW5hmN8J5XnvPBGWgcY0Y,7280
|
69
|
-
gamesentenceminer-2.9.4.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
70
|
-
gamesentenceminer-2.9.4.dist-info/entry_points.txt,sha256=2APEP25DbfjSxGeHtwBstMH8mulVhLkqF_b9bqzU6vQ,65
|
71
|
-
gamesentenceminer-2.9.4.dist-info/top_level.txt,sha256=V1hUY6xVSyUEohb0uDoN4UIE6rUZ_JYx8yMyPGX4PgQ,18
|
72
|
-
gamesentenceminer-2.9.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|