Ordnerstruktur aufgeräumt, .gitignore aktualisiert
This commit is contained in:
parent
41c2bfb671
commit
0877693bdb
20 changed files with 6 additions and 678 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,4 +2,3 @@ __pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
*.wav
|
*.wav
|
||||||
session_daten.json
|
session_daten.json
|
||||||
*.save
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
||||||
# config.py
|
# config.py
|
||||||
# Zentrale Stelle für Netzwerkparameter
|
# Zentrale Stelle für Netzwerkparameter
|
||||||
MISTY_IP = "192.168.68.57"
|
MISTY_IP = "192.168.68.55"
|
||||||
RTSP_URL = "rtsp://{MISTY_IP}:1936"
|
RTSP_URL = "rtsp://{MISTY_IP}:1936"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,53 +0,0 @@
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
|
|
||||||
# --- KONFIGURATION ---
|
|
||||||
# Die IP deines Roboters
|
|
||||||
MISTY_IP = "192.168.68.58"
|
|
||||||
# So soll die Datei auf dem Roboter und dem Server heißen
|
|
||||||
DATEI_NAME = "praesentation_aufnahme.wav"
|
|
||||||
# Dauer der Aufnahme in Sekunden
|
|
||||||
AUFNAHME_DAUER = 10
|
|
||||||
|
|
||||||
def aufnahme_starten():
|
|
||||||
# 1. Misty bescheid geben
|
|
||||||
print("--- Misty bereitet sich vor ---")
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/tts/speak", json={
|
|
||||||
"text": "Ich höre dir jetzt für 10 Sekunden zu. Fang an nach dem ich fertig bin mit sprechen.",
|
|
||||||
"speechLocale": "de-DE"
|
|
||||||
})
|
|
||||||
|
|
||||||
# Wir warten 4 Sekunden, damit sie sich nicht selbst beim Sprechen aufnimmt
|
|
||||||
time.sleep(4)
|
|
||||||
|
|
||||||
# 2. Aufnahme auf dem Roboter starten
|
|
||||||
print(f"--- Schritt 1: Aufnahme läuft für {AUFNAHME_DAUER} Sekunden ---")
|
|
||||||
start_url = f"http://{MISTY_IP}/api/audio/record/start"
|
|
||||||
requests.post(start_url, json={"FileName": DATEI_NAME})
|
|
||||||
|
|
||||||
# Das Programm pausiert hier für 10 Sekunden, während du sprichst
|
|
||||||
time.sleep(AUFNAHME_DAUER)
|
|
||||||
|
|
||||||
# 3. Aufnahme stoppen
|
|
||||||
print("--- Schritt 2: Aufnahme wird beendet ---")
|
|
||||||
stop_url = f"http://{MISTY_IP}/api/audio/record/stop"
|
|
||||||
requests.post(stop_url)
|
|
||||||
|
|
||||||
# 2 Sekunden warten, damit die Datei auf dem Roboter-Speicher fertig geschrieben wird
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 4. Datei vom Roboter auf den Ubuntu-Server kopieren
|
|
||||||
print(f"--- Schritt 3: Datei '{DATEI_NAME}' wird heruntergeladen ---")
|
|
||||||
download_url = f"http://{MISTY_IP}/api/audio?FileName={DATEI_NAME}"
|
|
||||||
r = requests.get(download_url)
|
|
||||||
|
|
||||||
if r.status_code == 200:
|
|
||||||
# Die Daten werden binär in eine lokale Datei geschrieben
|
|
||||||
with open(DATEI_NAME, 'wb') as f:
|
|
||||||
f.write(r.content)
|
|
||||||
print(f"Erfolg! Die Datei liegt jetzt bereit für die Analyse.")
|
|
||||||
else:
|
|
||||||
print(f"Fehler beim Download: Statuscode {r.status_code}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
aufnahme_starten()
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
ROBOT_IP = "192.168.68.64"
|
|
||||||
PORT = 1936
|
|
||||||
|
|
||||||
def post(path, payload):
|
|
||||||
url = f"http://{ROBOT_IP}{path}"
|
|
||||||
r = requests.post(url, data=json.dumps(payload), headers={"Content-Type": "application/json"}, timeout=10)
|
|
||||||
print(path, r.status_code)
|
|
||||||
try:
|
|
||||||
print(r.json())
|
|
||||||
except Exception:
|
|
||||||
print(r.text)
|
|
||||||
return r
|
|
||||||
|
|
||||||
# 1) Enable AV streaming service
|
|
||||||
post("/api/services/avstreaming/enable", {})
|
|
||||||
|
|
||||||
# 2) Start AV streaming (Misty as RTSP server)
|
|
||||||
payload = {
|
|
||||||
"url": f"rtspd:{PORT}",
|
|
||||||
"width": 640,
|
|
||||||
"height": 480,
|
|
||||||
"frameRate": 30,
|
|
||||||
"videoBitRate": 5000000,
|
|
||||||
"audioBitRate": 128000,
|
|
||||||
"audioSampleRateHz": 44100,
|
|
||||||
"userName": None,
|
|
||||||
"password": None
|
|
||||||
}
|
|
||||||
post("/api/avstreaming/start", payload)
|
|
||||||
|
|
||||||
print(f"\nJetzt in VLC öffnen: rtsp://{ROBOT_IP}:{PORT}\n")
|
|
||||||
time.sleep(999999)
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
import websocket
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
import whisper
|
|
||||||
import threading
|
|
||||||
|
|
||||||
# --- KONFIGURATION ---
|
|
||||||
MISTY_IP = "192.168.68.58"
|
|
||||||
DATEI_NAME = "bumper_aufnahme.wav"
|
|
||||||
AUFNAHME_DAUER = 10
|
|
||||||
|
|
||||||
# Flag, um zu verhindern, dass die Analyse mehrfach gleichzeitig startet
|
|
||||||
laeuft_gerade = False
|
|
||||||
|
|
||||||
def coaching_prozess():
|
|
||||||
global laeuft_gerade
|
|
||||||
laeuft_gerade = True
|
|
||||||
|
|
||||||
# 1. Start-Signal
|
|
||||||
print("--- Bumper gedrückt! Starte Coaching ---")
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/tts/speak", json={
|
|
||||||
"text": "Bumper erkannt. Ich höre dir jetzt für 10 Sekunden zu.",
|
|
||||||
"speechLocale": "de-DE"
|
|
||||||
})
|
|
||||||
time.sleep(4)
|
|
||||||
|
|
||||||
# 2. Aufnahme
|
|
||||||
print(f"--- Aufnahme läuft ({AUFNAHME_DAUER}s) ---")
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/audio/record/start", json={"FileName": DATEI_NAME})
|
|
||||||
time.sleep(AUFNAHME_DAUER)
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/audio/record/stop")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 3. Download
|
|
||||||
print("--- Übertragung der Audio-Datei ---")
|
|
||||||
r = requests.get(f"http://{MISTY_IP}/api/audio?FileName={DATEI_NAME}")
|
|
||||||
if r.status_code == 200:
|
|
||||||
with open(DATEI_NAME, 'wb') as f:
|
|
||||||
f.write(r.content)
|
|
||||||
else:
|
|
||||||
print("Download-Fehler!"); laeuft_gerade = False; return
|
|
||||||
|
|
||||||
# 4. KI-Analyse
|
|
||||||
print("--- Whisper Analyse läuft ---")
|
|
||||||
model = whisper.load_model("base")
|
|
||||||
result = model.transcribe(DATEI_NAME, language="German", initial_prompt="Äh, ähm.")
|
|
||||||
text = result["text"].lower()
|
|
||||||
|
|
||||||
# Zählen
|
|
||||||
anzahl_aehm = text.count("ähm")
|
|
||||||
anzahl_aeh = text.replace("ähm", "TEMP").count("äh")
|
|
||||||
gesamt = anzahl_aeh + anzahl_aehm
|
|
||||||
|
|
||||||
# 5. Feedback
|
|
||||||
if gesamt > 0:
|
|
||||||
msg = f"Ich habe {gesamt} Füllwörter gehört. Versuche flüssiger zu sprechen."
|
|
||||||
img = "e_DisorientedConfused.jpg"
|
|
||||||
else:
|
|
||||||
msg = "Hervorragend! Keine Füllwörter gefunden."
|
|
||||||
img = "e_Joy.jpg"
|
|
||||||
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/images/display", json={"FileName": img})
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/tts/speak", json={"text": msg, "speechLocale": "de-DE"})
|
|
||||||
|
|
||||||
print(f"Fertig! Text: {text}")
|
|
||||||
laeuft_gerade = False
|
|
||||||
|
|
||||||
def on_message(ws, message):
|
|
||||||
global laeuft_gerade
|
|
||||||
data = json.loads(message)
|
|
||||||
|
|
||||||
# Wir prüfen, ob das Event vom Bumper kommt
|
|
||||||
if "message" in data and "sensor" in data["message"]:
|
|
||||||
sensor = data["message"]["sensor"]
|
|
||||||
is_pressed = data["message"]["isPressed"]
|
|
||||||
|
|
||||||
# "br" steht für Bumper Right (Rechter Bumper)
|
|
||||||
if sensor == "br" and is_pressed and not laeuft_gerade:
|
|
||||||
# Starte den Prozess in einem eigenen Thread, damit die Verbindung nicht blockiert
|
|
||||||
threading.Thread(target=coaching_prozess).start()
|
|
||||||
|
|
||||||
def on_open(ws):
|
|
||||||
print("Verbindung zu Misty hergestellt. Drücke den RECHTEN BUMPER zum Starten.")
|
|
||||||
# Wir abonnieren das Bumper-Event
|
|
||||||
subscribe_msg = {
|
|
||||||
"Operation": "subscribe",
|
|
||||||
"Type": "BumpSensor",
|
|
||||||
"DebounceMs": 50,
|
|
||||||
"EventName": "BumperPress",
|
|
||||||
"ReturnProperty": None
|
|
||||||
}
|
|
||||||
ws.send(json.dumps(subscribe_msg))
|
|
||||||
|
|
||||||
# WebSocket starten
|
|
||||||
ws = websocket.WebSocketApp(f"ws://{MISTY_IP}/pubsub", on_open=on_open, on_message=on_message)
|
|
||||||
ws.run_forever()
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import requests
|
|
||||||
import base64
|
|
||||||
import time
|
|
||||||
|
|
||||||
from config import MISTY_IP
|
|
||||||
from analyse import analysiere, gib_feedback
|
|
||||||
|
|
||||||
DATEINAME = "aufnahme.wav"
|
|
||||||
AUFNAHME_DAUER_S = 10
|
|
||||||
|
|
||||||
def starte_aufnahme():
|
|
||||||
print(f"--- Schritt 1: Aufnahme ({AUFNAHME_DAUER_S}s) ---")
|
|
||||||
try:
|
|
||||||
requests.delete(f"http://{MISTY_IP}/api/audio?fileName={DATEINAME}", timeout=2)
|
|
||||||
response = requests.post(f"http://{MISTY_IP}/api/audio/record/start",
|
|
||||||
json={"fileName": DATEINAME}, timeout=5)
|
|
||||||
if response.status_code == 200:
|
|
||||||
print("🔴 Misty hört zu...")
|
|
||||||
time.sleep(AUFNAHME_DAUER_S)
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/audio/record/stop", timeout=5)
|
|
||||||
print("⏹️ Aufnahme beendet.")
|
|
||||||
time.sleep(3)
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Fehler bei Aufnahme: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def lade_datei():
|
|
||||||
print("--- Schritt 2: Datei vom Roboter laden ---")
|
|
||||||
url = f"http://{MISTY_IP}/api/audio?fileName={DATEINAME}&base64=true"
|
|
||||||
try:
|
|
||||||
response = requests.get(url, timeout=20)
|
|
||||||
if response.status_code == 200:
|
|
||||||
audio_bytes = base64.b64decode(response.json()["result"]["base64"])
|
|
||||||
with open(DATEINAME, "wb") as f:
|
|
||||||
f.write(audio_bytes)
|
|
||||||
print("✅ Datei geladen.")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Fehler beim Laden: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print("🚀 Rhetorik-Check gestartet")
|
|
||||||
if starte_aufnahme():
|
|
||||||
if lade_datei():
|
|
||||||
anzahl, text = analysiere(DATEINAME)
|
|
||||||
gib_feedback(anzahl)
|
|
||||||
print("--- PROGRAMM BEENDET ---")
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import subprocess
|
|
||||||
import numpy as np
|
|
||||||
import whisper
|
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
|
|
||||||
MISTY_IP = "192.168.68.57"
|
|
||||||
RTSP_URL = f"rtsp://{MISTY_IP}:1936"
|
|
||||||
|
|
||||||
print("Lade Whisper (tiny)...")
|
|
||||||
model = whisper.load_model("tiny")
|
|
||||||
|
|
||||||
def set_misty_led(r, g, b):
|
|
||||||
try:
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/led", json={"red": r, "green": g, "blue": b}, timeout=1)
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
ffmpeg_cmd = [
|
|
||||||
'ffmpeg', '-rtsp_transport', 'tcp', '-i', RTSP_URL,
|
|
||||||
'-vn', '-f', 's16le', '-ac', '1', '-ar', '16000', '-'
|
|
||||||
]
|
|
||||||
|
|
||||||
process = subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
|
||||||
set_misty_led(0, 255, 0) # Startet Grün
|
|
||||||
print(">>> MONITORING LÄUFT. Sprich jetzt!")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 3-Sekunden-Fenster
|
|
||||||
chunk_size = 16000 * 2 * 3
|
|
||||||
while True:
|
|
||||||
data = process.stdout.read(chunk_size)
|
|
||||||
if not data: break
|
|
||||||
|
|
||||||
audio = np.frombuffer(data, dtype=np.int16).astype(np.float32) / 32768.0
|
|
||||||
result = model.transcribe(audio, fp16=False, language="de")
|
|
||||||
text = result["text"].strip().lower()
|
|
||||||
|
|
||||||
if text:
|
|
||||||
print(f"Erkannt: {text}")
|
|
||||||
if any(w in text for w in ["äh", "ähm", "halt", "quasi"]):
|
|
||||||
print("⚠️ FÜLLWORT!")
|
|
||||||
set_misty_led(255, 0, 0) # Rot bei Fehler
|
|
||||||
time.sleep(1)
|
|
||||||
set_misty_led(0, 255, 0) # Zurück zu Grün
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
process.terminate()
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
from config import MISTY_IP
|
|
||||||
|
|
||||||
def setup_misty_audio():
|
|
||||||
print("--- Hard-Reset der Streaming-Dienste ---")
|
|
||||||
|
|
||||||
# 1. Bestehende Streams stoppen
|
|
||||||
try:
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/services/avstreaming/stop")
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# 2. Audio-Dienst aktivieren
|
|
||||||
print("1. Aktiviere Dienst...")
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/services/avstreaming/enable")
|
|
||||||
|
|
||||||
# 3. RTSP-Server starten (Port 1936 für Audio)
|
|
||||||
print("2. Starte RTSP-Server auf Port 1936...")
|
|
||||||
audio_payload = {
|
|
||||||
"Port": 1936,
|
|
||||||
"AudioSource": "Default",
|
|
||||||
"UserName": None,
|
|
||||||
"Password": None
|
|
||||||
}
|
|
||||||
# Wir nutzen hier wieder den Pfad, der bei dir funktioniert hat
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/services/avstreaming/audio/start", json=audio_payload)
|
|
||||||
|
|
||||||
# 4. Wartezeit für die Hardware
|
|
||||||
print("3. Warte auf Port-Freigabe (max 10 Sek)...")
|
|
||||||
for i in range(10):
|
|
||||||
print(".", end="", flush=True)
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
print("\nBereit! Der Stream sollte nun unter VLC oder Whisper erreichbar sein.")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"\nFehler beim Verbinden mit Misty ({MISTY_IP}): {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
setup_misty_audio()
|
|
||||||
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
|
|
||||||
MISTY_IP = "192.168.68.57"
|
|
||||||
|
|
||||||
def try_start(label, payload):
|
|
||||||
base_url = f"http://{MISTY_IP}/api/avstreaming/start"
|
|
||||||
print(f"Versuche {label}...")
|
|
||||||
try:
|
|
||||||
res = requests.post(base_url, json=payload, timeout=5)
|
|
||||||
if res.status_code == 200:
|
|
||||||
print(f"✅ {label} ERFOLGREICH!")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"❌ {label} fehlgeschlagen: {res.status_code} - {res.text}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fehler: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def run_all():
|
|
||||||
# Reset
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/avstreaming/stop")
|
|
||||||
|
|
||||||
# Variante A: 'URL' großgeschrieben mit null
|
|
||||||
payload_a = {"URL": None, "Width": 640, "Height": 480, "FrameRate": 15, "VideoBitRate": 1000000, "AudioBitRate": 128000, "AudioSampleRateHz": 16000}
|
|
||||||
|
|
||||||
# Variante B: 'Url' kleingeschrieben mit null
|
|
||||||
payload_b = {"Url": None, "Width": 640, "Height": 480, "FrameRate": 15, "VideoBitRate": 1000000, "AudioBitRate": 128000, "AudioSampleRateHz": 16000}
|
|
||||||
|
|
||||||
# Variante C: 'URL' mit lokalem Pfad (Manche Versionen brauchen das)
|
|
||||||
payload_c = {"URL": "rtsp://127.0.0.1:554/live", "Width": 640, "Height": 480, "FrameRate": 15, "VideoBitRate": 1000000, "AudioBitRate": 128000, "AudioSampleRateHz": 16000}
|
|
||||||
|
|
||||||
if not try_start("Variante A (URL: null)", payload_a):
|
|
||||||
if not try_start("Variante B (Url: null)", payload_b):
|
|
||||||
try_start("Variante C (Localhost IP)", payload_c)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_all()
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
from config import MISTY_IP
|
|
||||||
|
|
||||||
def start_misty_studio_clone():
|
|
||||||
print(f"--- Erzwungener Studio-Klon Start ({MISTY_IP}) ---")
|
|
||||||
|
|
||||||
# 1. Cleanup: Erst alles stoppen
|
|
||||||
requests.post(f"http://{MISTY_IP}/api/avstreaming/stop")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 2. Die exakte Struktur aus deinem Studio-Fund
|
|
||||||
# WICHTIG: Port muss im Body sein, url muss null sein
|
|
||||||
payload = {
|
|
||||||
"url": None,
|
|
||||||
"width": 0,
|
|
||||||
"height": 0,
|
|
||||||
"frameRate": 0,
|
|
||||||
"videoBitRate": 0,
|
|
||||||
"audioBitRate": 0,
|
|
||||||
"audioSampleRateHz": 0,
|
|
||||||
"userName": None,
|
|
||||||
"password": None,
|
|
||||||
"port": 1936
|
|
||||||
}
|
|
||||||
|
|
||||||
# Wir schicken es an den Endpoint, den das Studio nutzt
|
|
||||||
url = f"http://{MISTY_IP}/api/avstreaming/start"
|
|
||||||
|
|
||||||
print("Sende Paket...")
|
|
||||||
try:
|
|
||||||
response = requests.post(url, json=payload, timeout=10)
|
|
||||||
print(f"Status: {response.status_code}")
|
|
||||||
print(f"Antwort: {response.text}")
|
|
||||||
|
|
||||||
if response.status_code == 200 and "Success" in response.text:
|
|
||||||
print("\n✅ API sagt JA! Teste JETZT VLC.")
|
|
||||||
else:
|
|
||||||
print("\n❌ Misty hat das Paket abgelehnt.")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fehler: {e}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
start_misty_studio_clone()
|
|
||||||
108
old/test
108
old/test
|
|
@ -1,108 +0,0 @@
|
||||||
import whisper
|
|
||||||
import numpy as np
|
|
||||||
import subprocess
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
from config import RTSP_URL
|
|
||||||
|
|
||||||
# DEFINITION DER FÜLLWÖRTER
|
|
||||||
FILLER_WORDS = ["äh", "ähhm", "ähm", "mhm", "halt", "quasi", "sozusagen", "eigentlich"]
|
|
||||||
|
|
||||||
def analyze_text(text):
|
|
||||||
"""Sucht nach Füllwörtern im erkannten Text."""
|
|
||||||
text_clean = re.sub(r'[^\w\s]', '', text.lower())
|
|
||||||
# Entfernt einzelne Buchstaben/Satzzeichen und splittet in Wörter
|
|
||||||
words = text_clean.split()
|
|
||||||
found_fillers = {w: words.count(w) for w in FILLER_WORDS if w in words}
|
|
||||||
return sum(found_fillers.values()), found_fillers
|
|
||||||
|
|
||||||
def run_adaptive_whisper():
|
|
||||||
print(f"--- M2 Live-Coach: Analyse läuft ---")
|
|
||||||
|
|
||||||
# Modell laden
|
|
||||||
print("Lade Modell (base)...")
|
|
||||||
model = whisper.load_model("base")
|
|
||||||
|
|
||||||
# FFmpeg Befehl mit TCP für stabilere Verbindung
|
|
||||||
command = [
|
|
||||||
'ffmpeg',
|
|
||||||
'-rtsp_transport', 'tcp',
|
|
||||||
'-i', RTSP_URL,
|
|
||||||
'-ar', '16000',
|
|
||||||
'-ac', '1',
|
|
||||||
'-f', 's16le',
|
|
||||||
'-'
|
|
||||||
]
|
|
||||||
|
|
||||||
# Startet den FFmpeg-Prozess
|
|
||||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
audio_buffer = []
|
|
||||||
silence_start = None
|
|
||||||
|
|
||||||
# EINSTELLUNGEN FÜR DIE PAUSENERKENNUNG
|
|
||||||
THRESHOLD = 350 # Empfindlichkeit
|
|
||||||
SILENCE_DURATION = 2.5 # Sekunden Stille bis zum Ende
|
|
||||||
MIN_AUDIO_LENGTH = 15 # Mindestmenge an Daten
|
|
||||||
|
|
||||||
print(f"\nVerbindung zu: {RTSP_URL}")
|
|
||||||
print("[MISTY HÖRT ZU] Bitte sprich jetzt (2.5s Pause zum Beenden)...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
raw_chunk = process.stdout.read(3200)
|
|
||||||
if not raw_chunk:
|
|
||||||
break
|
|
||||||
|
|
||||||
chunk_np = np.frombuffer(raw_chunk, dtype=np.int16)
|
|
||||||
if chunk_np.size == 0: continue
|
|
||||||
|
|
||||||
audio_buffer.append(chunk_np)
|
|
||||||
amplitude = np.sqrt(np.mean(chunk_np**2))
|
|
||||||
|
|
||||||
if amplitude < THRESHOLD:
|
|
||||||
if silence_start is None:
|
|
||||||
silence_start = time.time()
|
|
||||||
elif time.time() - silence_start > SILENCE_DURATION:
|
|
||||||
if len(audio_buffer) > MIN_AUDIO_LENGTH:
|
|
||||||
print("\n[Pause erkannt - Analyse startet]")
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
sys.stdout.write(".")
|
|
||||||
sys.stdout.flush()
|
|
||||||
silence_start = None
|
|
||||||
|
|
||||||
process.terminate()
|
|
||||||
|
|
||||||
if not audio_buffer:
|
|
||||||
print("\n❌ Fehler: Keine Audiodaten empfangen.")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("Verarbeite Audio...")
|
|
||||||
full_audio = np.concatenate(audio_buffer).astype(np.float32) / 32768.0
|
|
||||||
|
|
||||||
# Transkription mit Füllwort-Support
|
|
||||||
result = model.transcribe(full_audio, language="de", initial_prompt="Äh, ähm, mhm.")
|
|
||||||
|
|
||||||
text = result['text'].strip()
|
|
||||||
count, details = analyze_text(text)
|
|
||||||
|
|
||||||
# --- AUSGABE ---
|
|
||||||
print("\n" + "═"*45)
|
|
||||||
print(f"ERKANNT: {text}")
|
|
||||||
print("─"*45)
|
|
||||||
print(f"ANALYSE: {count} Füllwörter gefunden.")
|
|
||||||
if count > 0:
|
|
||||||
for w, n in details.items():
|
|
||||||
print(f" -> '{w}': {n}x")
|
|
||||||
print("═"*45 + "\n")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"\nFehler: {e}")
|
|
||||||
finally:
|
|
||||||
if process and process.poll() is None:
|
|
||||||
process.kill()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_adaptive_whisper()
|
|
||||||
68
old/test.py
68
old/test.py
|
|
@ -1,68 +0,0 @@
|
||||||
import whisper
|
|
||||||
import numpy as np
|
|
||||||
import subprocess
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
from config import RTSP_URL, MISTY_IP
|
|
||||||
|
|
||||||
def run_test_inference():
|
|
||||||
print(f"--- Finaler Test-Lauf (SDK-Struktur) ---")
|
|
||||||
|
|
||||||
# Modell laden
|
|
||||||
print("Lade Whisper-Modell...")
|
|
||||||
model = whisper.load_model("base")
|
|
||||||
|
|
||||||
# FFmpeg-Befehl mit mehr "Geduld" (analyzeduration & probesize)
|
|
||||||
# Das hilft, wenn Misty den Stream langsam startet
|
|
||||||
command = [
|
|
||||||
'ffmpeg',
|
|
||||||
'-rtsp_transport', 'tcp',
|
|
||||||
'-analyzeduration', '5000000',
|
|
||||||
'-probesize', '5000000',
|
|
||||||
'-i', RTSP_URL,
|
|
||||||
'-ar', '16000',
|
|
||||||
'-ac', '1',
|
|
||||||
'-f', 's16le',
|
|
||||||
'-'
|
|
||||||
]
|
|
||||||
|
|
||||||
print(f"\nVersuche Verbindung zu: {RTSP_URL}")
|
|
||||||
# Startet den Prozess
|
|
||||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
|
|
||||||
audio_buffer = []
|
|
||||||
print("[MISTY HÖRT ZU] Sprich jetzt... (Sammle 10 Sekunden Audio)")
|
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
try:
|
|
||||||
# Wir sammeln jetzt erst mal stumpf 10 Sekunden, um den Puffer zu füllen
|
|
||||||
while time.time() - start_time < 10:
|
|
||||||
raw_chunk = process.stdout.read(3200)
|
|
||||||
if raw_chunk:
|
|
||||||
audio_buffer.append(np.frombuffer(raw_chunk, dtype=np.int16))
|
|
||||||
sys.stdout.write(".")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
process.terminate()
|
|
||||||
|
|
||||||
if not audio_buffer:
|
|
||||||
# Wenn nichts kam, schauen wir in den Error-Log von FFmpeg
|
|
||||||
_, stderr = process.communicate()
|
|
||||||
print(f"\n❌ FFmpeg Fehler-Log:\n{stderr.decode()}")
|
|
||||||
return
|
|
||||||
|
|
||||||
print("\n\nAnalyse startet...")
|
|
||||||
full_audio = np.concatenate(audio_buffer).astype(np.float32) / 32768.0
|
|
||||||
result = model.transcribe(full_audio, language="de")
|
|
||||||
|
|
||||||
print("\n" + "="*40)
|
|
||||||
print(f"ERGEBNIS: {result['text'].strip()}")
|
|
||||||
print("="*40 + "\n")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Fehler: {e}")
|
|
||||||
finally:
|
|
||||||
process.kill()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_test_inference()
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
import whisper
|
|
||||||
import numpy as np
|
|
||||||
import subprocess
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
from config import RTSP_URL
|
|
||||||
|
|
||||||
FILLER_WORDS = ["äh", "ähhm", "ähm", "mhm", "halt", "quasi", "sozusagen", "eigentlich"]
|
|
||||||
|
|
||||||
def analyze_text(text):
|
|
||||||
text_clean = re.sub(r'[^\w\s]', '', text.lower())
|
|
||||||
words = text_clean.split()
|
|
||||||
found_fillers = {w: words.count(w) for w in FILLER_WORDS if w in words}
|
|
||||||
return sum(found_fillers.values()), found_fillers
|
|
||||||
|
|
||||||
def run_adaptive_whisper():
|
|
||||||
print(f"--- M2 Live-Coach: Analyse läuft ---")
|
|
||||||
print("Lade KI-Modell...")
|
|
||||||
model = whisper.load_model("base")
|
|
||||||
|
|
||||||
# FFmpeg mit längerer Analysezeit und TCP-Zwang
|
|
||||||
command = [
|
|
||||||
'ffmpeg',
|
|
||||||
'-rtsp_transport', 'tcp',
|
|
||||||
'-i', RTSP_URL,
|
|
||||||
'-ar', '16000', '-ac', '1', '-f', 's16le', '-'
|
|
||||||
]
|
|
||||||
|
|
||||||
print(f"Verbinde zu: {RTSP_URL}")
|
|
||||||
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
|
||||||
|
|
||||||
audio_buffer = []
|
|
||||||
silence_start = None
|
|
||||||
THRESHOLD = 300 # Etwas empfindlicher
|
|
||||||
SILENCE_DURATION = 2.5
|
|
||||||
|
|
||||||
print("[WARTE AUF STREAM...]")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 10 Versuche, den Stream-Anfang zu finden
|
|
||||||
for _ in range(100):
|
|
||||||
raw_chunk = process.stdout.read(3200)
|
|
||||||
if raw_chunk:
|
|
||||||
print("[MISTY HÖRT ZU] - Daten fließen!")
|
|
||||||
audio_buffer.append(np.frombuffer(raw_chunk, dtype=np.int16))
|
|
||||||
break
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
if not audio_buffer:
|
|
||||||
print("❌ Fehler: Misty sendet keine Daten auf Port 1936.")
|
|
||||||
return
|
|
||||||
|
|
||||||
while True:
|
|
||||||
raw_chunk = process.stdout.read(3200)
|
|
||||||
if not raw_chunk: break
|
|
||||||
|
|
||||||
chunk_np = np.frombuffer(raw_chunk, dtype=np.int16)
|
|
||||||
audio_buffer.append(chunk_np)
|
|
||||||
amplitude = np.sqrt(np.mean(chunk_np**2)) if chunk_np.size > 0 else 0
|
|
||||||
|
|
||||||
if amplitude < THRESHOLD:
|
|
||||||
if silence_start is None:
|
|
||||||
silence_start = time.time()
|
|
||||||
elif time.time() - silence_start > SILENCE_DURATION:
|
|
||||||
if len(audio_buffer) > 20: break
|
|
||||||
else:
|
|
||||||
sys.stdout.write(".")
|
|
||||||
sys.stdout.flush()
|
|
||||||
silence_start = None
|
|
||||||
|
|
||||||
process.terminate()
|
|
||||||
full_audio = np.concatenate(audio_buffer).astype(np.float32) / 32768.0
|
|
||||||
result = model.transcribe(full_audio, language="de", initial_prompt="Äh, ähm, mhm.")
|
|
||||||
|
|
||||||
text = result['text'].strip()
|
|
||||||
count, details = analyze_text(text)
|
|
||||||
|
|
||||||
print("\n" + "═"*45)
|
|
||||||
print(f"TEXT: {text}")
|
|
||||||
print(f"FÜLLWÖRTER: {count}")
|
|
||||||
print("═"*45)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"\nFehler: {e}")
|
|
||||||
finally:
|
|
||||||
if process: process.kill()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run_adaptive_whisper()
|
|
||||||
|
|
@ -3,13 +3,13 @@
|
||||||
"sessions": [
|
"sessions": [
|
||||||
{
|
{
|
||||||
"nummer": 1,
|
"nummer": 1,
|
||||||
"zeit": "12:59",
|
"zeit": "14:06",
|
||||||
"text": "Blah, blah, blah, blah, blah, blah, blah, blah, blah.",
|
"text": "Hallo, ich bin der Koffee. Ich bin jetzt meine Gubrugest.",
|
||||||
"fuellwoerter_anzahl": 0,
|
"fuellwoerter_anzahl": 0,
|
||||||
"gefundene_woerter": {},
|
"gefundene_woerter": {},
|
||||||
"tempo": 102,
|
"tempo": 154,
|
||||||
"feedback": "Keine Füllwörter gefunden. Hervorragend! Dein Sprechtempo war sehr angenehm.",
|
"feedback": "Keine Füllwörter gefunden. Hervorragend! Dein Sprechtempo war etwas zu schnell. Versuche dich etwas zu verlangsamen.",
|
||||||
"gesicht": "e_Love.jpg"
|
"gesicht": "e_Contempt.jpg"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fehler": "WebSocket Fehler: "
|
"fehler": "WebSocket Fehler: "
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue