homeassistant 2025.7.0b0__py3-none-any.whl → 2025.7.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- homeassistant/components/aemet/sensor.py +1 -1
- homeassistant/components/airq/coordinator.py +2 -2
- homeassistant/components/alexa_devices/__init__.py +5 -2
- homeassistant/components/alexa_devices/notify.py +2 -0
- homeassistant/components/alexa_devices/quality_scale.yaml +1 -1
- homeassistant/components/alexa_devices/strings.json +11 -4
- homeassistant/components/alexa_devices/switch.py +2 -0
- homeassistant/components/alexa_devices/translations/bg.json +6 -4
- homeassistant/components/alexa_devices/translations/cs.json +0 -4
- homeassistant/components/alexa_devices/translations/de.json +6 -7
- homeassistant/components/alexa_devices/translations/el.json +4 -5
- homeassistant/components/alexa_devices/translations/en.json +12 -5
- homeassistant/components/alexa_devices/translations/es.json +0 -4
- homeassistant/components/alexa_devices/translations/et.json +4 -5
- homeassistant/components/alexa_devices/translations/ga.json +0 -6
- homeassistant/components/alexa_devices/translations/he.json +0 -4
- homeassistant/components/alexa_devices/translations/hu.json +0 -4
- homeassistant/components/alexa_devices/translations/id.json +1 -0
- homeassistant/components/alexa_devices/translations/lt.json +0 -4
- homeassistant/components/alexa_devices/translations/mk.json +12 -0
- homeassistant/components/alexa_devices/translations/nl.json +0 -4
- homeassistant/components/alexa_devices/translations/pl.json +0 -4
- homeassistant/components/alexa_devices/translations/pt.json +0 -4
- homeassistant/components/alexa_devices/translations/ru.json +4 -5
- homeassistant/components/alexa_devices/translations/sk.json +4 -5
- homeassistant/components/alexa_devices/translations/sv.json +17 -5
- homeassistant/components/alexa_devices/translations/tr.json +0 -4
- homeassistant/components/alexa_devices/translations/zh-Hans.json +15 -4
- homeassistant/components/alexa_devices/translations/zh-Hant.json +4 -5
- homeassistant/components/alexa_devices/utils.py +40 -0
- homeassistant/components/altruist/translations/id.json +11 -0
- homeassistant/components/anthropic/__init__.py +8 -1
- homeassistant/components/anthropic/translations/bg.json +21 -0
- homeassistant/components/anthropic/translations/ga.json +32 -1
- homeassistant/components/anthropic/translations/id.json +19 -0
- homeassistant/components/anthropic/translations/ru.json +30 -0
- homeassistant/components/buienradar/sensor.py +0 -1
- homeassistant/components/cambridge_audio/translations/sv.json +1 -1
- homeassistant/components/demo/translations/select.sv.json +2 -2
- homeassistant/components/derivative/translations/ga.json +20 -0
- homeassistant/components/derivative/translations/ru.json +3 -0
- homeassistant/components/devolo_home_control/translations/bg.json +6 -0
- homeassistant/components/devolo_home_control/translations/id.json +5 -0
- homeassistant/components/devolo_home_control/translations/sv.json +10 -0
- homeassistant/components/devolo_home_control/translations/zh-Hans.json +10 -0
- homeassistant/components/dlink/manifest.json +1 -1
- homeassistant/components/ecovacs/translations/sv.json +1 -1
- homeassistant/components/enphase_envoy/translations/sv.json +2 -2
- homeassistant/components/ezviz/translations/bg.json +6 -0
- homeassistant/components/ezviz/translations/mk.json +13 -0
- homeassistant/components/ezviz/translations/sv.json +10 -0
- homeassistant/components/ezviz/translations/zh-Hans.json +10 -0
- homeassistant/components/frontend/manifest.json +1 -1
- homeassistant/components/goodwe/translations/sv.json +5 -5
- homeassistant/components/google_generative_ai_conversation/__init__.py +15 -0
- homeassistant/components/google_generative_ai_conversation/config_flow.py +72 -36
- homeassistant/components/google_generative_ai_conversation/const.py +15 -2
- homeassistant/components/google_generative_ai_conversation/diagnostics.py +1 -0
- homeassistant/components/google_generative_ai_conversation/entity.py +7 -2
- homeassistant/components/google_generative_ai_conversation/helpers.py +73 -0
- homeassistant/components/google_generative_ai_conversation/strings.json +28 -1
- homeassistant/components/google_generative_ai_conversation/translations/bg.json +19 -0
- homeassistant/components/google_generative_ai_conversation/translations/de.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/el.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/en.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/es.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/et.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/ga.json +9 -0
- homeassistant/components/google_generative_ai_conversation/translations/id.json +30 -0
- homeassistant/components/google_generative_ai_conversation/translations/mk.json +11 -0
- homeassistant/components/google_generative_ai_conversation/translations/ru.json +67 -0
- homeassistant/components/google_generative_ai_conversation/translations/sk.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/sv.json +21 -0
- homeassistant/components/google_generative_ai_conversation/translations/zh-Hans.json +28 -0
- homeassistant/components/google_generative_ai_conversation/translations/zh-Hant.json +28 -0
- homeassistant/components/google_generative_ai_conversation/tts.py +48 -106
- homeassistant/components/group/translations/el.json +18 -18
- homeassistant/components/habitica/const.py +1 -1
- homeassistant/components/harmony/translations/select.sv.json +1 -1
- homeassistant/components/harmony/translations/sv.json +1 -1
- homeassistant/components/homeassistant_hardware/translations/ga.json +9 -0
- homeassistant/components/homeassistant_hardware/translations/mk.json +9 -0
- homeassistant/components/homeassistant_sky_connect/translations/ga.json +10 -0
- homeassistant/components/homeassistant_sky_connect/translations/mk.json +7 -0
- homeassistant/components/homeassistant_yellow/translations/ga.json +5 -0
- homeassistant/components/homewizard/translations/sv.json +3 -1
- homeassistant/components/http/auth.py +1 -1
- homeassistant/components/image/__init__.py +34 -3
- homeassistant/components/input_select/translations/sv.json +6 -6
- homeassistant/components/iron_os/translations/sv.json +1 -1
- homeassistant/components/keenetic_ndms2/translations/id.json +3 -0
- homeassistant/components/lamarzocco/translations/sv.json +3 -3
- homeassistant/components/lametric/translations/sv.json +2 -2
- homeassistant/components/lametric/update.py +1 -1
- homeassistant/components/lg_thinq/translations/sv.json +5 -5
- homeassistant/components/litterrobot/translations/bg.json +4 -0
- homeassistant/components/litterrobot/translations/ga.json +3 -0
- homeassistant/components/matter/translations/id.json +5 -0
- homeassistant/components/matter/vacuum.py +38 -26
- homeassistant/components/meater/__init__.py +5 -1
- homeassistant/components/meater/coordinator.py +4 -2
- homeassistant/components/media_source/local_source.py +21 -4
- homeassistant/components/mqtt/translations/bg.json +10 -0
- homeassistant/components/mqtt/translations/el.json +21 -0
- homeassistant/components/mqtt/translations/fi.json +3 -0
- homeassistant/components/mqtt/translations/ga.json +25 -0
- homeassistant/components/mqtt/translations/mk.json +23 -0
- homeassistant/components/mqtt/translations/ru.json +1 -0
- homeassistant/components/mqtt/translations/sv.json +24 -0
- homeassistant/components/mqtt/translations/zh-Hans.json +26 -0
- homeassistant/components/mqtt/translations/zh-Hant.json +19 -0
- homeassistant/components/music_assistant/button.py +0 -6
- homeassistant/components/ntfy/translations/id.json +13 -0
- homeassistant/components/ohme/translations/sv.json +1 -1
- homeassistant/components/ollama/__init__.py +2 -0
- homeassistant/components/ollama/const.py +2 -0
- homeassistant/components/ollama/translations/bg.json +19 -0
- homeassistant/components/ollama/translations/ga.json +31 -1
- homeassistant/components/ollama/translations/id.json +18 -0
- homeassistant/components/ollama/translations/mk.json +13 -1
- homeassistant/components/onewire/translations/sv.json +4 -4
- homeassistant/components/openai_conversation/__init__.py +2 -0
- homeassistant/components/openai_conversation/const.py +1 -1
- homeassistant/components/openai_conversation/conversation.py +1 -1
- homeassistant/components/openai_conversation/translations/bg.json +26 -0
- homeassistant/components/openai_conversation/translations/id.json +23 -0
- homeassistant/components/openai_conversation/translations/mk.json +44 -0
- homeassistant/components/playstation_network/translations/bg.json +25 -1
- homeassistant/components/playstation_network/translations/es.json +1 -1
- homeassistant/components/playstation_network/translations/ga.json +31 -0
- homeassistant/components/playstation_network/translations/id.json +14 -0
- homeassistant/components/playstation_network/translations/mk.json +18 -0
- homeassistant/components/playstation_network/translations/sv.json +29 -0
- homeassistant/components/playstation_network/translations/zh-Hans.json +29 -0
- homeassistant/components/qnap/translations/sv.json +1 -1
- homeassistant/components/remote_calendar/translations/fi.json +34 -0
- homeassistant/components/select/translations/sv.json +10 -10
- homeassistant/components/smarla/__init__.py +2 -2
- homeassistant/components/sonos/translations/bg.json +5 -0
- homeassistant/components/sonos/translations/el.json +6 -0
- homeassistant/components/sonos/translations/ga.json +8 -0
- homeassistant/components/sonos/translations/mk.json +10 -0
- homeassistant/components/sonos/translations/ru.json +6 -0
- homeassistant/components/sonos/translations/sv.json +6 -0
- homeassistant/components/sonos/translations/zh-Hans.json +9 -0
- homeassistant/components/sonos/translations/zh-Hant.json +6 -0
- homeassistant/components/switchbot/translations/bg.json +26 -0
- homeassistant/components/switchbot/translations/ga.json +33 -0
- homeassistant/components/switchbot/translations/id.json +19 -0
- homeassistant/components/switchbot/translations/mk.json +49 -0
- homeassistant/components/switchbot/translations/sv.json +52 -0
- homeassistant/components/switchbot/translations/zh-Hans.json +53 -0
- homeassistant/components/telegram_bot/__init__.py +20 -4
- homeassistant/components/telegram_bot/bot.py +33 -29
- homeassistant/components/telegram_bot/config_flow.py +49 -10
- homeassistant/components/telegram_bot/const.py +1 -1
- homeassistant/components/telegram_bot/strings.json +33 -10
- homeassistant/components/telegram_bot/translations/bg.json +0 -1
- homeassistant/components/telegram_bot/translations/cs.json +5 -12
- homeassistant/components/telegram_bot/translations/de.json +12 -11
- homeassistant/components/telegram_bot/translations/el.json +5 -12
- homeassistant/components/telegram_bot/translations/en-GB.json +5 -12
- homeassistant/components/telegram_bot/translations/en.json +35 -12
- homeassistant/components/telegram_bot/translations/es.json +5 -12
- homeassistant/components/telegram_bot/translations/et.json +11 -12
- homeassistant/components/telegram_bot/translations/fr.json +5 -12
- homeassistant/components/telegram_bot/translations/ga.json +5 -11
- homeassistant/components/telegram_bot/translations/he.json +3 -8
- homeassistant/components/telegram_bot/translations/hu.json +5 -12
- homeassistant/components/telegram_bot/translations/id.json +0 -5
- homeassistant/components/telegram_bot/translations/it.json +2 -5
- homeassistant/components/telegram_bot/translations/lt.json +5 -12
- homeassistant/components/telegram_bot/translations/mk.json +7 -5
- homeassistant/components/telegram_bot/translations/nl.json +5 -12
- homeassistant/components/telegram_bot/translations/pt.json +5 -12
- homeassistant/components/telegram_bot/translations/ru.json +12 -11
- homeassistant/components/telegram_bot/translations/sk.json +5 -12
- homeassistant/components/telegram_bot/translations/sv.json +5 -12
- homeassistant/components/telegram_bot/translations/tr.json +5 -12
- homeassistant/components/telegram_bot/translations/zh-Hans.json +5 -12
- homeassistant/components/telegram_bot/translations/zh-Hant.json +5 -12
- homeassistant/components/template/translations/sv.json +5 -5
- homeassistant/components/tilt_pi/translations/id.json +11 -0
- homeassistant/components/tts/__init__.py +15 -0
- homeassistant/components/unifiprotect/translations/zh-Hans.json +3 -3
- homeassistant/components/utility_meter/translations/sv.json +9 -9
- homeassistant/components/vegehub/translations/bg.json +2 -0
- homeassistant/components/vegehub/translations/id.json +11 -0
- homeassistant/components/whirlpool/translations/sv.json +12 -12
- homeassistant/components/zha/translations/bg.json +23 -0
- homeassistant/components/zha/translations/el.json +10 -0
- homeassistant/components/zha/translations/ga.json +20 -0
- homeassistant/components/zha/translations/id.json +6 -0
- homeassistant/components/zha/translations/sv.json +15 -0
- homeassistant/components/zha/translations/zh-Hans.json +50 -0
- homeassistant/components/zwave_js/api.py +1 -1
- homeassistant/components/zwave_js/config_flow.py +12 -8
- homeassistant/components/zwave_js/manifest.json +1 -1
- homeassistant/config_entries.py +6 -0
- homeassistant/const.py +1 -1
- homeassistant/package_constraints.txt +1 -1
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/METADATA +1 -1
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/RECORD +208 -192
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/WHEEL +0 -0
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/entry_points.txt +0 -0
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/licenses/LICENSE.md +0 -0
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/licenses/homeassistant/backports/LICENSE.Python +0 -0
- {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"config": {
|
|
3
3
|
"abort": {
|
|
4
|
+
"already_configured": "Layanan sudah dikonfigurasi",
|
|
4
5
|
"reauth_successful": "Autentikasi ulang berhasil"
|
|
5
6
|
},
|
|
6
7
|
"error": {
|
|
@@ -21,6 +22,35 @@
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
},
|
|
25
|
+
"config_subentries": {
|
|
26
|
+
"conversation": {
|
|
27
|
+
"abort": {
|
|
28
|
+
"reconfigure_successful": "Konfigurasi ulang berhasil"
|
|
29
|
+
},
|
|
30
|
+
"step": {
|
|
31
|
+
"set_options": {
|
|
32
|
+
"data": {
|
|
33
|
+
"chat_model": "Model",
|
|
34
|
+
"llm_hass_api": "Kendalikan Home Assistant",
|
|
35
|
+
"name": "Nama"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"tts": {
|
|
41
|
+
"abort": {
|
|
42
|
+
"reconfigure_successful": "Konfigurasi ulang berhasil"
|
|
43
|
+
},
|
|
44
|
+
"step": {
|
|
45
|
+
"set_options": {
|
|
46
|
+
"data": {
|
|
47
|
+
"chat_model": "Model",
|
|
48
|
+
"name": "Nama"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
24
54
|
"services": {
|
|
25
55
|
"generate_content": {
|
|
26
56
|
"description": "Menghasilkan konten dari perintah yang terdiri dari teks dan gambar secara opsional",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"config_subentries": {
|
|
3
|
+
"tts": {
|
|
4
|
+
"entry_type": "\u0422\u0435\u043a\u0441\u0442-\u0432\u043e-\u0433\u043e\u0432\u043e\u0440",
|
|
5
|
+
"initiate_flow": {
|
|
6
|
+
"reconfigure": "\u0420\u0435\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u0458 \u0458\u0430 \u0443\u0441\u043b\u0443\u0433\u0430\u0442\u0430 \u0437\u0430 \u043f\u0440\u0435\u0442\u0432\u043e\u0440\u0430\u045a\u0435 \u0442\u0435\u043a\u0441\u0442 \u0432\u043e \u0433\u043e\u0432\u043e\u0440",
|
|
7
|
+
"user": "\u0414\u043e\u0434\u0430\u0458 \u0443\u0441\u043b\u0443\u0433\u0430 \u0437\u0430 \u043f\u0440\u0435\u0442\u0432\u043e\u0440\u0430\u045a\u0435 \u0442\u0435\u043a\u0441\u0442 \u0432\u043e \u0433\u043e\u0432\u043e\u0440"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"config": {
|
|
3
3
|
"abort": {
|
|
4
|
+
"already_configured": "\u042d\u0442\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant",
|
|
4
5
|
"reauth_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e"
|
|
5
6
|
},
|
|
6
7
|
"error": {
|
|
@@ -21,6 +22,72 @@
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
},
|
|
25
|
+
"config_subentries": {
|
|
26
|
+
"conversation": {
|
|
27
|
+
"abort": {
|
|
28
|
+
"entry_not_loaded": "\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u043f\u043e\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430.",
|
|
29
|
+
"reconfigure_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e"
|
|
30
|
+
},
|
|
31
|
+
"entry_type": "\u0414\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430",
|
|
32
|
+
"error": {
|
|
33
|
+
"invalid_google_search_option": "\u041f\u043e\u0438\u0441\u043a Google \u043c\u043e\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \"\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 Home Assistant\" \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e."
|
|
34
|
+
},
|
|
35
|
+
"initiate_flow": {
|
|
36
|
+
"reconfigure": "\u041f\u0435\u0440\u0435\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443",
|
|
37
|
+
"user": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443"
|
|
38
|
+
},
|
|
39
|
+
"step": {
|
|
40
|
+
"set_options": {
|
|
41
|
+
"data": {
|
|
42
|
+
"chat_model": "\u041c\u043e\u0434\u0435\u043b\u044c",
|
|
43
|
+
"dangerous_block_threshold": "\u041f\u043e\u043e\u0449\u0440\u044f\u0435\u0442, \u0441\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043b\u0438 \u043f\u043e\u0434\u0441\u0442\u0440\u0435\u043a\u0430\u0435\u0442 \u043a \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0432\u0440\u0435\u0434\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439",
|
|
44
|
+
"enable_google_search_tool": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043f\u043e\u0438\u0441\u043a\u0430 Google",
|
|
45
|
+
"harassment_block_threshold": "\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0438\u043b\u0438 \u0432\u0440\u0435\u0434\u043d\u044b\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0438/\u0438\u043b\u0438 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
|
|
46
|
+
"hate_block_threshold": "\u0413\u0440\u0443\u0431\u044b\u0439, \u043d\u0435\u0443\u0432\u0430\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043b\u0438 \u043d\u0435\u043f\u0440\u0438\u0441\u0442\u043e\u0439\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442",
|
|
47
|
+
"llm_hass_api": "\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 Home Assistant",
|
|
48
|
+
"max_tokens": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0432 \u043e\u0442\u0432\u0435\u0442",
|
|
49
|
+
"name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",
|
|
50
|
+
"prompt": "\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438",
|
|
51
|
+
"sexual_block_threshold": "\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f \u043e \u0441\u0435\u043a\u0441\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043d\u0435\u043f\u0440\u0438\u0441\u0442\u043e\u0439\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b",
|
|
52
|
+
"temperature": "\u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430",
|
|
53
|
+
"top_k": "Top K",
|
|
54
|
+
"top_p": "Top P"
|
|
55
|
+
},
|
|
56
|
+
"data_description": {
|
|
57
|
+
"enable_google_search_tool": "\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \"\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 Home Assistant\" \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e. \u0421\u043c. \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0443\u0442\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \"Assist\".",
|
|
58
|
+
"prompt": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435, \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c LLM. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d."
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"tts": {
|
|
64
|
+
"abort": {
|
|
65
|
+
"entry_not_loaded": "\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u043f\u043e\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430.",
|
|
66
|
+
"reconfigure_successful": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e"
|
|
67
|
+
},
|
|
68
|
+
"entry_type": "\u0421\u0438\u043d\u0442\u0435\u0437 \u0440\u0435\u0447\u0438",
|
|
69
|
+
"initiate_flow": {
|
|
70
|
+
"reconfigure": "\u041f\u0435\u0440\u0435\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043b\u0443\u0436\u0431\u0443 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0440\u0435\u0447\u044c",
|
|
71
|
+
"user": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0443\u0436\u0431\u0443 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0440\u0435\u0447\u044c"
|
|
72
|
+
},
|
|
73
|
+
"step": {
|
|
74
|
+
"set_options": {
|
|
75
|
+
"data": {
|
|
76
|
+
"chat_model": "\u041c\u043e\u0434\u0435\u043b\u044c",
|
|
77
|
+
"dangerous_block_threshold": "\u041f\u043e\u043e\u0449\u0440\u044f\u0435\u0442, \u0441\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043b\u0438 \u043f\u043e\u0434\u0441\u0442\u0440\u0435\u043a\u0430\u0435\u0442 \u043a \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0432\u0440\u0435\u0434\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439",
|
|
78
|
+
"harassment_block_threshold": "\u041d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0438\u043b\u0438 \u0432\u0440\u0435\u0434\u043d\u044b\u0435 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0438/\u0438\u043b\u0438 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
|
|
79
|
+
"hate_block_threshold": "\u0413\u0440\u0443\u0431\u044b\u0439, \u043d\u0435\u0443\u0432\u0430\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043b\u0438 \u043d\u0435\u043f\u0440\u0438\u0441\u0442\u043e\u0439\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442",
|
|
80
|
+
"max_tokens": "\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0432 \u043e\u0442\u0432\u0435\u0442",
|
|
81
|
+
"name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",
|
|
82
|
+
"sexual_block_threshold": "\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f \u043e \u0441\u0435\u043a\u0441\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043d\u0435\u043f\u0440\u0438\u0441\u0442\u043e\u0439\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b",
|
|
83
|
+
"temperature": "\u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430",
|
|
84
|
+
"top_k": "Top K",
|
|
85
|
+
"top_p": "Top P"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
24
91
|
"issues": {
|
|
25
92
|
"deprecated_image_filename_parameter": {
|
|
26
93
|
"description": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 'image_filename' \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445 Google Generative AI \u0443\u0441\u0442\u0430\u0440\u0435\u043b. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c 'filenames' \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e.",
|
|
@@ -60,6 +60,34 @@
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
},
|
|
64
|
+
"tts": {
|
|
65
|
+
"abort": {
|
|
66
|
+
"entry_not_loaded": "Nie je mo\u017en\u00e9 prid\u00e1va\u0165 veci, ke\u010f je konfigur\u00e1cia vypnut\u00e1.",
|
|
67
|
+
"reconfigure_successful": "Rekonfigur\u00e1cia bola \u00faspe\u0161n\u00e1"
|
|
68
|
+
},
|
|
69
|
+
"entry_type": "Prevod textu na re\u010d",
|
|
70
|
+
"initiate_flow": {
|
|
71
|
+
"reconfigure": "Rekonfigur\u00e1cia slu\u017eby prevodu textu na re\u010d",
|
|
72
|
+
"user": "Prida\u0165 slu\u017ebu prevodu textu na re\u010d"
|
|
73
|
+
},
|
|
74
|
+
"step": {
|
|
75
|
+
"set_options": {
|
|
76
|
+
"data": {
|
|
77
|
+
"chat_model": "Model",
|
|
78
|
+
"dangerous_block_threshold": "Podporuje, u\u013eah\u010duje alebo nab\u00e1da k \u0161kodliv\u00fdm \u010dinom",
|
|
79
|
+
"harassment_block_threshold": "Negat\u00edvne alebo \u0161kodliv\u00e9 koment\u00e1re zameran\u00e9 na identitu a/alebo chr\u00e1nen\u00e9 vlastnosti",
|
|
80
|
+
"hate_block_threshold": "Obsah, ktor\u00fd je hrub\u00fd, ne\u00factiv\u00fd alebo vulg\u00e1rny",
|
|
81
|
+
"max_tokens": "Maxim\u00e1lny po\u010det tokenov, ktor\u00e9 sa maj\u00fa vr\u00e1ti\u0165 v odpovedi",
|
|
82
|
+
"name": "N\u00e1zov",
|
|
83
|
+
"recommended": "Odpor\u00fa\u010dan\u00e9 nastavenia modelu",
|
|
84
|
+
"sexual_block_threshold": "Obsahuje odkazy na sexu\u00e1lne akty alebo in\u00fd oplzl\u00fd obsah",
|
|
85
|
+
"temperature": "Teplota",
|
|
86
|
+
"top_k": "Top K",
|
|
87
|
+
"top_p": "Top P"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
},
|
|
65
93
|
"issues": {
|
|
@@ -40,6 +40,27 @@
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
},
|
|
44
|
+
"tts": {
|
|
45
|
+
"abort": {
|
|
46
|
+
"reconfigure_successful": "Omkonfigureringen lyckades"
|
|
47
|
+
},
|
|
48
|
+
"entry_type": "Text-till-tal",
|
|
49
|
+
"initiate_flow": {
|
|
50
|
+
"reconfigure": "Konfigurera om text-till-tal-tj\u00e4nst",
|
|
51
|
+
"user": "L\u00e4gg till text-till-tal-tj\u00e4nst"
|
|
52
|
+
},
|
|
53
|
+
"step": {
|
|
54
|
+
"set_options": {
|
|
55
|
+
"data": {
|
|
56
|
+
"chat_model": "Modell",
|
|
57
|
+
"name": "Namn",
|
|
58
|
+
"recommended": "Rekommenderade modellinst\u00e4llningar",
|
|
59
|
+
"sexual_block_threshold": "Inneh\u00e5ller referenser till sexuella handlingar eller annat oanst\u00e4ndigt inneh\u00e5ll",
|
|
60
|
+
"temperature": "Temperatur"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
43
64
|
}
|
|
44
65
|
},
|
|
45
66
|
"issues": {
|
|
@@ -60,6 +60,34 @@
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
},
|
|
64
|
+
"tts": {
|
|
65
|
+
"abort": {
|
|
66
|
+
"entry_not_loaded": "\u7981\u7528\u914d\u7f6e\u65f6\u65e0\u6cd5\u6dfb\u52a0\u5185\u5bb9\u3002",
|
|
67
|
+
"reconfigure_successful": "\u91cd\u65b0\u914d\u7f6e\u6210\u529f"
|
|
68
|
+
},
|
|
69
|
+
"entry_type": "\u6587\u672c\u8f6c\u8bed\u97f3",
|
|
70
|
+
"initiate_flow": {
|
|
71
|
+
"reconfigure": "\u91cd\u65b0\u914d\u7f6e\u6587\u672c\u8f6c\u8bed\u97f3\u670d\u52a1",
|
|
72
|
+
"user": "\u6dfb\u52a0\u6587\u672c\u8f6c\u8bed\u97f3\u670d\u52a1"
|
|
73
|
+
},
|
|
74
|
+
"step": {
|
|
75
|
+
"set_options": {
|
|
76
|
+
"data": {
|
|
77
|
+
"chat_model": "\u6a21\u578b",
|
|
78
|
+
"dangerous_block_threshold": "\u4fc3\u8fdb\u3001\u534f\u52a9\u6216\u9f13\u52b1\u6709\u5bb3\u884c\u4e3a",
|
|
79
|
+
"harassment_block_threshold": "\u9488\u5bf9\u8eab\u4efd\u548c/\u6216\u53d7\u4fdd\u62a4\u5c5e\u6027\u7684\u8d1f\u9762\u6216\u6709\u5bb3\u8bc4\u8bba",
|
|
80
|
+
"hate_block_threshold": "\u7c97\u9c81\u3001\u65e0\u793c\u6216\u4eb5\u6e0e\u7684\u5185\u5bb9",
|
|
81
|
+
"max_tokens": "\u56de\u5e94\u4e2d\u8fd4\u56de\u7684\u6700\u5927\u4ee4\u724c\u6570",
|
|
82
|
+
"name": "\u540d\u79f0",
|
|
83
|
+
"recommended": "\u63a8\u8350\u7684\u6a21\u578b\u8bbe\u7f6e",
|
|
84
|
+
"sexual_block_threshold": "\u5305\u542b\u5bf9\u6027\u884c\u4e3a\u6216\u5176\u4ed6\u6deb\u79fd\u5185\u5bb9\u7684\u5f15\u7528",
|
|
85
|
+
"temperature": "\u6e29\u5ea6",
|
|
86
|
+
"top_k": "Top K",
|
|
87
|
+
"top_p": "Top P"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
},
|
|
65
93
|
"issues": {
|
|
@@ -60,6 +60,34 @@
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
},
|
|
64
|
+
"tts": {
|
|
65
|
+
"abort": {
|
|
66
|
+
"entry_not_loaded": "\u7576\u8a2d\u5b9a\u88ab\u95dc\u9589\u6642\uff0c\u7121\u6cd5\u65b0\u589e\u9805\u76ee\u3002",
|
|
67
|
+
"reconfigure_successful": "\u91cd\u65b0\u8a2d\u5b9a\u6210\u529f"
|
|
68
|
+
},
|
|
69
|
+
"entry_type": "\u6587\u5b57\u8f49\u8a9e\u97f3",
|
|
70
|
+
"initiate_flow": {
|
|
71
|
+
"reconfigure": "\u91cd\u65b0\u8a2d\u5b9a\u6587\u5b57\u8f49\u8a9e\u97f3\u670d\u52d9",
|
|
72
|
+
"user": "\u65b0\u589e\u6587\u5b57\u8f49\u8a9e\u97f3\u670d\u52d9"
|
|
73
|
+
},
|
|
74
|
+
"step": {
|
|
75
|
+
"set_options": {
|
|
76
|
+
"data": {
|
|
77
|
+
"chat_model": "\u578b\u865f",
|
|
78
|
+
"dangerous_block_threshold": "\u4fc3\u9032\u3001\u4fbf\u5229\u6216\u9f13\u52f5\u6709\u5bb3\u884c\u70ba",
|
|
79
|
+
"harassment_block_threshold": "\u91dd\u5c0d\u8eab\u4efd\u53ca/\u6216\u53d7\u4fdd\u8b77\u5c6c\u6027\u7684\u8ca0\u9762\u6216\u6709\u5bb3\u8a55\u8ad6",
|
|
80
|
+
"hate_block_threshold": "\u7c97\u9b6f\u3001\u4e0d\u5c0a\u91cd\u6216\u893b\u7006\u7684\u5167\u5bb9",
|
|
81
|
+
"max_tokens": "\u56de\u61c9\u8fd4\u56de\u6700\u9ad8\u6b0a\u6756\u6578",
|
|
82
|
+
"name": "\u540d\u7a31",
|
|
83
|
+
"recommended": "\u5efa\u8b70\u6a21\u578b\u8a2d\u5b9a",
|
|
84
|
+
"sexual_block_threshold": "\u5305\u542b\u6027\u884c\u70ba\u6216\u5176\u4ed6\u6deb\u7a62\u5167\u5bb9",
|
|
85
|
+
"temperature": "\u6eab\u5ea6",
|
|
86
|
+
"top_k": "Top K",
|
|
87
|
+
"top_p": "Top P"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
},
|
|
65
93
|
"issues": {
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
import io
|
|
7
|
-
import logging
|
|
5
|
+
from collections.abc import Mapping
|
|
8
6
|
from typing import Any
|
|
9
|
-
import wave
|
|
10
7
|
|
|
11
8
|
from google.genai import types
|
|
9
|
+
from google.genai.errors import APIError, ClientError
|
|
10
|
+
from propcache.api import cached_property
|
|
12
11
|
|
|
13
12
|
from homeassistant.components.tts import (
|
|
14
13
|
ATTR_VOICE,
|
|
@@ -16,15 +15,14 @@ from homeassistant.components.tts import (
|
|
|
16
15
|
TtsAudioType,
|
|
17
16
|
Voice,
|
|
18
17
|
)
|
|
19
|
-
from homeassistant.config_entries import ConfigEntry
|
|
18
|
+
from homeassistant.config_entries import ConfigEntry, ConfigSubentry
|
|
20
19
|
from homeassistant.core import HomeAssistant, callback
|
|
21
20
|
from homeassistant.exceptions import HomeAssistantError
|
|
22
|
-
from homeassistant.helpers import device_registry as dr
|
|
23
21
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|
24
22
|
|
|
25
|
-
from .const import
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
from .const import CONF_CHAT_MODEL, LOGGER, RECOMMENDED_TTS_MODEL
|
|
24
|
+
from .entity import GoogleGenerativeAILLMBaseEntity
|
|
25
|
+
from .helpers import convert_to_wav
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
async def async_setup_entry(
|
|
@@ -32,15 +30,23 @@ async def async_setup_entry(
|
|
|
32
30
|
config_entry: ConfigEntry,
|
|
33
31
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
|
34
32
|
) -> None:
|
|
35
|
-
"""Set up TTS
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
"""Set up TTS entities."""
|
|
34
|
+
for subentry in config_entry.subentries.values():
|
|
35
|
+
if subentry.subentry_type != "tts":
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
async_add_entities(
|
|
39
|
+
[GoogleGenerativeAITextToSpeechEntity(config_entry, subentry)],
|
|
40
|
+
config_subentry_id=subentry.subentry_id,
|
|
41
|
+
)
|
|
38
42
|
|
|
39
43
|
|
|
40
|
-
class GoogleGenerativeAITextToSpeechEntity(
|
|
44
|
+
class GoogleGenerativeAITextToSpeechEntity(
|
|
45
|
+
TextToSpeechEntity, GoogleGenerativeAILLMBaseEntity
|
|
46
|
+
):
|
|
41
47
|
"""Google Generative AI text-to-speech entity."""
|
|
42
48
|
|
|
43
|
-
_attr_supported_options = [ATTR_VOICE
|
|
49
|
+
_attr_supported_options = [ATTR_VOICE]
|
|
44
50
|
# See https://ai.google.dev/gemini-api/docs/speech-generation#languages
|
|
45
51
|
_attr_supported_languages = [
|
|
46
52
|
"ar-EG",
|
|
@@ -68,6 +74,8 @@ class GoogleGenerativeAITextToSpeechEntity(TextToSpeechEntity):
|
|
|
68
74
|
"uk-UA",
|
|
69
75
|
"vi-VN",
|
|
70
76
|
]
|
|
77
|
+
# Unused, but required by base class.
|
|
78
|
+
# The Gemini TTS models detect the input language automatically.
|
|
71
79
|
_attr_default_language = "en-US"
|
|
72
80
|
# See https://ai.google.dev/gemini-api/docs/speech-generation#voices
|
|
73
81
|
_supported_voices = [
|
|
@@ -106,110 +114,44 @@ class GoogleGenerativeAITextToSpeechEntity(TextToSpeechEntity):
|
|
|
106
114
|
)
|
|
107
115
|
]
|
|
108
116
|
|
|
109
|
-
def __init__(self,
|
|
110
|
-
"""Initialize
|
|
111
|
-
|
|
112
|
-
self._attr_name = "Google Generative AI TTS"
|
|
113
|
-
self._attr_unique_id = f"{entry.entry_id}_tts"
|
|
114
|
-
self._attr_device_info = dr.DeviceInfo(
|
|
115
|
-
identifiers={(DOMAIN, entry.entry_id)},
|
|
116
|
-
manufacturer="Google",
|
|
117
|
-
model="Generative AI",
|
|
118
|
-
entry_type=dr.DeviceEntryType.SERVICE,
|
|
119
|
-
)
|
|
120
|
-
self._genai_client = entry.runtime_data
|
|
121
|
-
self._default_voice_id = self._supported_voices[0].voice_id
|
|
117
|
+
def __init__(self, config_entry: ConfigEntry, subentry: ConfigSubentry) -> None:
|
|
118
|
+
"""Initialize the TTS entity."""
|
|
119
|
+
super().__init__(config_entry, subentry, RECOMMENDED_TTS_MODEL)
|
|
122
120
|
|
|
123
121
|
@callback
|
|
124
|
-
def async_get_supported_voices(self, language: str) -> list[Voice]
|
|
122
|
+
def async_get_supported_voices(self, language: str) -> list[Voice]:
|
|
125
123
|
"""Return a list of supported voices for a language."""
|
|
126
124
|
return self._supported_voices
|
|
127
125
|
|
|
126
|
+
@cached_property
|
|
127
|
+
def default_options(self) -> Mapping[str, Any]:
|
|
128
|
+
"""Return a mapping with the default options."""
|
|
129
|
+
return {
|
|
130
|
+
ATTR_VOICE: self._supported_voices[0].voice_id,
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
async def async_get_tts_audio(
|
|
129
134
|
self, message: str, language: str, options: dict[str, Any]
|
|
130
135
|
) -> TtsAudioType:
|
|
131
136
|
"""Load tts audio file from the engine."""
|
|
137
|
+
config = self.create_generate_content_config()
|
|
138
|
+
config.response_modalities = ["AUDIO"]
|
|
139
|
+
config.speech_config = types.SpeechConfig(
|
|
140
|
+
voice_config=types.VoiceConfig(
|
|
141
|
+
prebuilt_voice_config=types.PrebuiltVoiceConfig(
|
|
142
|
+
voice_name=options[ATTR_VOICE]
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)
|
|
132
146
|
try:
|
|
133
|
-
response = self._genai_client.models.generate_content(
|
|
134
|
-
model=
|
|
147
|
+
response = await self._genai_client.aio.models.generate_content(
|
|
148
|
+
model=self.subentry.data.get(CONF_CHAT_MODEL, RECOMMENDED_TTS_MODEL),
|
|
135
149
|
contents=message,
|
|
136
|
-
config=
|
|
137
|
-
response_modalities=["AUDIO"],
|
|
138
|
-
speech_config=types.SpeechConfig(
|
|
139
|
-
voice_config=types.VoiceConfig(
|
|
140
|
-
prebuilt_voice_config=types.PrebuiltVoiceConfig(
|
|
141
|
-
voice_name=options.get(
|
|
142
|
-
ATTR_VOICE, self._default_voice_id
|
|
143
|
-
)
|
|
144
|
-
)
|
|
145
|
-
)
|
|
146
|
-
),
|
|
147
|
-
),
|
|
150
|
+
config=config,
|
|
148
151
|
)
|
|
149
|
-
|
|
150
152
|
data = response.candidates[0].content.parts[0].inline_data.data
|
|
151
153
|
mime_type = response.candidates[0].content.parts[0].inline_data.mime_type
|
|
152
|
-
except
|
|
153
|
-
|
|
154
|
-
"Error during processing of TTS request %s", exc, exc_info=True
|
|
155
|
-
)
|
|
154
|
+
except (APIError, ClientError, ValueError) as exc:
|
|
155
|
+
LOGGER.error("Error during TTS: %s", exc, exc_info=True)
|
|
156
156
|
raise HomeAssistantError(exc) from exc
|
|
157
|
-
return "wav",
|
|
158
|
-
|
|
159
|
-
def _convert_to_wav(self, audio_data: bytes, mime_type: str) -> bytes:
|
|
160
|
-
"""Generate a WAV file header for the given audio data and parameters.
|
|
161
|
-
|
|
162
|
-
Args:
|
|
163
|
-
audio_data: The raw audio data as a bytes object.
|
|
164
|
-
mime_type: Mime type of the audio data.
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
A bytes object representing the WAV file header.
|
|
168
|
-
|
|
169
|
-
"""
|
|
170
|
-
parameters = self._parse_audio_mime_type(mime_type)
|
|
171
|
-
|
|
172
|
-
wav_buffer = io.BytesIO()
|
|
173
|
-
with wave.open(wav_buffer, "wb") as wf:
|
|
174
|
-
wf.setnchannels(1)
|
|
175
|
-
wf.setsampwidth(parameters["bits_per_sample"] // 8)
|
|
176
|
-
wf.setframerate(parameters["rate"])
|
|
177
|
-
wf.writeframes(audio_data)
|
|
178
|
-
|
|
179
|
-
return wav_buffer.getvalue()
|
|
180
|
-
|
|
181
|
-
def _parse_audio_mime_type(self, mime_type: str) -> dict[str, int]:
|
|
182
|
-
"""Parse bits per sample and rate from an audio MIME type string.
|
|
183
|
-
|
|
184
|
-
Assumes bits per sample is encoded like "L16" and rate as "rate=xxxxx".
|
|
185
|
-
|
|
186
|
-
Args:
|
|
187
|
-
mime_type: The audio MIME type string (e.g., "audio/L16;rate=24000").
|
|
188
|
-
|
|
189
|
-
Returns:
|
|
190
|
-
A dictionary with "bits_per_sample" and "rate" keys. Values will be
|
|
191
|
-
integers if found, otherwise None.
|
|
192
|
-
|
|
193
|
-
"""
|
|
194
|
-
if not mime_type.startswith("audio/L"):
|
|
195
|
-
_LOGGER.warning("Received unexpected MIME type %s", mime_type)
|
|
196
|
-
raise HomeAssistantError(f"Unsupported audio MIME type: {mime_type}")
|
|
197
|
-
|
|
198
|
-
bits_per_sample = 16
|
|
199
|
-
rate = 24000
|
|
200
|
-
|
|
201
|
-
# Extract rate from parameters
|
|
202
|
-
parts = mime_type.split(";")
|
|
203
|
-
for param in parts: # Skip the main type part
|
|
204
|
-
param = param.strip()
|
|
205
|
-
if param.lower().startswith("rate="):
|
|
206
|
-
# Handle cases like "rate=" with no value or non-integer value and keep rate as default
|
|
207
|
-
with suppress(ValueError, IndexError):
|
|
208
|
-
rate_str = param.split("=", 1)[1]
|
|
209
|
-
rate = int(rate_str)
|
|
210
|
-
elif param.startswith("audio/L"):
|
|
211
|
-
# Keep bits_per_sample as default if conversion fails
|
|
212
|
-
with suppress(ValueError, IndexError):
|
|
213
|
-
bits_per_sample = int(param.split("L", 1)[1])
|
|
214
|
-
|
|
215
|
-
return {"bits_per_sample": bits_per_sample, "rate": rate}
|
|
157
|
+
return "wav", convert_to_wav(data, mime_type)
|