Small Commit
This commit is contained in:
BIN
de_DE-thorsten-medium.onnx
Normal file
BIN
de_DE-thorsten-medium.onnx
Normal file
Binary file not shown.
487
de_DE-thorsten-medium.onnx.json
Normal file
487
de_DE-thorsten-medium.onnx.json
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
{
|
||||||
|
"audio": {
|
||||||
|
"sample_rate": 22050,
|
||||||
|
"quality": "medium"
|
||||||
|
},
|
||||||
|
"espeak": {
|
||||||
|
"voice": "de"
|
||||||
|
},
|
||||||
|
"inference": {
|
||||||
|
"noise_scale": 0.667,
|
||||||
|
"length_scale": 1,
|
||||||
|
"noise_w": 0.8
|
||||||
|
},
|
||||||
|
"phoneme_type": "espeak",
|
||||||
|
"phoneme_map": {},
|
||||||
|
"phoneme_id_map": {
|
||||||
|
"_": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"^": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"$": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"!": [
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"'": [
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"(": [
|
||||||
|
6
|
||||||
|
],
|
||||||
|
")": [
|
||||||
|
7
|
||||||
|
],
|
||||||
|
",": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"-": [
|
||||||
|
9
|
||||||
|
],
|
||||||
|
".": [
|
||||||
|
10
|
||||||
|
],
|
||||||
|
":": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
";": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"?": [
|
||||||
|
13
|
||||||
|
],
|
||||||
|
"a": [
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"b": [
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"c": [
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"d": [
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"e": [
|
||||||
|
18
|
||||||
|
],
|
||||||
|
"f": [
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"h": [
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"i": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"j": [
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"k": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"l": [
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"m": [
|
||||||
|
25
|
||||||
|
],
|
||||||
|
"n": [
|
||||||
|
26
|
||||||
|
],
|
||||||
|
"o": [
|
||||||
|
27
|
||||||
|
],
|
||||||
|
"p": [
|
||||||
|
28
|
||||||
|
],
|
||||||
|
"q": [
|
||||||
|
29
|
||||||
|
],
|
||||||
|
"r": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"s": [
|
||||||
|
31
|
||||||
|
],
|
||||||
|
"t": [
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"u": [
|
||||||
|
33
|
||||||
|
],
|
||||||
|
"v": [
|
||||||
|
34
|
||||||
|
],
|
||||||
|
"w": [
|
||||||
|
35
|
||||||
|
],
|
||||||
|
"x": [
|
||||||
|
36
|
||||||
|
],
|
||||||
|
"y": [
|
||||||
|
37
|
||||||
|
],
|
||||||
|
"z": [
|
||||||
|
38
|
||||||
|
],
|
||||||
|
"æ": [
|
||||||
|
39
|
||||||
|
],
|
||||||
|
"ç": [
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"ð": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"ø": [
|
||||||
|
42
|
||||||
|
],
|
||||||
|
"ħ": [
|
||||||
|
43
|
||||||
|
],
|
||||||
|
"ŋ": [
|
||||||
|
44
|
||||||
|
],
|
||||||
|
"œ": [
|
||||||
|
45
|
||||||
|
],
|
||||||
|
"ǀ": [
|
||||||
|
46
|
||||||
|
],
|
||||||
|
"ǁ": [
|
||||||
|
47
|
||||||
|
],
|
||||||
|
"ǂ": [
|
||||||
|
48
|
||||||
|
],
|
||||||
|
"ǃ": [
|
||||||
|
49
|
||||||
|
],
|
||||||
|
"ɐ": [
|
||||||
|
50
|
||||||
|
],
|
||||||
|
"ɑ": [
|
||||||
|
51
|
||||||
|
],
|
||||||
|
"ɒ": [
|
||||||
|
52
|
||||||
|
],
|
||||||
|
"ɓ": [
|
||||||
|
53
|
||||||
|
],
|
||||||
|
"ɔ": [
|
||||||
|
54
|
||||||
|
],
|
||||||
|
"ɕ": [
|
||||||
|
55
|
||||||
|
],
|
||||||
|
"ɖ": [
|
||||||
|
56
|
||||||
|
],
|
||||||
|
"ɗ": [
|
||||||
|
57
|
||||||
|
],
|
||||||
|
"ɘ": [
|
||||||
|
58
|
||||||
|
],
|
||||||
|
"ə": [
|
||||||
|
59
|
||||||
|
],
|
||||||
|
"ɚ": [
|
||||||
|
60
|
||||||
|
],
|
||||||
|
"ɛ": [
|
||||||
|
61
|
||||||
|
],
|
||||||
|
"ɜ": [
|
||||||
|
62
|
||||||
|
],
|
||||||
|
"ɞ": [
|
||||||
|
63
|
||||||
|
],
|
||||||
|
"ɟ": [
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"ɠ": [
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"ɡ": [
|
||||||
|
66
|
||||||
|
],
|
||||||
|
"ɢ": [
|
||||||
|
67
|
||||||
|
],
|
||||||
|
"ɣ": [
|
||||||
|
68
|
||||||
|
],
|
||||||
|
"ɤ": [
|
||||||
|
69
|
||||||
|
],
|
||||||
|
"ɥ": [
|
||||||
|
70
|
||||||
|
],
|
||||||
|
"ɦ": [
|
||||||
|
71
|
||||||
|
],
|
||||||
|
"ɧ": [
|
||||||
|
72
|
||||||
|
],
|
||||||
|
"ɨ": [
|
||||||
|
73
|
||||||
|
],
|
||||||
|
"ɪ": [
|
||||||
|
74
|
||||||
|
],
|
||||||
|
"ɫ": [
|
||||||
|
75
|
||||||
|
],
|
||||||
|
"ɬ": [
|
||||||
|
76
|
||||||
|
],
|
||||||
|
"ɭ": [
|
||||||
|
77
|
||||||
|
],
|
||||||
|
"ɮ": [
|
||||||
|
78
|
||||||
|
],
|
||||||
|
"ɯ": [
|
||||||
|
79
|
||||||
|
],
|
||||||
|
"ɰ": [
|
||||||
|
80
|
||||||
|
],
|
||||||
|
"ɱ": [
|
||||||
|
81
|
||||||
|
],
|
||||||
|
"ɲ": [
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"ɳ": [
|
||||||
|
83
|
||||||
|
],
|
||||||
|
"ɴ": [
|
||||||
|
84
|
||||||
|
],
|
||||||
|
"ɵ": [
|
||||||
|
85
|
||||||
|
],
|
||||||
|
"ɶ": [
|
||||||
|
86
|
||||||
|
],
|
||||||
|
"ɸ": [
|
||||||
|
87
|
||||||
|
],
|
||||||
|
"ɹ": [
|
||||||
|
88
|
||||||
|
],
|
||||||
|
"ɺ": [
|
||||||
|
89
|
||||||
|
],
|
||||||
|
"ɻ": [
|
||||||
|
90
|
||||||
|
],
|
||||||
|
"ɽ": [
|
||||||
|
91
|
||||||
|
],
|
||||||
|
"ɾ": [
|
||||||
|
92
|
||||||
|
],
|
||||||
|
"ʀ": [
|
||||||
|
93
|
||||||
|
],
|
||||||
|
"ʁ": [
|
||||||
|
94
|
||||||
|
],
|
||||||
|
"ʂ": [
|
||||||
|
95
|
||||||
|
],
|
||||||
|
"ʃ": [
|
||||||
|
96
|
||||||
|
],
|
||||||
|
"ʄ": [
|
||||||
|
97
|
||||||
|
],
|
||||||
|
"ʈ": [
|
||||||
|
98
|
||||||
|
],
|
||||||
|
"ʉ": [
|
||||||
|
99
|
||||||
|
],
|
||||||
|
"ʊ": [
|
||||||
|
100
|
||||||
|
],
|
||||||
|
"ʋ": [
|
||||||
|
101
|
||||||
|
],
|
||||||
|
"ʌ": [
|
||||||
|
102
|
||||||
|
],
|
||||||
|
"ʍ": [
|
||||||
|
103
|
||||||
|
],
|
||||||
|
"ʎ": [
|
||||||
|
104
|
||||||
|
],
|
||||||
|
"ʏ": [
|
||||||
|
105
|
||||||
|
],
|
||||||
|
"ʐ": [
|
||||||
|
106
|
||||||
|
],
|
||||||
|
"ʑ": [
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"ʒ": [
|
||||||
|
108
|
||||||
|
],
|
||||||
|
"ʔ": [
|
||||||
|
109
|
||||||
|
],
|
||||||
|
"ʕ": [
|
||||||
|
110
|
||||||
|
],
|
||||||
|
"ʘ": [
|
||||||
|
111
|
||||||
|
],
|
||||||
|
"ʙ": [
|
||||||
|
112
|
||||||
|
],
|
||||||
|
"ʛ": [
|
||||||
|
113
|
||||||
|
],
|
||||||
|
"ʜ": [
|
||||||
|
114
|
||||||
|
],
|
||||||
|
"ʝ": [
|
||||||
|
115
|
||||||
|
],
|
||||||
|
"ʟ": [
|
||||||
|
116
|
||||||
|
],
|
||||||
|
"ʡ": [
|
||||||
|
117
|
||||||
|
],
|
||||||
|
"ʢ": [
|
||||||
|
118
|
||||||
|
],
|
||||||
|
"ʲ": [
|
||||||
|
119
|
||||||
|
],
|
||||||
|
"ˈ": [
|
||||||
|
120
|
||||||
|
],
|
||||||
|
"ˌ": [
|
||||||
|
121
|
||||||
|
],
|
||||||
|
"ː": [
|
||||||
|
122
|
||||||
|
],
|
||||||
|
"ˑ": [
|
||||||
|
123
|
||||||
|
],
|
||||||
|
"˞": [
|
||||||
|
124
|
||||||
|
],
|
||||||
|
"β": [
|
||||||
|
125
|
||||||
|
],
|
||||||
|
"θ": [
|
||||||
|
126
|
||||||
|
],
|
||||||
|
"χ": [
|
||||||
|
127
|
||||||
|
],
|
||||||
|
"ᵻ": [
|
||||||
|
128
|
||||||
|
],
|
||||||
|
"ⱱ": [
|
||||||
|
129
|
||||||
|
],
|
||||||
|
"0": [
|
||||||
|
130
|
||||||
|
],
|
||||||
|
"1": [
|
||||||
|
131
|
||||||
|
],
|
||||||
|
"2": [
|
||||||
|
132
|
||||||
|
],
|
||||||
|
"3": [
|
||||||
|
133
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
134
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
135
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
136
|
||||||
|
],
|
||||||
|
"7": [
|
||||||
|
137
|
||||||
|
],
|
||||||
|
"8": [
|
||||||
|
138
|
||||||
|
],
|
||||||
|
"9": [
|
||||||
|
139
|
||||||
|
],
|
||||||
|
"̧": [
|
||||||
|
140
|
||||||
|
],
|
||||||
|
"̃": [
|
||||||
|
141
|
||||||
|
],
|
||||||
|
"̪": [
|
||||||
|
142
|
||||||
|
],
|
||||||
|
"̯": [
|
||||||
|
143
|
||||||
|
],
|
||||||
|
"̩": [
|
||||||
|
144
|
||||||
|
],
|
||||||
|
"ʰ": [
|
||||||
|
145
|
||||||
|
],
|
||||||
|
"ˤ": [
|
||||||
|
146
|
||||||
|
],
|
||||||
|
"ε": [
|
||||||
|
147
|
||||||
|
],
|
||||||
|
"↓": [
|
||||||
|
148
|
||||||
|
],
|
||||||
|
"#": [
|
||||||
|
149
|
||||||
|
],
|
||||||
|
"\"": [
|
||||||
|
150
|
||||||
|
],
|
||||||
|
"↑": [
|
||||||
|
151
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"num_symbols": 256,
|
||||||
|
"num_speakers": 1,
|
||||||
|
"speaker_id_map": {},
|
||||||
|
"piper_version": "1.0.0",
|
||||||
|
"language": {
|
||||||
|
"code": "de_DE",
|
||||||
|
"family": "de",
|
||||||
|
"region": "DE",
|
||||||
|
"name_native": "Deutsch",
|
||||||
|
"name_english": "German",
|
||||||
|
"country_english": "Germany"
|
||||||
|
},
|
||||||
|
"dataset": "thorsten"
|
||||||
|
}
|
||||||
227
main_bak.py
Normal file
227
main_bak.py
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
import threading
|
||||||
|
import queue
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# KONFIGURATION
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
VOSK_MODEL_PATH = "vosk-model-de-0.21"
|
||||||
|
PIPER_BIN = "piper"
|
||||||
|
PIPER_MODEL = "de_DE-thorsten-medium.onnx"
|
||||||
|
SAMPLE_RATE = 22050
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# STATES
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
STATE_IDLE = "IDLE"
|
||||||
|
STATE_LISTENING = "LISTENING"
|
||||||
|
STATE_SPEAKING = "SPEAKING"
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# GLOBALER ZUSTAND
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
state = STATE_IDLE
|
||||||
|
context = {
|
||||||
|
"intent": None,
|
||||||
|
"slots": {},
|
||||||
|
"required_slots": [],
|
||||||
|
"pending_slot": None
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_queue = queue.Queue()
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# TTS (PIPER)
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def speak(text):
|
||||||
|
global state
|
||||||
|
state = STATE_SPEAKING
|
||||||
|
print(f"[TTS] {text}")
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[PIPER_BIN, "--model", PIPER_MODEL, "--output-raw"],
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
audio = process.communicate(input=text.encode("utf-8"))[0]
|
||||||
|
|
||||||
|
play = subprocess.Popen(
|
||||||
|
["aplay", "-r", str(SAMPLE_RATE), "-f", "S16_LE"],
|
||||||
|
stdin=subprocess.PIPE
|
||||||
|
)
|
||||||
|
play.communicate(audio)
|
||||||
|
|
||||||
|
state = STATE_LISTENING
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# INTENTS & SLOTS
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
INTENTS = {
|
||||||
|
"weather": {
|
||||||
|
"keywords": ["wetter", "temperatur", "regen"],
|
||||||
|
"required_slots": ["location"]
|
||||||
|
},
|
||||||
|
"timer": {
|
||||||
|
"keywords": ["timer"],
|
||||||
|
"required_slots": ["duration"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# evtl mit regex überarbeiten
|
||||||
|
|
||||||
|
def detect_intent(text):
|
||||||
|
text = text.lower()
|
||||||
|
for name, data in INTENTS.items():
|
||||||
|
if any(word in text for word in data["keywords"]):
|
||||||
|
return name
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# SKILLS
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def weather_skill(slots):
|
||||||
|
location = slots["location"]
|
||||||
|
return f"Das Wetter in {location} ist sonnig bei 20 Grad."
|
||||||
|
|
||||||
|
def timer_skill(slots):
|
||||||
|
duration = slots["duration"]
|
||||||
|
return f"Der Timer für {duration} Minuten wurde gestartet."
|
||||||
|
|
||||||
|
SKILLS = {
|
||||||
|
"weather": weather_skill,
|
||||||
|
"timer": timer_skill
|
||||||
|
}
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# DIALOGLOGIK
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def handle_text(text):
|
||||||
|
global context, state
|
||||||
|
|
||||||
|
if state != STATE_LISTENING:
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"[STT] {text}")
|
||||||
|
|
||||||
|
# 1. Rückfrage beantworten
|
||||||
|
if context["pending_slot"]:
|
||||||
|
context["slots"][context["pending_slot"]] = text
|
||||||
|
context["pending_slot"] = None
|
||||||
|
|
||||||
|
# 2. Intent erkennen
|
||||||
|
if not context["intent"]:
|
||||||
|
intent = detect_intent(text)
|
||||||
|
if not intent:
|
||||||
|
speak("Das habe ich nicht verstanden.")
|
||||||
|
reset_context()
|
||||||
|
return
|
||||||
|
|
||||||
|
context["intent"] = intent
|
||||||
|
context["required_slots"] = INTENTS[intent]["required_slots"]
|
||||||
|
|
||||||
|
# 3. Fehlende Slots prüfen
|
||||||
|
for slot in context["required_slots"]:
|
||||||
|
if slot not in context["slots"]:
|
||||||
|
context["pending_slot"] = slot
|
||||||
|
ask_for_slot(slot)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 4. Skill ausführen
|
||||||
|
result = SKILLS[context["intent"]](context["slots"])
|
||||||
|
speak(result)
|
||||||
|
reset_context()
|
||||||
|
|
||||||
|
|
||||||
|
def ask_for_slot(slot):
|
||||||
|
questions = {
|
||||||
|
"location": "Für welchen Ort?",
|
||||||
|
"duration": "Wie lange soll der Timer laufen?"
|
||||||
|
}
|
||||||
|
speak(questions.get(slot, "Bitte spezifizieren."))
|
||||||
|
|
||||||
|
|
||||||
|
def reset_context():
|
||||||
|
global context, state
|
||||||
|
context = {
|
||||||
|
"intent": None,
|
||||||
|
"slots": {},
|
||||||
|
"required_slots": [],
|
||||||
|
"pending_slot": None
|
||||||
|
}
|
||||||
|
state = STATE_IDLE
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# VOSK LISTENER
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def vosk_listener():
|
||||||
|
import vosk
|
||||||
|
import pyaudio
|
||||||
|
|
||||||
|
model = vosk.Model(VOSK_MODEL_PATH)
|
||||||
|
rec = vosk.KaldiRecognizer(model, SAMPLE_RATE)
|
||||||
|
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
stream = p.open(
|
||||||
|
format=pyaudio.paInt16,
|
||||||
|
channels=1,
|
||||||
|
rate=SAMPLE_RATE,
|
||||||
|
input=True,
|
||||||
|
frames_per_buffer=4000
|
||||||
|
)
|
||||||
|
stream.start_stream()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data = stream.read(4000, exception_on_overflow=False)
|
||||||
|
if rec.AcceptWaveform(data):
|
||||||
|
result = json.loads(rec.Result())
|
||||||
|
text = result.get("text", "")
|
||||||
|
if text:
|
||||||
|
audio_queue.put(text)
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# WAKEWORD (SIMPLIFIZIERT)
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def fake_wakeword_detector():
|
||||||
|
global state
|
||||||
|
while True:
|
||||||
|
if state == STATE_IDLE:
|
||||||
|
time.sleep(0.1)
|
||||||
|
state = STATE_LISTENING
|
||||||
|
speak("Wie kann ich helfen?")
|
||||||
|
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# MAIN LOOP
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
threading.Thread(target=vosk_listener, daemon=True).start()
|
||||||
|
threading.Thread(target=fake_wakeword_detector, daemon=True).start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
text = audio_queue.get(timeout=0.1)
|
||||||
|
handle_text(text)
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
27
test_tts.py
Normal file
27
test_tts.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
|
PIPER_BIN = "piper"
|
||||||
|
PIPER_MODEL = "de_DE-thorsten-medium.onnx"
|
||||||
|
SAMPLE_RATE = 22050 #aplay -v assistant/audio-tts/predefined.wav so rausgefunden
|
||||||
|
|
||||||
|
def speak(text):
|
||||||
|
|
||||||
|
print(f"[TTS] {text}")
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[PIPER_BIN, "--model", PIPER_MODEL, "--output-raw"],
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
audio = process.communicate(input=text.encode("utf-8"))[0]
|
||||||
|
|
||||||
|
play = subprocess.Popen(
|
||||||
|
["aplay", "-r", str(SAMPLE_RATE), "-f", "S16_LE"],
|
||||||
|
stdin=subprocess.PIPE
|
||||||
|
)
|
||||||
|
play.communicate(audio)
|
||||||
|
|
||||||
|
|
||||||
|
text="Das Auto musste repariert werden, bevor wir weiterfahren konnten, neuer text"
|
||||||
|
speak(text)
|
||||||
46
test_vosk.py
Normal file
46
test_vosk.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import threading
|
||||||
|
import queue
|
||||||
|
import json
|
||||||
|
|
||||||
|
audio_queue = queue.Queue()
|
||||||
|
SAMPLE_RATE = 16000
|
||||||
|
|
||||||
|
def vosk_listener():
|
||||||
|
import vosk
|
||||||
|
import pyaudio
|
||||||
|
|
||||||
|
VOSK_MODEL_PATH = "/home/tino/Documents/_Documents/Schule/4 Wilhelm Maybach Schule/2BKI Jahr 2/Abschlussprojekt/test assistant/assistant_all_in_one/vosk-model-de-0.21/"
|
||||||
|
|
||||||
|
model = vosk.Model(VOSK_MODEL_PATH)
|
||||||
|
rec = vosk.KaldiRecognizer(model, SAMPLE_RATE)
|
||||||
|
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
stream = p.open(
|
||||||
|
format=pyaudio.paInt16,
|
||||||
|
channels=1,
|
||||||
|
rate=SAMPLE_RATE,
|
||||||
|
input=True,
|
||||||
|
frames_per_buffer=4000
|
||||||
|
)
|
||||||
|
stream.start_stream()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data = stream.read(4000, exception_on_overflow=False)
|
||||||
|
if rec.AcceptWaveform(data):
|
||||||
|
result = json.loads(rec.Result())
|
||||||
|
text = result.get("text", "")
|
||||||
|
if text:
|
||||||
|
audio_queue.put(text)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
threading.Thread(target=vosk_listener, daemon=True).start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
text = audio_queue.get(timeout=0.1)
|
||||||
|
print("[SST]", text)
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user