Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/voice/language_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def enforce_input_language(text: str) -> str | None:

def clean_speakable_text(text: str) -> str:
value = re.sub(r"```.*?```", "", str(text or ""), flags=re.DOTALL)
value = re.sub(r"^\s*\[SPEAKER\]\s*", "", value, flags=re.IGNORECASE)
value = re.sub(r"[`*_#>|]", "", value)
value = re.sub(r"\s+", " ", value).strip()
return value
Expand Down
47 changes: 47 additions & 0 deletions docs/WINDOWS_UPDATE_VISION_SPEAKER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Biz-Windows: Foliensehen und saubere Sprachausgabe

Dieser Stand ergänzt v0.17.11 um die Entfernung des internen `[SPEAKER]`-Tags
aus gesprochenen Antworten. Der Folienweg vom Companion über `/lecture/context`
bis zur multimodalen Anfrage an das konfigurierte LLM ist bereits in v0.17.11
enthalten. Die iPad-/iPhone-App wird getrennt aktualisiert.

## Update der bestehenden Windows-VM

1. Die aktive Installation, den Git-Stand und lokale Änderungen ermitteln.
Vor dem Update die Konfiguration, `Soul.md`, `User.md`, den gesamten
`TrinityRuntime`-Ordner und die Voice-Referenzdateien sichern. Backups
außerhalb des Git-Repositories ablegen.
2. Den geprüften Git-Stand beziehen und Änderungen an der bestehenden
Installation vergleichen. Windows-spezifische oder lokale Anpassungen
übernehmen, statt sie durch Mac-Dateien zu ersetzen.
3. `system.profile=BIZ`, Modell-Endpunkt, Bridge- und Voice-Tokens,
Ubuntu-Verbindungen, Eve-Stimmprobe, Vault-Pfade und Wakeword-Varianten
aus der Windows-Konfiguration beibehalten. `core/config.json` nicht aus
dem Repository oder vom Mac übernehmen.
4. Die Windows-Trinity kontrolliert neu starten. Bestehende Chat- und
Sprachtests wiederholen; eine Modellantwort mit `[SPEAKER]` muss ohne
dieses Wort gesprochen werden. Die öffentliche Lautsprecherumschaltung
der älteren Desktop-Sprachausgabe separat prüfen.
5. Das Companion mit dem Tailscale-Endpunkt der Windows-Bridge verbinden und
eine PDF- und eine HTML-Folie testen: Seitenwechsel, Bildbestätigung in
den Companion-Einstellungen und eine Frage nach einem Detail, das nur
im Bild steht. Die Antwort muss über die Windows-Trinity laufen.

## Verteilung der Dienste

Die bestehende VM-/Ubuntu-Aufteilung ist unterstützt: Die Windows-VM hält
Sessions, Memory, Agenten und Freigaben; Ubuntu berechnet STT, TTS und das
Vision-LLM. Companion-Clients wählen die Windows-Bridge. Die Tailscale-
Verbindungen müssen für Bridge, Voice und Modell vorhanden bleiben.

Der Gemma4-Dienst auf Ubuntu benötigt für Bildanfragen eine ausreichend große
`batch-size` und `ubatch-size`. Auf der Workstation wurde am 22.09.2026 die
vorherige Kombination 512/128 nach einem reproduzierbaren Bild-Absturz auf
2048/2048 angehoben. Zwei synthetische Bildwerte und eine echte Companion-
Folie wurden anschließend korrekt gelesen. Dieser Serverwert gehört nicht
in die Windows-Trinity-Konfiguration.

Eine gemeinsame PRIVAT-/BIZ-Instanz ist eine eigene Migration. Sie benötigt
eine Entscheidung über Daten- und Zugriffsgrenzen sowie eine geprüfte
Übernahme der bisherigen Sessions und Memory-Datenbanken. Das Update hier
führt diese Migration nicht aus.
5 changes: 5 additions & 0 deletions tests/voice/test_voice_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ def test_german_policy_allows_short_technical_terms_but_rejects_english_paragrap
assert segment_for_speech("Erster Satz. Zweiter Satz.", max_chars=14) == ["Erster Satz.", "Zweiter Satz."]


def test_speaker_routing_marker_is_not_spoken():
assert segment_for_speech("[SPEAKER] Wir beginnen mit der Tabelle.") == ["Wir beginnen mit der Tabelle."]
assert segment_for_speech("Der Speaker ist hier ein Fachbegriff.") == ["Der Speaker ist hier ein Fachbegriff."]


def test_events_and_metrics_contain_no_prompt_content(tmp_path):
event = VoiceEvent("transcript.final", "s", "t", {"length": 12})
assert event.as_dict()["type"] == "transcript.final"
Expand Down
Loading