first commit

This commit is contained in:
ersterDetektiv
2026-09-25 06:47:14 +02:00
commit 6f198c3d51
9 changed files with 1100 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env python3
"""
Input-Helper: Entwicklungstool für den Sprachassistenten.
Nimmt Text-Eingabe im Terminal entgegen und leitet sie als JSON an llm_module.py weiter.
Aufruf:
python input_helper.py # interaktiver Modus (Endlosschleife)
python input_helper.py "Deine Frage" # einmaliger Aufruf mit Argument
python input_helper.py --emotion drunk # mit Emotion
Optionen:
--emotion NAME Emotion für TTS (amused|angry|disgusted|drunk|neutral|sleepy|surprised|whisper)
--no-play Nur JSON erzeugen, kein Audio abspielen
--json-only Gibt nur das JSON aus, ruft LLM nicht auf
--history Aktiviert Gesprächsverlauf (Kontext merken)
--help Diese Hilfe
"""
import sys
import json
import os
import subprocess
import argparse
from pathlib import Path
SCRIPT_DIR = Path(__file__).parent
LLM_INPUT_FILE = SCRIPT_DIR / "data" / "llm_input.json"
VALID_EMOTIONS = ["amused", "angry", "disgusted", "drunk", "neutral", "sleepy", "surprised", "whisper"]
def parse_args():
parser = argparse.ArgumentParser(description="Voice Assistant Input Helper", add_help=True)
parser.add_argument("text", nargs="?", help="Eingabetext (optional, sonst interaktiv)")
parser.add_argument("--emotion", default="neutral", choices=VALID_EMOTIONS,
help="Emotion für die TTS-Ausgabe (Standard: neutral)")
parser.add_argument("--no-play", action="store_true",
help="Kein Audio abspielen, nur Datei erzeugen")
parser.add_argument("--json-only", action="store_true",
help="Nur JSON ausgeben, LLM nicht aufrufen")
parser.add_argument("--history", action="store_true",
help="Gesprächsverlauf aktivieren")
return parser.parse_args()
def build_payload(text: str, emotion: str, autoplay: bool, history: list) -> dict:
"""Erstellt das JSON-Payload für das LLM-Modul."""
return {
"request": text,
"type": "query",
"emotion": emotion,
"autoplay": autoplay,
"history": history,
}
def save_and_run(payload: dict, json_only: bool):
"""Speichert JSON und ruft LLM-Modul auf."""
LLM_INPUT_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(LLM_INPUT_FILE, "w", encoding="utf-8") as f:
json.dump(payload, f, ensure_ascii=False, indent=2)
if json_only:
print(json.dumps(payload, ensure_ascii=False, indent=2))
return None
llm_script = SCRIPT_DIR / "llm_module.py"
venv_python = Path.home() / ".venv" / "bin" / "python"
python_bin = str(venv_python) if venv_python.exists() else sys.executable
result = subprocess.run(
[python_bin, str(llm_script), str(LLM_INPUT_FILE)],
cwd=SCRIPT_DIR,
)
return result.returncode
def get_last_answer() -> str | None:
"""Liest die letzte LLM-Antwort aus der TTS-Input-Datei (für History)."""
tts_file = SCRIPT_DIR / "data" / "tts_input.json"
if tts_file.exists():
try:
with open(tts_file) as f:
data = json.load(f)
return data.get("text")
except Exception:
pass
return None
def interactive_loop(args):
"""Interaktiver Modus: Eingabe in Schleife."""
history = []
print("=" * 60)
print(" Thorsten Voice Assistant – Entwicklungs-Helper")
print("=" * 60)
print(f" Emotion: {args.emotion} | History: {'an' if args.history else 'aus'}")
print(" Tippe deine Anfrage oder 'exit' zum Beenden.")
print(" Befehle: /emotion <name> /history /clear /exit")
print("=" * 60)
emotion = args.emotion
while True:
try:
user_input = input("\n>> ").strip()
except (EOFError, KeyboardInterrupt):
print("\n[Helper] Beendet.")
break
if not user_input:
continue
# Meta-Befehle
if user_input.lower() in ("exit", "quit", "/exit"):
print("[Helper] Beendet.")
break
elif user_input.startswith("/emotion "):
new_emotion = user_input.split(" ", 1)[1].strip().lower()
if new_emotion in VALID_EMOTIONS:
emotion = new_emotion
print(f"[Helper] Emotion geändert zu: {emotion}")
else:
print(f"[Helper] Ungültige Emotion. Verfügbar: {', '.join(VALID_EMOTIONS)}")
continue
elif user_input == "/history":
print(f"[Helper] Verlauf ({len(history)} Einträge):")
for i, h in enumerate(history):
print(f" [{i}] User: {h.get('user', '')} → Assistant: {h.get('assistant', '')[:50]}...")
continue
elif user_input == "/clear":
history.clear()
print("[Helper] Verlauf gelöscht.")
continue
last_request = user_input
payload = build_payload(user_input, emotion, not args.no_play, history if args.history else [])
save_and_run(payload, args.json_only)
# History aktualisieren
if args.history:
answer = get_last_answer()
if answer:
history.append({"user": last_request, "assistant": answer})
# Max. 10 Einträge behalten
if len(history) > 10:
history = history[-10:]
def main():
args = parse_args()
if args.text:
# Einmaliger Aufruf
payload = build_payload(args.text, args.emotion, not args.no_play, [])
save_and_run(payload, args.json_only)
else:
# Interaktiver Modus
interactive_loop(args)
if __name__ == "__main__":
main()