node-red-contrib-knx-ultimate 6.3.25 → 6.3.26
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 +9 -1
- package/examples/KNX AI - Conversational Control with Confirmation.json +4 -2
- package/examples/KNX AI - Summary Anomalies and Ask.json +4 -0
- package/examples/KNX AI - Telegrambot Direct Chat.json +7 -5
- package/nodes/knxUltimateAI.html +310 -124
- package/nodes/knxUltimateAI.js +1742 -264
- package/nodes/locales/de/knxUltimateAI.html +33 -7
- package/nodes/locales/de/knxUltimateAI.json +34 -15
- package/nodes/locales/en/knxUltimateAI.html +33 -7
- package/nodes/locales/en/knxUltimateAI.json +34 -15
- package/nodes/locales/es/knxUltimateAI.html +33 -7
- package/nodes/locales/es/knxUltimateAI.json +34 -15
- package/nodes/locales/fr/knxUltimateAI.html +33 -7
- package/nodes/locales/fr/knxUltimateAI.json +34 -15
- package/nodes/locales/it/knxUltimateAI.html +33 -7
- package/nodes/locales/it/knxUltimateAI.json +34 -15
- package/nodes/locales/zh-CN/knxUltimateAI.html +33 -7
- package/nodes/locales/zh-CN/knxUltimateAI.json +34 -15
- package/nodes/plugins/knxUltimateAI-vue/assets/app.css +1 -1
- package/nodes/plugins/knxUltimateAI-vue/assets/app.js +4 -4
- package/nodes/utils/knxAiTelegramVoice.js +475 -0
- package/nodes/utils/knxAiWebAccess.js +631 -0
- package/package.json +1 -1
- package/resources/KNXAIChatAdapterMappings.js +96 -2
package/nodes/knxUltimateAI.html
CHANGED
|
@@ -168,6 +168,7 @@
|
|
|
168
168
|
display: block;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
#knx-ai-setup-doctor-panel,
|
|
171
172
|
#knx-ai-detected-adapters-panel,
|
|
172
173
|
#knx-ai-chat-context-panel,
|
|
173
174
|
#knx-ai-chat-learning-link-panel {
|
|
@@ -186,6 +187,7 @@
|
|
|
186
187
|
margin: 18px 0 0;
|
|
187
188
|
}
|
|
188
189
|
|
|
190
|
+
#knx-ai-setup-doctor-panel>h4,
|
|
189
191
|
#knx-ai-detected-adapters-panel>h4,
|
|
190
192
|
#knx-ai-chat-context-panel>h4,
|
|
191
193
|
#knx-ai-chat-learning-link-panel>h4 {
|
|
@@ -194,6 +196,148 @@
|
|
|
194
196
|
font-weight: 600;
|
|
195
197
|
}
|
|
196
198
|
|
|
199
|
+
#knx-ai-setup-doctor-panel {
|
|
200
|
+
margin: 16px 0 18px;
|
|
201
|
+
border-color: rgba(255, 152, 0, 0.55);
|
|
202
|
+
background: linear-gradient(135deg, rgba(255, 152, 0, 0.10), var(--red-ui-secondary-background, #f7f7f7));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#knx-ai-setup-doctor-panel.status-ready {
|
|
206
|
+
border-color: rgba(46, 125, 50, 0.55);
|
|
207
|
+
background: linear-gradient(135deg, rgba(46, 125, 50, 0.10), var(--red-ui-secondary-background, #f7f7f7));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
#knx-ai-setup-doctor-panel.status-blocked {
|
|
211
|
+
border-color: rgba(198, 40, 40, 0.52);
|
|
212
|
+
background: linear-gradient(135deg, rgba(198, 40, 40, 0.09), var(--red-ui-secondary-background, #f7f7f7));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.knx-ai-setup-doctor-hero {
|
|
216
|
+
display: flex;
|
|
217
|
+
align-items: flex-start;
|
|
218
|
+
gap: 10px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.knx-ai-setup-doctor-summary {
|
|
222
|
+
flex: 1 1 auto;
|
|
223
|
+
min-width: 0;
|
|
224
|
+
line-height: 1.45;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.knx-ai-setup-doctor-score {
|
|
228
|
+
flex: 0 0 auto;
|
|
229
|
+
min-width: 48px;
|
|
230
|
+
padding: 6px 8px;
|
|
231
|
+
border-radius: 16px;
|
|
232
|
+
color: #7a4200;
|
|
233
|
+
background: rgba(255, 152, 0, 0.18);
|
|
234
|
+
text-align: center;
|
|
235
|
+
font-size: 12px;
|
|
236
|
+
font-weight: 700;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#knx-ai-setup-doctor-panel.status-ready .knx-ai-setup-doctor-score {
|
|
240
|
+
color: #256029;
|
|
241
|
+
background: rgba(46, 125, 50, 0.16);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#knx-ai-setup-doctor-panel.status-blocked .knx-ai-setup-doctor-score {
|
|
245
|
+
color: #842029;
|
|
246
|
+
background: rgba(198, 40, 40, 0.14);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.knx-ai-setup-doctor-check {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: flex-start;
|
|
252
|
+
gap: 8px;
|
|
253
|
+
padding: 7px 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.knx-ai-setup-doctor-check+.knx-ai-setup-doctor-check {
|
|
257
|
+
border-top: 1px solid var(--red-ui-form-input-border-color, #ddd);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.knx-ai-setup-doctor-check-copy {
|
|
261
|
+
flex: 1 1 auto;
|
|
262
|
+
min-width: 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.knx-ai-setup-doctor-check-detail,
|
|
266
|
+
#knx-ai-setup-doctor-status,
|
|
267
|
+
.knx-ai-setup-doctor-prompts-hint {
|
|
268
|
+
color: var(--red-ui-secondary-text-color, #777);
|
|
269
|
+
font-size: 12px;
|
|
270
|
+
line-height: 1.4;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.knx-ai-setup-doctor-badge {
|
|
274
|
+
flex: 0 0 auto;
|
|
275
|
+
min-width: 48px;
|
|
276
|
+
padding: 2px 7px;
|
|
277
|
+
border-radius: 10px;
|
|
278
|
+
text-align: center;
|
|
279
|
+
font-size: 11px;
|
|
280
|
+
font-weight: 700;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.knx-ai-setup-doctor-badge.pass {
|
|
284
|
+
color: #256029;
|
|
285
|
+
background: #dff0d8;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.knx-ai-setup-doctor-badge.warn {
|
|
289
|
+
color: #7a5200;
|
|
290
|
+
background: #fff3cd;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.knx-ai-setup-doctor-badge.fail {
|
|
294
|
+
color: #842029;
|
|
295
|
+
background: #f8d7da;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.knx-ai-setup-doctor-badge.info {
|
|
299
|
+
color: #245269;
|
|
300
|
+
background: #d9edf7;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.knx-ai-setup-doctor-prompts {
|
|
304
|
+
margin-top: 12px;
|
|
305
|
+
padding-top: 10px;
|
|
306
|
+
border-top: 1px dashed var(--red-ui-form-input-border-color, #ccc);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.knx-ai-setup-doctor-prompt-list {
|
|
310
|
+
display: flex;
|
|
311
|
+
flex-direction: column;
|
|
312
|
+
gap: 6px;
|
|
313
|
+
margin-top: 8px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.knx-ai-setup-doctor-prompt {
|
|
317
|
+
width: 100%;
|
|
318
|
+
margin: 0 !important;
|
|
319
|
+
text-align: left;
|
|
320
|
+
white-space: normal;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.knx-ai-setup-doctor-footer {
|
|
324
|
+
display: flex;
|
|
325
|
+
align-items: center;
|
|
326
|
+
justify-content: space-between;
|
|
327
|
+
gap: 10px;
|
|
328
|
+
margin-top: 10px;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.knx-ai-setup-doctor-deploy-hint {
|
|
332
|
+
color: var(--red-ui-secondary-text-color, #777);
|
|
333
|
+
font-size: 11px;
|
|
334
|
+
line-height: 1.35;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
#knx-ai-setup-doctor-refresh {
|
|
338
|
+
flex: 0 0 auto;
|
|
339
|
+
}
|
|
340
|
+
|
|
197
341
|
.knx-ai-detected-adapter {
|
|
198
342
|
display: flex;
|
|
199
343
|
align-items: center;
|
|
@@ -266,29 +410,6 @@
|
|
|
266
410
|
font-weight: 600;
|
|
267
411
|
}
|
|
268
412
|
|
|
269
|
-
#knx-ai-tts-ultimate-picker {
|
|
270
|
-
margin-top: 8px;
|
|
271
|
-
padding-top: 12px;
|
|
272
|
-
border-top: 1px solid var(--red-ui-form-input-border-color, #ddd);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
#knx-ai-tts-ultimate-picker label {
|
|
276
|
-
display: block;
|
|
277
|
-
width: 100%;
|
|
278
|
-
margin-bottom: 6px;
|
|
279
|
-
font-weight: 600;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
#node-input-ttsUltimateNodeId {
|
|
283
|
-
width: 100%;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
.knx-ai-tts-ultimate-hint {
|
|
287
|
-
margin-top: 6px;
|
|
288
|
-
color: var(--red-ui-secondary-text-color, #777);
|
|
289
|
-
font-size: 12px;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
413
|
@media (max-width: 900px) {
|
|
293
414
|
#knx-ai-ollama-install-row>label {
|
|
294
415
|
width: 100% !important;
|
|
@@ -320,23 +441,27 @@
|
|
|
320
441
|
llmPromptContextTokens: { value: 16384 },
|
|
321
442
|
llmAllowKnxCommands: { value: false },
|
|
322
443
|
llmRequireCommandConfirmation: { value: true },
|
|
444
|
+
webAccessEnabled: { value: false },
|
|
445
|
+
webProactiveEnabled: { value: false },
|
|
446
|
+
webProactiveIntervalMinutes: { value: 30 },
|
|
447
|
+
webMaxCallsPerHour: { value: 12 },
|
|
323
448
|
chatAdapterPreset: { value: "none" },
|
|
324
449
|
chatInputCode: { value: "" },
|
|
325
450
|
chatOutputCode: { value: "" },
|
|
326
|
-
ttsUltimateNodeId: { value: "" },
|
|
327
451
|
aiEducation: { value: "" }
|
|
328
452
|
},
|
|
329
453
|
credentials: {
|
|
330
454
|
llmApiKey: { type: "password" }
|
|
331
455
|
},
|
|
332
456
|
inputs: 1,
|
|
333
|
-
outputs:
|
|
457
|
+
outputs: 5,
|
|
334
458
|
outputLabels: function (i) {
|
|
335
459
|
switch (i) {
|
|
336
460
|
case 0: return this._('knxUltimateAI.outputs.summary');
|
|
337
461
|
case 1: return this._('knxUltimateAI.outputs.anomalies');
|
|
338
462
|
case 2: return this._('knxUltimateAI.outputs.assistant');
|
|
339
463
|
case 3: return this._('knxUltimateAI.outputs.knxCommands');
|
|
464
|
+
case 4: return this._('knxUltimateAI.outputs.ttsUltimate');
|
|
340
465
|
}
|
|
341
466
|
},
|
|
342
467
|
icon: "node-eye-icon.svg",
|
|
@@ -550,81 +675,6 @@
|
|
|
550
675
|
};
|
|
551
676
|
configureChatAdapterPicker.call(node);
|
|
552
677
|
|
|
553
|
-
const collectEditorTtsUltimateNodes = () => {
|
|
554
|
-
const tabById = new Map();
|
|
555
|
-
const entries = [];
|
|
556
|
-
try {
|
|
557
|
-
RED.nodes.eachNode(function (candidate) {
|
|
558
|
-
if (!candidate || String(candidate.type || "") !== "tab") return;
|
|
559
|
-
tabById.set(String(candidate.id || ""), String(candidate.label || candidate.name || ""));
|
|
560
|
-
});
|
|
561
|
-
RED.nodes.eachNode(function (candidate) {
|
|
562
|
-
if (!candidate || String(candidate.type || "") !== "ttsultimate") return;
|
|
563
|
-
const id = String(candidate.id || "").trim();
|
|
564
|
-
if (!id) return;
|
|
565
|
-
entries.push({
|
|
566
|
-
id: id,
|
|
567
|
-
name: String(candidate.name || "TTS Ultimate"),
|
|
568
|
-
flowId: String(candidate.z || ""),
|
|
569
|
-
flowName: tabById.get(String(candidate.z || "")) || "",
|
|
570
|
-
playerType: String(candidate.playertype || "sonos")
|
|
571
|
-
});
|
|
572
|
-
});
|
|
573
|
-
} catch (error) { }
|
|
574
|
-
return entries;
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
const populateTtsUltimatePicker = (runtimeSummary) => {
|
|
578
|
-
const $pickerContainer = $("#knx-ai-tts-ultimate-picker");
|
|
579
|
-
const $picker = $("#node-input-ttsUltimateNodeId");
|
|
580
|
-
if (!$picker.length) return;
|
|
581
|
-
const byId = new Map();
|
|
582
|
-
const runtimeNodes = runtimeSummary && Array.isArray(runtimeSummary.nodes) ? runtimeSummary.nodes : [];
|
|
583
|
-
runtimeNodes.forEach(function (item) {
|
|
584
|
-
if (item && item.id) byId.set(String(item.id), item);
|
|
585
|
-
});
|
|
586
|
-
collectEditorTtsUltimateNodes().forEach(function (item) {
|
|
587
|
-
byId.set(String(item.id), item);
|
|
588
|
-
});
|
|
589
|
-
const entries = Array.from(byId.values()).sort(function (left, right) {
|
|
590
|
-
return String((left.flowName || "") + "\u0000" + (left.name || "") + "\u0000" + left.id)
|
|
591
|
-
.localeCompare(String((right.flowName || "") + "\u0000" + (right.name || "") + "\u0000" + right.id));
|
|
592
|
-
});
|
|
593
|
-
const configuredId = String(node.ttsUltimateNodeId || "").trim();
|
|
594
|
-
$picker.empty();
|
|
595
|
-
$("<option></option>")
|
|
596
|
-
.attr("value", "")
|
|
597
|
-
.text(entries.length
|
|
598
|
-
? t("knxUltimateAI.selectlists.ttsUltimate.select", "Select a TTS Ultimate node")
|
|
599
|
-
: t("knxUltimateAI.selectlists.ttsUltimate.none", "No TTS Ultimate node found"))
|
|
600
|
-
.appendTo($picker);
|
|
601
|
-
entries.forEach(function (item) {
|
|
602
|
-
const flowName = String(item.flowName || t("knxUltimateAI.messages.ttsUltimateUnknownFlow", "Flow without name"));
|
|
603
|
-
const playerType = String(item.playerType || "sonos");
|
|
604
|
-
$("<option></option>")
|
|
605
|
-
.attr("value", item.id)
|
|
606
|
-
.text(flowName + " · " + String(item.name || "TTS Ultimate") + " · " + playerType)
|
|
607
|
-
.appendTo($picker);
|
|
608
|
-
});
|
|
609
|
-
if (configuredId && !byId.has(configuredId)) {
|
|
610
|
-
$("<option></option>")
|
|
611
|
-
.attr("value", configuredId)
|
|
612
|
-
.text(t("knxUltimateAI.messages.ttsUltimateUnavailable", "Unavailable TTS Ultimate node") + " · " + configuredId)
|
|
613
|
-
.appendTo($picker);
|
|
614
|
-
}
|
|
615
|
-
if (configuredId) {
|
|
616
|
-
$picker.val(configuredId);
|
|
617
|
-
} else if (entries.length === 1) {
|
|
618
|
-
$picker.val(entries[0].id);
|
|
619
|
-
} else {
|
|
620
|
-
$picker.val("");
|
|
621
|
-
}
|
|
622
|
-
const detected = entries.length > 0 || !!(runtimeSummary && runtimeSummary.detected);
|
|
623
|
-
$picker.prop("disabled", entries.length === 0 && !configuredId);
|
|
624
|
-
$pickerContainer.toggle(detected || !!configuredId);
|
|
625
|
-
};
|
|
626
|
-
populateTtsUltimatePicker(null);
|
|
627
|
-
|
|
628
678
|
const renderDetectedAdapters = (adapters) => {
|
|
629
679
|
const $list = $("#knx-ai-detected-adapters-list");
|
|
630
680
|
const $status = $("#knx-ai-detected-adapters-status");
|
|
@@ -632,7 +682,7 @@
|
|
|
632
682
|
$list.empty();
|
|
633
683
|
const entries = Array.isArray(adapters) ? adapters : [];
|
|
634
684
|
if (!entries.length) {
|
|
635
|
-
$status.text(t("knxUltimateAI.messages.detectedAdaptersNone", "No
|
|
685
|
+
$status.text(t("knxUltimateAI.messages.detectedAdaptersNone", "No compatible node detected.")).show();
|
|
636
686
|
return;
|
|
637
687
|
}
|
|
638
688
|
$status.hide();
|
|
@@ -662,6 +712,60 @@
|
|
|
662
712
|
});
|
|
663
713
|
};
|
|
664
714
|
|
|
715
|
+
const renderSetupDoctor = (snapshot) => {
|
|
716
|
+
const $panel = $("#knx-ai-setup-doctor-panel");
|
|
717
|
+
const $status = $("#knx-ai-setup-doctor-status");
|
|
718
|
+
const $content = $("#knx-ai-setup-doctor-content");
|
|
719
|
+
const $checks = $("#knx-ai-setup-doctor-checks").empty();
|
|
720
|
+
const $prompts = $("#knx-ai-setup-doctor-prompt-list").empty();
|
|
721
|
+
if (!snapshot || typeof snapshot !== "object") {
|
|
722
|
+
$panel.removeClass("status-ready status-attention status-blocked");
|
|
723
|
+
$content.hide();
|
|
724
|
+
$status.text(t("knxUltimateAI.messages.setupDoctorUnavailable", "Setup Doctor is temporarily unavailable.")).show();
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const badgeLabels = {
|
|
728
|
+
pass: t("knxUltimateAI.messages.setupDoctorPass", "OK"),
|
|
729
|
+
warn: t("knxUltimateAI.messages.setupDoctorWarn", "Check"),
|
|
730
|
+
fail: t("knxUltimateAI.messages.setupDoctorFail", "Fix"),
|
|
731
|
+
info: t("knxUltimateAI.messages.setupDoctorInfo", "Optional")
|
|
732
|
+
};
|
|
733
|
+
const snapshotStatus = ["ready", "attention", "blocked"].includes(String(snapshot.status)) ? String(snapshot.status) : "attention";
|
|
734
|
+
$panel.removeClass("status-ready status-attention status-blocked").addClass("status-" + snapshotStatus);
|
|
735
|
+
$("#knx-ai-setup-doctor-state").text(String(snapshot.statusLabel || snapshot.status || ""));
|
|
736
|
+
$("#knx-ai-setup-doctor-summary").text(String(snapshot.summary || ""));
|
|
737
|
+
$("#knx-ai-setup-doctor-score").text(String(Math.max(0, Number(snapshot.score) || 0)) + "%");
|
|
738
|
+
(Array.isArray(snapshot.checks) ? snapshot.checks : []).forEach(function (check) {
|
|
739
|
+
if (!check || !check.id) return;
|
|
740
|
+
const statusName = ["pass", "warn", "fail", "info"].includes(String(check.status)) ? String(check.status) : "info";
|
|
741
|
+
const $row = $("<div></div>").addClass("knx-ai-setup-doctor-check");
|
|
742
|
+
const $copy = $("<div></div>").addClass("knx-ai-setup-doctor-check-copy");
|
|
743
|
+
$("<strong></strong>").text(String(check.title || check.id)).appendTo($copy);
|
|
744
|
+
$("<div></div>").addClass("knx-ai-setup-doctor-check-detail").text(String(check.detail || "")).appendTo($copy);
|
|
745
|
+
$copy.appendTo($row);
|
|
746
|
+
$("<span></span>")
|
|
747
|
+
.addClass("knx-ai-setup-doctor-badge " + statusName)
|
|
748
|
+
.text(badgeLabels[statusName])
|
|
749
|
+
.appendTo($row);
|
|
750
|
+
$row.appendTo($checks);
|
|
751
|
+
});
|
|
752
|
+
const promptItems = snapshot.firstRun && Array.isArray(snapshot.firstRun.prompts) ? snapshot.firstRun.prompts : [];
|
|
753
|
+
promptItems.forEach(function (prompt) {
|
|
754
|
+
if (!prompt || !prompt.text) return;
|
|
755
|
+
$("<button type=\"button\"></button>")
|
|
756
|
+
.addClass("red-ui-button knx-ai-setup-doctor-prompt")
|
|
757
|
+
.text(String(prompt.text))
|
|
758
|
+
.on("click", function (evt) {
|
|
759
|
+
evt.preventDefault();
|
|
760
|
+
openKnxAiWebPage("assistant", String(prompt.text));
|
|
761
|
+
})
|
|
762
|
+
.appendTo($prompts);
|
|
763
|
+
});
|
|
764
|
+
$(".knx-ai-setup-doctor-prompts").toggle(promptItems.length > 0);
|
|
765
|
+
$status.hide();
|
|
766
|
+
$content.show();
|
|
767
|
+
};
|
|
768
|
+
|
|
665
769
|
const renderChatContextOverview = (overview) => {
|
|
666
770
|
const $status = $("#knx-ai-chat-context-status");
|
|
667
771
|
const $content = $("#knx-ai-chat-context-content");
|
|
@@ -749,8 +853,7 @@
|
|
|
749
853
|
adapterHistory: t("knxUltimateAI.messages.chatContextSourceAdapterHistory", "Persistent history of automatically detected adapter events."),
|
|
750
854
|
etsProject: t("knxUltimateAI.messages.chatContextSourceEtsProject", "ETS semantics and the full Node-RED project inventory."),
|
|
751
855
|
memoryEducation: t("knxUltimateAI.messages.chatContextSourceMemoryEducation", "Session context, AI Education and bounded home memory."),
|
|
752
|
-
cameras: t("knxUltimateAI.messages.chatContextSourceCameras", "Detected cameras and their available capabilities.")
|
|
753
|
-
ttsUltimate: t("knxUltimateAI.messages.chatContextSourceTtsUltimate", "Selected TTS Ultimate announcement target.")
|
|
856
|
+
cameras: t("knxUltimateAI.messages.chatContextSourceCameras", "Detected cameras and their available capabilities.")
|
|
754
857
|
};
|
|
755
858
|
(Array.isArray(overview.sources) ? overview.sources : []).forEach(function (sourceId) {
|
|
756
859
|
addRow(
|
|
@@ -802,24 +905,41 @@
|
|
|
802
905
|
$status.hide();
|
|
803
906
|
$content.show();
|
|
804
907
|
};
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
908
|
+
const editorLanguage = String((RED.settings && RED.settings.lang) || (window.navigator && window.navigator.language) || "en");
|
|
909
|
+
const loadKnxAiOverview = function (refreshSetup) {
|
|
910
|
+
const $refresh = $("#knx-ai-setup-doctor-refresh");
|
|
911
|
+
$refresh.prop("disabled", true).find("i.fa-refresh").addClass("fa-spin");
|
|
912
|
+
const requestData = { language: editorLanguage };
|
|
913
|
+
if (nodeId) requestData.nodeId = nodeId;
|
|
914
|
+
if (refreshSetup) requestData.refreshSetup = "1";
|
|
915
|
+
$.ajax({
|
|
916
|
+
url: "knxUltimateAI/adapters",
|
|
917
|
+
type: "GET",
|
|
918
|
+
data: requestData
|
|
814
919
|
})
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
.
|
|
819
|
-
|
|
820
|
-
|
|
920
|
+
.done(function (data) {
|
|
921
|
+
renderSetupDoctor(data && data.setupDoctor);
|
|
922
|
+
renderDetectedAdapters(data && data.adapters);
|
|
923
|
+
renderChatContextOverview(data && data.chatContext);
|
|
924
|
+
})
|
|
925
|
+
.fail(function () {
|
|
926
|
+
renderSetupDoctor(null);
|
|
927
|
+
$("#knx-ai-detected-adapters-status")
|
|
928
|
+
.text(t("knxUltimateAI.messages.detectedAdaptersUnavailable", "Compatible-node detection is temporarily unavailable."))
|
|
929
|
+
.show();
|
|
930
|
+
renderChatContextOverview(null);
|
|
931
|
+
})
|
|
932
|
+
.always(function () {
|
|
933
|
+
$refresh.prop("disabled", false).find("i.fa-refresh").removeClass("fa-spin");
|
|
934
|
+
});
|
|
935
|
+
};
|
|
936
|
+
loadKnxAiOverview(false);
|
|
937
|
+
$("#knx-ai-setup-doctor-refresh").on("click", function (evt) {
|
|
938
|
+
evt.preventDefault();
|
|
939
|
+
loadKnxAiOverview(true);
|
|
940
|
+
});
|
|
821
941
|
|
|
822
|
-
const openKnxAiWebPage = function (view) {
|
|
942
|
+
const openKnxAiWebPage = function (view, prompt) {
|
|
823
943
|
const adminRoot = resolveAdminRoot();
|
|
824
944
|
const targetBase = adminRoot + "/knxUltimateAI/sidebar/page";
|
|
825
945
|
const params = new URLSearchParams();
|
|
@@ -827,6 +947,9 @@
|
|
|
827
947
|
if (view === "chat-learning") {
|
|
828
948
|
params.set("tab", "settings");
|
|
829
949
|
params.set("settingsTab", "learning");
|
|
950
|
+
} else if (view === "assistant") {
|
|
951
|
+
params.set("tab", "assistant");
|
|
952
|
+
if (prompt) params.set("prompt", String(prompt));
|
|
830
953
|
}
|
|
831
954
|
const accessToken = resolveAccessToken();
|
|
832
955
|
if (accessToken) params.set("access_token", accessToken);
|
|
@@ -1167,6 +1290,14 @@
|
|
|
1167
1290
|
}
|
|
1168
1291
|
}
|
|
1169
1292
|
};
|
|
1293
|
+
const toggleWebAccess = () => {
|
|
1294
|
+
const enabled = $("#node-input-webAccessEnabled").prop("checked") === true;
|
|
1295
|
+
const proactive = enabled && $("#node-input-webProactiveEnabled").prop("checked") === true;
|
|
1296
|
+
$("#knx-ai-web-access-settings").toggle(enabled);
|
|
1297
|
+
$("#knx-ai-web-proactive-interval-row").toggle(proactive);
|
|
1298
|
+
};
|
|
1299
|
+
$("#node-input-webAccessEnabled, #node-input-webProactiveEnabled").on("change", toggleWebAccess);
|
|
1300
|
+
toggleWebAccess();
|
|
1170
1301
|
$("#node-input-llmProvider").on("change", function () {
|
|
1171
1302
|
toggleProvider({ applyDefaults: true, autoLoadModels: true });
|
|
1172
1303
|
});
|
|
@@ -1258,6 +1389,34 @@
|
|
|
1258
1389
|
</div>
|
|
1259
1390
|
</div>
|
|
1260
1391
|
|
|
1392
|
+
<div id="knx-ai-setup-doctor-panel">
|
|
1393
|
+
<h4><i class="fa fa-magic"></i> <span data-i18n="knxUltimateAI.sections.setupDoctor"></span></h4>
|
|
1394
|
+
<div id="knx-ai-setup-doctor-status" data-i18n="knxUltimateAI.messages.setupDoctorLoading"></div>
|
|
1395
|
+
<div id="knx-ai-setup-doctor-content" style="display:none;">
|
|
1396
|
+
<div class="knx-ai-setup-doctor-hero">
|
|
1397
|
+
<div class="knx-ai-setup-doctor-summary">
|
|
1398
|
+
<strong id="knx-ai-setup-doctor-state"></strong>
|
|
1399
|
+
<div id="knx-ai-setup-doctor-summary"></div>
|
|
1400
|
+
</div>
|
|
1401
|
+
<div id="knx-ai-setup-doctor-score" class="knx-ai-setup-doctor-score"></div>
|
|
1402
|
+
</div>
|
|
1403
|
+
<div id="knx-ai-setup-doctor-checks"></div>
|
|
1404
|
+
<div class="knx-ai-setup-doctor-prompts">
|
|
1405
|
+
<strong data-i18n="knxUltimateAI.messages.setupDoctorPromptsTitle"></strong>
|
|
1406
|
+
<div class="knx-ai-setup-doctor-prompts-hint" data-i18n="knxUltimateAI.messages.setupDoctorPromptsHint"></div>
|
|
1407
|
+
<div id="knx-ai-setup-doctor-prompt-list" class="knx-ai-setup-doctor-prompt-list"></div>
|
|
1408
|
+
</div>
|
|
1409
|
+
<div class="knx-ai-setup-doctor-footer">
|
|
1410
|
+
<div class="knx-ai-setup-doctor-deploy-hint">
|
|
1411
|
+
<i class="fa fa-info-circle"></i> <span data-i18n="knxUltimateAI.messages.setupDoctorDeployHint"></span>
|
|
1412
|
+
</div>
|
|
1413
|
+
<button type="button" class="red-ui-button" id="knx-ai-setup-doctor-refresh">
|
|
1414
|
+
<i class="fa fa-refresh"></i> <span data-i18n="knxUltimateAI.buttons.refreshSetupDoctor"></span>
|
|
1415
|
+
</button>
|
|
1416
|
+
</div>
|
|
1417
|
+
</div>
|
|
1418
|
+
</div>
|
|
1419
|
+
|
|
1261
1420
|
<div id="knx-ai-tabs">
|
|
1262
1421
|
<ul>
|
|
1263
1422
|
<li><a href="#knx-ai-tabs-assistant"><i class="fa fa-magic"></i> <span data-i18n="knxUltimateAI.sections.groupAssistant"></span></a></li>
|
|
@@ -1294,11 +1453,6 @@
|
|
|
1294
1453
|
<h4><i class="fa fa-puzzle-piece"></i> <span data-i18n="knxUltimateAI.sections.detectedAdapters"></span></h4>
|
|
1295
1454
|
<div id="knx-ai-detected-adapters-status" data-i18n="knxUltimateAI.messages.detectedAdaptersLoading"></div>
|
|
1296
1455
|
<div id="knx-ai-detected-adapters-list"></div>
|
|
1297
|
-
<div id="knx-ai-tts-ultimate-picker" style="display:none;">
|
|
1298
|
-
<label for="node-input-ttsUltimateNodeId"><i class="fa fa-volume-up"></i> <span data-i18n="knxUltimateAI.properties.ttsUltimateNodeId"></span></label>
|
|
1299
|
-
<select id="node-input-ttsUltimateNodeId"></select>
|
|
1300
|
-
<div class="knx-ai-tts-ultimate-hint" data-i18n="knxUltimateAI.messages.ttsUltimateHint"></div>
|
|
1301
|
-
</div>
|
|
1302
1456
|
</div>
|
|
1303
1457
|
<div id="knx-ai-chat-context-panel">
|
|
1304
1458
|
<h4><i class="fa fa-database"></i> <span data-i18n="knxUltimateAI.sections.chatContextOverview"></span></h4>
|
|
@@ -1394,6 +1548,38 @@
|
|
|
1394
1548
|
</div>
|
|
1395
1549
|
|
|
1396
1550
|
<div id="knx-ai-tab-home-intelligence">
|
|
1551
|
+
<div class="form-row">
|
|
1552
|
+
<strong><i class="fa fa-globe"></i> <span data-i18n="knxUltimateAI.sections.webIntelligence"></span></strong>
|
|
1553
|
+
</div>
|
|
1554
|
+
<div class="form-row">
|
|
1555
|
+
<input type="checkbox" id="node-input-webAccessEnabled" style="display:inline-block; width:auto; vertical-align:top;">
|
|
1556
|
+
<label style="width:auto" for="node-input-webAccessEnabled"> <span data-i18n="knxUltimateAI.properties.webAccessEnabled"></span></label>
|
|
1557
|
+
<div class="knx-ai-prompt-context-hint" data-i18n="knxUltimateAI.messages.webAccessHint"></div>
|
|
1558
|
+
</div>
|
|
1559
|
+
<div id="knx-ai-web-access-settings">
|
|
1560
|
+
<div class="form-row">
|
|
1561
|
+
<label style="width:290px" for="node-input-webMaxCallsPerHour"><i class="fa fa-tachometer"></i> <span data-i18n="knxUltimateAI.properties.webMaxCallsPerHour"></span></label>
|
|
1562
|
+
<input type="number" id="node-input-webMaxCallsPerHour" min="1" max="60" step="1" style="width:100%;">
|
|
1563
|
+
<div class="knx-ai-prompt-context-hint" data-i18n="knxUltimateAI.messages.webBudgetHint"></div>
|
|
1564
|
+
</div>
|
|
1565
|
+
<div class="form-row">
|
|
1566
|
+
<input type="checkbox" id="node-input-webProactiveEnabled" style="display:inline-block; width:auto; vertical-align:top;">
|
|
1567
|
+
<label style="width:auto" for="node-input-webProactiveEnabled"> <span data-i18n="knxUltimateAI.properties.webProactiveEnabled"></span></label>
|
|
1568
|
+
<div class="knx-ai-prompt-context-hint" data-i18n="knxUltimateAI.messages.webProactiveHint"></div>
|
|
1569
|
+
</div>
|
|
1570
|
+
<div class="form-row" id="knx-ai-web-proactive-interval-row">
|
|
1571
|
+
<label style="width:290px" for="node-input-webProactiveIntervalMinutes"><i class="fa fa-clock-o"></i> <span data-i18n="knxUltimateAI.properties.webProactiveIntervalMinutes"></span></label>
|
|
1572
|
+
<select style="width:100%" id="node-input-webProactiveIntervalMinutes">
|
|
1573
|
+
<option value="5" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.5"></option>
|
|
1574
|
+
<option value="10" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.10"></option>
|
|
1575
|
+
<option value="15" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.15"></option>
|
|
1576
|
+
<option value="30" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.30"></option>
|
|
1577
|
+
<option value="60" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.60"></option>
|
|
1578
|
+
<option value="180" data-i18n="knxUltimateAI.selectlists.webProactiveInterval.180"></option>
|
|
1579
|
+
</select>
|
|
1580
|
+
</div>
|
|
1581
|
+
</div>
|
|
1582
|
+
<hr>
|
|
1397
1583
|
<div class="form-row">
|
|
1398
1584
|
<label style="width:100%" for="node-input-aiEducation"><i class="fa fa-graduation-cap"></i> <span data-i18n="knxUltimateAI.properties.aiEducation"></span></label>
|
|
1399
1585
|
<textarea id="node-input-aiEducation" maxlength="16000" style="width:100%; min-height:180px; box-sizing:border-box;" data-i18n="[placeholder]knxUltimateAI.placeholder.aiEducation"></textarea>
|