fix voice language selection from voice settings

This commit is contained in:
techartdev
2026-02-20 20:42:26 +02:00
parent e29bbdb128
commit 0227a68001
5 changed files with 58 additions and 5 deletions
+7
View File
@@ -2,6 +2,13 @@
All notable changes to the OpenClaw Home Assistant Integration will be documented in this file.
## [0.1.29] - 2026-02-20
### Fixed
- Voice language selection now prioritizes the preferred Assist pipeline language (`assist_pipeline/pipeline/list`) instead of only using Home Assistant UI language.
- Added separate TTS language resolution so spoken replies follow Assist pipeline TTS language when available.
- Retained safe fallbacks to integration/UI/browser language when Assist pipeline data is unavailable.
## [0.1.28] - 2026-02-20
### Fixed
+1 -1
View File
@@ -76,7 +76,7 @@ _CARD_PATH = Path(__file__).parent / "www" / _CARD_FILENAME
# URL at which the card JS is served (registered via register_static_path)
_CARD_STATIC_URL = f"/openclaw/{_CARD_FILENAME}"
# Versioned URL used for Lovelace resource registration to avoid stale browser cache
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.28"
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.29"
OpenClawConfigEntry = ConfigEntry
+1 -1
View File
@@ -8,7 +8,7 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues",
"requirements": [],
"version": "0.1.28",
"version": "0.1.29",
"dependencies": ["conversation"],
"after_dependencies": ["hassio", "lovelace"]
}
@@ -13,7 +13,7 @@
* + subscribes to openclaw_message_received events.
*/
const CARD_VERSION = "0.2.7";
const CARD_VERSION = "0.2.8";
// Max time (ms) to show the thinking indicator before falling back to an error
const THINKING_TIMEOUT_MS = 120_000;
@@ -70,6 +70,7 @@ class OpenClawChatCard extends HTMLElement {
this._pendingResponses = 0;
this._speechLangOverride = null;
this._integrationVoiceLanguage = null;
this._integrationTtsLanguage = null;
this._allowBraveWebSpeechIntegration = false;
this._voiceBackendBlocked = false;
this._voiceStopRequested = false;
@@ -320,6 +321,37 @@ class OpenClawChatCard extends HTMLElement {
? this._normalizeSpeechLanguage(result.language)
: null;
try {
let pipelineResult;
if (typeof this._hass.callWS === "function") {
pipelineResult = await this._hass.callWS({ type: "assist_pipeline/pipeline/list" });
} else {
pipelineResult = await this._hass.connection.sendMessagePromise({
type: "assist_pipeline/pipeline/list",
});
}
const preferredPipelineId = pipelineResult?.preferred_pipeline;
const pipelines = Array.isArray(pipelineResult?.pipelines)
? pipelineResult.pipelines
: [];
const preferredPipeline =
pipelines.find((pipeline) => pipeline?.id === preferredPipelineId) || pipelines[0];
const sttLanguage = preferredPipeline?.stt_language || preferredPipeline?.language;
const ttsLanguage =
preferredPipeline?.tts_language || preferredPipeline?.language || preferredPipeline?.stt_language;
if (sttLanguage) {
this._integrationVoiceLanguage = this._normalizeSpeechLanguage(sttLanguage);
}
if (ttsLanguage) {
this._integrationTtsLanguage = this._normalizeSpeechLanguage(ttsLanguage);
}
} catch (pipelineErr) {
console.debug("OpenClaw: assist pipeline language detection skipped:", pipelineErr);
}
if (this._alwaysVoiceMode && !this._isVoiceMode) {
this._isVoiceMode = true;
this._startVoiceRecognition();
@@ -479,6 +511,20 @@ class OpenClawChatCard extends HTMLElement {
return this._normalizeSpeechLanguage(preferred);
}
_getSpeechSynthesisLanguage() {
const configuredLang = this._config.voice_language;
const preferred =
configuredLang ||
this._integrationTtsLanguage ||
this._integrationVoiceLanguage ||
this._hass?.locale?.language ||
this._hass?.selectedLanguage ||
this._hass?.language ||
navigator.language ||
"en-US";
return this._normalizeSpeechLanguage(preferred);
}
_isLikelyBraveBrowser() {
const ua = (navigator.userAgent || "").toLowerCase();
const uaDataBrands = navigator.userAgentData?.brands || [];
@@ -685,7 +731,7 @@ class OpenClawChatCard extends HTMLElement {
if (!("speechSynthesis" in window)) return;
// Strip markdown for TTS
const plain = text.replace(/[*_`#\[\]()]/g, "");
const language = this._getSpeechRecognitionLanguage();
const language = this._getSpeechSynthesisLanguage();
const speakNow = () => {
const utterance = new SpeechSynthesisUtterance(plain);
+1 -1
View File
@@ -1,7 +1,7 @@
(async () => {
try {
if (!customElements.get("openclaw-chat-card")) {
const src = "/openclaw/openclaw-chat-card.js?v=0.1.28";
const src = "/openclaw/openclaw-chat-card.js?v=0.1.29";
console.info("OpenClaw loader importing", src);
await import(src);
}