037c4b11df
- main.py: CustomTkinter GUI (400x520) mit Status-Indikator, Conversation-Log, Screenshot-Toggle und Settings-Dialog. Thread-sicherer UI-Queue für Hotkey-Callbacks. - hotkey_listener.py: pynput globaler Hotkey (press/release) + KeyCapturer für interaktive Hotkey-Konfiguration im Settings-Dialog. - config_manager.py: JSON-Settings in ~/.hermes-voice/settings.json mit DEFAULTS, load() merged gespeicherte mit Default-Werten. - audio_input.py: Vereinfacht auf start_recording/stop_recording/transcribe (kein Wake-Word-Loop mehr, direkt hotkey-gesteuert). - ai_client.py: Settings-dict statt config.py-Imports, MC2-URL/Modelle konfigurierbar. - requirements.txt: customtkinter>=5.2.0 + pynput>=1.7.6 hinzugefügt, pystray entfernt. - build.bat: PyInstaller --onefile --windowed → dist/HermesVoice.exe. - setup.bat: Veraltete Wake-Word-Hinweise entfernt, GUI-Check angepasst. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
import httpx
|
|
|
|
SYSTEM_PROMPT = (
|
|
"Du bist Hermes, ein hilfreicher KI-Assistent. "
|
|
"Antworte kurz und präzise, da deine Antwort vorgelesen wird. "
|
|
"Maximal 3-4 Sätze, kein Markdown."
|
|
)
|
|
REQUEST_TIMEOUT = 30
|
|
|
|
|
|
def ask(text: str, screenshot_b64: str | None, settings: dict) -> str:
|
|
"""Schickt Text (+ optionalen Screenshot) an MC2 und gibt die Antwort zurück."""
|
|
use_vision = screenshot_b64 is not None
|
|
model = settings.get("vision_model", "Qwen3-VL-2B-Instruct") if use_vision \
|
|
else settings.get("chat_model", "Hermes-4-14B")
|
|
base_url = settings.get("mc2_url", "http://192.168.178.151:9001/v1")
|
|
max_tokens = int(settings.get("max_response_tokens", 200))
|
|
|
|
if use_vision:
|
|
user_content = [
|
|
{"type": "text", "text": text},
|
|
{"type": "image_url", "image_url": {
|
|
"url": f"data:image/jpeg;base64,{screenshot_b64}"
|
|
}},
|
|
]
|
|
else:
|
|
user_content = text
|
|
|
|
payload = {
|
|
"model": model,
|
|
"messages": [
|
|
{"role": "system", "content": SYSTEM_PROMPT},
|
|
{"role": "user", "content": user_content},
|
|
],
|
|
"max_tokens": max_tokens,
|
|
"stream": False,
|
|
}
|
|
|
|
try:
|
|
with httpx.Client(timeout=REQUEST_TIMEOUT) as client:
|
|
response = client.post(f"{base_url}/chat/completions", json=payload)
|
|
response.raise_for_status()
|
|
return response.json()["choices"][0]["message"]["content"].strip()
|
|
except httpx.TimeoutException:
|
|
return "Entschuldigung, die Antwort hat zu lange gedauert."
|
|
except Exception as e:
|
|
return f"Verbindungsfehler: {e}"
|