node-red-contrib-knx-ultimate 7.1.4 → 8.0.2
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/CHANGELOG.md +20 -10
- package/MIGRATION.md +40 -0
- package/README.md +32 -6
- package/docs/README.md +34 -0
- package/docs/assets/brand/made-in-italy.svg +12 -0
- package/examples/Alerter - Device Alert Aggregation.json +5 -2
- package/examples/Auto Responder - Read Request Defaults.json +5 -2
- package/examples/Garage - Door Controller.json +5 -2
- package/examples/Global Context - Expose KNX Values.json +5 -2
- package/examples/KNX DateTime - Set Date and Time to Bus.json +111 -89
- package/examples/Load Control - Manual Shedding Mode.json +5 -2
- package/examples/Logger ETS File and Telegram Count.json +10 -2
- package/examples/Scene Controller Recall and Save.json +33 -6
- package/examples/Staircase - Timer, Override and Block.json +5 -2
- package/examples/WatchDog Connect Disconnect.json +98 -70
- package/nodes/commonFunctions.js +0 -587
- package/nodes/knxUltimate-config.html +0 -14
- package/nodes/knxUltimate-config.js +1 -18
- package/nodes/knxUltimate.html +1 -6
- package/nodes/knxUltimateIoTBridge.html +0 -14
- package/nodes/knxUltimateLegacyMigration.js +75 -0
- package/nodes/knxUltimateMultiRouting.html +1 -7
- package/nodes/knxUltimateRouterFilter.html +1 -7
- package/nodes/knxUltimateUtility.html +0 -6
- package/nodes/knxUltimateViewer.html +0 -6
- package/nodes/locales/de/knxUltimate-config.html +0 -8
- package/nodes/locales/de/knxUltimate.html +0 -8
- package/nodes/locales/de/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/de/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/de/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/de/knxUltimateUtility.html +0 -8
- package/nodes/locales/de/knxUltimateUtility.json +16 -1
- package/nodes/locales/de/knxUltimateViewer.html +0 -8
- package/nodes/locales/en/knxUltimate-config.html +0 -8
- package/nodes/locales/en/knxUltimate.html +0 -8
- package/nodes/locales/en/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/en/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/en/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/en/knxUltimateUtility.html +0 -8
- package/nodes/locales/en/knxUltimateUtility.json +16 -1
- package/nodes/locales/en/knxUltimateViewer.html +0 -8
- package/nodes/locales/es/knxUltimate-config.html +0 -8
- package/nodes/locales/es/knxUltimate.html +0 -8
- package/nodes/locales/es/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/es/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/es/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/es/knxUltimateUtility.html +0 -8
- package/nodes/locales/es/knxUltimateUtility.json +17 -2
- package/nodes/locales/es/knxUltimateViewer.html +0 -8
- package/nodes/locales/fr/knxUltimate-config.html +0 -8
- package/nodes/locales/fr/knxUltimate.html +0 -8
- package/nodes/locales/fr/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/fr/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/fr/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/fr/knxUltimateUtility.html +0 -8
- package/nodes/locales/fr/knxUltimateUtility.json +16 -1
- package/nodes/locales/fr/knxUltimateViewer.html +0 -8
- package/nodes/locales/it/knxUltimate-config.html +0 -8
- package/nodes/locales/it/knxUltimate.html +0 -8
- package/nodes/locales/it/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/it/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/it/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/it/knxUltimateUtility.html +0 -8
- package/nodes/locales/it/knxUltimateUtility.json +16 -1
- package/nodes/locales/it/knxUltimateViewer.html +0 -8
- package/nodes/locales/zh-CN/knxUltimate-config.html +0 -8
- package/nodes/locales/zh-CN/knxUltimate.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateUtility.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateUtility.json +16 -1
- package/nodes/locales/zh-CN/knxUltimateViewer.html +0 -8
- package/nodes/plugins/knxUltimate-v8-migration-recovery-plugin.html +140 -0
- package/package.json +22 -69
- package/resources/11f26b4500.js +2 -2
- package/resources/KNXAIChatAdapterMappings.js +2 -416
- package/resources/configNodeEditorSelection.js +2 -32
- package/resources/hueControllerEditorSelection.js +2 -32
- package/resources/hueControllerMigrationDialog.js +2 -254
- package/resources/hueControllerProfiles.js +2 -9319
- package/resources/knxUtilityProfiles.js +2041 -2082
- package/resources/legacyMigrationNotice.js +23 -111
- package/resources/matterQrScanner.js +2 -98
- package/resources/upgradeToV8.js +94 -26
- package/scripts/check-legacy-flows.js +142 -0
- package/examples/Hue Area Motion - Zone Presence.json +0 -77
- package/examples/Hue Battery - Level Status.json +0 -77
- package/examples/Hue Button - Short and Dim Commands.json +0 -83
- package/examples/Hue Camera Motion - Presence.json +0 -77
- package/examples/Hue Config - Bridge Template.json +0 -27
- package/examples/Hue Contact Sensor - Open Closed.json +0 -75
- package/examples/Hue Device Software Update - Availability.json +0 -77
- package/examples/Hue Humidity Sensor - Relative Humidity.json +0 -77
- package/examples/Hue Light - Switch and Brightness.json +0 -67
- package/examples/Hue Light Sensor - Lux to KNX.json +0 -77
- package/examples/Hue Motion - Presence Sensor.json +0 -76
- package/examples/Hue Plug - Switch and State.json +0 -63
- package/examples/Hue Scene - Recall from KNX.json +0 -63
- package/examples/Hue Tap Dial - Relative Dimming.json +0 -76
- package/examples/Hue Temperature Sensor - Celsius to KNX.json +0 -77
- package/examples/Hue Zigbee Connectivity - Online Status.json +0 -77
- package/examples/Matter Controller - Semantic Flow Input.json +0 -248
- package/nodes/hue-config.html +0 -378
- package/nodes/hue-config.js +0 -846
- package/nodes/icons/node-alerter-icon.png +0 -0
- package/nodes/icons/node-homekit-icon.png +0 -0
- package/nodes/icons/node-homekit-icon.svg +0 -10
- package/nodes/icons/node-hue-icon.svg +0 -10
- package/nodes/icons/node-knx-icon.png +0 -0
- package/nodes/icons/node-logger-icon.png +0 -0
- package/nodes/icons/node-logger2-icon.png +0 -0
- package/nodes/icons/node-logger2-icon.svg +0 -32
- package/nodes/icons/node-matter-bridge-icon.svg +0 -6
- package/nodes/icons/node-matter-controller-icon.svg +0 -6
- package/nodes/icons/node-matter-icon.svg +0 -12
- package/nodes/icons/node-scene-icon.png +0 -0
- package/nodes/icons/node-watchdog-icon.png +0 -0
- package/nodes/knxUltimateAI.html +0 -1826
- package/nodes/knxUltimateAI.js +0 -16797
- package/nodes/knxUltimateAIHomeAssistant.html +0 -54
- package/nodes/knxUltimateAIHomeAssistant.js +0 -152
- package/nodes/knxUltimateAlerter.html +0 -267
- package/nodes/knxUltimateAlerter.js +0 -300
- package/nodes/knxUltimateAutoResponder.html +0 -128
- package/nodes/knxUltimateAutoResponder.js +0 -264
- package/nodes/knxUltimateDateTime.html +0 -579
- package/nodes/knxUltimateDateTime.js +0 -282
- package/nodes/knxUltimateGarage.html +0 -337
- package/nodes/knxUltimateGarage.js +0 -504
- package/nodes/knxUltimateGlobalContext.html +0 -145
- package/nodes/knxUltimateGlobalContext.js +0 -208
- package/nodes/knxUltimateHATranslator.html +0 -85
- package/nodes/knxUltimateHATranslator.js +0 -83
- package/nodes/knxUltimateHueAreaMotion.html +0 -670
- package/nodes/knxUltimateHueAreaMotion.js +0 -218
- package/nodes/knxUltimateHueBattery.html +0 -646
- package/nodes/knxUltimateHueBattery.js +0 -182
- package/nodes/knxUltimateHueButton.html +0 -804
- package/nodes/knxUltimateHueButton.js +0 -292
- package/nodes/knxUltimateHueCameraMotion.html +0 -671
- package/nodes/knxUltimateHueCameraMotion.js +0 -218
- package/nodes/knxUltimateHueContactSensor.html +0 -609
- package/nodes/knxUltimateHueContactSensor.js +0 -188
- package/nodes/knxUltimateHueController.html +0 -1765
- package/nodes/knxUltimateHueController.js +0 -28
- package/nodes/knxUltimateHueHumiditySensor.html +0 -641
- package/nodes/knxUltimateHueHumiditySensor.js +0 -201
- package/nodes/knxUltimateHueLight.html +0 -2516
- package/nodes/knxUltimateHueLight.js +0 -1582
- package/nodes/knxUltimateHueLightSensor.html +0 -636
- package/nodes/knxUltimateHueLightSensor.js +0 -177
- package/nodes/knxUltimateHueMotion.html +0 -634
- package/nodes/knxUltimateHueMotion.js +0 -182
- package/nodes/knxUltimateHuePlug.html +0 -576
- package/nodes/knxUltimateHuePlug.js +0 -341
- package/nodes/knxUltimateHueScene.html +0 -967
- package/nodes/knxUltimateHueScene.js +0 -349
- package/nodes/knxUltimateHueTapDial.html +0 -640
- package/nodes/knxUltimateHueTapDial.js +0 -268
- package/nodes/knxUltimateHueTemperatureSensor.html +0 -639
- package/nodes/knxUltimateHueTemperatureSensor.js +0 -184
- package/nodes/knxUltimateHueZigbeeConnectivity.html +0 -648
- package/nodes/knxUltimateHueZigbeeConnectivity.js +0 -182
- package/nodes/knxUltimateHuedevice_software_update.html +0 -650
- package/nodes/knxUltimateHuedevice_software_update.js +0 -182
- package/nodes/knxUltimateLoadControl.html +0 -425
- package/nodes/knxUltimateLoadControl.js +0 -443
- package/nodes/knxUltimateLogger.html +0 -197
- package/nodes/knxUltimateLogger.js +0 -224
- package/nodes/knxUltimateMatterBridge.html +0 -689
- package/nodes/knxUltimateMatterBridge.js +0 -464
- package/nodes/knxUltimateMatterControllerDevice.html +0 -2851
- package/nodes/knxUltimateMatterControllerDevice.js +0 -1747
- package/nodes/knxUltimateSceneController.html +0 -529
- package/nodes/knxUltimateSceneController.js +0 -437
- package/nodes/knxUltimateStaircase.html +0 -346
- package/nodes/knxUltimateStaircase.js +0 -463
- package/nodes/knxUltimateWatchDog.html +0 -241
- package/nodes/knxUltimateWatchDog.js +0 -230
- package/nodes/locales/de/hue-config.html +0 -33
- package/nodes/locales/de/hue-config.json +0 -21
- package/nodes/locales/de/knxUltimateAI.html +0 -13
- package/nodes/locales/de/knxUltimateAI.json +0 -231
- package/nodes/locales/de/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/de/knxUltimateAlerter.html +0 -159
- package/nodes/locales/de/knxUltimateAlerter.json +0 -27
- package/nodes/locales/de/knxUltimateAutoResponder.html +0 -96
- package/nodes/locales/de/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/de/knxUltimateDateTime.html +0 -45
- package/nodes/locales/de/knxUltimateDateTime.json +0 -32
- package/nodes/locales/de/knxUltimateGarage.html +0 -79
- package/nodes/locales/de/knxUltimateGarage.json +0 -51
- package/nodes/locales/de/knxUltimateGlobalContext.html +0 -76
- package/nodes/locales/de/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/de/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/de/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/de/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/de/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/de/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/de/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/de/knxUltimateHueButton.html +0 -52
- package/nodes/locales/de/knxUltimateHueButton.json +0 -34
- package/nodes/locales/de/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/de/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/de/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/de/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/de/knxUltimateHueController.html +0 -690
- package/nodes/locales/de/knxUltimateHueController.json +0 -64
- package/nodes/locales/de/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/de/knxUltimateHueLight.html +0 -121
- package/nodes/locales/de/knxUltimateHueLight.json +0 -94
- package/nodes/locales/de/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/de/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/de/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/de/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/de/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/de/knxUltimateHueScene.html +0 -45
- package/nodes/locales/de/knxUltimateHueScene.json +0 -41
- package/nodes/locales/de/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/de/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/de/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/de/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/de/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/de/knxUltimateLoadControl.html +0 -69
- package/nodes/locales/de/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/de/knxUltimateLogger.html +0 -126
- package/nodes/locales/de/knxUltimateLogger.json +0 -31
- package/nodes/locales/de/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/de/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/de/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/de/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/de/knxUltimateSceneController.html +0 -98
- package/nodes/locales/de/knxUltimateSceneController.json +0 -32
- package/nodes/locales/de/knxUltimateStaircase.html +0 -77
- package/nodes/locales/de/knxUltimateStaircase.json +0 -62
- package/nodes/locales/de/knxUltimateWatchDog.html +0 -178
- package/nodes/locales/de/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/de/matter-config.html +0 -47
- package/nodes/locales/de/matter-config.json +0 -47
- package/nodes/locales/de/matterbridge-config.html +0 -45
- package/nodes/locales/de/matterbridge-config.json +0 -25
- package/nodes/locales/en/hue-config.html +0 -31
- package/nodes/locales/en/hue-config.json +0 -21
- package/nodes/locales/en/knxUltimateAI.html +0 -13
- package/nodes/locales/en/knxUltimateAI.json +0 -234
- package/nodes/locales/en/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/en/knxUltimateAlerter.html +0 -164
- package/nodes/locales/en/knxUltimateAlerter.json +0 -27
- package/nodes/locales/en/knxUltimateAutoResponder.html +0 -94
- package/nodes/locales/en/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/en/knxUltimateDateTime.html +0 -67
- package/nodes/locales/en/knxUltimateDateTime.json +0 -32
- package/nodes/locales/en/knxUltimateGarage.html +0 -79
- package/nodes/locales/en/knxUltimateGarage.json +0 -51
- package/nodes/locales/en/knxUltimateGlobalContext.html +0 -124
- package/nodes/locales/en/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/en/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/en/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/en/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/en/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/en/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/en/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/en/knxUltimateHueButton.html +0 -52
- package/nodes/locales/en/knxUltimateHueButton.json +0 -34
- package/nodes/locales/en/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/en/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/en/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/en/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/en/knxUltimateHueController.html +0 -691
- package/nodes/locales/en/knxUltimateHueController.json +0 -64
- package/nodes/locales/en/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/en/knxUltimateHueLight.html +0 -124
- package/nodes/locales/en/knxUltimateHueLight.json +0 -94
- package/nodes/locales/en/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/en/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/en/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/en/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/en/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/en/knxUltimateHueScene.html +0 -45
- package/nodes/locales/en/knxUltimateHueScene.json +0 -41
- package/nodes/locales/en/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/en/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/en/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/en/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/en/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/en/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/en/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/en/knxUltimateLogger.html +0 -161
- package/nodes/locales/en/knxUltimateLogger.json +0 -31
- package/nodes/locales/en/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/en/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/en/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/en/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/en/knxUltimateSceneController.html +0 -117
- package/nodes/locales/en/knxUltimateSceneController.json +0 -32
- package/nodes/locales/en/knxUltimateStaircase.html +0 -77
- package/nodes/locales/en/knxUltimateStaircase.json +0 -62
- package/nodes/locales/en/knxUltimateWatchDog.html +0 -244
- package/nodes/locales/en/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/en/matter-config.html +0 -47
- package/nodes/locales/en/matter-config.json +0 -48
- package/nodes/locales/en/matterbridge-config.html +0 -45
- package/nodes/locales/en/matterbridge-config.json +0 -25
- package/nodes/locales/es/hue-config.html +0 -31
- package/nodes/locales/es/hue-config.json +0 -21
- package/nodes/locales/es/knxUltimateAI.html +0 -13
- package/nodes/locales/es/knxUltimateAI.json +0 -231
- package/nodes/locales/es/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/es/knxUltimateAlerter.html +0 -164
- package/nodes/locales/es/knxUltimateAlerter.json +0 -27
- package/nodes/locales/es/knxUltimateAutoResponder.html +0 -81
- package/nodes/locales/es/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/es/knxUltimateDateTime.html +0 -45
- package/nodes/locales/es/knxUltimateDateTime.json +0 -32
- package/nodes/locales/es/knxUltimateGarage.html +0 -79
- package/nodes/locales/es/knxUltimateGarage.json +0 -51
- package/nodes/locales/es/knxUltimateGlobalContext.html +0 -128
- package/nodes/locales/es/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/es/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/es/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/es/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/es/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/es/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/es/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/es/knxUltimateHueButton.html +0 -52
- package/nodes/locales/es/knxUltimateHueButton.json +0 -34
- package/nodes/locales/es/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/es/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/es/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/es/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/es/knxUltimateHueController.html +0 -691
- package/nodes/locales/es/knxUltimateHueController.json +0 -64
- package/nodes/locales/es/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/es/knxUltimateHueLight.html +0 -124
- package/nodes/locales/es/knxUltimateHueLight.json +0 -94
- package/nodes/locales/es/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/es/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/es/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/es/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/es/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/es/knxUltimateHueScene.html +0 -45
- package/nodes/locales/es/knxUltimateHueScene.json +0 -41
- package/nodes/locales/es/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/es/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/es/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/es/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/es/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/es/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/es/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/es/knxUltimateLogger.html +0 -162
- package/nodes/locales/es/knxUltimateLogger.json +0 -31
- package/nodes/locales/es/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/es/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/es/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/es/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/es/knxUltimateSceneController.html +0 -115
- package/nodes/locales/es/knxUltimateSceneController.json +0 -32
- package/nodes/locales/es/knxUltimateStaircase.html +0 -77
- package/nodes/locales/es/knxUltimateStaircase.json +0 -62
- package/nodes/locales/es/knxUltimateWatchDog.html +0 -230
- package/nodes/locales/es/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/es/matter-config.html +0 -47
- package/nodes/locales/es/matter-config.json +0 -47
- package/nodes/locales/es/matterbridge-config.html +0 -45
- package/nodes/locales/es/matterbridge-config.json +0 -25
- package/nodes/locales/fr/hue-config.html +0 -31
- package/nodes/locales/fr/hue-config.json +0 -21
- package/nodes/locales/fr/knxUltimateAI.html +0 -13
- package/nodes/locales/fr/knxUltimateAI.json +0 -231
- package/nodes/locales/fr/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/fr/knxUltimateAlerter.html +0 -164
- package/nodes/locales/fr/knxUltimateAlerter.json +0 -27
- package/nodes/locales/fr/knxUltimateAutoResponder.html +0 -92
- package/nodes/locales/fr/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/fr/knxUltimateDateTime.html +0 -45
- package/nodes/locales/fr/knxUltimateDateTime.json +0 -32
- package/nodes/locales/fr/knxUltimateGarage.html +0 -79
- package/nodes/locales/fr/knxUltimateGarage.json +0 -51
- package/nodes/locales/fr/knxUltimateGlobalContext.html +0 -122
- package/nodes/locales/fr/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/fr/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/fr/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/fr/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/fr/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/fr/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/fr/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/fr/knxUltimateHueButton.html +0 -52
- package/nodes/locales/fr/knxUltimateHueButton.json +0 -34
- package/nodes/locales/fr/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/fr/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/fr/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/fr/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/fr/knxUltimateHueController.html +0 -691
- package/nodes/locales/fr/knxUltimateHueController.json +0 -64
- package/nodes/locales/fr/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/fr/knxUltimateHueLight.html +0 -124
- package/nodes/locales/fr/knxUltimateHueLight.json +0 -86
- package/nodes/locales/fr/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/fr/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/fr/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/fr/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/fr/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/fr/knxUltimateHueScene.html +0 -45
- package/nodes/locales/fr/knxUltimateHueScene.json +0 -41
- package/nodes/locales/fr/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/fr/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/fr/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/fr/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/fr/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/fr/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/fr/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/fr/knxUltimateLogger.html +0 -160
- package/nodes/locales/fr/knxUltimateLogger.json +0 -31
- package/nodes/locales/fr/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/fr/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/fr/knxUltimateSceneController.html +0 -117
- package/nodes/locales/fr/knxUltimateSceneController.json +0 -32
- package/nodes/locales/fr/knxUltimateStaircase.html +0 -77
- package/nodes/locales/fr/knxUltimateStaircase.json +0 -62
- package/nodes/locales/fr/knxUltimateWatchDog.html +0 -228
- package/nodes/locales/fr/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/fr/matter-config.html +0 -47
- package/nodes/locales/fr/matter-config.json +0 -47
- package/nodes/locales/fr/matterbridge-config.html +0 -45
- package/nodes/locales/fr/matterbridge-config.json +0 -25
- package/nodes/locales/it/hue-config.html +0 -33
- package/nodes/locales/it/hue-config.json +0 -21
- package/nodes/locales/it/knxUltimateAI.html +0 -13
- package/nodes/locales/it/knxUltimateAI.json +0 -234
- package/nodes/locales/it/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/it/knxUltimateAlerter.html +0 -159
- package/nodes/locales/it/knxUltimateAlerter.json +0 -27
- package/nodes/locales/it/knxUltimateAutoResponder.html +0 -96
- package/nodes/locales/it/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/it/knxUltimateDateTime.html +0 -67
- package/nodes/locales/it/knxUltimateDateTime.json +0 -32
- package/nodes/locales/it/knxUltimateGarage.html +0 -79
- package/nodes/locales/it/knxUltimateGarage.json +0 -51
- package/nodes/locales/it/knxUltimateGlobalContext.html +0 -81
- package/nodes/locales/it/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/it/knxUltimateHATranslator.html +0 -24
- package/nodes/locales/it/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/it/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/it/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/it/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/it/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/it/knxUltimateHueButton.html +0 -52
- package/nodes/locales/it/knxUltimateHueButton.json +0 -34
- package/nodes/locales/it/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/it/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/it/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/it/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/it/knxUltimateHueController.html +0 -690
- package/nodes/locales/it/knxUltimateHueController.json +0 -64
- package/nodes/locales/it/knxUltimateHueHumiditySensor 2.html +0 -11
- package/nodes/locales/it/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/it/knxUltimateHueLight.html +0 -124
- package/nodes/locales/it/knxUltimateHueLight.json +0 -94
- package/nodes/locales/it/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/it/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/it/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/it/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/it/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/it/knxUltimateHueScene.html +0 -45
- package/nodes/locales/it/knxUltimateHueScene.json +0 -41
- package/nodes/locales/it/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/it/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/it/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/it/knxUltimateHuedevice_software_update.html +0 -35
- package/nodes/locales/it/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/it/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/it/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/it/knxUltimateLogger.html +0 -132
- package/nodes/locales/it/knxUltimateLogger.json +0 -31
- package/nodes/locales/it/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/it/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/it/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/it/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/it/knxUltimateSceneController.html +0 -101
- package/nodes/locales/it/knxUltimateSceneController.json +0 -32
- package/nodes/locales/it/knxUltimateStaircase.html +0 -77
- package/nodes/locales/it/knxUltimateStaircase.json +0 -62
- package/nodes/locales/it/knxUltimateWatchDog.html +0 -194
- package/nodes/locales/it/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/it/matter-config.html +0 -47
- package/nodes/locales/it/matter-config.json +0 -48
- package/nodes/locales/it/matterbridge-config.html +0 -45
- package/nodes/locales/it/matterbridge-config.json +0 -25
- package/nodes/locales/zh-CN/hue-config.html +0 -33
- package/nodes/locales/zh-CN/hue-config.json +0 -21
- package/nodes/locales/zh-CN/knxUltimateAI.html +0 -13
- package/nodes/locales/zh-CN/knxUltimateAI.json +0 -231
- package/nodes/locales/zh-CN/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/zh-CN/knxUltimateAlerter.html +0 -159
- package/nodes/locales/zh-CN/knxUltimateAlerter.json +0 -27
- package/nodes/locales/zh-CN/knxUltimateAutoResponder.html +0 -94
- package/nodes/locales/zh-CN/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/zh-CN/knxUltimateDateTime.html +0 -45
- package/nodes/locales/zh-CN/knxUltimateDateTime.json +0 -32
- package/nodes/locales/zh-CN/knxUltimateGarage.html +0 -79
- package/nodes/locales/zh-CN/knxUltimateGarage.json +0 -51
- package/nodes/locales/zh-CN/knxUltimateGlobalContext.html +0 -77
- package/nodes/locales/zh-CN/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/zh-CN/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/zh-CN/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/zh-CN/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/zh-CN/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueButton.html +0 -52
- package/nodes/locales/zh-CN/knxUltimateHueButton.json +0 -34
- package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/zh-CN/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/zh-CN/knxUltimateHueController.html +0 -693
- package/nodes/locales/zh-CN/knxUltimateHueController.json +0 -64
- package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueLight.html +0 -126
- package/nodes/locales/zh-CN/knxUltimateHueLight.json +0 -86
- package/nodes/locales/zh-CN/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueLightSensor.json +0 -9
- package/nodes/locales/zh-CN/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/zh-CN/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/zh-CN/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/zh-CN/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/zh-CN/knxUltimateHueScene.html +0 -45
- package/nodes/locales/zh-CN/knxUltimateHueScene.json +0 -41
- package/nodes/locales/zh-CN/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/zh-CN/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/zh-CN/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/zh-CN/knxUltimateLogger.html +0 -126
- package/nodes/locales/zh-CN/knxUltimateLogger.json +0 -31
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/zh-CN/knxUltimateSceneController.html +0 -98
- package/nodes/locales/zh-CN/knxUltimateSceneController.json +0 -32
- package/nodes/locales/zh-CN/knxUltimateStaircase.html +0 -77
- package/nodes/locales/zh-CN/knxUltimateStaircase.json +0 -62
- package/nodes/locales/zh-CN/knxUltimateWatchDog.html +0 -178
- package/nodes/locales/zh-CN/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/zh-CN/matter-config.html +0 -47
- package/nodes/locales/zh-CN/matter-config.json +0 -47
- package/nodes/locales/zh-CN/matterbridge-config.html +0 -45
- package/nodes/locales/zh-CN/matterbridge-config.json +0 -25
- package/nodes/matter-config.html +0 -578
- package/nodes/matter-config.js +0 -387
- package/nodes/matterbridge-config.html +0 -198
- package/nodes/matterbridge-config.js +0 -261
- package/nodes/plugins/knxUltimate-cerebrum-runtime-plugin.js +0 -79
- package/nodes/plugins/knxUltimate-migration-notice-plugin.html +0 -44
- package/nodes/plugins/knxUltimateAI-vue/assets/app.css +0 -1
- package/nodes/plugins/knxUltimateAI-vue/assets/app.js +0 -13
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-html2canvas.esm.js +0 -5
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-index.es.js +0 -5
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-jspdf.es.min.js +0 -79
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-purify.es.js +0 -3
- package/nodes/plugins/knxUltimateAI-vue/index.html +0 -13
- package/nodes/utils/HueEventStream.mjs +0 -176
- package/nodes/utils/colorManipulators/XYFromRGB_Supergiovane.js +0 -113
- package/nodes/utils/colorManipulators/hueColorConverter.js +0 -521
- package/nodes/utils/http.js +0 -291
- package/nodes/utils/hueControllerProfileAdapter.js +0 -104
- package/nodes/utils/hueControllerProfiles/runtime/area_motion.js +0 -221
- package/nodes/utils/hueControllerProfiles/runtime/button.js +0 -295
- package/nodes/utils/hueControllerProfiles/runtime/camera_motion.js +0 -221
- package/nodes/utils/hueControllerProfiles/runtime/contact.js +0 -191
- package/nodes/utils/hueControllerProfiles/runtime/device_power.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/device_software_update.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/humidity.js +0 -204
- package/nodes/utils/hueControllerProfiles/runtime/light.js +0 -1585
- package/nodes/utils/hueControllerProfiles/runtime/light_level.js +0 -180
- package/nodes/utils/hueControllerProfiles/runtime/motion.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/plug.js +0 -344
- package/nodes/utils/hueControllerProfiles/runtime/relative_rotary.js +0 -271
- package/nodes/utils/hueControllerProfiles/runtime/scene.js +0 -352
- package/nodes/utils/hueControllerProfiles/runtime/temperature.js +0 -187
- package/nodes/utils/hueControllerProfiles/runtime/zigbee_connectivity.js +0 -185
- package/nodes/utils/hueControllerResourceCatalog.js +0 -71
- package/nodes/utils/hueEngine.mjs +0 -469
- package/nodes/utils/knxAiCamera.js +0 -302
- package/nodes/utils/knxAiCatalogRetrieval.js +0 -349
- package/nodes/utils/knxAiCerebrum.js +0 -406
- package/nodes/utils/knxAiChatContext.js +0 -496
- package/nodes/utils/knxAiEventHistory.js +0 -521
- package/nodes/utils/knxAiHomeMemory.js +0 -1021
- package/nodes/utils/knxAiScheduler.js +0 -445
- package/nodes/utils/knxAiSemanticContext.js +0 -662
- package/nodes/utils/knxAiTelegramVoice.js +0 -545
- package/nodes/utils/knxAiWebAccess.js +0 -631
- package/nodes/utils/lightEngines/canonicalLight.js +0 -75
- package/nodes/utils/lightEngines/hueLightEngine.js +0 -51
- package/nodes/utils/lightEngines/index.js +0 -25
- package/nodes/utils/lightEngines/knxLightCommand.js +0 -79
- package/nodes/utils/lightEngines/lightEngine.js +0 -46
- package/nodes/utils/lightEngines/matterHueShim.js +0 -59
- package/nodes/utils/lightEngines/matterLightEngine.js +0 -117
- package/nodes/utils/matterBridgeDeviceFactory.mjs +0 -780
- package/nodes/utils/matterBridgeEngine.mjs +0 -297
- package/nodes/utils/matterControllerCommandGate.js +0 -47
- package/nodes/utils/matterControllerProfiles/doorLock.js +0 -258
- package/nodes/utils/matterControllerProfiles/fan.js +0 -19
- package/nodes/utils/matterControllerProfiles/index.js +0 -34
- package/nodes/utils/matterControllerProfiles/mappedEndpoint.js +0 -217
- package/nodes/utils/matterControllerProfiles/switch.js +0 -13
- package/nodes/utils/matterControllerProfiles/thermostat.js +0 -19
- package/nodes/utils/matterControllerProfiles/universal.js +0 -462
- package/nodes/utils/matterControllerProfiles/windowCovering.js +0 -19
- package/nodes/utils/matterControllerSemanticInput.js +0 -212
- package/nodes/utils/matterEngine.mjs +0 -894
- package/nodes/utils/matterEnvironmentLock.mjs +0 -32
- package/nodes/utils/matterKnxConverter.js +0 -204
- package/nodes/utils/matterStorageBackup.js +0 -100
- package/resources/HA-icon.png +0 -0
- package/resources/dim.png +0 -0
- package/resources/rgb.png +0 -0
- package/resources/tunablewhite.png +0 -0
- package/resources/zxing-browser-0.2.0.min.js +0 -1
- package/resources/zxing-browser-LICENSE.txt +0 -21
|
@@ -1,545 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
|
-
const KNX_AI_TELEGRAM_VOICE_MAX_BYTES = 20 * 1024 * 1024
|
|
4
|
-
const KNX_AI_TELEGRAM_VOICE_MAX_DURATION_SECONDS = 5 * 60
|
|
5
|
-
const KNX_AI_VOICE_API_TIMEOUT_MS = 120000
|
|
6
|
-
const KNX_AI_VOICE_TRANSCRIPTION_MODEL = 'gpt-4o-mini-transcribe'
|
|
7
|
-
const KNX_AI_VOICE_SPEECH_MODEL = 'gpt-4o-mini-tts'
|
|
8
|
-
const KNX_AI_VOICE_SPEECH_VOICE = 'alloy'
|
|
9
|
-
const KNX_AI_VOICE_SPEECH_MAX_CHARS = 4096
|
|
10
|
-
const KNX_AI_VOICE_DEFAULT_BASE_URL = 'https://api.openai.com/v1'
|
|
11
|
-
|
|
12
|
-
const normalizeKnxAiLlmProvider = (value) => {
|
|
13
|
-
const normalized = String(value || '').trim().toLowerCase().replace(/[ -]+/g, '_')
|
|
14
|
-
if (!normalized || normalized === 'openai' || normalized === 'openai_compatible') return 'openai_compat'
|
|
15
|
-
return normalized
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const isKnxAiOpenAiCompatibleChatProvider = (value) => {
|
|
19
|
-
const provider = normalizeKnxAiLlmProvider(value)
|
|
20
|
-
return provider === 'openai_compat'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const resolveKnxAiVoiceServiceConfig = ({
|
|
24
|
-
chatProvider,
|
|
25
|
-
chatBaseUrl,
|
|
26
|
-
chatApiKey
|
|
27
|
-
} = {}) => {
|
|
28
|
-
const provider = normalizeKnxAiLlmProvider(chatProvider)
|
|
29
|
-
const chatCompatible = isKnxAiOpenAiCompatibleChatProvider(provider)
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
apiKey: chatCompatible ? String(chatApiKey || '').trim() : '',
|
|
33
|
-
baseUrl: chatCompatible ? (String(chatBaseUrl || '').trim() || KNX_AI_VOICE_DEFAULT_BASE_URL) : '',
|
|
34
|
-
chatCompatible,
|
|
35
|
-
chatProvider: provider,
|
|
36
|
-
source: chatCompatible ? 'chat' : 'unconfigured',
|
|
37
|
-
speechModel: KNX_AI_VOICE_SPEECH_MODEL,
|
|
38
|
-
speechVoice: KNX_AI_VOICE_SPEECH_VOICE,
|
|
39
|
-
transcriptionModel: KNX_AI_VOICE_TRANSCRIPTION_MODEL
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const isOfficialOpenAiVoiceUrl = (value) => {
|
|
44
|
-
try {
|
|
45
|
-
const parsed = new URL(String(value || '').trim())
|
|
46
|
-
const hostname = parsed.hostname.toLowerCase()
|
|
47
|
-
return parsed.protocol === 'https:' && (hostname === 'api.openai.com' || hostname.endsWith('.api.openai.com'))
|
|
48
|
-
} catch (error) {
|
|
49
|
-
return false
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const normalizeVoiceMediaType = (value) => {
|
|
54
|
-
const normalized = String(value || '').split(';')[0].trim().toLowerCase()
|
|
55
|
-
return normalized.startsWith('audio/') ? normalized : 'audio/ogg'
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const extensionForVoiceMediaType = (mediaType) => {
|
|
59
|
-
const normalized = normalizeVoiceMediaType(mediaType)
|
|
60
|
-
if (normalized === 'audio/mpeg' || normalized === 'audio/mp3') return '.mp3'
|
|
61
|
-
if (normalized === 'audio/mp4' || normalized === 'audio/m4a' || normalized === 'audio/x-m4a') return '.m4a'
|
|
62
|
-
if (normalized === 'audio/wav' || normalized === 'audio/x-wav') return '.wav'
|
|
63
|
-
if (normalized === 'audio/webm') return '.webm'
|
|
64
|
-
return '.ogg'
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const sanitizeVoiceFilename = ({ filename, mediaType, fallback = 'telegram-voice' } = {}) => {
|
|
68
|
-
const source = path.basename(String(filename || '').trim()).replace(/[^a-zA-Z0-9._-]/g, '-')
|
|
69
|
-
if (source) return source.slice(0, 240)
|
|
70
|
-
return `${fallback}${extensionForVoiceMediaType(mediaType)}`
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const getAiVoiceDisclosure = (language) => {
|
|
74
|
-
const normalized = String(language || '').trim().toLowerCase().split(/[-_]/)[0]
|
|
75
|
-
const labels = {
|
|
76
|
-
de: 'KI-generierte Stimme',
|
|
77
|
-
en: 'AI-generated voice',
|
|
78
|
-
es: 'Voz generada por IA',
|
|
79
|
-
fr: 'Voix générée par l’IA',
|
|
80
|
-
it: 'Voce generata dall’IA',
|
|
81
|
-
zh: 'AI 生成的语音'
|
|
82
|
-
}
|
|
83
|
-
return labels[normalized] || labels.en
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const deriveOpenAiCompatibleAudioUrl = (baseUrl, resource = 'transcriptions') => {
|
|
87
|
-
const resourceName = String(resource || '').trim().toLowerCase()
|
|
88
|
-
if (resourceName !== 'transcriptions' && resourceName !== 'speech') {
|
|
89
|
-
throw new Error(`Unsupported OpenAI audio resource '${resourceName}'`)
|
|
90
|
-
}
|
|
91
|
-
let parsed
|
|
92
|
-
try {
|
|
93
|
-
parsed = new URL(String(baseUrl || 'https://api.openai.com/v1/chat/completions').trim())
|
|
94
|
-
} catch (error) {
|
|
95
|
-
throw new Error('Invalid OpenAI-compatible base URL for voice processing')
|
|
96
|
-
}
|
|
97
|
-
if (parsed.username || parsed.password) throw new Error('OpenAI-compatible voice URL must not contain credentials')
|
|
98
|
-
const pathname = parsed.pathname.replace(/\/+$/, '') || '/v1'
|
|
99
|
-
const terminalPaths = ['/chat/completions', '/completions', '/responses']
|
|
100
|
-
const terminal = terminalPaths.find(item => pathname.endsWith(item))
|
|
101
|
-
let apiRoot = terminal ? pathname.slice(0, -terminal.length) : pathname
|
|
102
|
-
if (!terminal && !/\/v1$/i.test(apiRoot)) {
|
|
103
|
-
const versionIndex = apiRoot.toLowerCase().lastIndexOf('/v1/')
|
|
104
|
-
if (versionIndex >= 0) apiRoot = apiRoot.slice(0, versionIndex + 3)
|
|
105
|
-
}
|
|
106
|
-
parsed.pathname = `${apiRoot.replace(/\/+$/, '')}/audio/${resourceName}`
|
|
107
|
-
parsed.hash = ''
|
|
108
|
-
return parsed.toString()
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const findTelegramVoiceMetadata = (message) => {
|
|
112
|
-
const source = message && typeof message === 'object' ? message : {}
|
|
113
|
-
const original = source.originalMessage && typeof source.originalMessage === 'object'
|
|
114
|
-
? source.originalMessage
|
|
115
|
-
: {}
|
|
116
|
-
if (original.voice && typeof original.voice === 'object') return original.voice
|
|
117
|
-
if (original.message && original.message.voice && typeof original.message.voice === 'object') return original.message.voice
|
|
118
|
-
return {}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const resolveTelegramVoiceAllowedOrigin = (message) => {
|
|
122
|
-
const details = message && message.telegramBot && typeof message.telegramBot === 'object'
|
|
123
|
-
? message.telegramBot
|
|
124
|
-
: {}
|
|
125
|
-
const candidate = String(details.baseApiUrl || details.baseapiurl || details.baseApiURL || '').trim()
|
|
126
|
-
if (!candidate) return 'https://api.telegram.org'
|
|
127
|
-
try { return new URL(candidate).origin } catch (error) { return 'https://api.telegram.org' }
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const applyKnxAiTelegramVoiceInputPresetFallback = ({ preset, message } = {}) => {
|
|
131
|
-
const normalizedPreset = String(preset || '')
|
|
132
|
-
if (!['windkh-telegrambot', 'redbot-telegram'].includes(normalizedPreset) || !message || typeof message !== 'object') return null
|
|
133
|
-
const telegram = message.payload && typeof message.payload === 'object' ? message.payload : null
|
|
134
|
-
if (!telegram) return null
|
|
135
|
-
const chatId = telegram.chatId
|
|
136
|
-
if (chatId === undefined || chatId === null || chatId === '') return null
|
|
137
|
-
const original = message.originalMessage && typeof message.originalMessage === 'object'
|
|
138
|
-
? message.originalMessage
|
|
139
|
-
: {}
|
|
140
|
-
const voice = findTelegramVoiceMetadata(message)
|
|
141
|
-
|
|
142
|
-
if (normalizedPreset === 'redbot-telegram') {
|
|
143
|
-
const redbotType = String(telegram.type || '').trim().toLowerCase()
|
|
144
|
-
if ((redbotType !== 'audio' && redbotType !== 'voice') || !Buffer.isBuffer(telegram.content)) return null
|
|
145
|
-
const mediaType = normalizeVoiceMediaType(voice.mime_type || telegram.mimeType)
|
|
146
|
-
message.sessionId = String(chatId)
|
|
147
|
-
message.language = (original.from && original.from.language_code) ||
|
|
148
|
-
(original.message && original.message.from && original.message.from.language_code) ||
|
|
149
|
-
telegram.language ||
|
|
150
|
-
message.language ||
|
|
151
|
-
''
|
|
152
|
-
message.topic = 'ask'
|
|
153
|
-
delete message.prompt
|
|
154
|
-
message.knxAi = Object.assign({}, message.knxAi, {
|
|
155
|
-
sessionId: String(chatId),
|
|
156
|
-
voiceInput: {
|
|
157
|
-
source: 'telegram',
|
|
158
|
-
originalType: 'voice',
|
|
159
|
-
transport: 'redbot-buffer',
|
|
160
|
-
data: telegram.content,
|
|
161
|
-
fileId: String(voice.file_id || '').trim(),
|
|
162
|
-
mediaType,
|
|
163
|
-
filename: sanitizeVoiceFilename({ filename: telegram.filename || voice.file_name, mediaType }),
|
|
164
|
-
durationSeconds: Math.max(0, Number(voice.duration || telegram.duration) || 0),
|
|
165
|
-
fileSize: Math.max(0, Number(voice.file_size || telegram.fileSize) || telegram.content.length)
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
return message
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (telegram.type !== 'voice') return null
|
|
172
|
-
const mediaType = normalizeVoiceMediaType(voice.mime_type || telegram.contentType || telegram.mimeType)
|
|
173
|
-
const fileId = String(telegram.content || voice.file_id || '').trim()
|
|
174
|
-
const weblink = String(telegram.weblink || message.weblink || '').trim()
|
|
175
|
-
if (!fileId && !weblink) return null
|
|
176
|
-
|
|
177
|
-
message.sessionId = String(chatId)
|
|
178
|
-
message.language = (original.from && original.from.language_code) ||
|
|
179
|
-
(original.message && original.message.from && original.message.from.language_code) ||
|
|
180
|
-
message.language ||
|
|
181
|
-
''
|
|
182
|
-
message.topic = 'ask'
|
|
183
|
-
delete message.prompt
|
|
184
|
-
message.knxAi = Object.assign({}, message.knxAi, {
|
|
185
|
-
sessionId: String(chatId),
|
|
186
|
-
voiceInput: {
|
|
187
|
-
source: 'telegram',
|
|
188
|
-
originalType: 'voice',
|
|
189
|
-
fileId,
|
|
190
|
-
weblink,
|
|
191
|
-
allowedOrigin: resolveTelegramVoiceAllowedOrigin(message),
|
|
192
|
-
mediaType,
|
|
193
|
-
filename: sanitizeVoiceFilename({ filename: telegram.filename || voice.file_name, mediaType }),
|
|
194
|
-
durationSeconds: Math.max(0, Number(voice.duration || telegram.duration) || 0),
|
|
195
|
-
fileSize: Math.max(0, Number(voice.file_size || telegram.fileSize) || 0)
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
return message
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const isKnxAiTelegramVoiceInput = (message) => {
|
|
202
|
-
const voiceInput = message && message.knxAi && message.knxAi.voiceInput
|
|
203
|
-
return !!(voiceInput && voiceInput.source === 'telegram' && voiceInput.originalType === 'voice')
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const redactKnxAiTelegramVoiceLocations = (message) => {
|
|
207
|
-
if (!message || typeof message !== 'object') return message
|
|
208
|
-
if (message.payload && typeof message.payload === 'object') {
|
|
209
|
-
message.payload = Object.assign({}, message.payload)
|
|
210
|
-
if (Buffer.isBuffer(message.payload.content)) message.payload.content = ''
|
|
211
|
-
delete message.payload.weblink
|
|
212
|
-
delete message.payload.path
|
|
213
|
-
}
|
|
214
|
-
delete message.weblink
|
|
215
|
-
delete message.path
|
|
216
|
-
if (message.knxAi && message.knxAi.voiceInput && typeof message.knxAi.voiceInput === 'object') {
|
|
217
|
-
const voiceInput = Object.assign({}, message.knxAi.voiceInput)
|
|
218
|
-
delete voiceInput.data
|
|
219
|
-
delete voiceInput.weblink
|
|
220
|
-
delete voiceInput.path
|
|
221
|
-
message.knxAi = Object.assign({}, message.knxAi, { voiceInput })
|
|
222
|
-
}
|
|
223
|
-
return message
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const responseHeader = (response, name) => {
|
|
227
|
-
if (!response || !response.headers) return ''
|
|
228
|
-
if (typeof response.headers.get === 'function') return String(response.headers.get(name) || '')
|
|
229
|
-
const normalizedName = String(name || '').toLowerCase()
|
|
230
|
-
const entry = Object.entries(response.headers).find(([key]) => String(key).toLowerCase() === normalizedName)
|
|
231
|
-
return entry ? String(entry[1] || '') : ''
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const readBoundedResponseBuffer = async (response, maxBytes) => {
|
|
235
|
-
const limit = Math.max(1, Number(maxBytes) || KNX_AI_TELEGRAM_VOICE_MAX_BYTES)
|
|
236
|
-
const declaredLength = Number(responseHeader(response, 'content-length'))
|
|
237
|
-
if (Number.isFinite(declaredLength) && declaredLength > limit) {
|
|
238
|
-
throw new Error(`Voice audio exceeds the ${Math.round(limit / (1024 * 1024))} MB limit`)
|
|
239
|
-
}
|
|
240
|
-
if (response && response.body && typeof response.body.getReader === 'function') {
|
|
241
|
-
const reader = response.body.getReader()
|
|
242
|
-
const chunks = []
|
|
243
|
-
let total = 0
|
|
244
|
-
try {
|
|
245
|
-
while (true) {
|
|
246
|
-
const part = await reader.read()
|
|
247
|
-
if (part.done) break
|
|
248
|
-
const chunk = Buffer.from(part.value)
|
|
249
|
-
total += chunk.length
|
|
250
|
-
if (total > limit) {
|
|
251
|
-
try { await reader.cancel() } catch (error) { /* ignore */ }
|
|
252
|
-
throw new Error(`Voice audio exceeds the ${Math.round(limit / (1024 * 1024))} MB limit`)
|
|
253
|
-
}
|
|
254
|
-
chunks.push(chunk)
|
|
255
|
-
}
|
|
256
|
-
} finally {
|
|
257
|
-
try { reader.releaseLock() } catch (error) { /* ignore */ }
|
|
258
|
-
}
|
|
259
|
-
return Buffer.concat(chunks, total)
|
|
260
|
-
}
|
|
261
|
-
if (!response || typeof response.arrayBuffer !== 'function') throw new Error('Voice download returned no audio data')
|
|
262
|
-
const data = Buffer.from(await response.arrayBuffer())
|
|
263
|
-
if (data.length > limit) throw new Error(`Voice audio exceeds the ${Math.round(limit / (1024 * 1024))} MB limit`)
|
|
264
|
-
return data
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const extractAudioApiError = (text) => {
|
|
268
|
-
const raw = String(text || '').trim()
|
|
269
|
-
if (!raw) return ''
|
|
270
|
-
try {
|
|
271
|
-
const json = JSON.parse(raw)
|
|
272
|
-
const candidate = json && json.error && json.error.message
|
|
273
|
-
? json.error.message
|
|
274
|
-
: json && (json.message || json.detail || json.error)
|
|
275
|
-
if (candidate) return String(candidate).replace(/\s+/g, ' ').trim().slice(0, 1200)
|
|
276
|
-
} catch (error) { /* use response text */ }
|
|
277
|
-
return raw.replace(/\s+/g, ' ').slice(0, 1200)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const fetchKnxAiTelegramVoice = async ({
|
|
281
|
-
voiceInput,
|
|
282
|
-
fetchImpl = globalThis.fetch,
|
|
283
|
-
timeoutMs = KNX_AI_VOICE_API_TIMEOUT_MS,
|
|
284
|
-
maxBytes = KNX_AI_TELEGRAM_VOICE_MAX_BYTES
|
|
285
|
-
} = {}) => {
|
|
286
|
-
const source = voiceInput && typeof voiceInput === 'object' ? voiceInput : {}
|
|
287
|
-
const declaredSize = Math.max(0, Number(source.fileSize) || 0)
|
|
288
|
-
if (declaredSize > maxBytes) throw new Error(`Voice audio exceeds the ${Math.round(maxBytes / (1024 * 1024))} MB limit`)
|
|
289
|
-
const declaredDuration = Math.max(0, Number(source.durationSeconds) || 0)
|
|
290
|
-
if (declaredDuration > KNX_AI_TELEGRAM_VOICE_MAX_DURATION_SECONDS) {
|
|
291
|
-
throw new Error(`Voice message exceeds the ${Math.round(KNX_AI_TELEGRAM_VOICE_MAX_DURATION_SECONDS / 60)}-minute limit`)
|
|
292
|
-
}
|
|
293
|
-
const mediaType = normalizeVoiceMediaType(source.mediaType)
|
|
294
|
-
const filename = sanitizeVoiceFilename({ filename: source.filename, mediaType })
|
|
295
|
-
if (Buffer.isBuffer(source.data)) {
|
|
296
|
-
if (!source.data.length) throw new Error('Telegram returned an empty voice message')
|
|
297
|
-
if (source.data.length > maxBytes) throw new Error(`Voice audio exceeds the ${Math.round(maxBytes / (1024 * 1024))} MB limit`)
|
|
298
|
-
return {
|
|
299
|
-
data: Buffer.from(source.data),
|
|
300
|
-
mediaType,
|
|
301
|
-
filename,
|
|
302
|
-
source: String(source.transport || 'telegram-buffer')
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
const weblink = String(source.weblink || '').trim()
|
|
306
|
-
if (weblink) {
|
|
307
|
-
let parsed
|
|
308
|
-
try {
|
|
309
|
-
parsed = new URL(weblink)
|
|
310
|
-
} catch (error) {
|
|
311
|
-
throw new Error('Telegram returned an invalid voice download link')
|
|
312
|
-
}
|
|
313
|
-
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
314
|
-
throw new Error('Telegram voice download link must use HTTP or HTTPS')
|
|
315
|
-
}
|
|
316
|
-
if (parsed.username || parsed.password) throw new Error('Telegram voice download link must not contain credentials')
|
|
317
|
-
const allowedOrigin = String(source.allowedOrigin || 'https://api.telegram.org').trim()
|
|
318
|
-
if (parsed.origin !== allowedOrigin) throw new Error('Telegram voice download link has an unexpected origin')
|
|
319
|
-
if (typeof fetchImpl !== 'function') throw new Error('Voice download is unavailable in this Node.js runtime')
|
|
320
|
-
const controller = new AbortController()
|
|
321
|
-
const timer = setTimeout(() => controller.abort(), Math.max(1000, Number(timeoutMs) || KNX_AI_VOICE_API_TIMEOUT_MS))
|
|
322
|
-
try {
|
|
323
|
-
let response
|
|
324
|
-
try {
|
|
325
|
-
response = await fetchImpl(parsed.toString(), { signal: controller.signal, redirect: 'manual' })
|
|
326
|
-
} catch (error) {
|
|
327
|
-
if (error && error.name === 'AbortError') throw new Error('Telegram voice download timed out')
|
|
328
|
-
throw new Error('Telegram voice download failed (network error)')
|
|
329
|
-
}
|
|
330
|
-
if (!response || !response.ok) {
|
|
331
|
-
const status = response && response.status ? `HTTP ${response.status}` : 'network error'
|
|
332
|
-
throw new Error(`Telegram voice download failed (${status})`)
|
|
333
|
-
}
|
|
334
|
-
const data = await readBoundedResponseBuffer(response, maxBytes)
|
|
335
|
-
if (!data.length) throw new Error('Telegram returned an empty voice message')
|
|
336
|
-
return {
|
|
337
|
-
data,
|
|
338
|
-
mediaType: normalizeVoiceMediaType(responseHeader(response, 'content-type') || mediaType),
|
|
339
|
-
filename,
|
|
340
|
-
source: 'telegram-weblink'
|
|
341
|
-
}
|
|
342
|
-
} finally {
|
|
343
|
-
clearTimeout(timer)
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
throw new Error('Telegram did not provide a downloadable voice link')
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const postKnxAiVoiceTranscription = async ({
|
|
351
|
-
url,
|
|
352
|
-
apiKey,
|
|
353
|
-
audio,
|
|
354
|
-
model = KNX_AI_VOICE_TRANSCRIPTION_MODEL,
|
|
355
|
-
language = '',
|
|
356
|
-
fetchImpl = globalThis.fetch,
|
|
357
|
-
timeoutMs = KNX_AI_VOICE_API_TIMEOUT_MS
|
|
358
|
-
} = {}) => {
|
|
359
|
-
if (!audio || !Buffer.isBuffer(audio.data) || !audio.data.length) throw new Error('Missing voice audio to transcribe')
|
|
360
|
-
if (typeof fetchImpl !== 'function' || typeof globalThis.FormData !== 'function' || typeof globalThis.Blob !== 'function') {
|
|
361
|
-
throw new Error('Voice transcription requires Node.js FormData support')
|
|
362
|
-
}
|
|
363
|
-
const form = new globalThis.FormData()
|
|
364
|
-
form.append('file', new globalThis.Blob([audio.data], { type: normalizeVoiceMediaType(audio.mediaType) }), sanitizeVoiceFilename(audio))
|
|
365
|
-
form.append('model', String(model || KNX_AI_VOICE_TRANSCRIPTION_MODEL))
|
|
366
|
-
const normalizedLanguage = String(language || '').trim().toLowerCase().split(/[-_]/)[0]
|
|
367
|
-
if (/^[a-z]{2,3}$/.test(normalizedLanguage)) form.append('language', normalizedLanguage)
|
|
368
|
-
const controller = new AbortController()
|
|
369
|
-
const timer = setTimeout(() => controller.abort(), Math.max(1000, Number(timeoutMs) || KNX_AI_VOICE_API_TIMEOUT_MS))
|
|
370
|
-
try {
|
|
371
|
-
let response
|
|
372
|
-
try {
|
|
373
|
-
response = await fetchImpl(url, {
|
|
374
|
-
method: 'POST',
|
|
375
|
-
headers: apiKey ? { authorization: `Bearer ${apiKey}` } : {},
|
|
376
|
-
body: form,
|
|
377
|
-
signal: controller.signal
|
|
378
|
-
})
|
|
379
|
-
} catch (error) {
|
|
380
|
-
if (error && error.name === 'AbortError') throw new Error('Voice transcription timed out')
|
|
381
|
-
throw new Error('Voice transcription failed (network error)')
|
|
382
|
-
}
|
|
383
|
-
const text = await response.text()
|
|
384
|
-
if (!response.ok) {
|
|
385
|
-
const detail = extractAudioApiError(text)
|
|
386
|
-
throw new Error(detail ? `Voice transcription failed (HTTP ${response.status}: ${detail})` : `Voice transcription failed (HTTP ${response.status})`)
|
|
387
|
-
}
|
|
388
|
-
let json
|
|
389
|
-
try { json = JSON.parse(text) } catch (error) { json = null }
|
|
390
|
-
const transcript = String(json && json.text !== undefined ? json.text : text).trim()
|
|
391
|
-
if (!transcript) throw new Error('Voice transcription returned no text')
|
|
392
|
-
return { text: transcript, model: String(model || KNX_AI_VOICE_TRANSCRIPTION_MODEL) }
|
|
393
|
-
} finally {
|
|
394
|
-
clearTimeout(timer)
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const postKnxAiVoiceSpeech = async ({
|
|
399
|
-
url,
|
|
400
|
-
apiKey,
|
|
401
|
-
text,
|
|
402
|
-
model = KNX_AI_VOICE_SPEECH_MODEL,
|
|
403
|
-
voice = KNX_AI_VOICE_SPEECH_VOICE,
|
|
404
|
-
fetchImpl = globalThis.fetch,
|
|
405
|
-
timeoutMs = KNX_AI_VOICE_API_TIMEOUT_MS,
|
|
406
|
-
maxBytes = KNX_AI_TELEGRAM_VOICE_MAX_BYTES
|
|
407
|
-
} = {}) => {
|
|
408
|
-
const input = String(text === undefined || text === null ? '' : text).trim()
|
|
409
|
-
if (!input) throw new Error('Missing text for voice reply')
|
|
410
|
-
if (input.length > KNX_AI_VOICE_SPEECH_MAX_CHARS) {
|
|
411
|
-
throw new Error(`Voice reply exceeds the ${KNX_AI_VOICE_SPEECH_MAX_CHARS}-character speech limit`)
|
|
412
|
-
}
|
|
413
|
-
if (typeof fetchImpl !== 'function') throw new Error('Voice synthesis is unavailable in this Node.js runtime')
|
|
414
|
-
const controller = new AbortController()
|
|
415
|
-
const timer = setTimeout(() => controller.abort(), Math.max(1000, Number(timeoutMs) || KNX_AI_VOICE_API_TIMEOUT_MS))
|
|
416
|
-
try {
|
|
417
|
-
let response
|
|
418
|
-
try {
|
|
419
|
-
response = await fetchImpl(url, {
|
|
420
|
-
method: 'POST',
|
|
421
|
-
headers: Object.assign(
|
|
422
|
-
{ 'content-type': 'application/json' },
|
|
423
|
-
apiKey ? { authorization: `Bearer ${apiKey}` } : {}
|
|
424
|
-
),
|
|
425
|
-
body: JSON.stringify({
|
|
426
|
-
model: String(model || KNX_AI_VOICE_SPEECH_MODEL),
|
|
427
|
-
voice: String(voice || KNX_AI_VOICE_SPEECH_VOICE),
|
|
428
|
-
input,
|
|
429
|
-
response_format: 'opus'
|
|
430
|
-
}),
|
|
431
|
-
signal: controller.signal
|
|
432
|
-
})
|
|
433
|
-
} catch (error) {
|
|
434
|
-
if (error && error.name === 'AbortError') throw new Error('Voice synthesis timed out')
|
|
435
|
-
throw new Error('Voice synthesis failed (network error)')
|
|
436
|
-
}
|
|
437
|
-
if (!response.ok) {
|
|
438
|
-
const detail = extractAudioApiError(await response.text())
|
|
439
|
-
throw new Error(detail ? `Voice synthesis failed (HTTP ${response.status}: ${detail})` : `Voice synthesis failed (HTTP ${response.status})`)
|
|
440
|
-
}
|
|
441
|
-
const data = await readBoundedResponseBuffer(response, maxBytes)
|
|
442
|
-
if (!data.length) throw new Error('Voice synthesis returned no audio')
|
|
443
|
-
return {
|
|
444
|
-
data,
|
|
445
|
-
mediaType: 'audio/ogg',
|
|
446
|
-
filename: 'knx-ai-reply.ogg',
|
|
447
|
-
model: String(model || KNX_AI_VOICE_SPEECH_MODEL),
|
|
448
|
-
voice: String(voice || KNX_AI_VOICE_SPEECH_VOICE)
|
|
449
|
-
}
|
|
450
|
-
} finally {
|
|
451
|
-
clearTimeout(timer)
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
const applyKnxAiTelegramVoiceOutputPresetFallback = ({ preset, message, inputMessage } = {}) => {
|
|
456
|
-
const normalizedPreset = String(preset || '')
|
|
457
|
-
if (!['windkh-telegrambot', 'redbot-telegram'].includes(normalizedPreset) || !message || typeof message !== 'object') return message
|
|
458
|
-
const audio = message.knxAi && message.knxAi.audio
|
|
459
|
-
if (!audio || !Buffer.isBuffer(audio.data) || !audio.data.length) return message
|
|
460
|
-
const currentPayload = message.payload && typeof message.payload === 'object' ? message.payload : null
|
|
461
|
-
if (currentPayload && (currentPayload.type === 'voice' || currentPayload.type === 'audio' || currentPayload.type === 'photo')) return message
|
|
462
|
-
if (normalizedPreset === 'redbot-telegram' && currentPayload && currentPayload.type === 'inline-buttons') return message
|
|
463
|
-
const confirmation = message.knxAi && message.knxAi.confirmationRequest
|
|
464
|
-
if (normalizedPreset === 'redbot-telegram' && confirmation && confirmation.required === true) return message
|
|
465
|
-
const source = inputMessage && typeof inputMessage === 'object'
|
|
466
|
-
? inputMessage
|
|
467
|
-
: message.inputMessage && typeof message.inputMessage === 'object'
|
|
468
|
-
? message.inputMessage
|
|
469
|
-
: message
|
|
470
|
-
const sourcePayload = source.payload && typeof source.payload === 'object' ? source.payload : {}
|
|
471
|
-
const chatId = currentPayload && currentPayload.chatId !== undefined
|
|
472
|
-
? currentPayload.chatId
|
|
473
|
-
: sourcePayload.chatId !== undefined
|
|
474
|
-
? sourcePayload.chatId
|
|
475
|
-
: source.chatId
|
|
476
|
-
if (chatId === undefined || chatId === null || chatId === '') return message
|
|
477
|
-
let caption = currentPayload ? currentPayload.content : message.payload
|
|
478
|
-
if (caption && typeof caption === 'object') caption = caption.error || caption.message || ''
|
|
479
|
-
const language = message.knxAi && message.knxAi.language
|
|
480
|
-
? message.knxAi.language
|
|
481
|
-
: source.language
|
|
482
|
-
caption = [getAiVoiceDisclosure(language), String(caption === undefined || caption === null ? '' : caption)]
|
|
483
|
-
.filter(Boolean)
|
|
484
|
-
.join('\n')
|
|
485
|
-
.slice(0, 1024)
|
|
486
|
-
|
|
487
|
-
if (normalizedPreset === 'redbot-telegram') {
|
|
488
|
-
const transport = currentPayload && currentPayload.transport
|
|
489
|
-
? currentPayload.transport
|
|
490
|
-
: sourcePayload.transport || 'telegram'
|
|
491
|
-
const userId = currentPayload && currentPayload.userId !== undefined
|
|
492
|
-
? currentPayload.userId
|
|
493
|
-
: sourcePayload.userId
|
|
494
|
-
message.payload = {
|
|
495
|
-
transport,
|
|
496
|
-
chatId,
|
|
497
|
-
type: 'audio',
|
|
498
|
-
inbound: false,
|
|
499
|
-
content: audio.data,
|
|
500
|
-
filename: sanitizeVoiceFilename({ filename: audio.filename, mediaType: audio.mediaType, fallback: 'knx-ai-reply' }),
|
|
501
|
-
mimeType: normalizeVoiceMediaType(audio.mediaType),
|
|
502
|
-
caption
|
|
503
|
-
}
|
|
504
|
-
if (userId !== undefined) message.payload.userId = userId
|
|
505
|
-
return message
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const options = Object.assign({}, currentPayload && currentPayload.options ? currentPayload.options : {})
|
|
509
|
-
if (caption) options.caption = caption
|
|
510
|
-
message.payload = {
|
|
511
|
-
chatId,
|
|
512
|
-
type: 'voice',
|
|
513
|
-
content: audio.data,
|
|
514
|
-
options,
|
|
515
|
-
fileOptions: {
|
|
516
|
-
filename: sanitizeVoiceFilename({ filename: audio.filename, mediaType: audio.mediaType, fallback: 'knx-ai-reply' }),
|
|
517
|
-
contentType: normalizeVoiceMediaType(audio.mediaType)
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return message
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
module.exports = {
|
|
524
|
-
KNX_AI_TELEGRAM_VOICE_MAX_BYTES,
|
|
525
|
-
KNX_AI_TELEGRAM_VOICE_MAX_DURATION_SECONDS,
|
|
526
|
-
KNX_AI_VOICE_API_TIMEOUT_MS,
|
|
527
|
-
KNX_AI_VOICE_DEFAULT_BASE_URL,
|
|
528
|
-
KNX_AI_VOICE_SPEECH_MAX_CHARS,
|
|
529
|
-
KNX_AI_VOICE_SPEECH_MODEL,
|
|
530
|
-
KNX_AI_VOICE_SPEECH_VOICE,
|
|
531
|
-
KNX_AI_VOICE_TRANSCRIPTION_MODEL,
|
|
532
|
-
applyKnxAiTelegramVoiceInputPresetFallback,
|
|
533
|
-
applyKnxAiTelegramVoiceOutputPresetFallback,
|
|
534
|
-
deriveOpenAiCompatibleAudioUrl,
|
|
535
|
-
fetchKnxAiTelegramVoice,
|
|
536
|
-
isKnxAiOpenAiCompatibleChatProvider,
|
|
537
|
-
isKnxAiTelegramVoiceInput,
|
|
538
|
-
isOfficialOpenAiVoiceUrl,
|
|
539
|
-
normalizeKnxAiLlmProvider,
|
|
540
|
-
postKnxAiVoiceSpeech,
|
|
541
|
-
postKnxAiVoiceTranscription,
|
|
542
|
-
readBoundedResponseBuffer,
|
|
543
|
-
redactKnxAiTelegramVoiceLocations,
|
|
544
|
-
resolveKnxAiVoiceServiceConfig
|
|
545
|
-
}
|