home-assistant-intents 2025.6.23__tar.gz → 2025.8.27__tar.gz

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.
Files changed (142) hide show
  1. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/MANIFEST.in +1 -0
  2. {home_assistant_intents-2025.6.23/home_assistant_intents.egg-info → home_assistant_intents-2025.8.27}/PKG-INFO +4 -4
  3. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/README.md +2 -2
  4. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/__init__.py +135 -1
  5. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ca.json +303 -6
  6. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/cs.json +36 -0
  7. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/da.json +23 -0
  8. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/de.json +1056 -336
  9. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/el.json +888 -20
  10. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/en.json +274 -9
  11. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/fr.json +1 -1
  12. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/it.json +49 -24
  13. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/nl.json +101 -0
  14. home_assistant_intents-2025.6.23/home_assistant_intents/data/pt-br.json → home_assistant_intents-2025.8.27/home_assistant_intents/data/pt-BR.json +439 -44
  15. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ro.json +294 -1
  16. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sk.json +53 -0
  17. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sr.json +20 -0
  18. home_assistant_intents-2025.6.23/home_assistant_intents/data/zh-cn.json → home_assistant_intents-2025.8.27/home_assistant_intents/data/zh-CN.json +1 -1
  19. home_assistant_intents-2025.6.23/home_assistant_intents/data/zh-hk.json → home_assistant_intents-2025.8.27/home_assistant_intents/data/zh-HK.json +1 -1
  20. home_assistant_intents-2025.6.23/home_assistant_intents/data/zh-tw.json → home_assistant_intents-2025.8.27/home_assistant_intents/data/zh-TW.json +1 -1
  21. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/config.json +274 -0
  22. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/config.json +77 -0
  23. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/climate_HassClimateGetTemperature.db +0 -0
  24. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/climate_HassClimateGetTemperature.json +44 -0
  25. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/climate_HassClimateSetTemperature.db +0 -0
  26. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/climate_HassClimateSetTemperature.json +37 -0
  27. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassSetPosition.db +0 -0
  28. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassSetPosition.json +38 -0
  29. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassTurnOff.db +0 -0
  30. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassTurnOff.json +25 -0
  31. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassTurnOn.db +0 -0
  32. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/cover_HassTurnOn.json +24 -0
  33. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassFanSetSpeed.db +0 -0
  34. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassFanSetSpeed.json +36 -0
  35. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassTurnOff.db +0 -0
  36. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassTurnOff.json +26 -0
  37. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassTurnOn.db +0 -0
  38. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/fan_HassTurnOn.json +25 -0
  39. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassGetCurrentDate.db +0 -0
  40. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassGetCurrentDate.json +22 -0
  41. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassGetCurrentTime.db +0 -0
  42. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassGetCurrentTime.json +22 -0
  43. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassNevermind.db +0 -0
  44. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassNevermind.json +13 -0
  45. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTimerStatus.db +0 -0
  46. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTimerStatus.json +36 -0
  47. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTurnOff.db +0 -0
  48. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTurnOff.json +23 -0
  49. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTurnOn.db +0 -0
  50. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/homeassistant_HassTurnOn.json +23 -0
  51. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassLightSet.db +0 -0
  52. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassLightSet.json +51 -0
  53. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassTurnOff.db +0 -0
  54. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassTurnOff.json +64 -0
  55. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassTurnOn.db +0 -0
  56. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/light_HassTurnOn.json +65 -0
  57. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/lock_HassTurnOff.db +0 -0
  58. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/lock_HassTurnOff.json +29 -0
  59. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/lock_HassTurnOn.db +0 -0
  60. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/lock_HassTurnOn.json +29 -0
  61. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaNext.db +0 -0
  62. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaNext.json +25 -0
  63. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaPause.db +0 -0
  64. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaPause.json +24 -0
  65. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaPrevious.db +0 -0
  66. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaPrevious.json +29 -0
  67. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaUnpause.db +0 -0
  68. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassMediaUnpause.json +25 -0
  69. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassSetVolume.db +0 -0
  70. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassSetVolume.json +31 -0
  71. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassSetVolumeRelative.db +0 -0
  72. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/media_player_HassSetVolumeRelative.json +30 -0
  73. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/scene_HassTurnOn.db +0 -0
  74. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/scene_HassTurnOn.json +30 -0
  75. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/script_HassTurnOn.db +0 -0
  76. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/script_HassTurnOn.json +23 -0
  77. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/vacuum_HassVacuumReturnToBase.db +0 -0
  78. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/vacuum_HassVacuumReturnToBase.json +17 -0
  79. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/vacuum_HassVacuumStart.db +0 -0
  80. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/vacuum_HassVacuumStart.json +19 -0
  81. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassSetPosition.db +0 -0
  82. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassSetPosition.json +34 -0
  83. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassTurnOff.db +0 -0
  84. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassTurnOff.json +19 -0
  85. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassTurnOn.db +0 -0
  86. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/valve_HassTurnOn.json +18 -0
  87. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/weather_HassGetWeather.db +0 -0
  88. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/ngram/weather_HassGetWeather.json +25 -0
  89. home_assistant_intents-2025.8.27/home_assistant_intents/fuzzy/en/responses.json +131 -0
  90. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/languages.py +4 -4
  91. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27/home_assistant_intents.egg-info}/PKG-INFO +4 -4
  92. home_assistant_intents-2025.8.27/home_assistant_intents.egg-info/SOURCES.txt +140 -0
  93. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/pyproject.toml +4 -3
  94. home_assistant_intents-2025.6.23/home_assistant_intents.egg-info/SOURCES.txt +0 -71
  95. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/LICENSE.md +0 -0
  96. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ar.json +0 -0
  97. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/bg.json +0 -0
  98. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/bn.json +0 -0
  99. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/de-CH.json +0 -0
  100. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/es.json +0 -0
  101. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/et.json +0 -0
  102. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/eu.json +0 -0
  103. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/fa.json +0 -0
  104. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/fi.json +0 -0
  105. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/gl.json +0 -0
  106. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/he.json +0 -0
  107. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/hi.json +0 -0
  108. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/hr.json +0 -0
  109. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/hu.json +0 -0
  110. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/id.json +0 -0
  111. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/is.json +0 -0
  112. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ja.json +0 -0
  113. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ka.json +0 -0
  114. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ko.json +0 -0
  115. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/kw.json +0 -0
  116. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/lb.json +0 -0
  117. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/lt.json +0 -0
  118. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/lv.json +0 -0
  119. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ml.json +0 -0
  120. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/mn.json +0 -0
  121. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ms.json +0 -0
  122. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/nb.json +0 -0
  123. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ne.json +0 -0
  124. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/pl.json +0 -0
  125. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/pt.json +0 -0
  126. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ru.json +0 -0
  127. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sl.json +0 -0
  128. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sr-Latn.json +0 -0
  129. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sv.json +0 -0
  130. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/sw.json +0 -0
  131. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/te.json +0 -0
  132. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/th.json +0 -0
  133. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/tr.json +0 -0
  134. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/uk.json +0 -0
  135. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/ur.json +0 -0
  136. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/data/vi.json +0 -0
  137. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents/language_scores.json +0 -0
  138. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents.egg-info/dependency_links.txt +0 -0
  139. /home_assistant_intents-2025.6.23/home_assistant_intents.egg-info/zip-safe → /home_assistant_intents-2025.8.27/home_assistant_intents.egg-info/not-zip-safe +0 -0
  140. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/home_assistant_intents.egg-info/top_level.txt +0 -0
  141. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/setup.cfg +0 -0
  142. {home_assistant_intents-2025.6.23 → home_assistant_intents-2025.8.27}/tests/test_intents.py +0 -0
@@ -1,2 +1,3 @@
1
1
  include LICENSE.md
2
2
  recursive-include home_assistant_intents/data *.json
3
+ recursive-include home_assistant_intents/fuzzy *.json *.db
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: home-assistant-intents
3
- Version: 2025.6.23
3
+ Version: 2025.8.27
4
4
  Summary: Intents for Home Assistant
5
5
  Author-email: The Home Assistant Authors <hello@home-assistant.io>
6
6
  License-Expression: Apache-2.0
7
- Project-URL: Source Code, https://github.com/home-assistant/intents
7
+ Project-URL: Source Code, https://github.com/OHF-Voice/intents
8
8
  Keywords: home,assistant,intent,recognition
9
9
  Platform: any
10
10
  Classifier: Development Status :: 3 - Alpha
@@ -22,7 +22,7 @@ Dynamic: license-file
22
22
 
23
23
  # Home Assistant Intents Package
24
24
 
25
- Packaging for [intents](https://github.com/home-assistant/intents/)
25
+ Packaging for [intents](https://github.com/OHF-Voice/intents/)
26
26
 
27
27
 
28
28
  ## Install
@@ -30,7 +30,7 @@ Packaging for [intents](https://github.com/home-assistant/intents/)
30
30
  Clone the repo and create a virtual environment:
31
31
 
32
32
  ``` sh
33
- git clone --recursive https://github.com/home-assistant/intents-package
33
+ git clone --recursive https://github.com/OHF-Voice/intents-package
34
34
  cd intents-package
35
35
  script/setup
36
36
  ```
@@ -1,6 +1,6 @@
1
1
  # Home Assistant Intents Package
2
2
 
3
- Packaging for [intents](https://github.com/home-assistant/intents/)
3
+ Packaging for [intents](https://github.com/OHF-Voice/intents/)
4
4
 
5
5
 
6
6
  ## Install
@@ -8,7 +8,7 @@ Packaging for [intents](https://github.com/home-assistant/intents/)
8
8
  Clone the repo and create a virtual environment:
9
9
 
10
10
  ``` sh
11
- git clone --recursive https://github.com/home-assistant/intents-package
11
+ git clone --recursive https://github.com/OHF-Voice/intents-package
12
12
  cd intents-package
13
13
  script/setup
14
14
  ```
@@ -7,13 +7,14 @@ import typing
7
7
  from dataclasses import dataclass
8
8
  from enum import Enum
9
9
  from pathlib import Path
10
- from typing import IO, Any, Callable, Dict, List, Optional
10
+ from typing import IO, Any, Callable, Collection, Dict, List, Optional, Set, Tuple
11
11
 
12
12
  from .languages import LANGUAGES
13
13
 
14
14
  _PACKAGE = "home_assistant_intents"
15
15
  _DIR = Path(typing.cast(os.PathLike, importlib.resources.files(_PACKAGE)))
16
16
  _DATA_DIR = _DIR / "data"
17
+ _FUZZY_DIR = _DIR / "fuzzy"
17
18
 
18
19
 
19
20
  class ErrorKey(str, Enum):
@@ -155,3 +156,136 @@ def get_language_scores(
155
156
  )
156
157
  for lang_key, lang_scores in scores_dict.items()
157
158
  }
159
+
160
+
161
+ # -----------------------------------------------------------------------------
162
+
163
+
164
+ @dataclass
165
+ class FuzzyConfig:
166
+ """Shared configuration for fuzzy matching."""
167
+
168
+ # intent -> (slot, slot) -> {name domains}
169
+ slot_combinations: Dict[str, Dict[Tuple[str, ...], Set[str]]]
170
+ """Name domains for all intent slot combinations."""
171
+
172
+ # list name -> [slot names]
173
+ slot_list_names: Dict[str, List[str]]
174
+ """Mapping between list and slot names."""
175
+
176
+
177
+ @dataclass
178
+ class FuzzyNgramModel:
179
+ """N-gram model for fuzzy matching."""
180
+
181
+ order: int
182
+ """N-gram order."""
183
+
184
+ words: Dict[str, int]
185
+ """Words to integer ids."""
186
+
187
+ database_path: Path
188
+ """Path to sqlite3 database file."""
189
+
190
+
191
+ FuzzyLanguageResponses = Dict[str, Dict[Tuple[str, ...], Dict[str, str]]]
192
+
193
+
194
+ @dataclass
195
+ class FuzzyLanguageInfo:
196
+ """Language specific information for fuzzy matching."""
197
+
198
+ language: str
199
+
200
+ # domain -> [keywords]
201
+ domain_keywords: Dict[str, List[str]]
202
+ """Keywords that hint at a domain."""
203
+
204
+ # intent -> model
205
+ ngram_models: Dict[str, FuzzyNgramModel]
206
+ """N-gram model for each intent."""
207
+
208
+ # intent -> (slot, slot) -> domain -> response
209
+ responses: FuzzyLanguageResponses
210
+ """Response code mapping per slot combination."""
211
+
212
+ stop_words: Optional[Collection[str]] = None
213
+ """Words that can be ignored if unknown."""
214
+
215
+
216
+ def get_fuzzy_config(
217
+ json_load: Callable[[IO[str]], Dict[str, Any]] = json.load,
218
+ ) -> FuzzyConfig:
219
+ """Return shared configuration for fuzzy matching."""
220
+ with open(_FUZZY_DIR / "config.json", "r", encoding="utf-8") as config_file:
221
+ config_dict = json_load(config_file)
222
+
223
+ return FuzzyConfig(
224
+ slot_combinations={
225
+ intent_name: {
226
+ tuple(sorted(combo_key_str.split())): set(name_domains)
227
+ for combo_key_str, name_domains in intent_combos.items()
228
+ }
229
+ for intent_name, intent_combos in config_dict["slot_combinations"].items()
230
+ },
231
+ slot_list_names={
232
+ list_name: slot_names
233
+ for list_name, slot_names in config_dict["slot_list_names"].items()
234
+ },
235
+ )
236
+
237
+
238
+ def get_fuzzy_languages() -> Set[str]:
239
+ """Return languages with fuzzy matching support."""
240
+ return {lang_dir.name for lang_dir in _FUZZY_DIR.iterdir() if lang_dir.is_dir()}
241
+
242
+
243
+ def get_fuzzy_language(
244
+ language: str,
245
+ json_load: Callable[[IO[str]], Dict[str, Any]] = json.load,
246
+ ) -> Optional[FuzzyLanguageInfo]:
247
+ """Return fuzzy matching information for a language."""
248
+ lang_fuzzy_dir = _FUZZY_DIR / language
249
+ lang_ngram_dir = lang_fuzzy_dir / "ngram"
250
+
251
+ if not lang_ngram_dir.is_dir():
252
+ return None
253
+
254
+ with open(lang_fuzzy_dir / "config.json", "r", encoding="utf-8") as config_file:
255
+ lang_config = json_load(config_file)
256
+
257
+ ngram_models: Dict[str, FuzzyNgramModel] = {}
258
+ for intent_ngram_path in lang_ngram_dir.glob("*.json"):
259
+ intent_db_path = intent_ngram_path.with_suffix(".db")
260
+ if not intent_db_path.exists():
261
+ continue
262
+
263
+ with open(intent_ngram_path, "r", encoding="utf-8") as intent_ngram_file:
264
+ intent_ngram_dict = json_load(intent_ngram_file)
265
+
266
+ intent_name = intent_ngram_path.stem
267
+ ngram_models[intent_name] = FuzzyNgramModel(
268
+ order=intent_ngram_dict["order"],
269
+ words=intent_ngram_dict["words"],
270
+ database_path=intent_db_path,
271
+ )
272
+
273
+ with open(
274
+ lang_fuzzy_dir / "responses.json", "r", encoding="utf-8"
275
+ ) as responses_file:
276
+ lang_responses_dict = json_load(responses_file)
277
+ lang_responses = {
278
+ intent_name: {
279
+ tuple(sorted(combo_key_str.split())): domain_responses
280
+ for combo_key_str, domain_responses in intent_responses.items()
281
+ }
282
+ for intent_name, intent_responses in lang_responses_dict.items()
283
+ }
284
+
285
+ return FuzzyLanguageInfo(
286
+ language=language,
287
+ domain_keywords=lang_config["domain_keywords"],
288
+ stop_words=lang_config.get("stop_words"),
289
+ ngram_models=ngram_models,
290
+ responses=lang_responses,
291
+ )
@@ -1,6 +1,44 @@
1
1
  {
2
2
  "language": "ca",
3
3
  "intents": {
4
+ "HassMediaSearchAndPlay": {
5
+ "data": [
6
+ {
7
+ "sentences": [
8
+ "<reproduir> [el |la |l']{media_class} [de |d']{search_query}",
9
+ "<reproduir> {search_query} [<pronom_singular>]{media_class}",
10
+ "<reproduir> {search_query}"
11
+ ],
12
+ "requires_context": {
13
+ "area": {
14
+ "slot": true
15
+ }
16
+ }
17
+ },
18
+ {
19
+ "sentences": [
20
+ "<reproduir> [el |la |l']{media_class} [de |d']{search_query} [<area>]",
21
+ "<reproduir> {search_query} [<preposicio_base_singular>] <name> <area>",
22
+ "<reproduir> {search_query} [el |la |l']{media_class} <area>",
23
+ "<reproduir> {search_query} <area>"
24
+ ]
25
+ },
26
+ {
27
+ "sentences": [
28
+ "<reproduir> {search_query}",
29
+ "<reproduir> {search_query} [<preposicio_base_singular>] <name>",
30
+ "<reproduir> [el |la |l']{media_class} [de |d']{search_query} [<preposicio_base_singular>] <name> [<area>]",
31
+ "<reproduir> {search_query} [el |la |l']{media_class} [<preposicio_base_singular>] <name>",
32
+ "<reproduir> {search_query} <name>",
33
+ "<reproduir> {search_query} <name> <area>",
34
+ "<reproduir> {search_query} <area>"
35
+ ],
36
+ "requires_context": {
37
+ "domain": "media_player"
38
+ }
39
+ }
40
+ ]
41
+ },
4
42
  "HassTurnOff": {
5
43
  "data": [
6
44
  {
@@ -559,7 +597,7 @@
559
597
  "my_list": "[la] [meva] llista [de (la compra|compres|comprar)]",
560
598
  "my_list_req": "[la] [meva] llista de (la compra|compres|comprar)",
561
599
  "item": "{shopping_list_item:item}",
562
- "add": "(afeg[e]ix|posa)"
600
+ "add": "(afeg[e]ix|posa|fica)"
563
601
  }
564
602
  }
565
603
  ]
@@ -889,7 +927,8 @@
889
927
  {
890
928
  "sentences": [
891
929
  "([Fes un] anunci|anuncia) [a tot arreu] [que digui|dient] [que] {message}",
892
- "[Fes un] broadcast [a tot arreu] [que digui|dient] [que] {message}"
930
+ "[Fes un] broadcast [a tot arreu] [que digui|dient] [que] {message}",
931
+ "avisa [a tot arreu] [dient] [de que|que] {message}"
893
932
  ]
894
933
  }
895
934
  ]
@@ -943,10 +982,34 @@
943
982
  "data": [
944
983
  {
945
984
  "sentences": [
946
- "(<pujar>|<baixar>|<configura>) ([el] (volum|so)|[la] veu) [<preposicio>] {name} [a|al] {volume:volume_level}[<percent>]"
985
+ "(<pujar>|<baixar>|<configura>) ([el] (volum|so)|[la] veu) [<preposicio>] {name} (a|al) {volume:volume_level}[<percent>]"
947
986
  ],
948
987
  "requires_context": {
949
988
  "domain": "media_player"
989
+ },
990
+ "required_keywords": [
991
+ "a",
992
+ "al"
993
+ ]
994
+ }
995
+ ]
996
+ },
997
+ "HassListCompleteItem": {
998
+ "data": [
999
+ {
1000
+ "sentences": [
1001
+ "<completa> <item> de la [meva] llista (de|del|de la|amb nom|anomenada) {name}",
1002
+ "<completa> <item> de <my_list>",
1003
+ "<completa> de <my_list> [un[a|es]|que] <item>"
1004
+ ],
1005
+ "response": "item_completed",
1006
+ "requires_context": {
1007
+ "domain": "todo"
1008
+ },
1009
+ "expansion_rules": {
1010
+ "my_list": "[la] [meva] llista [de|del|de la] {name}",
1011
+ "item": "{todo_list_item:item}",
1012
+ "completa": "(acaba|completa|desmarca|elimina|cancel[·l]a)[r]"
950
1013
  }
951
1014
  }
952
1015
  ]
@@ -976,6 +1039,170 @@
976
1039
  ]
977
1040
  }
978
1041
  ]
1042
+ },
1043
+ "HassSetVolumeRelative": {
1044
+ "data": [
1045
+ {
1046
+ "sentences": [
1047
+ "(<pujar>|posa[r|-li]) [el|més] (volum|so)",
1048
+ "(<pujar>|posa[r|-li]) [la|més] (veu)",
1049
+ "més <volum>"
1050
+ ],
1051
+ "slots": {
1052
+ "volume_step": "up"
1053
+ },
1054
+ "requires_context": {
1055
+ "area": {
1056
+ "slot": true
1057
+ }
1058
+ }
1059
+ },
1060
+ {
1061
+ "sentences": [
1062
+ "(<pujar>|posa[r|-li]) [el|més] (volum|so) [per|un|al] <volume_step>",
1063
+ "(<pujar>|posa[r|-li]) [la|més] (veu) [per|un|al] <volume_step>"
1064
+ ],
1065
+ "expansion_rules": {
1066
+ "volume_step": "{volume_step_up:volume_step}[<percent>]"
1067
+ },
1068
+ "requires_context": {
1069
+ "area": {
1070
+ "slot": true
1071
+ }
1072
+ }
1073
+ },
1074
+ {
1075
+ "sentences": [
1076
+ "(<baixar>) [el|més] (volum|so)",
1077
+ "(<baixar>) [la|més] (veu)",
1078
+ "menys <volum>"
1079
+ ],
1080
+ "slots": {
1081
+ "volume_step": "down"
1082
+ },
1083
+ "requires_context": {
1084
+ "area": {
1085
+ "slot": true
1086
+ }
1087
+ }
1088
+ },
1089
+ {
1090
+ "sentences": [
1091
+ "(<baixar>) [el|més] (volum|so) [per|un|al] <volume_step>",
1092
+ "(<baixar>) [la|més] (veu) [per|un|al] <volume_step>"
1093
+ ],
1094
+ "expansion_rules": {
1095
+ "volume_step": "{volume_step_down:volume_step}[<percent>]"
1096
+ },
1097
+ "requires_context": {
1098
+ "area": {
1099
+ "slot": true
1100
+ }
1101
+ }
1102
+ },
1103
+ {
1104
+ "sentences": [
1105
+ "(<name>;més <volum>)",
1106
+ "(<pujar>) [el|la|més] <volum> [de|del|per|pel|al|a] <name>",
1107
+ "<name> <pujar> [el|la] <volum>"
1108
+ ],
1109
+ "slots": {
1110
+ "volume_step": "up"
1111
+ },
1112
+ "requires_context": {
1113
+ "domain": "media_player"
1114
+ }
1115
+ },
1116
+ {
1117
+ "sentences": [
1118
+ "(<name>;més <volum>) [per|un|al] <volume_step>",
1119
+ "<name>;<volume_step> més [de] <volum>",
1120
+ "(<pujar>) [el|la|més] <volum> [de|del|per|pel|al|a] <name> [per|un|al] <volume_step>",
1121
+ "<name> <pujar> [el|la] <volum> [per|un|al] <volume_step>"
1122
+ ],
1123
+ "expansion_rules": {
1124
+ "volume_step": "{volume_step_up:volume_step}[<percent>]"
1125
+ },
1126
+ "slots": {
1127
+ "volume_step": "up"
1128
+ },
1129
+ "requires_context": {
1130
+ "domain": "media_player"
1131
+ }
1132
+ },
1133
+ {
1134
+ "sentences": [
1135
+ "(<name>;menys <volum>)",
1136
+ "(<baixar>) [el|la] <volum> [de|del|per|pel|al|a] <name>",
1137
+ "<name> <baixar> [el|la] <volum>"
1138
+ ],
1139
+ "slots": {
1140
+ "volume_step": "down"
1141
+ },
1142
+ "requires_context": {
1143
+ "domain": "media_player"
1144
+ }
1145
+ },
1146
+ {
1147
+ "sentences": [
1148
+ "(<name>;menys <volum>) [per|un|al] <volume_step>",
1149
+ "<name>;<volume_step> menys [de] <volum>",
1150
+ "(<baixar>) [el|la] <volum> [de|del|per|pel|al|a] <name> [per|un|al] <volume_step>",
1151
+ "<name> <baixar> [el|la] <volum> [per|un|al] <volume_step>"
1152
+ ],
1153
+ "expansion_rules": {
1154
+ "volume_step": "{volume_step_down:volume_step}[<percent>]"
1155
+ },
1156
+ "slots": {
1157
+ "volume_step": "down"
1158
+ },
1159
+ "requires_context": {
1160
+ "domain": "media_player"
1161
+ }
1162
+ },
1163
+ {
1164
+ "sentences": [
1165
+ "(<area_floor>;més <volum>)",
1166
+ "(<pujar>) [el|la|més] <volum> <area_floor>",
1167
+ "<area_floor> <pujar> [el|la] <volum>"
1168
+ ],
1169
+ "slots": {
1170
+ "volume_step": "up"
1171
+ }
1172
+ },
1173
+ {
1174
+ "sentences": [
1175
+ "(<area_floor>;més <volum>) [per|un|al] <volume_step>",
1176
+ "<area_floor>;<volume_step> més [de] <volum>",
1177
+ "(<pujar>) [el|la|més] <volum> <area_floor> [per|un|al] <volume_step>",
1178
+ "<area_floor> <pujar> [el|la] <volum> [per|un|al] <volume_step>"
1179
+ ],
1180
+ "expansion_rules": {
1181
+ "volume_step": "{volume_step_up:volume_step}[<percent>]"
1182
+ }
1183
+ },
1184
+ {
1185
+ "sentences": [
1186
+ "(<area_floor>;menys <volum>)",
1187
+ "(<baixar>) [el|la] <volum> <area_floor>",
1188
+ "<area_floor> <baixar> [el|la] <volum>"
1189
+ ],
1190
+ "slots": {
1191
+ "volume_step": "down"
1192
+ }
1193
+ },
1194
+ {
1195
+ "sentences": [
1196
+ "(<area_floor>;menys <volum>) [per|un|al] <volume_step>",
1197
+ "<area_floor>;<volume_step> menys [de] <volum>",
1198
+ "(<baixar>) [el|la] <volum> <area_floor> [per|un|al] <volume_step>",
1199
+ "<area_floor> <baixar> [el|la] <volum> [per|un|al] <volume_step>"
1200
+ ],
1201
+ "expansion_rules": {
1202
+ "volume_step": "{volume_step_down:volume_step}[<percent>]"
1203
+ }
1204
+ }
1205
+ ]
979
1206
  }
980
1207
  },
981
1208
  "responses": {
@@ -995,7 +1222,7 @@
995
1222
  "all": "{% if not query.unmatched: %}\n Si\n{% else %}\n {% set no_match = query.unmatched | map(attribute=\"name\") | sort | list %}\n {% if no_match | length > 4 %}\n No, ni {{ no_match[:3] | join(\", \") }} ni els altres {{ (no_match | length - 3) }} ho són\n {% elif no_match | length == 1 %}\n No, el dispositiu {{ no_match|first }} no\n {%- else -%}\n No, ni\n {% for name in no_match -%}\n {% if not loop.first and not loop.last %}, {% elif loop.last and not loop.first %} ni {% endif -%}\n {{ name }}\n {%- endfor %}\n {% endif %}\n{% endif %}\n",
996
1223
  "which": "{% if not query.matched %}\n Cap dispositiu\n{% else: %}\n {% set match = query.matched | map(attribute=\"name\") | sort | list %}\n {% if match | length > 4 %}\n {{ match[:3] | join(\", \") }} i uns altres {{ (match | length - 3) }} més\n {% else %}\n {%- for name in match -%}\n {% if not loop.first and not loop.last %}, {% elif loop.last and not loop.first %} i {% endif -%}\n {{ name }}\n {%- endfor -%}\n {% endif %}\n{% endif %}\n",
997
1224
  "how_many": "{{ query.matched | length }}\n",
998
- "where": "{% if state == \"not_home\" %}\n {{ slots.name | capitalize }} és a fora\n{% else %}\n {{ slots.name | capitalize }} es troba a {{ state.state }}\n{% endif %}\n"
1225
+ "where": "{% if not query.matched %}\n No conec a ningú que es digui {{ slots.name | capitalize }}\n{% else %}\n {% if state == \"not_home\" %}\n {{ slots.name | capitalize }} és a fora\n {% elif state == \"home\" %}\n {{ slots.name | capitalize }} és a casa\n {% else %}\n {{ slots.name | capitalize }} es troba a {{ state.state }}\n {% endif %}\n{% endif %}\n"
999
1226
  },
1000
1227
  "HassTurnOff": {
1001
1228
  "default": "Apago {{ slots.name }}",
@@ -1082,15 +1309,24 @@
1082
1309
  "HassMediaNext": {
1083
1310
  "default": "Reproduint el següent"
1084
1311
  },
1312
+ "HassSetVolumeRelative": {
1313
+ "default": "Volum establert"
1314
+ },
1085
1315
  "HassCancelTimer": {
1086
1316
  "default": "Temporitzador cancel·lat"
1087
1317
  },
1318
+ "HassMediaSearchAndPlay": {
1319
+ "default": "{% if slots.media: %}\nReproduïnt\n{% else: %}\nNo ho trobo\n{% endif %}\n"
1320
+ },
1088
1321
  "HassClimateGetTemperature": {
1089
1322
  "default": "{% set current_temperature = state_attr(state.entity_id, 'current_temperature') %} {% set temperature = state.state if current_temperature is none else current_temperature %} {{ temperature | float | abs | round(1) | replace('.0', '') | replace('.',',') }} {{ 'grau' if temperature | float | abs == 1 else 'graus' }} {{ 'sota zero' if temperature | float < 0 else '' }}\n"
1090
1323
  },
1091
1324
  "HassSetVolume": {
1092
1325
  "default": "Volum establert"
1093
1326
  },
1327
+ "HassListCompleteItem": {
1328
+ "item_completed": "Completat {{ slots.item }}"
1329
+ },
1094
1330
  "HassDecreaseTimer": {
1095
1331
  "default": "Canvio el temporitzador"
1096
1332
  },
@@ -1365,6 +1601,63 @@
1365
1601
  },
1366
1602
  "message": {
1367
1603
  "wildcard": true
1604
+ },
1605
+ "search_query": {
1606
+ "wildcard": true
1607
+ },
1608
+ "media_class": {
1609
+ "values": [
1610
+ {
1611
+ "in": "artista",
1612
+ "out": "artist"
1613
+ },
1614
+ {
1615
+ "in": "(album|àlbum|disc)",
1616
+ "out": "album"
1617
+ },
1618
+ {
1619
+ "in": "(track|pista|peça|cançó|tema)",
1620
+ "out": "track"
1621
+ },
1622
+ {
1623
+ "in": "(playlist|llista de reproducció)",
1624
+ "out": "playlist"
1625
+ },
1626
+ {
1627
+ "in": "(podcast|pòdcast)",
1628
+ "out": "podcast"
1629
+ },
1630
+ {
1631
+ "in": "(peli|pel·lícula|film|vídeo)",
1632
+ "out": "movie"
1633
+ },
1634
+ {
1635
+ "in": "(show|sèrie [de TV|de televisió]|[l']episodi|capítol)",
1636
+ "out": "tv_show"
1637
+ }
1638
+ ]
1639
+ },
1640
+ "fan_speed": {
1641
+ "range": {
1642
+ "type": "percentage",
1643
+ "from": 0,
1644
+ "to": 100
1645
+ }
1646
+ },
1647
+ "volume_step_up": {
1648
+ "range": {
1649
+ "type": "percentage",
1650
+ "from": 0,
1651
+ "to": 100
1652
+ }
1653
+ },
1654
+ "volume_step_down": {
1655
+ "range": {
1656
+ "type": "percentage",
1657
+ "from": 0,
1658
+ "to": 100,
1659
+ "multiplier": -1
1660
+ }
1368
1661
  }
1369
1662
  },
1370
1663
  "expansion_rules": {
@@ -1380,6 +1673,8 @@
1380
1673
  "preposicio": "<preposicio_base> [<pronom>]",
1381
1674
  "name": "[<pronom_singular>]{name}",
1382
1675
  "area": "[<preposicio_singular>]{area}",
1676
+ "floor": "[<preposicio_singular>] [planta|pis] {floor}",
1677
+ "area_floor": "(<area>|<floor>)",
1383
1678
  "quin_es": "(quin|quina|què) és",
1384
1679
  "lluentor": "{brightness}[<percent>]",
1385
1680
  "al_stt_typo": "(del|el|en|o)",
@@ -1394,10 +1689,11 @@
1394
1689
  "llums_typo": "[[d]el[s]|la|les] (juny|junta|junts)",
1395
1690
  "temp": "(temperatura)",
1396
1691
  "graus": "{temperature} [graus]",
1397
- "pujar": "([a]puja|aixeca)[r|t]",
1398
- "baixar": "[a]baixa[r|t]",
1692
+ "pujar": "([a]puja|aixeca|posa)[r|t|-li]",
1693
+ "baixar": "[a]baixa[r|t|-li]",
1399
1694
  "configura": "(posa[r]|puja[r]|configura[r]|ajusta[r]|canvia[r]|establ(ir|eix|ix))",
1400
1695
  "posició": "{position}[<percent>]",
1696
+ "fan_speed": "{fan_speed:percentage}[<percent>]",
1401
1697
  "percent": "(%|per[ ]cent)",
1402
1698
  "cancela": "cancel[·l]a[r|t]",
1403
1699
  "seguent": "següent|(proper|pròxim)[a]",
@@ -1413,6 +1709,7 @@
1413
1709
  "again": "([un|una] altr(e|a) (cop|vegada)|de nou)",
1414
1710
  "torna_a": "(torna[r] a)",
1415
1711
  "can_you": "[pots|podries]",
1712
+ "volum": "(volum|so|veu)",
1416
1713
  "temporitzador": "(temporitzador|compte enrere|minuter|cronòmetre)",
1417
1714
  "timer_set": "(posa|crea|comença|inicia|activa|programa|fixa|estableix|engega|<timer_set_typos>)[r|t|'m]",
1418
1715
  "timer_set_typos": "(cosa)",
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "language": "cs",
3
3
  "intents": {
4
+ "HassMediaSearchAndPlay": {
5
+ "data": [
6
+ {
7
+ "sentences": [
8
+ "přehraj {search_query}",
9
+ "[s]pusť {search_query}",
10
+ "[pře]hr(e|a)j {search_query}"
11
+ ],
12
+ "requires_context": {
13
+ "area": {
14
+ "slot": true
15
+ }
16
+ }
17
+ },
18
+ {
19
+ "sentences": [
20
+ "přehraj {search_query} <area>",
21
+ "[s]pusť {search_query} <area>",
22
+ "[pře]hr(e|a)j {search_query} <area>"
23
+ ]
24
+ },
25
+ {
26
+ "sentences": [
27
+ "přehraj {search_query} <v> {name} [<area>]",
28
+ "[s]pusť {search_query} <v> {name} [<area>]",
29
+ "[pře]hr(e|a)j {search_query} <v> {name} [<area>]"
30
+ ],
31
+ "requires_context": {
32
+ "domain": "media_player"
33
+ }
34
+ }
35
+ ]
36
+ },
4
37
  "HassTurnOff": {
5
38
  "data": [
6
39
  {
@@ -3831,6 +3864,9 @@
3831
3864
  "HassCancelTimer": {
3832
3865
  "default": "Časovač zastaven"
3833
3866
  },
3867
+ "HassMediaSearchAndPlay": {
3868
+ "default": "{% if slots.media: %}\nPřehrávání začíná\n{% else: %}\nNenalezen žádný odpovídající obsah\n{% endif %}\n"
3869
+ },
3834
3870
  "HassClimateGetTemperature": {
3835
3871
  "default": "{% set current_temperature = state_attr(state.entity_id, 'current_temperature') %} {% set temperature = state.state if current_temperature is none else current_temperature %} {% if temperature is not none %}\n {% set rounded_temp = (temperature | int) if temperature % 1 == 0 else (temperature | float | round(1)) %}\n {% set degree_word = 'stupeň' if rounded_temp == 1 else 'stupně' if rounded_temp in [2,3,4] or rounded_temp % 1 != 0 else 'stupňů' %}\n {{ rounded_temp }} {{ degree_word }}\n{% else %}\n Omlouvám se, ale nemohu zjistit aktuální teplotu.\n{% endif %}\n"
3836
3872
  },