iobroker.assistant 1.3.0 → 1.3.1
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.
- package/README.md +6 -0
- package/admin/custom/.vite/manifest.json +1 -1
- package/admin/custom/assets/{Components-x2Dfv8qE.js → Components-D77NmS_I.js} +1 -1
- package/admin/custom/customComponents.js +1 -1
- package/admin/custom/mf-manifest.json +1 -1
- package/admin/custom/mf-stats.json +1 -1
- package/build/lib/nlu.js +14 -0
- package/build/lib/nlu.js.map +1 -1
- package/build/lib/piAgent.js +5 -0
- package/build/lib/piAgent.js.map +1 -1
- package/build/lib/voice/esphome.js +3 -0
- package/build/lib/voice/esphome.js.map +1 -1
- package/build/main.js +119 -58
- package/build/main.js.map +1 -1
- package/io-package.json +14 -14
- package/package.json +1 -1
package/build/lib/nlu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nlu.js","sourceRoot":"","sources":["../../src/lib/nlu.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tier-0 rule-based NLU (no model, no install, offline) — a TypeScript port of the proven matching\n * approach from the Python assistant \"Hannah\" (`core/hannah/nlu.py`), reduced to the intents this\n * adapter needs: turn on/off, set level, set color, and status queries.\n *\n * It matches a free-text command against the known rooms and devices (room + device + action, longest\n * match wins) and returns a structured {@link NluIntent} the caller executes directly via the ioBroker\n * API — bypassing the LLM entirely for the common commands. Anything it cannot confidently resolve\n * returns `null`, so the caller falls through to the local/cloud LLM.\n */\n\n/** A device as the NLU needs to see it: friendly name, room, type and its controls (controlType → stateId). */\nexport interface NluDevice {\n name: string;\n room: string;\n /** type-detector type, e.g. 'light', 'socket', 'dimmer', 'rgb', 'thermostat'. */\n type: string;\n /** controlType → state id (e.g. `power`, `level`, `brightness`, `actual`, …). */\n controls: Record<string, string>;\n /** controlType → writable flag. */\n writable: Record<string, boolean>;\n /** controlType → ioBroker value type ('boolean'|'number'|'string'|…), to pick the right control. */\n types: Record<string, string>;\n /** controlType → ioBroker role (e.g. 'switch.light', 'level.dimmer'), to find the on/off switch. */\n roles?: Record<string, string>;\n}\n\nexport type NluActionType =\n | 'on'\n | 'off'\n | 'level'\n | 'color'\n | 'query'\n | 'listByState'\n | 'categoryQuery'\n | 'timerSet'\n | 'timerQuery'\n | 'timerCancel'\n | 'alarmSet'\n | 'alarmQuery'\n | 'alarmCancel'\n | 'timeQuery'\n | 'dateQuery'\n | 'weatherQuery'\n | 'volumeSet';\n\nexport interface NluIntent {\n action: NluActionType;\n /** Single-device actions (on/off/level/color/query). */\n device?: NluDevice;\n /** State id to act on (writable for on/off/level/color, readable for query). */\n stateId?: string;\n /** Value to write (bool for on/off, number for level, hex/temp string for color). */\n value?: boolean | number | string;\n /**\n * Secondary write applied after the primary one — used to also flip a dimmer's on/off switch when\n * setting its level (\"30%\" → level 30 **and** switch on), when the device has a separate switch control.\n */\n also?: { stateId: string; value: boolean };\n /** Matched room display name, if any. */\n room?: string;\n confidence: number;\n // ── Aggregate query (action 'listByState'), e.g. \"which windows are open\" ──\n /** All devices of the queried category (e.g. every window). */\n devices?: NluDevice[];\n /** The queried device category, e.g. 'window'. */\n category?: string;\n /** Which state to report on, e.g. 'open'. */\n stateFilter?: string;\n // ── Category query (action 'categoryQuery'), e.g. \"how is the air in the living room\" ──\n /** Device types to read, in order of preference (e.g. ['airQuality']). */\n types?: string[];\n // ── Timer intents (timerSet/timerQuery/timerCancel) ──\n /** Duration in seconds for `timerSet`. */\n durationSec?: number;\n /** Optional timer/alarm label (e.g. \"die Nudeln\"), or a match hint for `timerCancel`/`alarmCancel`. */\n label?: string;\n // ── Alarm intents (alarmSet/alarmQuery/alarmCancel) ──\n /** Hour 0–23 for `alarmSet`. */\n hour?: number;\n /** Minute 0–59 for `alarmSet`. */\n minute?: number;\n /** Weekdays (0 = Sunday … 6 = Saturday) for `alarmSet`; empty = one-shot next occurrence. */\n weekdays?: number[];\n // ── Weather (action 'weatherQuery') ──\n /** Which part of the forecast was asked for. */\n when?: WeatherWhen;\n // ── Satellite volume (action 'volumeSet'): `value` = absolute level 0–100, or `delta` ──\n /** Relative change in percentage points (\"lauter\" = +10). */\n delta?: number;\n // ── A device command for later (\"Licht in 2 Stunden aus\", \"Rollo um 22 Uhr zu\"): never executed now ──\n /** Run the command after this many seconds. */\n delaySec?: number;\n /** Run the command at this clock time; `day` = days from today when said (\"morgen\" = 1), else the next one. */\n at?: { hour: number; minute: number; day?: number };\n}\n\n/** When a deferred command runs */\ntype CommandTime = { delaySec: number } | { at: { hour: number; minute: number; day?: number } };\n\n/** The part of the forecast a weather question is about: current conditions, or a forecast day. */\nexport type WeatherWhen = 'now' | 'today' | 'tomorrow' | 'dayAfter';\n\n/** Options of the {@link Nlu} that depend on what the adapter has configured. */\nexport interface NluOptions {\n /** A weather source is configured, so weather questions can be answered locally. */\n weather?: boolean;\n}\n\nconst TURN_ON = new Set([\n // de/en\n 'an',\n 'ein',\n 'einschalten',\n 'anschalten',\n 'anmachen',\n 'aktiviere',\n 'aktivieren',\n 'starte',\n 'start',\n 'on',\n // ru\n 'включи',\n 'включить',\n 'вруби',\n 'врубить',\n 'зажги',\n 'запусти',\n]);\nconst TURN_OFF = new Set([\n // de/en\n 'aus',\n 'ausschalten',\n 'abschalten',\n 'ausmachen',\n 'deaktiviere',\n 'deaktivieren',\n 'stoppe',\n 'stop',\n 'off',\n // ru\n 'выключи',\n 'выключить',\n 'выруби',\n 'вырубить',\n 'погаси',\n 'потуши',\n 'отключи',\n]);\nconst QUERY_WORDS = new Set([\n // de/en\n 'wie',\n 'was',\n 'ist',\n 'sind',\n 'status',\n 'wieviel',\n 'welche',\n 'welcher',\n 'zeig',\n 'zeige',\n 'laeuft',\n 'how',\n 'what',\n 'is',\n 'are',\n 'show',\n // ru\n 'какая',\n 'какой',\n 'какое',\n 'сколько',\n 'покажи',\n 'что',\n 'статус',\n]);\n/** Filler words removed before matching (so \"mach das Licht an\" → [\"licht\",\"an\"]). */\nconst FILLER = new Set([\n // de/en\n 'bitte',\n 'mal',\n 'doch',\n 'denn',\n 'einfach',\n 'kannst',\n 'du',\n 'koenntest',\n 'mach',\n 'die',\n 'das',\n 'den',\n 'der',\n 'the',\n 'please',\n 'und',\n 'im',\n 'in',\n 'auf',\n 'zum',\n 'zur',\n // ru\n 'пожалуйста',\n 'давай',\n 'ну',\n 'мне',\n 'на',\n 'в',\n 'и',\n]);\n/** Color names (de + ru) → hex, or a special token for color temperature. */\nconst COLORS: Record<string, string> = {\n rot: '#FF0000',\n gruen: '#00FF00',\n blau: '#0000FF',\n gelb: '#FFFF00',\n orange: '#FF8000',\n lila: '#8000FF',\n pink: '#FF69B4',\n magenta: '#FF00FF',\n cyan: '#00FFFF',\n tuerkis: '#00CED1',\n weiss: '#FFFFFF',\n warmweiss: 'warm',\n kaltweiss: 'cold',\n красный: '#FF0000',\n зеленый: '#00FF00',\n синий: '#0000FF',\n голубой: '#00BFFF',\n желтый: '#FFFF00',\n оранжевый: '#FF8000',\n фиолетовый: '#8000FF',\n розовый: '#FF69B4',\n белый: '#FFFFFF',\n};\n/** Device types that accept a color. */\nconst COLOR_TYPES = new Set(['rgb', 'rgbSingle', 'rgbwSingle', 'hue', 'cie', 'ct']);\n\n/** type-detector types that count as \"windows\" for the \"which windows are open\" aggregate query. */\nconst WINDOW_TYPES = new Set(['window', 'windowTilt']);\n/** Words (de/en/ru, stemmed) that name a window. */\nconst WINDOW_WORDS = ['fenster', 'window', 'windows', 'окно', 'окна', 'окон'];\n/**\n * Measurement words (de/en/ru, stemmed) → the `@iobroker/type-detector` device types that answer them.\n * This is what makes \"wie ist die Luft im Wohnzimmer\" work without a device being named: the question\n * is about a *kind* of value, not about one thing. Ported from the Python original's `category_words`\n * (`C:\\iot\\Hannah`, `core/hannah/settings_manager.py`), mapped onto our detector types.\n */\nconst CATEGORY_WORDS: { words: string[]; category: string; types: string[] }[] = [\n // Order matters, most specific first: `wordInText` is suffix-tolerant (it has to be, for German and\n // Russian inflection), so the bare word \"luft\" also matches \"Luftdruck\" and \"Luftfeuchtigkeit\". The\n // compound categories therefore have to be tested before the plain-\"Luft\" one, or they are unreachable.\n {\n words: ['luftfeucht', 'feuchtigkeit', 'feucht', 'humidity', 'humid', 'влажност'],\n category: 'humidity',\n types: ['humidity'],\n },\n {\n words: ['luftdruck', 'druck', 'pressure', 'давлени'],\n category: 'pressure',\n types: ['pressure'],\n },\n {\n words: ['helligkeit', 'hell', 'lux', 'beleuchtungsstaerke', 'brightness', 'illuminance', 'светло', 'яркост'],\n category: 'illuminance',\n types: ['illuminance'],\n },\n {\n words: ['luft', 'luftqualitaet', 'luftguete', 'raumluft', 'iaq', 'co2', 'voc', 'air', 'воздух'],\n category: 'airQuality',\n types: ['airQuality'],\n },\n {\n // Last: 'warm'/'temperatur' are the words people use most, so a more specific category above wins\n // when both appear (\"wie warm und wie feucht ist es\" is answered about the humidity).\n words: ['temperatur', 'warm', 'kalt', 'grad', 'temperature', 'cold', 'температур', 'тепло', 'холодно'],\n category: 'temperature',\n types: ['temperature', 'thermostat'],\n },\n];\n\n/** Words that ask about every room at once (\"wie warm ist es überall\"). */\nconst EVERYWHERE_WORDS = ['ueberall', 'alle', 'allen', 'everywhere', 'all', 'везде', 'всюду'];\n\n/** Words (stemmed) that make a question a weather question on their own. */\nconst WEATHER_WORDS = ['wetter', 'wetterbericht', 'vorhersage', 'weather', 'forecast', 'погода', 'прогноз'];\n/**\n * Precipitation words, matched as whole tokens: stemming \"regen\" would also catch \"Regelung\", and nobody\n * gives a smart home the order \"rain\" — these only ever start a question.\n */\nconst RAIN_TOKENS = new Set([\n 'regnet',\n 'regnen',\n 'regen',\n 'schneit',\n 'schnee',\n 'gewitter',\n 'rain',\n 'raining',\n 'snow',\n 'snowing',\n 'дождь',\n 'дождя',\n 'снег',\n 'гроза',\n]);\n/** A weather question about some other place or a later day is left to the LLM and its `get_weather` tool. */\nconst WEATHER_ELSEWHERE = new Set(['in', 'fuer', 'for', 'в', 'во', 'для']);\nconst WEATHER_LATER_RE =\n /(?<![\\p{L}])(woche\\p{L}*|wochenende|week\\p{L}*|недел\\p{L}*|выходн\\p{L}*|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag|monday|tuesday|wednesday|thursday|friday|saturday|sunday|понедельник|вторник|среду|четверг|пятницу|субботу|воскресенье)(?![\\p{L}])/u;\n\n/** Words (stemmed) that name the playback volume. */\nconst VOLUME_WORDS = ['lautstaerke', 'volume', 'громкость'];\nconst LOUDER_TOKENS = new Set(['lauter', 'louder', 'громче', 'погромче']);\nconst QUIETER_TOKENS = new Set(['leiser', 'quieter', 'softer', 'тише', 'потише']);\nconst VOLUME_MAX_TOKENS = new Set(['maximum', 'max', 'voll', 'full', 'максимум', 'полную']);\nconst VOLUME_MIN_TOKENS = new Set(['minimum', 'min', 'минимум']);\n/** Step of a bare \"lauter\"/\"leiser\", in percentage points. */\nconst VOLUME_STEP = 10;\n\n/** Words (de/en/ru, stemmed) that mean \"open\". */\nconst OPEN_WORDS = ['offen', 'geoeffnet', 'geoffnet', 'auf', 'open', 'открыт', 'открыта', 'открыты', 'открытые'];\n\n/** Words (de/en/ru, stemmed) that make a query an on/off question (\"is the light on?\"). */\nconst ON_OFF_QUERY_WORDS = [\n 'an',\n 'ein',\n 'aus',\n 'eingeschaltet',\n 'ausgeschaltet',\n 'on',\n 'off',\n 'включен',\n 'включена',\n 'включено',\n 'выключен',\n 'выключена',\n 'работает',\n];\n\n/**\n * State-id suffixes of pure measurements/indicators — never the on/off switch or level (but note ACTUAL\n * is NOT here: it is a valid read-back for \"is it on\"). Used to keep pickControl off metering states.\n */\nconst METER_SUFFIX =\n /(CONSUMPTION|ELECTRIC_POWER|CURRENT|VOLTAGE|ENERGY|POWER|LOWBAT|BATTERY|UNREACH|RSSI|TEMPERATURE)$/i;\n\n// ── Timers / reminders (de/en/ru) ───────────────────────────────────────────\n/**\n * Marks a command as being about a countdown timer. Never fires on the bare word \"time\" (\"what time is\n * it\") — it needs the full \"timer\". \"timers?\" carries no leading word boundary so German compounds\n * (\"Küchentimer\", \"Eieruhr\"-style) and the plural still match; the prefix forms keep a boundary.\n */\nconst TIMER_RE = /(?:(?<![\\p{L}])(reminder|remind|erinner\\p{L}*|таймер\\p{L}*|напомн\\p{L}*)|timers?)(?![\\p{L}])/iu;\n/** Words that turn a timer command into \"cancel/stop the timer\" (de/en/ru). */\nconst TIMER_CANCEL_RE =\n /(?<![\\p{L}])(abbrech\\p{L}*|beend\\p{L}*|stopp?\\p{L}*|loesch\\p{L}*|cancel|delete|remove|clear|отмен\\p{L}*|удал\\p{L}*|сброс\\p{L}*|стоп)(?![\\p{L}])/iu;\n/** Number words → digits (normalized: umlauts expanded), de/en/ru, plus common fractions. */\nconst NUMBER_WORDS: Record<string, string> = {\n ein: '1',\n eine: '1',\n einen: '1',\n eins: '1',\n zwei: '2',\n drei: '3',\n vier: '4',\n fuenf: '5',\n sechs: '6',\n sieben: '7',\n acht: '8',\n neun: '9',\n zehn: '10',\n elf: '11',\n zwoelf: '12',\n anderthalb: '1.5',\n eineinhalb: '1.5',\n halbe: '0.5',\n halb: '0.5',\n viertel: '0.25',\n dreiviertel: '0.75',\n one: '1',\n two: '2',\n three: '3',\n four: '4',\n five: '5',\n six: '6',\n seven: '7',\n eight: '8',\n nine: '9',\n ten: '10',\n eleven: '11',\n twelve: '12',\n half: '0.5',\n quarter: '0.25',\n один: '1',\n одну: '1',\n два: '2',\n две: '2',\n три: '3',\n четыре: '4',\n пять: '5',\n шесть: '6',\n семь: '7',\n восемь: '8',\n девять: '9',\n десять: '10',\n};\n/** Units 1–9 (normalized), de/en/ru — the parts of a spelled-out number above twelve */\nconst UNIT_WORDS: Record<string, number> = {\n eins: 1,\n zwei: 2,\n drei: 3,\n vier: 4,\n fuenf: 5,\n sechs: 6,\n sieben: 7,\n acht: 8,\n neun: 9,\n one: 1,\n two: 2,\n three: 3,\n four: 4,\n five: 5,\n six: 6,\n seven: 7,\n eight: 8,\n nine: 9,\n один: 1,\n одна: 1,\n одно: 1,\n два: 2,\n две: 2,\n три: 3,\n четыре: 4,\n пять: 5,\n шесть: 6,\n семь: 7,\n восемь: 8,\n девять: 9,\n};\n/** 10–19, de/en/ru */\nconst TEEN_WORDS: Record<string, number> = {\n zehn: 10,\n elf: 11,\n zwoelf: 12,\n dreizehn: 13,\n vierzehn: 14,\n fuenfzehn: 15,\n sechzehn: 16,\n siebzehn: 17,\n achtzehn: 18,\n neunzehn: 19,\n ten: 10,\n eleven: 11,\n twelve: 12,\n thirteen: 13,\n fourteen: 14,\n fifteen: 15,\n sixteen: 16,\n seventeen: 17,\n eighteen: 18,\n nineteen: 19,\n десять: 10,\n одиннадцать: 11,\n двенадцать: 12,\n тринадцать: 13,\n четырнадцать: 14,\n пятнадцать: 15,\n шестнадцать: 16,\n семнадцать: 17,\n восемнадцать: 18,\n девятнадцать: 19,\n};\n/** Tens 20–90, de/en/ru */\nconst TEN_WORDS: Record<string, number> = {\n zwanzig: 20,\n dreissig: 30,\n vierzig: 40,\n fuenfzig: 50,\n sechzig: 60,\n siebzig: 70,\n achtzig: 80,\n neunzig: 90,\n twenty: 20,\n thirty: 30,\n forty: 40,\n fifty: 50,\n sixty: 60,\n seventy: 70,\n eighty: 80,\n ninety: 90,\n двадцать: 20,\n тридцать: 30,\n сорок: 40,\n пятьдесят: 50,\n шестьдесят: 60,\n семьдесят: 70,\n восемьдесят: 80,\n девяносто: 90,\n};\nconst HUNDRED_WORDS = new Set(['hundert', 'einhundert', 'hundred', 'сто']);\n\n/** Value of one spelled-out number word (\"fuenfundzwanzig\", \"twenty-five\", \"fünfzig\"), or null */\nfunction numberWordValue(word: string): number | null {\n if (HUNDRED_WORDS.has(word)) {\n return 100;\n }\n const direct = TEN_WORDS[word] ?? TEEN_WORDS[word] ?? UNIT_WORDS[word];\n if (direct !== undefined) {\n return direct;\n }\n // de \"fünfundzwanzig\" (unit first, \"ein\" as in \"einundzwanzig\"), en \"twenty-five\"\n const de = /^(\\p{L}+?)und(\\p{L}+)$/u.exec(word);\n if (de && TEN_WORDS[de[2]] !== undefined && (de[1] === 'ein' || UNIT_WORDS[de[1]] !== undefined)) {\n return TEN_WORDS[de[2]] + (UNIT_WORDS[de[1]] ?? 1);\n }\n const en = /^(\\p{L}+)-(\\p{L}+)$/u.exec(word);\n if (en && TEN_WORDS[en[1]] !== undefined && UNIT_WORDS[en[2]] !== undefined) {\n return TEN_WORDS[en[1]] + UNIT_WORDS[en[2]];\n }\n return null;\n}\n\n/**\n * Spelled-out whole numbers up to 100 → digits in normalized text (de/en/ru): \"fuenfzig prozent\" → \"50 prozent\",\n * \"twenty five\" → \"25\", \"двадцать пять\" → \"25\", \"one hundred\" → \"100\". Speech recognition writes numbers as words\n * often enough that a level command would otherwise miss. Articles (\"ein\", \"a\") stay words.\n *\n * @param text normalized text\n */\nexport function spelledNumbersToDigits(text: string): string {\n const words = text.split(/\\s+/).filter(Boolean);\n const out: string[] = [];\n for (let i = 0; i < words.length; i++) {\n const [, word, tail] = /^(.*?)([.,!?;:]*)$/u.exec(words[i])!;\n let value = numberWordValue(word);\n if (value === null) {\n // \"one hundred\", \"a hundred\", \"ein hundert\"\n const next = words[i + 1]?.replace(/[.,!?;:]+$/u, '');\n if (['one', 'a', 'ein'].includes(word) && next && HUNDRED_WORDS.has(next)) {\n out.push(`100${/[.,!?;:]+$/u.exec(words[i + 1])?.[0] || ''}`);\n i++;\n continue;\n }\n out.push(words[i]);\n continue;\n }\n let end = tail;\n // en \"twenty five\", ru \"двадцать пять\": a ten followed by a unit\n if (TEN_WORDS[word] !== undefined && !tail && i + 1 < words.length) {\n const [, nextWord, nextTail] = /^(.*?)([.,!?;:]*)$/u.exec(words[i + 1])!;\n if (UNIT_WORDS[nextWord] !== undefined) {\n value += UNIT_WORDS[nextWord];\n end = nextTail;\n i++;\n }\n }\n out.push(`${value}${end}`);\n }\n return out.join(' ');\n}\n\n/** Fixed phrases replaced up front so their fractions don't collide with the general number-word pass. */\nconst DURATION_PHRASES: [RegExp, string][] = [\n [/(?<![\\p{L}])dreiviertelstunde(?![\\p{L}])/iu, '45 minuten'],\n [/(?<![\\p{L}])viertelstunde(?![\\p{L}])/iu, '15 minuten'],\n [/(?<![\\p{L}])eine? halbe stunde(?![\\p{L}])/iu, '30 minuten'],\n [/(?<![\\p{L}])halbe stunde(?![\\p{L}])/iu, '30 minuten'],\n [/half an hour/iu, '30 minutes'],\n [/a half hour/iu, '30 minutes'],\n [/quarter of an hour/iu, '15 minutes'],\n [/quarter hour/iu, '15 minutes'],\n [/(?<![\\p{L}])полтора часа(?![\\p{L}])/iu, '90 минут'],\n [/(?<![\\p{L}])полчаса(?![\\p{L}])/iu, '30 минут'],\n // a unit without a number: \"in einer Stunde\", \"in an hour\", \"через час\", \"через минуту\"\n [/(?<![\\p{L}])einer halben stunde(?![\\p{L}])/iu, '30 minuten'],\n [/(?<![\\p{L}])einer? (stunde|minute)(?![\\p{L}])/iu, '1 $1'],\n [/(?<![\\p{L}])an? (hour|minute)(?![\\p{L}])/iu, '1 $1'],\n [/(?<![\\p{L}])через (час|минуту)(?![\\p{L}])/iu, 'через 1 $1'],\n];\n/** Prepositions of a delay: \"in 2 Stunden\", \"nach 10 Minuten\", \"через 2 часа\", \"after 5 minutes\" */\nconst DELAY_PREPOSITION_RE = /(?<![\\p{L}])(?:in|nach|через|after)\\s+/gu;\n/**\n * A clock time that cannot be anything else: \"22:30\", \"7 Uhr\", \"7 o'clock\", \"7 pm\", \"в 7 часов\", \"в 10 вечера\",\n * \"halb acht\" — unlike a bare \"um 3\", which is as often \"um 3 lauter\" or \"um 20 Prozent\".\n */\nconst CLOCK_RE =\n /\\d{1,2}:\\d{2}|\\d\\s*(?:uhr|o.?clock|[ap]m)(?![\\p{L}])|(?<![\\p{L}])(?:в|во)\\s+\\d{1,2}\\s*(?:час\\p{L}*|утра|вечера|ночи|дня)(?![\\p{L}])|(?<![\\p{L}])(?:halb|viertel|dreiviertel|quarter|half past)\\s/u;\n/** Percent values, removed before looking for a clock time (\"um 20 Prozent\" is no time) */\nconst PERCENT_RE = /\\d+(?:[.,]\\d+)?\\s*(?:%|prozent|percent|процент\\p{L}*)/giu;\n/** Day words for a clock time, the longer first (\"übermorgen\" before \"morgen\") */\nconst DAY_WORDS: [RegExp, number][] = [\n [/(?<![\\p{L}])(?:uebermorgen|day after tomorrow|послезавтра)(?![\\p{L}])/u, 2],\n [/(?<![\\p{L}])(?:morgen|tomorrow|завтра)(?![\\p{L}])/u, 1],\n [/(?<![\\p{L}])(?:heute|today|сегодня)(?![\\p{L}])/u, 0],\n];\nconst HOUR_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:stunden?|hours?|hrs?|h|час(?:а|ов)?)(?![\\p{L}])/giu;\nconst MIN_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:minuten?|mins?|minutes?|минут[уы]?)(?![\\p{L}])/giu;\nconst SEC_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:sekunden?|secs?|seconds?|секунд[уы]?)(?![\\p{L}])/giu;\n/** Duration/number tokens stripped from a timer label (\"timer für 5 minuten für die Nudeln\" → \"die Nudeln\"). */\nconst LABEL_STOP_WORDS = new Set([\n 'in',\n 'im',\n 'mich',\n 'me',\n 'my',\n 'den',\n 'die',\n 'das',\n 'der',\n 'the',\n 'a',\n 'an',\n 'auf',\n 'noch',\n 'ein',\n 'eine',\n 'einen',\n 'timer',\n 'reminder',\n 'remind',\n 'таймер',\n 'на',\n 'через',\n 'про',\n 'about',\n 'to',\n 'for',\n 'fuer',\n 'stunde',\n 'stunden',\n 'minute',\n 'minuten',\n 'min',\n 'sekunde',\n 'sekunden',\n 'sec',\n 'hour',\n 'hours',\n 'minutes',\n 'seconds',\n 'second',\n 'час',\n 'часа',\n 'часов',\n 'минут',\n 'минуту',\n 'минуты',\n 'секунд',\n 'секунду',\n 'секунды',\n]);\n/** Marker words after which a timer label follows (\"… an die Nudeln\", \"remind me to call mom\"). */\nconst LABEL_MARKERS = new Set(['an', 'fuer', 'for', 'to', 'about', 'про']);\n\n// ── Alarms / wake-ups at a fixed clock time (de/en/ru) ──────────────────────\n/**\n * Marks a command as being about an alarm / wake-up (\"Wecker\", \"weck mich\", \"alarm\", \"будильник\"). Like\n * {@link TIMER_RE}, \"alarms?\"/\"wecker\" carry no leading boundary so compounds (\"Küchenwecker\") and the\n * plural still match; the verb-prefix forms (\"weck…\", \"разбуд…\") keep a boundary. \"буди…\" and not just\n * \"буд…\": that would also catch \"будет\" (will be), and turn \"будет ли дождь?\" into an alarm query.\n */\nconst ALARM_RE = /(?:(?<![\\p{L}])(weck\\p{L}*|wake|буди\\p{L}*|разбуд\\p{L}*)|alarms?|wecker)(?![\\p{L}])/iu;\n/** Hour number words → digits (no fractions — those are handled by the clock regexes). de/en/ru, 1–12. */\nconst HOUR_WORDS: Record<string, string> = {\n ein: '1',\n eine: '1',\n einen: '1',\n eins: '1',\n zwei: '2',\n drei: '3',\n vier: '4',\n fuenf: '5',\n sechs: '6',\n sieben: '7',\n acht: '8',\n neun: '9',\n zehn: '10',\n elf: '11',\n zwoelf: '12',\n one: '1',\n two: '2',\n three: '3',\n four: '4',\n five: '5',\n six: '6',\n seven: '7',\n eight: '8',\n nine: '9',\n ten: '10',\n eleven: '11',\n twelve: '12',\n один: '1',\n два: '2',\n три: '3',\n четыре: '4',\n пять: '5',\n шесть: '6',\n семь: '7',\n восемь: '8',\n девять: '9',\n десять: '10',\n одиннадцать: '11',\n двенадцать: '12',\n};\n/** Weekday word (normalized, prefix-matched for inflection) → 0 (Sun) … 6 (Sat). */\nconst WEEKDAYS: [RegExp, number][] = [\n [/(?<![\\p{L}])(montag|monday|понедельник)/iu, 1],\n [/(?<![\\p{L}])(dienstag|tuesday|вторник)/iu, 2],\n [/(?<![\\p{L}])(mittwoch|wednesday|сред)/iu, 3],\n [/(?<![\\p{L}])(donnerstag|thursday|четверг)/iu, 4],\n [/(?<![\\p{L}])(freitag|friday|пятниц)/iu, 5],\n [/(?<![\\p{L}])(samstag|sonnabend|saturday|суббот)/iu, 6],\n [/(?<![\\p{L}])(sonntag|sunday|воскресень)/iu, 0],\n];\n\n/**\n * Parse a clock time from free text (de/en/ru): \"7:30\", \"7 Uhr\", \"7 Uhr 30\", \"halb acht\" (7:30),\n * \"viertel nach sieben\" (7:15), \"viertel vor acht\"/\"dreiviertel acht\" (7:45), \"half past seven\",\n * \"quarter past/to\", \"в 7 часов\", plus am/pm. Returns {hour 0-23, minute 0-59} or null.\n */\nexport function parseClockTime(text: string): { hour: number; minute: number } | null {\n let t = normalize(text);\n // Substitute hour number words → digits (\"halb acht\" → \"halb 8\"), leaving fraction words intact.\n t = t\n .split(/\\s+/)\n .map(w => (Object.prototype.hasOwnProperty.call(HOUR_WORDS, w) ? HOUR_WORDS[w] : w))\n .join(' ');\n\n const pm = /(?<![\\p{L}])(pm|nachmittags|abends|вечера)(?![\\p{L}])/u.test(t);\n const am = /(?<![\\p{L}])(am|morgens|vormittags|utra|утра|nachts)(?![\\p{L}])/u.test(t);\n const applyMeridiem = (h: number): number => {\n if (pm && h < 12) {\n return h + 12;\n }\n if (am && h === 12) {\n return 0;\n }\n return h;\n };\n const ok = (h: number, m: number): { hour: number; minute: number } | null =>\n h >= 0 && h <= 23 && m >= 0 && m <= 59 ? { hour: h, minute: m } : null;\n\n let m: RegExpMatchArray | null;\n // HH:MM\n if ((m = t.match(/(?<!\\d)(\\d{1,2}):(\\d{2})(?!\\d)/))) {\n return ok(applyMeridiem(+m[1]), +m[2]);\n }\n // \"viertel nach H\" → H:15 ; \"viertel vor H\" / \"dreiviertel H\" → (H-1):45\n if ((m = t.match(/viertel\\s+nach\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 15);\n }\n if ((m = t.match(/(?:viertel\\s+vor|dreiviertel)\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 45);\n }\n if ((m = t.match(/quarter\\s+past\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 15);\n }\n if ((m = t.match(/quarter\\s+to\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 45);\n }\n // \"halb H\" (German) → (H-1):30 ; \"half past H\" (English) → H:30\n if ((m = t.match(/half\\s+past\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 30);\n }\n if ((m = t.match(/(?<![\\p{L}])halb\\s+(\\d{1,2})/u))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 30);\n }\n // \"H Uhr MM\" / \"H Uhr\" / \"H часов MM\"\n if ((m = t.match(/(\\d{1,2})\\s*(?:uhr|часов|часа|час)\\s*(\\d{1,2})(?![\\p{L}])/u))) {\n return ok(applyMeridiem(+m[1]), +m[2]);\n }\n if ((m = t.match(/(\\d{1,2})\\s*(?:uhr|o.?clock|часов|часа|час)(?![\\p{L}])/u))) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n // \"um/at/в H\" (bare hour after an explicit time preposition) — but not when a duration unit follows,\n // so \"Timer um 5 Minuten\" is not misread as 5 o'clock.\n if (\n (m = t.match(\n /(?<![\\p{L}])(?:um|at|в|во)\\s+(\\d{1,2})(?![\\d:])(?!\\s*(?:minut|stund|sekund|min|sek|hour|second))/u,\n ))\n ) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n // Bare hour qualified only by am/pm (\"7 pm\", \"8 am\").\n if ((pm || am) && (m = t.match(/(?<![\\d.])(\\d{1,2})(?![\\d.:])/))) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n return null;\n}\n\n/**\n * Parse recurrence from free text → weekday numbers (0 = Sun … 6 = Sat). \"täglich\"/\"jeden Tag\"/\"daily\"\n * → all 7; \"wochentags\"/\"werktags\"/\"weekdays\" → Mon–Fri; \"wochenende\"/\"weekend\" → Sat+Sun; otherwise the\n * union of the named weekdays. Empty array = one-shot.\n */\nexport function parseWeekdays(text: string): number[] {\n const t = normalize(text);\n if (/(?<![\\p{L}])(taeglich|jeden tag|daily|every day|ежедневно|каждый день)(?![\\p{L}])/u.test(t)) {\n return [0, 1, 2, 3, 4, 5, 6];\n }\n if (/(?<![\\p{L}])(wochentags|werktags|weekdays|по будням|будни)(?![\\p{L}])/u.test(t)) {\n return [1, 2, 3, 4, 5];\n }\n if (/(?<![\\p{L}])(wochenende|weekend|выходн\\p{L}*)(?![\\p{L}])/u.test(t)) {\n return [0, 6];\n }\n const days = new Set<number>();\n for (const [re, day] of WEEKDAYS) {\n if (re.test(t)) {\n days.add(day);\n }\n }\n return [...days].sort();\n}\n\n/**\n * Parse a free-text duration (\"1 Stunde 30 Minuten\", \"in 5 minuten\", \"полтора часа\") into seconds; null\n * if none is found. With `assumeMinutes`, a bare number with no unit (\"timer 5\") counts as minutes.\n */\nexport function parseDurationSeconds(text: string, assumeMinutes = false): number | null {\n let t = normalize(text);\n for (const [re, rep] of DURATION_PHRASES) {\n t = t.replace(re, rep);\n }\n // Replace standalone number words with digits so \"fünf minuten\" → \"5 minuten\".\n t = t\n .split(/\\s+/)\n .map(w => (Object.prototype.hasOwnProperty.call(NUMBER_WORDS, w) ? NUMBER_WORDS[w] : w))\n .join(' ');\n\n let total = 0;\n let matched = false;\n const sum = (re: RegExp, factor: number): void => {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(t))) {\n total += parseFloat(m[1].replace(',', '.')) * factor;\n matched = true;\n }\n };\n sum(HOUR_RE, 3600);\n sum(MIN_RE, 60);\n sum(SEC_RE, 1);\n\n if (!matched && assumeMinutes) {\n const bare = t.match(/(?<![\\d.])(\\d+(?:[.,]\\d+)?)(?![\\d.])/);\n if (bare) {\n total = parseFloat(bare[1].replace(',', '.')) * 60;\n matched = true;\n }\n }\n return matched && total > 0 ? Math.round(total) : null;\n}\n\n/**\n * \"Make it stop\" words (de/en/ru), used to silence a ringing timer/alarm. Kept separate from the device\n * TURN_OFF set (no \"aus\") so it only reacts to an explicit stop/quiet phrase, not \"turn the light off\".\n */\nconst STOP_RE =\n /(?<![\\p{L}])(stopp?\\p{L}*|halt|aufhoer\\p{L}*|ruhe|ruhig|genug|schluss|abbrech\\p{L}*|beend\\p{L}*|ende|still|cancel|enough|quiet|dismiss|silence|стоп|хватит|тихо|довольно|прекрат\\p{L}*|отмен\\p{L}*|замолч\\p{L}*|тишин\\p{L}*)(?![\\p{L}])/iu;\n\n/** True if the text is a \"stop / be quiet\" command (used to silence a ringing timer/alarm). */\nexport function isStopCommand(text: string): boolean {\n return STOP_RE.test(normalize(text));\n}\n\n/** Normalize for matching: lowercase, German umlauts → ascii, ß → ss, Russian ё → е. */\nexport function normalize(s: string): string {\n return s\n .toLowerCase()\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ü/g, 'ue')\n .replace(/ß/g, 'ss')\n .replace(/ё/g, 'е');\n}\n\nconst STRIP = /[.,!?;:()[\\]]/g;\nconst escapeRe = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Does a name word appear in the text? Matches on a Unicode word boundary and allows a differing\n * suffix (crude stemming) so inflected forms match too — essential for Russian (\"подсветку\" for\n * \"подсветка\", \"кокпита\" for \"кокпит\"). Longer words drop more trailing characters.\n */\nfunction wordInText(word: string, text: string): boolean {\n const stem =\n word.length >= 6 ? word.slice(0, word.length - 2) : word.length >= 5 ? word.slice(0, word.length - 1) : word;\n try {\n return new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escapeRe(stem)}`, 'u').test(text);\n } catch {\n return text.includes(stem);\n }\n}\n\n/**\n * Directionless command verbs: they mark an imperative but carry no on/off/level of their own. A segment\n * holding nothing but such a verb and a device name (\"schalte das Licht\" in \"schalte das Licht und die\n * Lampe an\") may therefore borrow the action from its sibling segment.\n */\nconst NEUTRAL_VERBS = new Set([\n // de\n 'schalte',\n 'schalt',\n 'schalten',\n 'stelle',\n 'stell',\n 'stellen',\n 'setze',\n 'setz',\n 'setzen',\n 'drehe',\n 'dreh',\n 'fahre',\n 'fahr',\n 'mache',\n 'machen',\n // en\n 'set',\n 'put',\n 'turn',\n 'switch',\n 'change',\n 'adjust',\n 'make',\n // ru\n 'поставь',\n 'установи',\n 'выстави',\n 'сделай',\n]);\n\n/** Conjunctions that join two commands in one utterance (de/en/ru). */\nconst CONJUNCTIONS = 'und|sowie|dann|danach|and|then|plus|и|затем|потом';\n\n/**\n * Separators between two commands: a run of conjunctions (\"und dann\"), a comma or a semicolon. A comma\n * directly followed by a digit is NOT a separator (decimal values like \"50,5 %\").\n */\nconst SPLIT_RE = new RegExp(`\\\\s*[;,](?!\\\\d)\\\\s*|\\\\s+(?:${CONJUNCTIONS})(?:\\\\s+(?:${CONJUNCTIONS}))*\\\\s+`, 'giu');\n\n/**\n * Split a combined command (\"Schalte A an und setze B auf 30 %\") into its parts; a single-element array\n * when there is nothing to split.\n */\nexport function splitCommands(text: string): string[] {\n return text\n .split(SPLIT_RE)\n .map(s => s.trim())\n .filter(Boolean);\n}\n\n/** Normalized views of one command, shared by every matching step. */\ninterface Prepared {\n /** The original segment text (kept for the \"?\" test and the schedule parser). */\n raw: string;\n /** Lowercased/umlaut-expanded text with aliases applied — still contains filler words. */\n norm: string;\n /** `norm` split into words, filler removed. */\n tokens: string[];\n /** `tokens` joined by a space — the text every name matcher works on. */\n joined: string;\n tokenSet: Set<string>;\n}\n\n/**\n * The \"what to do\" half of a device command, kept separate from the \"which device\" half so the segments\n * of a combined command can share one verb (\"Schalte A und B **an**\").\n */\ninterface CommandFeatures {\n action: 'on' | 'off' | null;\n level: number | null;\n color: string | null;\n isQuery: boolean;\n /** The question asks about on/off (\"ist das Licht an?\"), not about a value (\"wie warm ist es?\"). */\n onOffQuery: boolean;\n}\n\n/** True when a segment states no action at all (\"… und die Lampe\") and may inherit its sibling's. */\nfunction isBare(f: CommandFeatures): boolean {\n return !f.action && f.level === null && !f.color && !f.isQuery;\n}\n\nexport class Nlu {\n private readonly rooms: string[];\n private readonly devices: NluDevice[];\n /** Synonym dictionary as normalized [from, to] pairs, applied to the input before matching. */\n private readonly aliases: [string, string][];\n private readonly opts: NluOptions;\n\n constructor(\n rooms: string[],\n devices: NluDevice[],\n aliases: { from: string; to: string }[] = [],\n opts: NluOptions = {},\n ) {\n this.rooms = rooms.filter(Boolean);\n this.devices = devices;\n this.opts = opts;\n this.aliases = aliases\n .map(a => [normalize(a.from || ''), normalize(a.to || '')] as [string, string])\n .filter(([from]) => from);\n }\n\n /**\n * Rewrite synonyms to canonical terms on the (normalized) input, matching whole words/phrases only\n * (Unicode boundaries). E.g. \"tv\" → \"fernseher\", \"deckenlicht\" → \"licht wohnzimmer\". No-op when the\n * dictionary is empty. Applied once up front so all downstream matching sees the canonical wording.\n */\n private applyAliases(norm: string): string {\n let out = norm;\n for (const [from, to] of this.aliases) {\n try {\n out = out.replace(new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escapeRe(from)}(?![\\\\p{L}\\\\p{N}])`, 'gu'), to);\n } catch {\n // Defensive: a malformed alias must never break parsing.\n }\n }\n return out;\n }\n\n /** Parse a single command; returns a structured intent or null if nothing could be resolved confidently. */\n parse(text: string): NluIntent | null {\n const p = this.prepare(text);\n return p ? this.parsePrepared(p, null) : null;\n }\n\n /**\n * Parse a possibly **combined** command into the intents to execute, in order:\n * - several commands joined by a conjunction — \"Schalte A an und setze B auf 30 %\",\n * - one verb driving several devices — \"Schalte A und B an\", where the segment that names only a\n * device inherits its sibling's action.\n * Falls back to the single-command reading unless the split produces at least two intents, so a device\n * or room name containing \"und\"/\"and\" — or \"1 Stunde und 30 Minuten\" — still parses as one command.\n */\n parseAll(text: string): NluIntent[] {\n const combined = this.parseCombined(text);\n if (combined.length > 1) {\n return combined;\n }\n // Several commands, one of them for later, and not every part understood: the time must not be applied to\n // the whole sentence (\"Licht an und Rollo in 10 Minuten zu\" would switch the light on in 10 minutes).\n const whole = this.prepare(text);\n if (whole && splitCommands(text).length > 1 && this.parseWhen(whole)) {\n return [];\n }\n const single = this.parse(text);\n return single ? [single] : [];\n }\n\n /** Segment-wise parse of a combined command; `[]` unless it yields at least two intents. */\n private parseCombined(text: string): NluIntent[] {\n const segments = splitCommands(text);\n if (segments.length < 2) {\n return [];\n }\n const parts: Prepared[] = [];\n for (const segment of segments) {\n const p = this.prepare(segment);\n if (p) {\n parts.push(p);\n }\n }\n if (parts.length < 2) {\n return [];\n }\n const features = parts.map(p => this.extractFeatures(p));\n const intents: NluIntent[] = [];\n for (let i = 0; i < parts.length; i++) {\n // A segment stating no action borrows the nearest sibling's — looking ahead first, because the\n // verb usually comes last in this shape (\"schalte A | und B **an**\"). The time comes with it: in\n // \"schalte A und B in 10 Minuten aus\" both wait.\n let from = -1;\n if (isBare(features[i])) {\n from = features.findIndex((f, j) => j > i && !isBare(f));\n for (let j = i - 1; from < 0 && j >= 0; j--) {\n from = isBare(features[j]) ? -1 : j;\n }\n }\n const inherited = from >= 0 ? features[from] : null;\n const inheritedTime = from >= 0 ? this.parseWhen(parts[from]) : null;\n const intent = this.parsePrepared(\n parts[i],\n inherited,\n inheritedTime && inheritedTime !== 'unclear' ? inheritedTime : null,\n );\n if (intent) {\n intents.push(intent);\n }\n }\n return intents.length > 1 ? intents : [];\n }\n\n /** Normalized views of a command (aliases applied, filler dropped); null when nothing remains to match. */\n private prepare(text: string): Prepared | null {\n const norm = this.applyAliases(normalize(text.replace(STRIP, ' ')));\n const tokens = norm.split(/\\s+/).filter(t => t && !FILLER.has(t));\n if (!tokens.length) {\n return null;\n }\n return { raw: text, norm, tokens, joined: tokens.join(' '), tokenSet: new Set(tokens) };\n }\n\n /**\n * Resolve one prepared command. Device-independent intents (timer/alarm/time/aggregate query) are tried\n * first and never inherit anything; `inherited` supplies the action for a segment that names only a\n * device (see {@link parseCombined}).\n */\n private parsePrepared(\n p: Prepared,\n inherited: CommandFeatures | null,\n inheritedTime: CommandTime | null = null,\n ): NluIntent | null {\n // Timer / alarm intents (\"timer 5 minuten\", \"weck mich um 7 Uhr\", \"wie lange noch\") — before\n // window/device matching, and device-independent.\n const schedule = this.parseSchedule(p.raw, p.norm, p.joined);\n if (schedule) {\n return schedule;\n }\n\n // A command for later (\"Licht in 2 Stunden aus\", \"выключи свет через 2 часа\") must never run now: it\n // becomes a deferred device intent, or goes to the LLM. Before the time query — \"через 2 часа\" has \"час\".\n const time = this.parseWhen(p);\n if (time) {\n const roomName = this.findRoom(p.joined);\n const device = this.findDevice(p.joined, roomName);\n if (time !== 'unclear') {\n return device ? this.deferred(p, device, roomName, time) : null;\n }\n if (device) {\n return null; // \"Licht um 7 aus\" — maybe 7 o'clock, maybe not: the LLM asks or knows\n }\n // no device: \"um 3 lauter\" is a volume step, go on\n }\n\n // Time / date query (\"what time is it\", \"which day is today\") — device-independent, answered from\n // the host clock. After the schedule parse so a clock phrase with a timer/alarm keyword still wins.\n const timeQuery = this.parseTimeQuery(p.joined);\n if (timeQuery) {\n return timeQuery;\n }\n\n // Aggregate query first (\"which windows are open\") — before single-device matching.\n const windowsQuery = this.parseWindowsOpen(p.joined);\n if (windowsQuery) {\n return windowsQuery;\n }\n\n const roomName = this.findRoom(p.joined);\n const device = this.findDevice(p.joined, roomName);\n if (!device) {\n // No device named — so \"lauter\" is meant for the speaker that heard it, \"wie wird das Wetter\" goes to\n // the weather adapter, and a question may still be about a kind of measurement. A named device\n // always wins: \"Fernseher lauter\" is about the TV.\n const features = this.extractFeatures(p);\n return this.parseVolume(p) ?? this.parseWeatherQuery(p, features) ?? this.parseCategoryQuery(p, features);\n }\n let features = this.extractFeatures(p);\n if (inherited && this.namesOnly(p, device, roomName)) {\n features = inherited;\n if (inheritedTime) {\n return this.deferred(p, device, roomName, inheritedTime, inherited);\n }\n }\n return this.buildDeviceIntent(device, roomName, features);\n }\n\n /**\n * When a command is meant to run: after a delay (\"in 2 Stunden\", \"через полчаса\", \"in 10 minutes\") or at a clock\n * time (\"um 22 Uhr\", \"morgen um 7:30\", \"в 10 вечера\", \"at 10 pm\"). `unclear`: a time that could be meant\n * otherwise (\"um 7\", a weekday, \"jeden Tag\") — a device command with it is left to the LLM. Null: no time.\n */\n private parseWhen(p: Prepared): CommandTime | 'unclear' | null {\n const norm = spelledNumbersToDigits(p.norm);\n DELAY_PREPOSITION_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = DELAY_PREPOSITION_RE.exec(norm))) {\n // the duration right after the preposition: \"in der Küche\" is no delay, \"in 2 Stunden\" is\n const words = norm.substring(m.index).split(/\\s+/).slice(0, 5).join(' ');\n const seconds = parseDurationSeconds(words, false);\n if (seconds) {\n return { delaySec: seconds };\n }\n }\n const raw = p.raw.replace(PERCENT_RE, ' ');\n const clock = parseClockTime(raw);\n if (!clock) {\n return null;\n }\n if (!CLOCK_RE.test(spelledNumbersToDigits(normalize(raw))) || parseWeekdays(p.norm).length) {\n return 'unclear';\n }\n const day = DAY_WORDS.find(([re]) => re.test(p.norm))?.[1];\n return { at: day === undefined ? { ...clock } : { ...clock, day } };\n }\n\n /** A device command for later: only switching and setting (a question about later is the LLM's) */\n private deferred(\n p: Prepared,\n device: NluDevice,\n roomName: string,\n time: CommandTime,\n features: CommandFeatures = this.extractFeatures(p),\n ): NluIntent | null {\n // \"Licht an und in 2 Stunden wieder aus\": two actions with one time — which one is meant for later?\n if (p.tokens.some(t => TURN_ON.has(t)) && p.tokens.some(t => TURN_OFF.has(t))) {\n return null;\n }\n const intent = this.buildDeviceIntent(device, roomName, features);\n if (!intent || !['on', 'off', 'level', 'color'].includes(intent.action)) {\n return null;\n }\n return { ...intent, ...time };\n }\n\n /** The action half of a command: on/off, level, color, and whether it is a question. */\n private extractFeatures(p: Prepared): CommandFeatures {\n return {\n action: this.findAction(p.tokenSet), // 'on' | 'off' | null\n level: this.findLevel(p.norm),\n color: this.findColor(p.joined),\n // A question (\"ist das Licht an?\") must never trigger a write — only the query branch does.\n isQuery: p.tokens.some(t => QUERY_WORDS.has(t)) || p.raw.trim().endsWith('?'),\n onOffQuery: ON_OFF_QUERY_WORDS.some(w => wordInText(w, p.joined)),\n };\n }\n\n /**\n * True when the segment holds nothing but the device name, its room and a directionless verb — the only\n * case in which borrowing a sibling's action is safe. Any unmatched word (\"mach die Musik *lauter*\")\n * means the segment carries an intent of its own that the rules do not cover: leave it to the LLM.\n */\n private namesOnly(p: Prepared, device: NluDevice, roomName: string): boolean {\n const known = [device.name, roomName]\n .filter(Boolean)\n .flatMap(n => normalize(n).split(/\\s+/))\n .filter(Boolean);\n return p.tokens.every(t => NEUTRAL_VERBS.has(t) || known.some(w => wordInText(w, t) || wordInText(t, w)));\n }\n\n /** Turn a resolved device plus the command's action half into an intent (branches in priority order). */\n private buildDeviceIntent(device: NluDevice, roomName: string, f: CommandFeatures): NluIntent | null {\n // 1. Set level (dimmer/blind …) — needs a numeric level-like control.\n if (f.level !== null && !f.isQuery) {\n const stateId = this.pickControl(device, ['level', 'brightness', 'dimmer'], true, 'number');\n if (stateId) {\n const intent: NluIntent = {\n action: 'level',\n device,\n stateId,\n value: f.level,\n room: roomName,\n confidence: 0.9,\n };\n // Many dimmers have a separate on/off switch that setting the level does not flip — so also\n // turn it on (level > 0) / off (0%) if the device has one. Devices without a switch are\n // unaffected. The switch is found by role/type, not by name (not every device names it ON_SET).\n const sw = this.findSwitch(device, stateId);\n if (sw) {\n intent.also = { stateId: sw, value: f.level > 0 };\n }\n return intent;\n }\n }\n\n // 2. Set color — only a hex color on a color-capable device (warm/cold color-temp is out of scope for v1).\n if (f.color && f.color.startsWith('#') && COLOR_TYPES.has(device.type) && !f.isQuery) {\n const stateId = this.pickControl(device, ['rgb', 'color', 'hue', 'cie', 'ct'], true);\n if (stateId) {\n return { action: 'color', device, stateId, value: f.color, room: roomName, confidence: 0.85 };\n }\n }\n\n // 3. Turn on / off — prefer a writable boolean switch (never a metering state like CONSUMPTION).\n if (f.action && !f.isQuery) {\n const stateId = this.pickControl(device, ['power', 'switch', 'on', 'level'], true, 'boolean');\n if (stateId) {\n // If only a numeric (dimmer/level) control is available, on/off means full/zero level, not a\n // boolean 1/0 (writing `true` to a 0–100 state would land on ~1%).\n const numeric = this.valueTypeOf(device, stateId) === 'number';\n return {\n action: f.action,\n device,\n stateId,\n value: numeric ? (f.action === 'on' ? 100 : 0) : f.action === 'on',\n room: roomName,\n confidence: 0.9,\n };\n }\n }\n\n // 4. Status query — read the right control: an on/off question (\"is the light on?\") reads the\n // boolean switch/feedback; a value question (\"what temperature?\") reads the actual value.\n if (f.isQuery) {\n const order = f.onOffQuery\n ? ['power', 'switch', 'on', 'actual', 'level']\n : ['actual', 'value', 'level', 'power'];\n const stateId = this.pickControl(device, order, false, f.onOffQuery ? 'boolean' : undefined);\n if (stateId) {\n return { action: 'query', device, stateId, room: roomName, confidence: 0.7 };\n }\n }\n\n return null;\n }\n\n /**\n * Timer (countdown) / alarm (fixed clock time) command (de/en/ru). Requires a timer or alarm keyword,\n * then classifies in priority order:\n * - a cancel word → `timerCancel` / `alarmCancel`,\n * - a parseable clock time → `alarmSet` (with weekdays / label / room),\n * - an explicit duration with a unit (\"5 Minuten\") → `timerSet` (so \"weck mich in 5 Minuten\" is a\n * countdown, not a clock time),\n * - a bare number: an hour in the alarm domain (\"Wecker auf 8\"), else minutes → `timerSet`,\n * - otherwise → `timerQuery` / `alarmQuery` (list what is running).\n */\n private parseSchedule(raw: string, norm: string, joined: string): NluIntent | null {\n const isTimer = TIMER_RE.test(norm);\n const isAlarm = ALARM_RE.test(norm);\n if (!isTimer && !isAlarm) {\n return null;\n }\n // Prefer the alarm reading only when it is the sole keyword (so \"erinnere mich um 7\" → alarm, but\n // \"timer …\" stays a timer even if it also mentions \"wecker\").\n const alarmDomain = isAlarm && !isTimer;\n const room = this.findRoom(joined) || undefined;\n const label = (): string | undefined => this.findTimerLabel(norm) || undefined;\n const alarm = (hour: number, minute: number, confidence: number): NluIntent => ({\n action: 'alarmSet',\n hour,\n minute,\n weekdays: parseWeekdays(norm),\n label: label(),\n room,\n confidence,\n });\n\n if (TIMER_CANCEL_RE.test(norm)) {\n return { action: alarmDomain ? 'alarmCancel' : 'timerCancel', label: label(), room, confidence: 0.9 };\n }\n\n // Clock time first (parsed from the raw text — the normalized `norm` has ':' stripped, which would\n // turn \"6:30\" into \"6 30\"). The \"um H\" rule already refuses a following duration unit, and the ru\n // \"H часов\" o'clock form is resolved here before it could be mistaken for \"H hours\".\n const clock = parseClockTime(raw);\n if (clock) {\n return alarm(clock.hour, clock.minute, 0.9);\n }\n\n // Explicit duration with a unit (\"5 Minuten\", \"1 Stunde\") → a countdown timer, even for \"Wecker in …\".\n const explicit = parseDurationSeconds(norm, false);\n if (explicit) {\n return { action: 'timerSet', durationSec: explicit, label: label(), room, confidence: 0.9 };\n }\n\n // A bare number: an hour for an alarm (\"Wecker auf 8\"), otherwise minutes for a timer (\"Timer 5\").\n const bare = parseDurationSeconds(norm, true);\n if (bare) {\n const hour = Math.round(bare / 60);\n if (alarmDomain && hour >= 0 && hour <= 23) {\n return alarm(hour, 0, 0.8);\n }\n return { action: 'timerSet', durationSec: bare, label: label(), room, confidence: 0.9 };\n }\n return { action: alarmDomain ? 'alarmQuery' : 'timerQuery', room, confidence: 0.7 };\n }\n\n /**\n * Extract a timer label: the text after the last marker word (\"an\", \"for\", \"to\", \"про\", …), stripped\n * of duration/number/filler tokens. \"erinnere mich in 5 minuten an den ofen\" → \"ofen\"; \"timer für 5\n * minuten\" → \"\" (no label). Operates on the normalized text (lowercased) — fine for a spoken reply.\n */\n private findTimerLabel(norm: string): string {\n const tokens = norm.split(/\\s+/).filter(Boolean);\n let start = -1;\n for (let i = 0; i < tokens.length; i++) {\n if (LABEL_MARKERS.has(tokens[i])) {\n start = i + 1;\n }\n }\n if (start < 0 || start >= tokens.length) {\n return '';\n }\n const words = tokens.slice(start).filter(w => !LABEL_STOP_WORDS.has(w) && !/^\\d+([.,]\\d+)?$/.test(w));\n return words.join(' ').trim();\n }\n\n /**\n * \"What time is it?\" / \"What's the date/day today?\" (de/en/ru) → a device-independent time or date\n * query, answered directly by the adapter from the host clock (no LLM). The date branch is checked\n * first so \"which day is it\" is not swallowed by the time branch. Matching is stem-tolerant via\n * {@link wordInText}; \"сейчас\"/\"today\"/\"monday\" don't false-match \"час\"/\"day\" (word-boundary guarded).\n */\n private parseTimeQuery(text: string): NluIntent | null {\n const has = (w: string): boolean => wordInText(w, text);\n if (WEATHER_WORDS.some(has)) {\n return null; // \"what is the weather the day after tomorrow\" asks about the weather, not the date\n }\n const qualifier = (): boolean =>\n has('heute') ||\n has('welch') ||\n has('what') ||\n has('which') ||\n has('today') ||\n has('сегодня') ||\n has('какой') ||\n has('какое');\n // Date / weekday question.\n const isDate =\n has('datum') ||\n has('wochentag') ||\n has('date') ||\n has('число') ||\n has('дата') ||\n ((has('tag') || has('day') || has('день')) && qualifier());\n if (isDate) {\n return { action: 'dateQuery', confidence: 0.9 };\n }\n // Time-of-day question. \"wie viel Uhr\" needs both words so a bare \"Uhr\" (rare here) doesn't trigger.\n const isTime =\n has('spaet') ||\n has('uhrzeit') ||\n has('time') ||\n has('clock') ||\n has('час') ||\n has('время') ||\n (has('uhr') && has('viel'));\n if (isTime) {\n return { action: 'timeQuery', confidence: 0.9 };\n }\n return null;\n }\n\n /**\n * \"Which windows are open?\" (de/en/ru) → an aggregate query over all window devices. Matches when the\n * text mentions a window word AND an \"open\" word; optionally restricted to a matched room.\n */\n /**\n * \"How is the air in the living room?\", \"how warm is it?\", \"how bright is it everywhere?\" — a\n * question about a kind of measurement rather than about a named device. Returns null unless the\n * house actually has devices of that kind, so the LLM still gets its chance.\n *\n * Only treated as a category query when no device was named: \"wie warm ist die Heizung\" is about\n * that thermostat, and the device path answers it better.\n */\n private parseCategoryQuery(p: Prepared, features: CommandFeatures): NluIntent | null {\n if (!features.isQuery) {\n return null; // a statement, not a question — nothing to report\n }\n const match = CATEGORY_WORDS.find(c => c.words.some(w => wordInText(w, p.joined)));\n if (!match) {\n return null;\n }\n const roomName = this.findRoom(p.joined);\n const everywhere = EVERYWHERE_WORDS.some(w => wordInText(w, p.joined));\n const room = everywhere ? '' : roomName;\n const devices = this.devices.filter(d => match.types.includes(d.type) && (!room || d.room === room));\n if (!devices.length) {\n return null; // nothing of that kind here (or not in that room) → let the LLM answer\n }\n return {\n action: 'categoryQuery',\n category: match.category,\n types: match.types,\n devices,\n room: room || undefined,\n confidence: 0.8,\n };\n }\n\n /**\n * \"Wie wird das Wetter morgen?\", \"regnet es heute?\", \"wie warm wird es übermorgen?\" (de/en/ru) → the\n * configured weather adapter, read and spoken without an LLM. Only today, tomorrow and the day after\n * — other days, other places (\"Wetter in Berlin\") and the plain \"wie warm ist es\" (the house sensors,\n * see {@link parseCategoryQuery}) stay with their own paths.\n */\n private parseWeatherQuery(p: Prepared, features: CommandFeatures): NluIntent | null {\n if (!this.opts.weather) {\n return null;\n }\n const t = p.joined;\n const tokens = p.tokens;\n const has = (w: string): boolean => p.tokenSet.has(w);\n let when: WeatherWhen = 'now';\n if (has('uebermorgen') || t.includes('day after tomorrow') || has('послезавтра')) {\n when = 'dayAfter';\n } else if (has('heute') || has('today') || has('сегодня')) {\n when = 'today'; // also \"heute Morgen\"\n } else if (\n has('tomorrow') ||\n has('завтра') ||\n tokens.some((w, i) => w === 'morgen' && tokens[i - 1] !== 'guten')\n ) {\n when = 'tomorrow';\n }\n const weatherWord = WEATHER_WORDS.some(w => wordInText(w, t));\n const rain = tokens.some(w => RAIN_TOKENS.has(w));\n const temperature = (CATEGORY_WORDS.find(c => c.category === 'temperature')?.words || []).some(w =>\n wordInText(w, t),\n );\n // A temperature question is about the forecast only when it names a day; without one it is about the house.\n if (!weatherWord && !rain && !(temperature && features.isQuery && when !== 'now')) {\n return null;\n }\n // The filler list drops prepositions from the tokens, so look for them in the full text.\n if (WEATHER_LATER_RE.test(t) || p.norm.split(/\\s+/).some(w => WEATHER_ELSEWHERE.has(w))) {\n return null;\n }\n return { action: 'weatherQuery', when, confidence: 0.85 };\n }\n\n /**\n * \"Lautstärke 5\", \"Lautstärke auf 40 Prozent\", \"lauter\", \"etwas leiser\", \"volume 7\", \"громче\" → the\n * playback volume of the satellite that heard it (or of the named room's satellite). A bare number up\n * to 10 is a step on a 1–10 scale, anything above is percent. \"Wie ist die Lautstärke\" is not a command.\n */\n private parseVolume(p: Prepared): NluIntent | null {\n const louder = p.tokens.some(w => LOUDER_TOKENS.has(w));\n const quieter = p.tokens.some(w => QUIETER_TOKENS.has(w));\n const volumeWord = VOLUME_WORDS.some(w => wordInText(w, p.joined));\n if (!louder && !quieter && !volumeWord) {\n return null;\n }\n const percent = /(?:prozent|percent|процент\\p{L}*|%)/u.test(p.norm);\n // \"ein bisschen lauter\" is no step count — only digits and the number words from two upwards count.\n const num = spelledNumbersToDigits(p.tokens.join(' '))\n .split(' ')\n .map(w => (/^\\d+$/.test(w) ? w : ['ein', 'eine', 'einen'].includes(w) ? '' : NUMBER_WORDS[w] || ''))\n .find(w => /^\\d+$/.test(w));\n const n = num === undefined ? null : parseInt(num, 10);\n const scaled = n === null ? null : n <= 10 && !percent ? n * 10 : n;\n const room = this.findRoom(p.joined) || undefined;\n if (louder !== quieter) {\n const step = scaled ?? VOLUME_STEP;\n return { action: 'volumeSet', delta: louder ? step : -step, room, confidence: 0.85 };\n }\n if (!volumeWord) {\n return null;\n }\n let level = scaled;\n if (p.tokens.some(w => VOLUME_MAX_TOKENS.has(w))) {\n level = 100;\n } else if (p.tokens.some(w => VOLUME_MIN_TOKENS.has(w))) {\n level = VOLUME_STEP;\n }\n if (level === null) {\n return null;\n }\n return { action: 'volumeSet', value: Math.min(100, Math.max(0, level)), room, confidence: 0.85 };\n }\n\n private parseWindowsOpen(text: string): NluIntent | null {\n if (!WINDOW_WORDS.some(w => wordInText(w, text)) || !OPEN_WORDS.some(w => wordInText(w, text))) {\n return null;\n }\n const roomName = this.findRoom(text);\n const windows = this.devices.filter(d => WINDOW_TYPES.has(d.type) && (!roomName || d.room === roomName));\n if (!windows.length) {\n return null; // no window devices known → let the LLM handle it\n }\n return {\n action: 'listByState',\n category: 'window',\n stateFilter: 'open',\n devices: windows,\n room: roomName || undefined,\n confidence: 0.9,\n };\n }\n\n /** The room whose significant words all appear in the text (stem-tolerant); longest name wins. */\n private findRoom(text: string): string {\n let best = '';\n let bestLen = 0;\n for (const name of this.rooms) {\n const n = normalize(name);\n const words = n.split(/\\s+/).filter(w => w.length >= 3);\n if (!words.length) {\n continue;\n }\n if (words.every(w => wordInText(w, text)) && n.length > bestLen) {\n best = name;\n bestLen = n.length;\n }\n }\n return best;\n }\n\n /**\n * Device whose significant name words all appear in the text (stem-tolerant for inflection).\n * Prefers devices in the matched room; the longest matching name wins.\n */\n private findDevice(text: string, roomName: string): NluDevice | null {\n const normRoom = roomName ? normalize(roomName) : '';\n const spaces: NluDevice[][] = [];\n if (roomName) {\n spaces.push(this.devices.filter(d => d.room === roomName));\n }\n spaces.push(this.devices.filter(d => !roomName || d.room !== roomName));\n\n for (const space of spaces) {\n let best: NluDevice | null = null;\n let bestLen = 0;\n for (const dev of space) {\n const nk = normalize(dev.name);\n if (!nk || (normRoom && normRoom.includes(nk))) {\n continue; // skip a device whose name is part of the room name\n }\n const words = nk.split(/\\s+/).filter(w => w.length >= 3);\n if (!words.length) {\n continue;\n }\n if (words.every(w => wordInText(w, text)) && nk.length > bestLen) {\n best = dev;\n bestLen = nk.length;\n }\n }\n if (best) {\n return best;\n }\n }\n return null;\n }\n\n private findAction(tokens: Set<string>): 'on' | 'off' | null {\n for (const t of tokens) {\n if (TURN_OFF.has(t)) {\n return 'off';\n }\n if (TURN_ON.has(t)) {\n return 'on';\n }\n }\n return null;\n }\n\n private findLevel(text: string): number | null {\n const m = spelledNumbersToDigits(text).match(/(\\d+(?:[.,]\\d+)?)\\s*(?:prozent|percent|процент\\w*|%)/u);\n return m ? parseFloat(m[1].replace(',', '.')) : null;\n }\n\n private findColor(text: string): string | null {\n for (const [name, hex] of Object.entries(COLORS)) {\n if (wordInText(name, text)) {\n return hex;\n }\n }\n return null;\n }\n\n /**\n * Pick a control state id. Tries the ordered controlType keys (preferring `preferType`, then any type),\n * then falls back to any usable **non-metering** control — so a query/command never lands on a\n * CONSUMPTION/CURRENT/… measurement. `mustWrite` additionally requires the control to be writable.\n */\n private pickControl(device: NluDevice, order: string[], mustWrite: boolean, preferType?: string): string {\n const types = device.types || {};\n const usable = (key: string): boolean => !!device.controls[key] && (!mustWrite || !!device.writable[key]);\n if (preferType) {\n // 1. an ordered key of the preferred value type (e.g. a boolean switch for on/off).\n for (const key of order) {\n if (usable(key) && types[key] === preferType) {\n return device.controls[key];\n }\n }\n // 2. ANY control of the preferred type (non-metering). Catches a boolean switch stored under a\n // non-standard control key (e.g. `ON_SET`), so on/off never lands on a numeric level/dimmer\n // control when a real boolean switch exists on the device.\n for (const [key, id] of Object.entries(device.controls)) {\n if (usable(key) && types[key] === preferType && !METER_SUFFIX.test(id)) {\n return id;\n }\n }\n }\n // 3. an ordered key of any type.\n for (const key of order) {\n if (usable(key)) {\n return device.controls[key];\n }\n }\n // 4. fallback: any usable non-metering control.\n for (const [key, id] of Object.entries(device.controls)) {\n if (usable(key) && !METER_SUFFIX.test(id)) {\n return id;\n }\n }\n return '';\n }\n\n /** The ioBroker value type ('boolean'|'number'|…) of a device control by its state id, '' if unknown. */\n private valueTypeOf(device: NluDevice, stateId: string): string {\n for (const [key, id] of Object.entries(device.controls)) {\n if (id === stateId) {\n return device.types[key] || '';\n }\n }\n return '';\n }\n\n /**\n * The device's on/off switch control (state id) other than `excludeStateId`, so a level command can also\n * power the device on. Role-based: a writable control with a `switch…` role wins; otherwise any writable\n * boolean, non-metering control; '' if the device has no separate switch.\n */\n private findSwitch(device: NluDevice, excludeStateId: string): string {\n const roles = device.roles || {};\n let fallback = '';\n for (const [key, id] of Object.entries(device.controls)) {\n if (id === excludeStateId || !device.writable[key] || METER_SUFFIX.test(id)) {\n continue;\n }\n const role = roles[key] || '';\n if (/^switch(\\.|$)/i.test(role)) {\n return id; // a role-confirmed switch is the best match\n }\n if (!fallback && device.types[key] === 'boolean') {\n fallback = id; // any writable boolean control as a fallback\n }\n }\n return fallback;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"nlu.js","sourceRoot":"","sources":["../../src/lib/nlu.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tier-0 rule-based NLU (no model, no install, offline) — a TypeScript port of the proven matching\n * approach from the Python assistant \"Hannah\" (`core/hannah/nlu.py`), reduced to the intents this\n * adapter needs: turn on/off, set level, set color, and status queries.\n *\n * It matches a free-text command against the known rooms and devices (room + device + action, longest\n * match wins) and returns a structured {@link NluIntent} the caller executes directly via the ioBroker\n * API — bypassing the LLM entirely for the common commands. Anything it cannot confidently resolve\n * returns `null`, so the caller falls through to the local/cloud LLM.\n */\n\n/** A device as the NLU needs to see it: friendly name, room, type and its controls (controlType → stateId). */\nexport interface NluDevice {\n name: string;\n room: string;\n /** type-detector type, e.g. 'light', 'socket', 'dimmer', 'rgb', 'thermostat'. */\n type: string;\n /** controlType → state id (e.g. `power`, `level`, `brightness`, `actual`, …). */\n controls: Record<string, string>;\n /** controlType → writable flag. */\n writable: Record<string, boolean>;\n /** controlType → ioBroker value type ('boolean'|'number'|'string'|…), to pick the right control. */\n types: Record<string, string>;\n /** controlType → ioBroker role (e.g. 'switch.light', 'level.dimmer'), to find the on/off switch. */\n roles?: Record<string, string>;\n}\n\nexport type NluActionType =\n | 'on'\n | 'off'\n | 'level'\n | 'color'\n | 'query'\n | 'listByState'\n | 'categoryQuery'\n | 'timerSet'\n | 'timerQuery'\n | 'timerCancel'\n | 'alarmSet'\n | 'alarmQuery'\n | 'alarmCancel'\n | 'timeQuery'\n | 'dateQuery'\n | 'weatherQuery'\n | 'volumeSet';\n\nexport interface NluIntent {\n action: NluActionType;\n /** Single-device actions (on/off/level/color/query). */\n device?: NluDevice;\n /** State id to act on (writable for on/off/level/color, readable for query). */\n stateId?: string;\n /** Value to write (bool for on/off, number for level, hex/temp string for color). */\n value?: boolean | number | string;\n /**\n * Secondary write applied after the primary one — used to also flip a dimmer's on/off switch when\n * setting its level (\"30%\" → level 30 **and** switch on), when the device has a separate switch control.\n */\n also?: { stateId: string; value: boolean };\n /** Matched room display name, if any. */\n room?: string;\n confidence: number;\n // ── Aggregate query (action 'listByState'), e.g. \"which windows are open\" ──\n /** All devices of the queried category (e.g. every window). */\n devices?: NluDevice[];\n /** The queried device category, e.g. 'window'. */\n category?: string;\n /** Which state to report on, e.g. 'open'. */\n stateFilter?: string;\n // ── Category query (action 'categoryQuery'), e.g. \"how is the air in the living room\" ──\n /** Device types to read, in order of preference (e.g. ['airQuality']). */\n types?: string[];\n // ── Timer intents (timerSet/timerQuery/timerCancel) ──\n /** Duration in seconds for `timerSet`. */\n durationSec?: number;\n /** Optional timer/alarm label (e.g. \"die Nudeln\"), or a match hint for `timerCancel`/`alarmCancel`. */\n label?: string;\n // ── Alarm intents (alarmSet/alarmQuery/alarmCancel) ──\n /** Hour 0–23 for `alarmSet`. */\n hour?: number;\n /** Minute 0–59 for `alarmSet`. */\n minute?: number;\n /** Weekdays (0 = Sunday … 6 = Saturday) for `alarmSet`; empty = one-shot next occurrence. */\n weekdays?: number[];\n // ── Weather (action 'weatherQuery') ──\n /** Which part of the forecast was asked for. */\n when?: WeatherWhen;\n // ── Satellite volume (action 'volumeSet'): `value` = absolute level 0–100, or `delta` ──\n /** Relative change in percentage points (\"lauter\" = +10). */\n delta?: number;\n // ── A device command for later (\"Licht in 2 Stunden aus\", \"Rollo um 22 Uhr zu\"): never executed now ──\n /** Run the command after this many seconds. */\n delaySec?: number;\n /** Run the command at this clock time; `day` = days from today when said (\"morgen\" = 1), else the next one. */\n at?: { hour: number; minute: number; day?: number };\n}\n\n/** When a deferred command runs */\ntype CommandTime = { delaySec: number } | { at: { hour: number; minute: number; day?: number } };\n\n/** The part of the forecast a weather question is about: current conditions, or a forecast day. */\nexport type WeatherWhen = 'now' | 'today' | 'tomorrow' | 'dayAfter';\n\n/** Options of the {@link Nlu} that depend on what the adapter has configured. */\nexport interface NluOptions {\n /** A weather source is configured, so weather questions can be answered locally. */\n weather?: boolean;\n}\n\nconst TURN_ON = new Set([\n // de/en\n 'an',\n 'ein',\n 'einschalten',\n 'anschalten',\n 'anmachen',\n 'aktiviere',\n 'aktivieren',\n 'starte',\n 'start',\n 'on',\n // ru\n 'включи',\n 'включить',\n 'вруби',\n 'врубить',\n 'зажги',\n 'запусти',\n]);\nconst TURN_OFF = new Set([\n // de/en\n 'aus',\n 'ausschalten',\n 'abschalten',\n 'ausmachen',\n 'deaktiviere',\n 'deaktivieren',\n 'stoppe',\n 'stop',\n 'off',\n // ru\n 'выключи',\n 'выключить',\n 'выруби',\n 'вырубить',\n 'погаси',\n 'потуши',\n 'отключи',\n]);\nconst QUERY_WORDS = new Set([\n // de/en\n 'wie',\n 'was',\n 'ist',\n 'sind',\n 'status',\n 'wieviel',\n 'welche',\n 'welcher',\n 'zeig',\n 'zeige',\n 'laeuft',\n 'how',\n 'what',\n 'is',\n 'are',\n 'show',\n // ru\n 'какая',\n 'какой',\n 'какое',\n 'сколько',\n 'покажи',\n 'что',\n 'статус',\n]);\n/** Filler words removed before matching (so \"mach das Licht an\" → [\"licht\",\"an\"]). */\nconst FILLER = new Set([\n // de/en\n 'bitte',\n 'mal',\n 'doch',\n 'denn',\n 'einfach',\n 'kannst',\n 'du',\n 'koenntest',\n 'mach',\n 'die',\n 'das',\n 'den',\n 'der',\n 'the',\n 'please',\n 'und',\n 'im',\n 'in',\n 'auf',\n 'zum',\n 'zur',\n // ru\n 'пожалуйста',\n 'давай',\n 'ну',\n 'мне',\n 'на',\n 'в',\n 'и',\n]);\n/** Color names (de + ru) → hex, or a special token for color temperature. */\nconst COLORS: Record<string, string> = {\n rot: '#FF0000',\n gruen: '#00FF00',\n blau: '#0000FF',\n gelb: '#FFFF00',\n orange: '#FF8000',\n lila: '#8000FF',\n pink: '#FF69B4',\n magenta: '#FF00FF',\n cyan: '#00FFFF',\n tuerkis: '#00CED1',\n weiss: '#FFFFFF',\n warmweiss: 'warm',\n kaltweiss: 'cold',\n красный: '#FF0000',\n зеленый: '#00FF00',\n синий: '#0000FF',\n голубой: '#00BFFF',\n желтый: '#FFFF00',\n оранжевый: '#FF8000',\n фиолетовый: '#8000FF',\n розовый: '#FF69B4',\n белый: '#FFFFFF',\n};\n/** Device types that accept a color. */\nconst COLOR_TYPES = new Set(['rgb', 'rgbSingle', 'rgbwSingle', 'hue', 'cie', 'ct']);\n\n/** type-detector types that count as \"windows\" for the \"which windows are open\" aggregate query. */\nconst WINDOW_TYPES = new Set(['window', 'windowTilt']);\n/** Words (de/en/ru, stemmed) that name a window. */\nconst WINDOW_WORDS = ['fenster', 'window', 'windows', 'окно', 'окна', 'окон'];\n/**\n * Measurement words (de/en/ru, stemmed) → the `@iobroker/type-detector` device types that answer them.\n * This is what makes \"wie ist die Luft im Wohnzimmer\" work without a device being named: the question\n * is about a *kind* of value, not about one thing. Ported from the Python original's `category_words`\n * (`C:\\iot\\Hannah`, `core/hannah/settings_manager.py`), mapped onto our detector types.\n */\nconst CATEGORY_WORDS: { words: string[]; category: string; types: string[] }[] = [\n // Order matters, most specific first: `wordInText` is suffix-tolerant (it has to be, for German and\n // Russian inflection), so the bare word \"luft\" also matches \"Luftdruck\" and \"Luftfeuchtigkeit\". The\n // compound categories therefore have to be tested before the plain-\"Luft\" one, or they are unreachable.\n {\n words: ['luftfeucht', 'feuchtigkeit', 'feucht', 'humidity', 'humid', 'влажност'],\n category: 'humidity',\n types: ['humidity'],\n },\n {\n words: ['luftdruck', 'druck', 'pressure', 'давлени'],\n category: 'pressure',\n types: ['pressure'],\n },\n {\n words: ['helligkeit', 'hell', 'lux', 'beleuchtungsstaerke', 'brightness', 'illuminance', 'светло', 'яркост'],\n category: 'illuminance',\n types: ['illuminance'],\n },\n {\n words: ['luft', 'luftqualitaet', 'luftguete', 'raumluft', 'iaq', 'co2', 'voc', 'air', 'воздух'],\n category: 'airQuality',\n types: ['airQuality'],\n },\n {\n // Last: 'warm'/'temperatur' are the words people use most, so a more specific category above wins\n // when both appear (\"wie warm und wie feucht ist es\" is answered about the humidity).\n words: ['temperatur', 'warm', 'kalt', 'grad', 'temperature', 'cold', 'температур', 'тепло', 'холодно'],\n category: 'temperature',\n types: ['temperature', 'thermostat'],\n },\n];\n\n/** Words that ask about every room at once (\"wie warm ist es überall\"). */\nconst EVERYWHERE_WORDS = ['ueberall', 'alle', 'allen', 'everywhere', 'all', 'везде', 'всюду'];\n\n/** Words (stemmed) that make a question a weather question on their own. */\nconst WEATHER_WORDS = ['wetter', 'wetterbericht', 'vorhersage', 'weather', 'forecast', 'погода', 'прогноз'];\n/**\n * Precipitation words, matched as whole tokens: stemming \"regen\" would also catch \"Regelung\", and nobody\n * gives a smart home the order \"rain\" — these only ever start a question.\n */\nconst RAIN_TOKENS = new Set([\n 'regnet',\n 'regnen',\n 'regen',\n 'schneit',\n 'schnee',\n 'gewitter',\n 'rain',\n 'raining',\n 'snow',\n 'snowing',\n 'дождь',\n 'дождя',\n 'снег',\n 'гроза',\n]);\n/** A weather question about some other place or a later day is left to the LLM and its `get_weather` tool. */\nconst WEATHER_ELSEWHERE = new Set(['in', 'fuer', 'for', 'в', 'во', 'для']);\nconst WEATHER_LATER_RE =\n /(?<![\\p{L}])(woche\\p{L}*|wochenende|week\\p{L}*|недел\\p{L}*|выходн\\p{L}*|montag|dienstag|mittwoch|donnerstag|freitag|samstag|sonntag|monday|tuesday|wednesday|thursday|friday|saturday|sunday|понедельник|вторник|среду|четверг|пятницу|субботу|воскресенье)(?![\\p{L}])/u;\n\n/** Words (stemmed) that name the playback volume. */\nconst VOLUME_WORDS = ['lautstaerke', 'volume', 'громкость'];\nconst LOUDER_TOKENS = new Set(['lauter', 'louder', 'громче', 'погромче']);\nconst QUIETER_TOKENS = new Set(['leiser', 'quieter', 'softer', 'тише', 'потише']);\nconst VOLUME_MAX_TOKENS = new Set(['maximum', 'max', 'voll', 'full', 'максимум', 'полную']);\nconst VOLUME_MIN_TOKENS = new Set(['minimum', 'min', 'минимум']);\n/** Step of a bare \"lauter\"/\"leiser\", in percentage points. */\nconst VOLUME_STEP = 10;\n\n/** Words (de/en/ru, stemmed) that mean \"open\". */\nconst OPEN_WORDS = ['offen', 'geoeffnet', 'geoffnet', 'auf', 'open', 'открыт', 'открыта', 'открыты', 'открытые'];\n\n/** Words (de/en/ru, stemmed) that make a query an on/off question (\"is the light on?\"). */\nconst ON_OFF_QUERY_WORDS = [\n 'an',\n 'ein',\n 'aus',\n 'eingeschaltet',\n 'ausgeschaltet',\n 'on',\n 'off',\n 'включен',\n 'включена',\n 'включено',\n 'выключен',\n 'выключена',\n 'работает',\n];\n\n/**\n * State-id suffixes of pure measurements/indicators — never the on/off switch or level (but note ACTUAL\n * is NOT here: it is a valid read-back for \"is it on\"). Used to keep pickControl off metering states.\n */\nconst METER_SUFFIX =\n /(CONSUMPTION|ELECTRIC_POWER|CURRENT|VOLTAGE|ENERGY|POWER|LOWBAT|BATTERY|UNREACH|RSSI|TEMPERATURE)$/i;\n\n// ── Timers / reminders (de/en/ru) ───────────────────────────────────────────\n/**\n * Marks a command as being about a countdown timer. Never fires on the bare word \"time\" (\"what time is\n * it\") — it needs the full \"timer\". \"timers?\" carries no leading word boundary so German compounds\n * (\"Küchentimer\", \"Eieruhr\"-style) and the plural still match; the prefix forms keep a boundary.\n */\nconst TIMER_RE = /(?:(?<![\\p{L}])(reminder|remind|erinner\\p{L}*|таймер\\p{L}*|напомн\\p{L}*)|timers?)(?![\\p{L}])/iu;\n/** Words that turn a timer command into \"cancel/stop the timer\" (de/en/ru). */\nconst TIMER_CANCEL_RE =\n /(?<![\\p{L}])(abbrech\\p{L}*|beend\\p{L}*|stopp?\\p{L}*|loesch\\p{L}*|cancel|delete|remove|clear|отмен\\p{L}*|удал\\p{L}*|сброс\\p{L}*|стоп)(?![\\p{L}])/iu;\n/** Number words → digits (normalized: umlauts expanded), de/en/ru, plus common fractions. */\nconst NUMBER_WORDS: Record<string, string> = {\n ein: '1',\n eine: '1',\n einen: '1',\n eins: '1',\n zwei: '2',\n drei: '3',\n vier: '4',\n fuenf: '5',\n sechs: '6',\n sieben: '7',\n acht: '8',\n neun: '9',\n zehn: '10',\n elf: '11',\n zwoelf: '12',\n anderthalb: '1.5',\n eineinhalb: '1.5',\n halbe: '0.5',\n halb: '0.5',\n viertel: '0.25',\n dreiviertel: '0.75',\n one: '1',\n two: '2',\n three: '3',\n four: '4',\n five: '5',\n six: '6',\n seven: '7',\n eight: '8',\n nine: '9',\n ten: '10',\n eleven: '11',\n twelve: '12',\n half: '0.5',\n quarter: '0.25',\n один: '1',\n одну: '1',\n два: '2',\n две: '2',\n три: '3',\n четыре: '4',\n пять: '5',\n шесть: '6',\n семь: '7',\n восемь: '8',\n девять: '9',\n десять: '10',\n};\n/** Units 1–9 (normalized), de/en/ru — the parts of a spelled-out number above twelve */\nconst UNIT_WORDS: Record<string, number> = {\n eins: 1,\n zwei: 2,\n drei: 3,\n vier: 4,\n fuenf: 5,\n sechs: 6,\n sieben: 7,\n acht: 8,\n neun: 9,\n one: 1,\n two: 2,\n three: 3,\n four: 4,\n five: 5,\n six: 6,\n seven: 7,\n eight: 8,\n nine: 9,\n один: 1,\n одна: 1,\n одно: 1,\n два: 2,\n две: 2,\n три: 3,\n четыре: 4,\n пять: 5,\n шесть: 6,\n семь: 7,\n восемь: 8,\n девять: 9,\n};\n/** 10–19, de/en/ru */\nconst TEEN_WORDS: Record<string, number> = {\n zehn: 10,\n elf: 11,\n zwoelf: 12,\n dreizehn: 13,\n vierzehn: 14,\n fuenfzehn: 15,\n sechzehn: 16,\n siebzehn: 17,\n achtzehn: 18,\n neunzehn: 19,\n ten: 10,\n eleven: 11,\n twelve: 12,\n thirteen: 13,\n fourteen: 14,\n fifteen: 15,\n sixteen: 16,\n seventeen: 17,\n eighteen: 18,\n nineteen: 19,\n десять: 10,\n одиннадцать: 11,\n двенадцать: 12,\n тринадцать: 13,\n четырнадцать: 14,\n пятнадцать: 15,\n шестнадцать: 16,\n семнадцать: 17,\n восемнадцать: 18,\n девятнадцать: 19,\n};\n/** Tens 20–90, de/en/ru */\nconst TEN_WORDS: Record<string, number> = {\n zwanzig: 20,\n dreissig: 30,\n vierzig: 40,\n fuenfzig: 50,\n sechzig: 60,\n siebzig: 70,\n achtzig: 80,\n neunzig: 90,\n twenty: 20,\n thirty: 30,\n forty: 40,\n fifty: 50,\n sixty: 60,\n seventy: 70,\n eighty: 80,\n ninety: 90,\n двадцать: 20,\n тридцать: 30,\n сорок: 40,\n пятьдесят: 50,\n шестьдесят: 60,\n семьдесят: 70,\n восемьдесят: 80,\n девяносто: 90,\n};\nconst HUNDRED_WORDS = new Set(['hundert', 'einhundert', 'hundred', 'сто']);\n\n/** Value of one spelled-out number word (\"fuenfundzwanzig\", \"twenty-five\", \"fünfzig\"), or null */\nfunction numberWordValue(word: string): number | null {\n if (HUNDRED_WORDS.has(word)) {\n return 100;\n }\n const direct = TEN_WORDS[word] ?? TEEN_WORDS[word] ?? UNIT_WORDS[word];\n if (direct !== undefined) {\n return direct;\n }\n // de \"fünfundzwanzig\" (unit first, \"ein\" as in \"einundzwanzig\"), en \"twenty-five\"\n const de = /^(\\p{L}+?)und(\\p{L}+)$/u.exec(word);\n if (de && TEN_WORDS[de[2]] !== undefined && (de[1] === 'ein' || UNIT_WORDS[de[1]] !== undefined)) {\n return TEN_WORDS[de[2]] + (UNIT_WORDS[de[1]] ?? 1);\n }\n const en = /^(\\p{L}+)-(\\p{L}+)$/u.exec(word);\n if (en && TEN_WORDS[en[1]] !== undefined && UNIT_WORDS[en[2]] !== undefined) {\n return TEN_WORDS[en[1]] + UNIT_WORDS[en[2]];\n }\n return null;\n}\n\n/**\n * Spelled-out whole numbers up to 100 → digits in normalized text (de/en/ru): \"fuenfzig prozent\" → \"50 prozent\",\n * \"twenty five\" → \"25\", \"двадцать пять\" → \"25\", \"one hundred\" → \"100\". Speech recognition writes numbers as words\n * often enough that a level command would otherwise miss. Articles (\"ein\", \"a\") stay words.\n *\n * @param text normalized text\n */\nexport function spelledNumbersToDigits(text: string): string {\n const words = text.split(/\\s+/).filter(Boolean);\n const out: string[] = [];\n for (let i = 0; i < words.length; i++) {\n const [, word, tail] = /^(.*?)([.,!?;:]*)$/u.exec(words[i])!;\n let value = numberWordValue(word);\n if (value === null) {\n // \"one hundred\", \"a hundred\", \"ein hundert\"\n const next = words[i + 1]?.replace(/[.,!?;:]+$/u, '');\n if (['one', 'a', 'ein'].includes(word) && next && HUNDRED_WORDS.has(next)) {\n out.push(`100${/[.,!?;:]+$/u.exec(words[i + 1])?.[0] || ''}`);\n i++;\n continue;\n }\n out.push(words[i]);\n continue;\n }\n let end = tail;\n // en \"twenty five\", ru \"двадцать пять\": a ten followed by a unit\n if (TEN_WORDS[word] !== undefined && !tail && i + 1 < words.length) {\n const [, nextWord, nextTail] = /^(.*?)([.,!?;:]*)$/u.exec(words[i + 1])!;\n if (UNIT_WORDS[nextWord] !== undefined) {\n value += UNIT_WORDS[nextWord];\n end = nextTail;\n i++;\n }\n }\n out.push(`${value}${end}`);\n }\n return out.join(' ');\n}\n\n/** Fixed phrases replaced up front so their fractions don't collide with the general number-word pass. */\nconst DURATION_PHRASES: [RegExp, string][] = [\n [/(?<![\\p{L}])dreiviertelstunde(?![\\p{L}])/iu, '45 minuten'],\n [/(?<![\\p{L}])viertelstunde(?![\\p{L}])/iu, '15 minuten'],\n [/(?<![\\p{L}])eine? halbe stunde(?![\\p{L}])/iu, '30 minuten'],\n [/(?<![\\p{L}])halbe stunde(?![\\p{L}])/iu, '30 minuten'],\n [/half an hour/iu, '30 minutes'],\n [/a half hour/iu, '30 minutes'],\n [/quarter of an hour/iu, '15 minutes'],\n [/quarter hour/iu, '15 minutes'],\n [/(?<![\\p{L}])полтора часа(?![\\p{L}])/iu, '90 минут'],\n [/(?<![\\p{L}])полчаса(?![\\p{L}])/iu, '30 минут'],\n // a unit without a number: \"in einer Stunde\", \"in an hour\", \"через час\", \"через минуту\"\n [/(?<![\\p{L}])einer halben stunde(?![\\p{L}])/iu, '30 minuten'],\n [/(?<![\\p{L}])einer? (stunde|minute)(?![\\p{L}])/iu, '1 $1'],\n [/(?<![\\p{L}])an? (hour|minute)(?![\\p{L}])/iu, '1 $1'],\n [/(?<![\\p{L}])через (час|минуту)(?![\\p{L}])/iu, 'через 1 $1'],\n];\n/** Prepositions of a delay: \"in 2 Stunden\", \"nach 10 Minuten\", \"через 2 часа\", \"after 5 minutes\" */\nconst DELAY_PREPOSITION_RE = /(?<![\\p{L}])(?:in|nach|через|after)\\s+/gu;\n/**\n * A clock time that cannot be anything else: \"22:30\", \"7 Uhr\", \"7 o'clock\", \"7 pm\", \"в 7 часов\", \"в 10 вечера\",\n * \"halb acht\" — unlike a bare \"um 3\", which is as often \"um 3 lauter\" or \"um 20 Prozent\".\n */\nconst CLOCK_RE =\n /\\d{1,2}:\\d{2}|\\d\\s*(?:uhr|o.?clock|[ap]m)(?![\\p{L}])|(?<![\\p{L}])(?:в|во)\\s+\\d{1,2}\\s*(?:час\\p{L}*|утра|вечера|ночи|дня)(?![\\p{L}])|(?<![\\p{L}])(?:halb|viertel|dreiviertel|quarter|half past)\\s/u;\n/** Percent values, removed before looking for a clock time (\"um 20 Prozent\" is no time) */\nconst PERCENT_RE = /\\d+(?:[.,]\\d+)?\\s*(?:%|prozent|percent|процент\\p{L}*)/giu;\n/** Day words for a clock time, the longer first (\"übermorgen\" before \"morgen\") */\nconst DAY_WORDS: [RegExp, number][] = [\n [/(?<![\\p{L}])(?:uebermorgen|day after tomorrow|послезавтра)(?![\\p{L}])/u, 2],\n [/(?<![\\p{L}])(?:morgen|tomorrow|завтра)(?![\\p{L}])/u, 1],\n [/(?<![\\p{L}])(?:heute|today|сегодня)(?![\\p{L}])/u, 0],\n];\nconst HOUR_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:stunden?|hours?|hrs?|h|час(?:а|ов)?)(?![\\p{L}])/giu;\nconst MIN_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:minuten?|mins?|minutes?|минут[уы]?)(?![\\p{L}])/giu;\nconst SEC_RE = /(\\d+(?:[.,]\\d+)?)\\s*(?:sekunden?|secs?|seconds?|секунд[уы]?)(?![\\p{L}])/giu;\n/** Duration/number tokens stripped from a timer label (\"timer für 5 minuten für die Nudeln\" → \"die Nudeln\"). */\nconst LABEL_STOP_WORDS = new Set([\n 'in',\n 'im',\n 'mich',\n 'me',\n 'my',\n 'den',\n 'die',\n 'das',\n 'der',\n 'the',\n 'a',\n 'an',\n 'auf',\n 'noch',\n 'ein',\n 'eine',\n 'einen',\n 'timer',\n 'reminder',\n 'remind',\n 'таймер',\n 'на',\n 'через',\n 'про',\n 'about',\n 'to',\n 'for',\n 'fuer',\n 'stunde',\n 'stunden',\n 'minute',\n 'minuten',\n 'min',\n 'sekunde',\n 'sekunden',\n 'sec',\n 'hour',\n 'hours',\n 'minutes',\n 'seconds',\n 'second',\n 'час',\n 'часа',\n 'часов',\n 'минут',\n 'минуту',\n 'минуты',\n 'секунд',\n 'секунду',\n 'секунды',\n]);\n/** Marker words after which a timer label follows (\"… an die Nudeln\", \"remind me to call mom\"). */\nconst LABEL_MARKERS = new Set(['an', 'fuer', 'for', 'to', 'about', 'про']);\n\n// ── Alarms / wake-ups at a fixed clock time (de/en/ru) ──────────────────────\n/**\n * Marks a command as being about an alarm / wake-up (\"Wecker\", \"weck mich\", \"alarm\", \"будильник\"). Like\n * {@link TIMER_RE}, \"alarms?\"/\"wecker\" carry no leading boundary so compounds (\"Küchenwecker\") and the\n * plural still match; the verb-prefix forms (\"weck…\", \"разбуд…\") keep a boundary. \"буди…\" and not just\n * \"буд…\": that would also catch \"будет\" (will be), and turn \"будет ли дождь?\" into an alarm query.\n */\nconst ALARM_RE = /(?:(?<![\\p{L}])(weck\\p{L}*|wake|буди\\p{L}*|разбуд\\p{L}*)|alarms?|wecker)(?![\\p{L}])/iu;\n/** Hour number words → digits (no fractions — those are handled by the clock regexes). de/en/ru, 1–12. */\nconst HOUR_WORDS: Record<string, string> = {\n ein: '1',\n eine: '1',\n einen: '1',\n eins: '1',\n zwei: '2',\n drei: '3',\n vier: '4',\n fuenf: '5',\n sechs: '6',\n sieben: '7',\n acht: '8',\n neun: '9',\n zehn: '10',\n elf: '11',\n zwoelf: '12',\n one: '1',\n two: '2',\n three: '3',\n four: '4',\n five: '5',\n six: '6',\n seven: '7',\n eight: '8',\n nine: '9',\n ten: '10',\n eleven: '11',\n twelve: '12',\n один: '1',\n два: '2',\n три: '3',\n четыре: '4',\n пять: '5',\n шесть: '6',\n семь: '7',\n восемь: '8',\n девять: '9',\n десять: '10',\n одиннадцать: '11',\n двенадцать: '12',\n};\n/** Weekday word (normalized, prefix-matched for inflection) → 0 (Sun) … 6 (Sat). */\nconst WEEKDAYS: [RegExp, number][] = [\n [/(?<![\\p{L}])(montag|monday|понедельник)/iu, 1],\n [/(?<![\\p{L}])(dienstag|tuesday|вторник)/iu, 2],\n [/(?<![\\p{L}])(mittwoch|wednesday|сред)/iu, 3],\n [/(?<![\\p{L}])(donnerstag|thursday|четверг)/iu, 4],\n [/(?<![\\p{L}])(freitag|friday|пятниц)/iu, 5],\n [/(?<![\\p{L}])(samstag|sonnabend|saturday|суббот)/iu, 6],\n [/(?<![\\p{L}])(sonntag|sunday|воскресень)/iu, 0],\n];\n\n/**\n * Parse a clock time from free text (de/en/ru): \"7:30\", \"7 Uhr\", \"7 Uhr 30\", \"halb acht\" (7:30),\n * \"viertel nach sieben\" (7:15), \"viertel vor acht\"/\"dreiviertel acht\" (7:45), \"half past seven\",\n * \"quarter past/to\", \"в 7 часов\", plus am/pm. Returns {hour 0-23, minute 0-59} or null.\n */\nexport function parseClockTime(text: string): { hour: number; minute: number } | null {\n let t = normalize(text);\n // Substitute hour number words → digits (\"halb acht\" → \"halb 8\"), leaving fraction words intact.\n t = t\n .split(/\\s+/)\n .map(w => (Object.prototype.hasOwnProperty.call(HOUR_WORDS, w) ? HOUR_WORDS[w] : w))\n .join(' ');\n\n const pm = /(?<![\\p{L}])(pm|nachmittags|abends|вечера)(?![\\p{L}])/u.test(t);\n const am = /(?<![\\p{L}])(am|morgens|vormittags|utra|утра|nachts)(?![\\p{L}])/u.test(t);\n const applyMeridiem = (h: number): number => {\n if (pm && h < 12) {\n return h + 12;\n }\n if (am && h === 12) {\n return 0;\n }\n return h;\n };\n const ok = (h: number, m: number): { hour: number; minute: number } | null =>\n h >= 0 && h <= 23 && m >= 0 && m <= 59 ? { hour: h, minute: m } : null;\n\n let m: RegExpMatchArray | null;\n // HH:MM\n if ((m = t.match(/(?<!\\d)(\\d{1,2}):(\\d{2})(?!\\d)/))) {\n return ok(applyMeridiem(+m[1]), +m[2]);\n }\n // \"viertel nach H\" → H:15 ; \"viertel vor H\" / \"dreiviertel H\" → (H-1):45\n if ((m = t.match(/viertel\\s+nach\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 15);\n }\n if ((m = t.match(/(?:viertel\\s+vor|dreiviertel)\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 45);\n }\n if ((m = t.match(/quarter\\s+past\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 15);\n }\n if ((m = t.match(/quarter\\s+to\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 45);\n }\n // \"halb H\" (German) → (H-1):30 ; \"half past H\" (English) → H:30\n if ((m = t.match(/half\\s+past\\s+(\\d{1,2})/))) {\n return ok(applyMeridiem(+m[1]), 30);\n }\n if ((m = t.match(/(?<![\\p{L}])halb\\s+(\\d{1,2})/u))) {\n return ok(applyMeridiem((+m[1] + 23) % 24), 30);\n }\n // \"H Uhr MM\" / \"H Uhr\" / \"H часов MM\"\n if ((m = t.match(/(\\d{1,2})\\s*(?:uhr|часов|часа|час)\\s*(\\d{1,2})(?![\\p{L}])/u))) {\n return ok(applyMeridiem(+m[1]), +m[2]);\n }\n if ((m = t.match(/(\\d{1,2})\\s*(?:uhr|o.?clock|часов|часа|час)(?![\\p{L}])/u))) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n // \"um/at/в H\" (bare hour after an explicit time preposition) — but not when a duration unit follows,\n // so \"Timer um 5 Minuten\" is not misread as 5 o'clock.\n if (\n (m = t.match(\n /(?<![\\p{L}])(?:um|at|в|во)\\s+(\\d{1,2})(?![\\d:])(?!\\s*(?:minut|stund|sekund|min|sek|hour|second))/u,\n ))\n ) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n // Bare hour qualified only by am/pm (\"7 pm\", \"8 am\").\n if ((pm || am) && (m = t.match(/(?<![\\d.])(\\d{1,2})(?![\\d.:])/))) {\n return ok(applyMeridiem(+m[1]), 0);\n }\n return null;\n}\n\n/**\n * Parse recurrence from free text → weekday numbers (0 = Sun … 6 = Sat). \"täglich\"/\"jeden Tag\"/\"daily\"\n * → all 7; \"wochentags\"/\"werktags\"/\"weekdays\" → Mon–Fri; \"wochenende\"/\"weekend\" → Sat+Sun; otherwise the\n * union of the named weekdays. Empty array = one-shot.\n */\nexport function parseWeekdays(text: string): number[] {\n const t = normalize(text);\n if (/(?<![\\p{L}])(taeglich|jeden tag|daily|every day|ежедневно|каждый день)(?![\\p{L}])/u.test(t)) {\n return [0, 1, 2, 3, 4, 5, 6];\n }\n if (/(?<![\\p{L}])(wochentags|werktags|weekdays|по будням|будни)(?![\\p{L}])/u.test(t)) {\n return [1, 2, 3, 4, 5];\n }\n if (/(?<![\\p{L}])(wochenende|weekend|выходн\\p{L}*)(?![\\p{L}])/u.test(t)) {\n return [0, 6];\n }\n const days = new Set<number>();\n for (const [re, day] of WEEKDAYS) {\n if (re.test(t)) {\n days.add(day);\n }\n }\n return [...days].sort();\n}\n\n/**\n * Parse a free-text duration (\"1 Stunde 30 Minuten\", \"in 5 minuten\", \"полтора часа\") into seconds; null\n * if none is found. With `assumeMinutes`, a bare number with no unit (\"timer 5\") counts as minutes.\n */\nexport function parseDurationSeconds(text: string, assumeMinutes = false): number | null {\n let t = normalize(text);\n for (const [re, rep] of DURATION_PHRASES) {\n t = t.replace(re, rep);\n }\n // Replace standalone number words with digits so \"fünf minuten\" → \"5 minuten\".\n t = t\n .split(/\\s+/)\n .map(w => (Object.prototype.hasOwnProperty.call(NUMBER_WORDS, w) ? NUMBER_WORDS[w] : w))\n .join(' ');\n\n let total = 0;\n let matched = false;\n const sum = (re: RegExp, factor: number): void => {\n re.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(t))) {\n total += parseFloat(m[1].replace(',', '.')) * factor;\n matched = true;\n }\n };\n sum(HOUR_RE, 3600);\n sum(MIN_RE, 60);\n sum(SEC_RE, 1);\n\n if (!matched && assumeMinutes) {\n const bare = t.match(/(?<![\\d.])(\\d+(?:[.,]\\d+)?)(?![\\d.])/);\n if (bare) {\n total = parseFloat(bare[1].replace(',', '.')) * 60;\n matched = true;\n }\n }\n return matched && total > 0 ? Math.round(total) : null;\n}\n\n/**\n * \"Make it stop\" words (de/en/ru), used to silence a ringing timer/alarm. Kept separate from the device\n * TURN_OFF set (no \"aus\") so it only reacts to an explicit stop/quiet phrase, not \"turn the light off\".\n */\nconst STOP_RE =\n /(?<![\\p{L}])(stopp?\\p{L}*|halt|aufhoer\\p{L}*|ruhe|ruhig|genug|schluss|abbrech\\p{L}*|beend\\p{L}*|ende|still|cancel|enough|quiet|dismiss|silence|стоп|хватит|тихо|довольно|прекрат\\p{L}*|отмен\\p{L}*|замолч\\p{L}*|тишин\\p{L}*)(?![\\p{L}])/iu;\n\n/** True if the text is a \"stop / be quiet\" command (used to silence a ringing timer/alarm). */\nexport function isStopCommand(text: string): boolean {\n return STOP_RE.test(normalize(text));\n}\n\n/**\n * \"Skript\"/\"script\"/\"скрипт\" in any form, German compounds (\"Lichtskript\") and Cyrillic flexion (\"скрипте\") included,\n * plus JavaScript/TypeScript/Blockly. \"script\" only at the start of a word, so \"description\" or \"subscription\" do not\n * count; \"скрипка\"/\"скрипит\" are other words.\n */\nconst SCRIPT_RE = /skript|(?<![\\p{L}])(?:java|type)?script|скрипт|blockly/iu;\n\n/**\n * True if the text is about a script. Such a request goes to the cloud model only: the rules would take its details for\n * commands of their own (\"… a script that switches the kitchen light every hour\" was answered with the time).\n */\nexport function mentionsScript(text: string): boolean {\n return SCRIPT_RE.test(normalize(text));\n}\n\n/** Normalize for matching: lowercase, German umlauts → ascii, ß → ss, Russian ё → е. */\nexport function normalize(s: string): string {\n return s\n .toLowerCase()\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ü/g, 'ue')\n .replace(/ß/g, 'ss')\n .replace(/ё/g, 'е');\n}\n\nconst STRIP = /[.,!?;:()[\\]]/g;\nconst escapeRe = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * Does a name word appear in the text? Matches on a Unicode word boundary and allows a differing\n * suffix (crude stemming) so inflected forms match too — essential for Russian (\"подсветку\" for\n * \"подсветка\", \"кокпита\" for \"кокпит\"). Longer words drop more trailing characters.\n */\nfunction wordInText(word: string, text: string): boolean {\n const stem =\n word.length >= 6 ? word.slice(0, word.length - 2) : word.length >= 5 ? word.slice(0, word.length - 1) : word;\n try {\n return new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escapeRe(stem)}`, 'u').test(text);\n } catch {\n return text.includes(stem);\n }\n}\n\n/**\n * Directionless command verbs: they mark an imperative but carry no on/off/level of their own. A segment\n * holding nothing but such a verb and a device name (\"schalte das Licht\" in \"schalte das Licht und die\n * Lampe an\") may therefore borrow the action from its sibling segment.\n */\nconst NEUTRAL_VERBS = new Set([\n // de\n 'schalte',\n 'schalt',\n 'schalten',\n 'stelle',\n 'stell',\n 'stellen',\n 'setze',\n 'setz',\n 'setzen',\n 'drehe',\n 'dreh',\n 'fahre',\n 'fahr',\n 'mache',\n 'machen',\n // en\n 'set',\n 'put',\n 'turn',\n 'switch',\n 'change',\n 'adjust',\n 'make',\n // ru\n 'поставь',\n 'установи',\n 'выстави',\n 'сделай',\n]);\n\n/** Conjunctions that join two commands in one utterance (de/en/ru). */\nconst CONJUNCTIONS = 'und|sowie|dann|danach|and|then|plus|и|затем|потом';\n\n/**\n * Separators between two commands: a run of conjunctions (\"und dann\"), a comma or a semicolon. A comma\n * directly followed by a digit is NOT a separator (decimal values like \"50,5 %\").\n */\nconst SPLIT_RE = new RegExp(`\\\\s*[;,](?!\\\\d)\\\\s*|\\\\s+(?:${CONJUNCTIONS})(?:\\\\s+(?:${CONJUNCTIONS}))*\\\\s+`, 'giu');\n\n/**\n * Split a combined command (\"Schalte A an und setze B auf 30 %\") into its parts; a single-element array\n * when there is nothing to split.\n */\nexport function splitCommands(text: string): string[] {\n return text\n .split(SPLIT_RE)\n .map(s => s.trim())\n .filter(Boolean);\n}\n\n/** Normalized views of one command, shared by every matching step. */\ninterface Prepared {\n /** The original segment text (kept for the \"?\" test and the schedule parser). */\n raw: string;\n /** Lowercased/umlaut-expanded text with aliases applied — still contains filler words. */\n norm: string;\n /** `norm` split into words, filler removed. */\n tokens: string[];\n /** `tokens` joined by a space — the text every name matcher works on. */\n joined: string;\n tokenSet: Set<string>;\n}\n\n/**\n * The \"what to do\" half of a device command, kept separate from the \"which device\" half so the segments\n * of a combined command can share one verb (\"Schalte A und B **an**\").\n */\ninterface CommandFeatures {\n action: 'on' | 'off' | null;\n level: number | null;\n color: string | null;\n isQuery: boolean;\n /** The question asks about on/off (\"ist das Licht an?\"), not about a value (\"wie warm ist es?\"). */\n onOffQuery: boolean;\n}\n\n/** True when a segment states no action at all (\"… und die Lampe\") and may inherit its sibling's. */\nfunction isBare(f: CommandFeatures): boolean {\n return !f.action && f.level === null && !f.color && !f.isQuery;\n}\n\nexport class Nlu {\n private readonly rooms: string[];\n private readonly devices: NluDevice[];\n /** Synonym dictionary as normalized [from, to] pairs, applied to the input before matching. */\n private readonly aliases: [string, string][];\n private readonly opts: NluOptions;\n\n constructor(\n rooms: string[],\n devices: NluDevice[],\n aliases: { from: string; to: string }[] = [],\n opts: NluOptions = {},\n ) {\n this.rooms = rooms.filter(Boolean);\n this.devices = devices;\n this.opts = opts;\n this.aliases = aliases\n .map(a => [normalize(a.from || ''), normalize(a.to || '')] as [string, string])\n .filter(([from]) => from);\n }\n\n /**\n * Rewrite synonyms to canonical terms on the (normalized) input, matching whole words/phrases only\n * (Unicode boundaries). E.g. \"tv\" → \"fernseher\", \"deckenlicht\" → \"licht wohnzimmer\". No-op when the\n * dictionary is empty. Applied once up front so all downstream matching sees the canonical wording.\n */\n private applyAliases(norm: string): string {\n let out = norm;\n for (const [from, to] of this.aliases) {\n try {\n out = out.replace(new RegExp(`(?<![\\\\p{L}\\\\p{N}])${escapeRe(from)}(?![\\\\p{L}\\\\p{N}])`, 'gu'), to);\n } catch {\n // Defensive: a malformed alias must never break parsing.\n }\n }\n return out;\n }\n\n /** Parse a single command; returns a structured intent or null if nothing could be resolved confidently. */\n parse(text: string): NluIntent | null {\n const p = this.prepare(text);\n return p ? this.parsePrepared(p, null) : null;\n }\n\n /**\n * Parse a possibly **combined** command into the intents to execute, in order:\n * - several commands joined by a conjunction — \"Schalte A an und setze B auf 30 %\",\n * - one verb driving several devices — \"Schalte A und B an\", where the segment that names only a\n * device inherits its sibling's action.\n * Falls back to the single-command reading unless the split produces at least two intents, so a device\n * or room name containing \"und\"/\"and\" — or \"1 Stunde und 30 Minuten\" — still parses as one command.\n */\n parseAll(text: string): NluIntent[] {\n const combined = this.parseCombined(text);\n if (combined.length > 1) {\n return combined;\n }\n // Several commands, one of them for later, and not every part understood: the time must not be applied to\n // the whole sentence (\"Licht an und Rollo in 10 Minuten zu\" would switch the light on in 10 minutes).\n const whole = this.prepare(text);\n if (whole && splitCommands(text).length > 1 && this.parseWhen(whole)) {\n return [];\n }\n const single = this.parse(text);\n return single ? [single] : [];\n }\n\n /** Segment-wise parse of a combined command; `[]` unless it yields at least two intents. */\n private parseCombined(text: string): NluIntent[] {\n const segments = splitCommands(text);\n if (segments.length < 2) {\n return [];\n }\n const parts: Prepared[] = [];\n for (const segment of segments) {\n const p = this.prepare(segment);\n if (p) {\n parts.push(p);\n }\n }\n if (parts.length < 2) {\n return [];\n }\n const features = parts.map(p => this.extractFeatures(p));\n const intents: NluIntent[] = [];\n for (let i = 0; i < parts.length; i++) {\n // A segment stating no action borrows the nearest sibling's — looking ahead first, because the\n // verb usually comes last in this shape (\"schalte A | und B **an**\"). The time comes with it: in\n // \"schalte A und B in 10 Minuten aus\" both wait.\n let from = -1;\n if (isBare(features[i])) {\n from = features.findIndex((f, j) => j > i && !isBare(f));\n for (let j = i - 1; from < 0 && j >= 0; j--) {\n from = isBare(features[j]) ? -1 : j;\n }\n }\n const inherited = from >= 0 ? features[from] : null;\n const inheritedTime = from >= 0 ? this.parseWhen(parts[from]) : null;\n const intent = this.parsePrepared(\n parts[i],\n inherited,\n inheritedTime && inheritedTime !== 'unclear' ? inheritedTime : null,\n );\n if (intent) {\n intents.push(intent);\n }\n }\n return intents.length > 1 ? intents : [];\n }\n\n /** Normalized views of a command (aliases applied, filler dropped); null when nothing remains to match. */\n private prepare(text: string): Prepared | null {\n const norm = this.applyAliases(normalize(text.replace(STRIP, ' ')));\n const tokens = norm.split(/\\s+/).filter(t => t && !FILLER.has(t));\n if (!tokens.length) {\n return null;\n }\n return { raw: text, norm, tokens, joined: tokens.join(' '), tokenSet: new Set(tokens) };\n }\n\n /**\n * Resolve one prepared command. Device-independent intents (timer/alarm/time/aggregate query) are tried\n * first and never inherit anything; `inherited` supplies the action for a segment that names only a\n * device (see {@link parseCombined}).\n */\n private parsePrepared(\n p: Prepared,\n inherited: CommandFeatures | null,\n inheritedTime: CommandTime | null = null,\n ): NluIntent | null {\n // Timer / alarm intents (\"timer 5 minuten\", \"weck mich um 7 Uhr\", \"wie lange noch\") — before\n // window/device matching, and device-independent.\n const schedule = this.parseSchedule(p.raw, p.norm, p.joined);\n if (schedule) {\n return schedule;\n }\n\n // A command for later (\"Licht in 2 Stunden aus\", \"выключи свет через 2 часа\") must never run now: it\n // becomes a deferred device intent, or goes to the LLM. Before the time query — \"через 2 часа\" has \"час\".\n const time = this.parseWhen(p);\n if (time) {\n const roomName = this.findRoom(p.joined);\n const device = this.findDevice(p.joined, roomName);\n if (time !== 'unclear') {\n return device ? this.deferred(p, device, roomName, time) : null;\n }\n if (device) {\n return null; // \"Licht um 7 aus\" — maybe 7 o'clock, maybe not: the LLM asks or knows\n }\n // no device: \"um 3 lauter\" is a volume step, go on\n }\n\n // Time / date query (\"what time is it\", \"which day is today\") — device-independent, answered from\n // the host clock. After the schedule parse so a clock phrase with a timer/alarm keyword still wins.\n const timeQuery = this.parseTimeQuery(p.joined);\n if (timeQuery) {\n return timeQuery;\n }\n\n // Aggregate query first (\"which windows are open\") — before single-device matching.\n const windowsQuery = this.parseWindowsOpen(p.joined);\n if (windowsQuery) {\n return windowsQuery;\n }\n\n const roomName = this.findRoom(p.joined);\n const device = this.findDevice(p.joined, roomName);\n if (!device) {\n // No device named — so \"lauter\" is meant for the speaker that heard it, \"wie wird das Wetter\" goes to\n // the weather adapter, and a question may still be about a kind of measurement. A named device\n // always wins: \"Fernseher lauter\" is about the TV.\n const features = this.extractFeatures(p);\n return this.parseVolume(p) ?? this.parseWeatherQuery(p, features) ?? this.parseCategoryQuery(p, features);\n }\n let features = this.extractFeatures(p);\n if (inherited && this.namesOnly(p, device, roomName)) {\n features = inherited;\n if (inheritedTime) {\n return this.deferred(p, device, roomName, inheritedTime, inherited);\n }\n }\n return this.buildDeviceIntent(device, roomName, features);\n }\n\n /**\n * When a command is meant to run: after a delay (\"in 2 Stunden\", \"через полчаса\", \"in 10 minutes\") or at a clock\n * time (\"um 22 Uhr\", \"morgen um 7:30\", \"в 10 вечера\", \"at 10 pm\"). `unclear`: a time that could be meant\n * otherwise (\"um 7\", a weekday, \"jeden Tag\") — a device command with it is left to the LLM. Null: no time.\n */\n private parseWhen(p: Prepared): CommandTime | 'unclear' | null {\n const norm = spelledNumbersToDigits(p.norm);\n DELAY_PREPOSITION_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = DELAY_PREPOSITION_RE.exec(norm))) {\n // the duration right after the preposition: \"in der Küche\" is no delay, \"in 2 Stunden\" is\n const words = norm.substring(m.index).split(/\\s+/).slice(0, 5).join(' ');\n const seconds = parseDurationSeconds(words, false);\n if (seconds) {\n return { delaySec: seconds };\n }\n }\n const raw = p.raw.replace(PERCENT_RE, ' ');\n const clock = parseClockTime(raw);\n if (!clock) {\n return null;\n }\n if (!CLOCK_RE.test(spelledNumbersToDigits(normalize(raw))) || parseWeekdays(p.norm).length) {\n return 'unclear';\n }\n const day = DAY_WORDS.find(([re]) => re.test(p.norm))?.[1];\n return { at: day === undefined ? { ...clock } : { ...clock, day } };\n }\n\n /** A device command for later: only switching and setting (a question about later is the LLM's) */\n private deferred(\n p: Prepared,\n device: NluDevice,\n roomName: string,\n time: CommandTime,\n features: CommandFeatures = this.extractFeatures(p),\n ): NluIntent | null {\n // \"Licht an und in 2 Stunden wieder aus\": two actions with one time — which one is meant for later?\n if (p.tokens.some(t => TURN_ON.has(t)) && p.tokens.some(t => TURN_OFF.has(t))) {\n return null;\n }\n const intent = this.buildDeviceIntent(device, roomName, features);\n if (!intent || !['on', 'off', 'level', 'color'].includes(intent.action)) {\n return null;\n }\n return { ...intent, ...time };\n }\n\n /** The action half of a command: on/off, level, color, and whether it is a question. */\n private extractFeatures(p: Prepared): CommandFeatures {\n return {\n action: this.findAction(p.tokenSet), // 'on' | 'off' | null\n level: this.findLevel(p.norm),\n color: this.findColor(p.joined),\n // A question (\"ist das Licht an?\") must never trigger a write — only the query branch does.\n isQuery: p.tokens.some(t => QUERY_WORDS.has(t)) || p.raw.trim().endsWith('?'),\n onOffQuery: ON_OFF_QUERY_WORDS.some(w => wordInText(w, p.joined)),\n };\n }\n\n /**\n * True when the segment holds nothing but the device name, its room and a directionless verb — the only\n * case in which borrowing a sibling's action is safe. Any unmatched word (\"mach die Musik *lauter*\")\n * means the segment carries an intent of its own that the rules do not cover: leave it to the LLM.\n */\n private namesOnly(p: Prepared, device: NluDevice, roomName: string): boolean {\n const known = [device.name, roomName]\n .filter(Boolean)\n .flatMap(n => normalize(n).split(/\\s+/))\n .filter(Boolean);\n return p.tokens.every(t => NEUTRAL_VERBS.has(t) || known.some(w => wordInText(w, t) || wordInText(t, w)));\n }\n\n /** Turn a resolved device plus the command's action half into an intent (branches in priority order). */\n private buildDeviceIntent(device: NluDevice, roomName: string, f: CommandFeatures): NluIntent | null {\n // 1. Set level (dimmer/blind …) — needs a numeric level-like control.\n if (f.level !== null && !f.isQuery) {\n const stateId = this.pickControl(device, ['level', 'brightness', 'dimmer'], true, 'number');\n if (stateId) {\n const intent: NluIntent = {\n action: 'level',\n device,\n stateId,\n value: f.level,\n room: roomName,\n confidence: 0.9,\n };\n // Many dimmers have a separate on/off switch that setting the level does not flip — so also\n // turn it on (level > 0) / off (0%) if the device has one. Devices without a switch are\n // unaffected. The switch is found by role/type, not by name (not every device names it ON_SET).\n const sw = this.findSwitch(device, stateId);\n if (sw) {\n intent.also = { stateId: sw, value: f.level > 0 };\n }\n return intent;\n }\n }\n\n // 2. Set color — only a hex color on a color-capable device (warm/cold color-temp is out of scope for v1).\n if (f.color && f.color.startsWith('#') && COLOR_TYPES.has(device.type) && !f.isQuery) {\n const stateId = this.pickControl(device, ['rgb', 'color', 'hue', 'cie', 'ct'], true);\n if (stateId) {\n return { action: 'color', device, stateId, value: f.color, room: roomName, confidence: 0.85 };\n }\n }\n\n // 3. Turn on / off — prefer a writable boolean switch (never a metering state like CONSUMPTION).\n if (f.action && !f.isQuery) {\n const stateId = this.pickControl(device, ['power', 'switch', 'on', 'level'], true, 'boolean');\n if (stateId) {\n // If only a numeric (dimmer/level) control is available, on/off means full/zero level, not a\n // boolean 1/0 (writing `true` to a 0–100 state would land on ~1%).\n const numeric = this.valueTypeOf(device, stateId) === 'number';\n return {\n action: f.action,\n device,\n stateId,\n value: numeric ? (f.action === 'on' ? 100 : 0) : f.action === 'on',\n room: roomName,\n confidence: 0.9,\n };\n }\n }\n\n // 4. Status query — read the right control: an on/off question (\"is the light on?\") reads the\n // boolean switch/feedback; a value question (\"what temperature?\") reads the actual value.\n if (f.isQuery) {\n const order = f.onOffQuery\n ? ['power', 'switch', 'on', 'actual', 'level']\n : ['actual', 'value', 'level', 'power'];\n const stateId = this.pickControl(device, order, false, f.onOffQuery ? 'boolean' : undefined);\n if (stateId) {\n return { action: 'query', device, stateId, room: roomName, confidence: 0.7 };\n }\n }\n\n return null;\n }\n\n /**\n * Timer (countdown) / alarm (fixed clock time) command (de/en/ru). Requires a timer or alarm keyword,\n * then classifies in priority order:\n * - a cancel word → `timerCancel` / `alarmCancel`,\n * - a parseable clock time → `alarmSet` (with weekdays / label / room),\n * - an explicit duration with a unit (\"5 Minuten\") → `timerSet` (so \"weck mich in 5 Minuten\" is a\n * countdown, not a clock time),\n * - a bare number: an hour in the alarm domain (\"Wecker auf 8\"), else minutes → `timerSet`,\n * - otherwise → `timerQuery` / `alarmQuery` (list what is running).\n */\n private parseSchedule(raw: string, norm: string, joined: string): NluIntent | null {\n const isTimer = TIMER_RE.test(norm);\n const isAlarm = ALARM_RE.test(norm);\n if (!isTimer && !isAlarm) {\n return null;\n }\n // Prefer the alarm reading only when it is the sole keyword (so \"erinnere mich um 7\" → alarm, but\n // \"timer …\" stays a timer even if it also mentions \"wecker\").\n const alarmDomain = isAlarm && !isTimer;\n const room = this.findRoom(joined) || undefined;\n const label = (): string | undefined => this.findTimerLabel(norm) || undefined;\n const alarm = (hour: number, minute: number, confidence: number): NluIntent => ({\n action: 'alarmSet',\n hour,\n minute,\n weekdays: parseWeekdays(norm),\n label: label(),\n room,\n confidence,\n });\n\n if (TIMER_CANCEL_RE.test(norm)) {\n return { action: alarmDomain ? 'alarmCancel' : 'timerCancel', label: label(), room, confidence: 0.9 };\n }\n\n // Clock time first (parsed from the raw text — the normalized `norm` has ':' stripped, which would\n // turn \"6:30\" into \"6 30\"). The \"um H\" rule already refuses a following duration unit, and the ru\n // \"H часов\" o'clock form is resolved here before it could be mistaken for \"H hours\".\n const clock = parseClockTime(raw);\n if (clock) {\n return alarm(clock.hour, clock.minute, 0.9);\n }\n\n // Explicit duration with a unit (\"5 Minuten\", \"1 Stunde\") → a countdown timer, even for \"Wecker in …\".\n const explicit = parseDurationSeconds(norm, false);\n if (explicit) {\n return { action: 'timerSet', durationSec: explicit, label: label(), room, confidence: 0.9 };\n }\n\n // A bare number: an hour for an alarm (\"Wecker auf 8\"), otherwise minutes for a timer (\"Timer 5\").\n const bare = parseDurationSeconds(norm, true);\n if (bare) {\n const hour = Math.round(bare / 60);\n if (alarmDomain && hour >= 0 && hour <= 23) {\n return alarm(hour, 0, 0.8);\n }\n return { action: 'timerSet', durationSec: bare, label: label(), room, confidence: 0.9 };\n }\n return { action: alarmDomain ? 'alarmQuery' : 'timerQuery', room, confidence: 0.7 };\n }\n\n /**\n * Extract a timer label: the text after the last marker word (\"an\", \"for\", \"to\", \"про\", …), stripped\n * of duration/number/filler tokens. \"erinnere mich in 5 minuten an den ofen\" → \"ofen\"; \"timer für 5\n * minuten\" → \"\" (no label). Operates on the normalized text (lowercased) — fine for a spoken reply.\n */\n private findTimerLabel(norm: string): string {\n const tokens = norm.split(/\\s+/).filter(Boolean);\n let start = -1;\n for (let i = 0; i < tokens.length; i++) {\n if (LABEL_MARKERS.has(tokens[i])) {\n start = i + 1;\n }\n }\n if (start < 0 || start >= tokens.length) {\n return '';\n }\n const words = tokens.slice(start).filter(w => !LABEL_STOP_WORDS.has(w) && !/^\\d+([.,]\\d+)?$/.test(w));\n return words.join(' ').trim();\n }\n\n /**\n * \"What time is it?\" / \"What's the date/day today?\" (de/en/ru) → a device-independent time or date\n * query, answered directly by the adapter from the host clock (no LLM). The date branch is checked\n * first so \"which day is it\" is not swallowed by the time branch. Matching is stem-tolerant via\n * {@link wordInText}; \"сейчас\"/\"today\"/\"monday\" don't false-match \"час\"/\"day\" (word-boundary guarded).\n */\n private parseTimeQuery(text: string): NluIntent | null {\n const has = (w: string): boolean => wordInText(w, text);\n if (WEATHER_WORDS.some(has)) {\n return null; // \"what is the weather the day after tomorrow\" asks about the weather, not the date\n }\n const qualifier = (): boolean =>\n has('heute') ||\n has('welch') ||\n has('what') ||\n has('which') ||\n has('today') ||\n has('сегодня') ||\n has('какой') ||\n has('какое');\n // Date / weekday question.\n const isDate =\n has('datum') ||\n has('wochentag') ||\n has('date') ||\n has('число') ||\n has('дата') ||\n ((has('tag') || has('day') || has('день')) && qualifier());\n if (isDate) {\n return { action: 'dateQuery', confidence: 0.9 };\n }\n // Time-of-day question. \"wie viel Uhr\" needs both words so a bare \"Uhr\" (rare here) doesn't trigger.\n const isTime =\n has('spaet') ||\n has('uhrzeit') ||\n has('time') ||\n has('clock') ||\n has('час') ||\n has('время') ||\n (has('uhr') && has('viel'));\n if (isTime) {\n return { action: 'timeQuery', confidence: 0.9 };\n }\n return null;\n }\n\n /**\n * \"Which windows are open?\" (de/en/ru) → an aggregate query over all window devices. Matches when the\n * text mentions a window word AND an \"open\" word; optionally restricted to a matched room.\n */\n /**\n * \"How is the air in the living room?\", \"how warm is it?\", \"how bright is it everywhere?\" — a\n * question about a kind of measurement rather than about a named device. Returns null unless the\n * house actually has devices of that kind, so the LLM still gets its chance.\n *\n * Only treated as a category query when no device was named: \"wie warm ist die Heizung\" is about\n * that thermostat, and the device path answers it better.\n */\n private parseCategoryQuery(p: Prepared, features: CommandFeatures): NluIntent | null {\n if (!features.isQuery) {\n return null; // a statement, not a question — nothing to report\n }\n const match = CATEGORY_WORDS.find(c => c.words.some(w => wordInText(w, p.joined)));\n if (!match) {\n return null;\n }\n const roomName = this.findRoom(p.joined);\n const everywhere = EVERYWHERE_WORDS.some(w => wordInText(w, p.joined));\n const room = everywhere ? '' : roomName;\n const devices = this.devices.filter(d => match.types.includes(d.type) && (!room || d.room === room));\n if (!devices.length) {\n return null; // nothing of that kind here (or not in that room) → let the LLM answer\n }\n return {\n action: 'categoryQuery',\n category: match.category,\n types: match.types,\n devices,\n room: room || undefined,\n confidence: 0.8,\n };\n }\n\n /**\n * \"Wie wird das Wetter morgen?\", \"regnet es heute?\", \"wie warm wird es übermorgen?\" (de/en/ru) → the\n * configured weather adapter, read and spoken without an LLM. Only today, tomorrow and the day after\n * — other days, other places (\"Wetter in Berlin\") and the plain \"wie warm ist es\" (the house sensors,\n * see {@link parseCategoryQuery}) stay with their own paths.\n */\n private parseWeatherQuery(p: Prepared, features: CommandFeatures): NluIntent | null {\n if (!this.opts.weather) {\n return null;\n }\n const t = p.joined;\n const tokens = p.tokens;\n const has = (w: string): boolean => p.tokenSet.has(w);\n let when: WeatherWhen = 'now';\n if (has('uebermorgen') || t.includes('day after tomorrow') || has('послезавтра')) {\n when = 'dayAfter';\n } else if (has('heute') || has('today') || has('сегодня')) {\n when = 'today'; // also \"heute Morgen\"\n } else if (\n has('tomorrow') ||\n has('завтра') ||\n tokens.some((w, i) => w === 'morgen' && tokens[i - 1] !== 'guten')\n ) {\n when = 'tomorrow';\n }\n const weatherWord = WEATHER_WORDS.some(w => wordInText(w, t));\n const rain = tokens.some(w => RAIN_TOKENS.has(w));\n const temperature = (CATEGORY_WORDS.find(c => c.category === 'temperature')?.words || []).some(w =>\n wordInText(w, t),\n );\n // A temperature question is about the forecast only when it names a day; without one it is about the house.\n if (!weatherWord && !rain && !(temperature && features.isQuery && when !== 'now')) {\n return null;\n }\n // The filler list drops prepositions from the tokens, so look for them in the full text.\n if (WEATHER_LATER_RE.test(t) || p.norm.split(/\\s+/).some(w => WEATHER_ELSEWHERE.has(w))) {\n return null;\n }\n return { action: 'weatherQuery', when, confidence: 0.85 };\n }\n\n /**\n * \"Lautstärke 5\", \"Lautstärke auf 40 Prozent\", \"lauter\", \"etwas leiser\", \"volume 7\", \"громче\" → the\n * playback volume of the satellite that heard it (or of the named room's satellite). A bare number up\n * to 10 is a step on a 1–10 scale, anything above is percent. \"Wie ist die Lautstärke\" is not a command.\n */\n private parseVolume(p: Prepared): NluIntent | null {\n const louder = p.tokens.some(w => LOUDER_TOKENS.has(w));\n const quieter = p.tokens.some(w => QUIETER_TOKENS.has(w));\n const volumeWord = VOLUME_WORDS.some(w => wordInText(w, p.joined));\n if (!louder && !quieter && !volumeWord) {\n return null;\n }\n const percent = /(?:prozent|percent|процент\\p{L}*|%)/u.test(p.norm);\n // \"ein bisschen lauter\" is no step count — only digits and the number words from two upwards count.\n const num = spelledNumbersToDigits(p.tokens.join(' '))\n .split(' ')\n .map(w => (/^\\d+$/.test(w) ? w : ['ein', 'eine', 'einen'].includes(w) ? '' : NUMBER_WORDS[w] || ''))\n .find(w => /^\\d+$/.test(w));\n const n = num === undefined ? null : parseInt(num, 10);\n const scaled = n === null ? null : n <= 10 && !percent ? n * 10 : n;\n const room = this.findRoom(p.joined) || undefined;\n if (louder !== quieter) {\n const step = scaled ?? VOLUME_STEP;\n return { action: 'volumeSet', delta: louder ? step : -step, room, confidence: 0.85 };\n }\n if (!volumeWord) {\n return null;\n }\n let level = scaled;\n if (p.tokens.some(w => VOLUME_MAX_TOKENS.has(w))) {\n level = 100;\n } else if (p.tokens.some(w => VOLUME_MIN_TOKENS.has(w))) {\n level = VOLUME_STEP;\n }\n if (level === null) {\n return null;\n }\n return { action: 'volumeSet', value: Math.min(100, Math.max(0, level)), room, confidence: 0.85 };\n }\n\n private parseWindowsOpen(text: string): NluIntent | null {\n if (!WINDOW_WORDS.some(w => wordInText(w, text)) || !OPEN_WORDS.some(w => wordInText(w, text))) {\n return null;\n }\n const roomName = this.findRoom(text);\n const windows = this.devices.filter(d => WINDOW_TYPES.has(d.type) && (!roomName || d.room === roomName));\n if (!windows.length) {\n return null; // no window devices known → let the LLM handle it\n }\n return {\n action: 'listByState',\n category: 'window',\n stateFilter: 'open',\n devices: windows,\n room: roomName || undefined,\n confidence: 0.9,\n };\n }\n\n /** The room whose significant words all appear in the text (stem-tolerant); longest name wins. */\n private findRoom(text: string): string {\n let best = '';\n let bestLen = 0;\n for (const name of this.rooms) {\n const n = normalize(name);\n const words = n.split(/\\s+/).filter(w => w.length >= 3);\n if (!words.length) {\n continue;\n }\n if (words.every(w => wordInText(w, text)) && n.length > bestLen) {\n best = name;\n bestLen = n.length;\n }\n }\n return best;\n }\n\n /**\n * Device whose significant name words all appear in the text (stem-tolerant for inflection).\n * Prefers devices in the matched room; the longest matching name wins.\n */\n private findDevice(text: string, roomName: string): NluDevice | null {\n const normRoom = roomName ? normalize(roomName) : '';\n const spaces: NluDevice[][] = [];\n if (roomName) {\n spaces.push(this.devices.filter(d => d.room === roomName));\n }\n spaces.push(this.devices.filter(d => !roomName || d.room !== roomName));\n\n for (const space of spaces) {\n let best: NluDevice | null = null;\n let bestLen = 0;\n for (const dev of space) {\n const nk = normalize(dev.name);\n if (!nk || (normRoom && normRoom.includes(nk))) {\n continue; // skip a device whose name is part of the room name\n }\n const words = nk.split(/\\s+/).filter(w => w.length >= 3);\n if (!words.length) {\n continue;\n }\n if (words.every(w => wordInText(w, text)) && nk.length > bestLen) {\n best = dev;\n bestLen = nk.length;\n }\n }\n if (best) {\n return best;\n }\n }\n return null;\n }\n\n private findAction(tokens: Set<string>): 'on' | 'off' | null {\n for (const t of tokens) {\n if (TURN_OFF.has(t)) {\n return 'off';\n }\n if (TURN_ON.has(t)) {\n return 'on';\n }\n }\n return null;\n }\n\n private findLevel(text: string): number | null {\n const m = spelledNumbersToDigits(text).match(/(\\d+(?:[.,]\\d+)?)\\s*(?:prozent|percent|процент\\w*|%)/u);\n return m ? parseFloat(m[1].replace(',', '.')) : null;\n }\n\n private findColor(text: string): string | null {\n for (const [name, hex] of Object.entries(COLORS)) {\n if (wordInText(name, text)) {\n return hex;\n }\n }\n return null;\n }\n\n /**\n * Pick a control state id. Tries the ordered controlType keys (preferring `preferType`, then any type),\n * then falls back to any usable **non-metering** control — so a query/command never lands on a\n * CONSUMPTION/CURRENT/… measurement. `mustWrite` additionally requires the control to be writable.\n */\n private pickControl(device: NluDevice, order: string[], mustWrite: boolean, preferType?: string): string {\n const types = device.types || {};\n const usable = (key: string): boolean => !!device.controls[key] && (!mustWrite || !!device.writable[key]);\n if (preferType) {\n // 1. an ordered key of the preferred value type (e.g. a boolean switch for on/off).\n for (const key of order) {\n if (usable(key) && types[key] === preferType) {\n return device.controls[key];\n }\n }\n // 2. ANY control of the preferred type (non-metering). Catches a boolean switch stored under a\n // non-standard control key (e.g. `ON_SET`), so on/off never lands on a numeric level/dimmer\n // control when a real boolean switch exists on the device.\n for (const [key, id] of Object.entries(device.controls)) {\n if (usable(key) && types[key] === preferType && !METER_SUFFIX.test(id)) {\n return id;\n }\n }\n }\n // 3. an ordered key of any type.\n for (const key of order) {\n if (usable(key)) {\n return device.controls[key];\n }\n }\n // 4. fallback: any usable non-metering control.\n for (const [key, id] of Object.entries(device.controls)) {\n if (usable(key) && !METER_SUFFIX.test(id)) {\n return id;\n }\n }\n return '';\n }\n\n /** The ioBroker value type ('boolean'|'number'|…) of a device control by its state id, '' if unknown. */\n private valueTypeOf(device: NluDevice, stateId: string): string {\n for (const [key, id] of Object.entries(device.controls)) {\n if (id === stateId) {\n return device.types[key] || '';\n }\n }\n return '';\n }\n\n /**\n * The device's on/off switch control (state id) other than `excludeStateId`, so a level command can also\n * power the device on. Role-based: a writable control with a `switch…` role wins; otherwise any writable\n * boolean, non-metering control; '' if the device has no separate switch.\n */\n private findSwitch(device: NluDevice, excludeStateId: string): string {\n const roles = device.roles || {};\n let fallback = '';\n for (const [key, id] of Object.entries(device.controls)) {\n if (id === excludeStateId || !device.writable[key] || METER_SUFFIX.test(id)) {\n continue;\n }\n const role = roles[key] || '';\n if (/^switch(\\.|$)/i.test(role)) {\n return id; // a role-confirmed switch is the best match\n }\n if (!fallback && device.types[key] === 'boolean') {\n fallback = id; // any writable boolean control as a fallback\n }\n }\n return fallback;\n }\n}\n"]}
|