Ordnerstruktur aufgeräumt, .gitignore aktualisiert

This commit is contained in:
TiffanyBrugger 2026-07-24 14:08:12 +00:00
parent 41c2bfb671
commit 0877693bdb
20 changed files with 6 additions and 678 deletions

1
.gitignore vendored
View file

@ -2,4 +2,3 @@ __pycache__/
*.pyc *.pyc
*.wav *.wav
session_daten.json session_daten.json
*.save

Binary file not shown.

Binary file not shown.

View file

@ -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"

View file

@ -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()

View file

@ -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)

View file

@ -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()

View file

@ -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 ---")

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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
View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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: "