maidr 2.22.0 → 2.23.0
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/dist/maidr.js +573 -570
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/dist/maidr.js
CHANGED
|
@@ -12,77 +12,77 @@ class Constants {
|
|
|
12
12
|
* @memberof HtmlIds
|
|
13
13
|
* @default 'chart-container'
|
|
14
14
|
*/
|
|
15
|
-
chart_container_id =
|
|
15
|
+
chart_container_id = "chart-container";
|
|
16
16
|
/**
|
|
17
17
|
* HTML id of the main container div.
|
|
18
18
|
* @type {string}
|
|
19
19
|
* @memberof HtmlIds
|
|
20
20
|
* @default 'maidr-container'
|
|
21
21
|
*/
|
|
22
|
-
main_container_id =
|
|
22
|
+
main_container_id = "maidr-container";
|
|
23
23
|
/**
|
|
24
24
|
* HTML id of the div containing the braille display input
|
|
25
25
|
* @type {string}
|
|
26
26
|
* @memberof HtmlIds
|
|
27
27
|
* @default 'braille-div'
|
|
28
28
|
*/
|
|
29
|
-
braille_container_id =
|
|
29
|
+
braille_container_id = "braille-div";
|
|
30
30
|
/**
|
|
31
31
|
* HTML id of the actual braille input element.
|
|
32
32
|
* @type {string}
|
|
33
33
|
* @memberof HtmlIds
|
|
34
34
|
* @default 'braille-input'
|
|
35
35
|
*/
|
|
36
|
-
braille_input_id =
|
|
36
|
+
braille_input_id = "braille-input";
|
|
37
37
|
/**
|
|
38
38
|
* HTML id of the div containing the info box.
|
|
39
39
|
* @type {string}
|
|
40
40
|
* @memberof HtmlIds
|
|
41
41
|
* @default 'info'
|
|
42
42
|
*/
|
|
43
|
-
info_id =
|
|
43
|
+
info_id = "info";
|
|
44
44
|
/**
|
|
45
45
|
* HTML id of the div containing announcements that hook directly into the screen reader via aria-live.
|
|
46
46
|
* @type {string}
|
|
47
47
|
* @memberof HtmlIds
|
|
48
48
|
* @default 'announcements'
|
|
49
49
|
*/
|
|
50
|
-
announcement_container_id =
|
|
50
|
+
announcement_container_id = "announcements";
|
|
51
51
|
/**
|
|
52
52
|
* HTML id of the div containing the end chime. To be implemented in the future.
|
|
53
53
|
* @type {string}
|
|
54
54
|
* @memberof HtmlIds
|
|
55
55
|
* @default 'end_chime'
|
|
56
56
|
*/
|
|
57
|
-
end_chime_id =
|
|
57
|
+
end_chime_id = "end_chime";
|
|
58
58
|
/**
|
|
59
59
|
* HTML id of the main container div.
|
|
60
60
|
* @type {string}
|
|
61
61
|
* @memberof HtmlIds
|
|
62
62
|
* @default 'container'
|
|
63
63
|
*/
|
|
64
|
-
container_id =
|
|
64
|
+
container_id = "container";
|
|
65
65
|
/**
|
|
66
66
|
* The main project id, used throughout the application.
|
|
67
67
|
* @type {string}
|
|
68
68
|
* @memberof HtmlIds
|
|
69
69
|
* @default 'maidr'
|
|
70
70
|
*/
|
|
71
|
-
project_id =
|
|
71
|
+
project_id = "maidr";
|
|
72
72
|
/**
|
|
73
73
|
* HTML id of the div containing the review text.
|
|
74
74
|
* @type {string}
|
|
75
75
|
* @memberof HtmlIds
|
|
76
76
|
* @default 'review_container'
|
|
77
77
|
*/
|
|
78
|
-
review_id_container =
|
|
78
|
+
review_id_container = "review_container";
|
|
79
79
|
/**
|
|
80
80
|
* HTML id of the review input element.
|
|
81
81
|
* @type {string}
|
|
82
82
|
* @memberof HtmlIds
|
|
83
83
|
* @default 'review'
|
|
84
84
|
*/
|
|
85
|
-
review_id =
|
|
85
|
+
review_id = "review";
|
|
86
86
|
/**
|
|
87
87
|
* Storage element, used to store the last focused element before moving to the review input so we can switch back to it easily.
|
|
88
88
|
* @type {HTMLElement}
|
|
@@ -99,7 +99,7 @@ class Constants {
|
|
|
99
99
|
* @type {string}
|
|
100
100
|
* @memberof HtmlIds
|
|
101
101
|
*/
|
|
102
|
-
chartId =
|
|
102
|
+
chartId = "";
|
|
103
103
|
/**
|
|
104
104
|
* @typedef {Object} EventListenerSetupObject
|
|
105
105
|
* @property {HTMLElement} element - The element to attach the event listener to.
|
|
@@ -128,7 +128,7 @@ class Constants {
|
|
|
128
128
|
* @memberof BTSModes
|
|
129
129
|
* @default 'verbose'
|
|
130
130
|
*/
|
|
131
|
-
textMode =
|
|
131
|
+
textMode = "verbose";
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* The current braille mode. Can be 'off' or 'on'.
|
|
@@ -136,7 +136,7 @@ class Constants {
|
|
|
136
136
|
* @memberof BTSModes
|
|
137
137
|
* @default 'off'
|
|
138
138
|
*/
|
|
139
|
-
brailleMode =
|
|
139
|
+
brailleMode = "off";
|
|
140
140
|
|
|
141
141
|
/**
|
|
142
142
|
* We lock the selection so we don't pick up programatic selection changes
|
|
@@ -151,14 +151,14 @@ class Constants {
|
|
|
151
151
|
* @memberof BTSModes
|
|
152
152
|
* @default 'on'
|
|
153
153
|
*/
|
|
154
|
-
sonifMode =
|
|
154
|
+
sonifMode = "on";
|
|
155
155
|
/**
|
|
156
156
|
* The current review mode. Can be 'on' or 'off'.
|
|
157
157
|
* @type {("on"|"off")}
|
|
158
158
|
* @memberof BTSModes
|
|
159
159
|
* @default 'off'
|
|
160
160
|
*/
|
|
161
|
-
reviewMode =
|
|
161
|
+
reviewMode = "off";
|
|
162
162
|
|
|
163
163
|
// basic chart properties
|
|
164
164
|
/**
|
|
@@ -199,14 +199,14 @@ class Constants {
|
|
|
199
199
|
* @memberof HtmlIds
|
|
200
200
|
* @default ''
|
|
201
201
|
*/
|
|
202
|
-
plotId =
|
|
202
|
+
plotId = ""; // update with id in chart specific js
|
|
203
203
|
/**
|
|
204
204
|
* The chart type, sort of a short name of the chart such as 'box', 'bar', 'line', etc.
|
|
205
205
|
* @type {string}
|
|
206
206
|
* @default ''
|
|
207
207
|
* @memberof BasicChartProperties
|
|
208
208
|
*/
|
|
209
|
-
chartType =
|
|
209
|
+
chartType = "";
|
|
210
210
|
/**
|
|
211
211
|
* The navigation orientation of the chart. 0 = row navigation (up/down), 1 = col navigation (left/right).
|
|
212
212
|
* @type {number}
|
|
@@ -220,7 +220,7 @@ class Constants {
|
|
|
220
220
|
* @default 'horz'
|
|
221
221
|
* @memberof BasicChartProperties
|
|
222
222
|
*/
|
|
223
|
-
plotOrientation =
|
|
223
|
+
plotOrientation = "horz";
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
226
|
* @namespace AudioProperties
|
|
@@ -330,7 +330,7 @@ class Constants {
|
|
|
330
330
|
* @default '#03C809' (green)
|
|
331
331
|
* @memberof UserSettings
|
|
332
332
|
*/
|
|
333
|
-
colorSelected =
|
|
333
|
+
colorSelected = "#03C809";
|
|
334
334
|
/**
|
|
335
335
|
* The length of the braille display in characters. Braille displays have a variety of sizes; 40 is pretty common, 32 is quite reliable. Set this to your actual display length so that the system can scale and display braille properly for you (where possible).
|
|
336
336
|
* @type {number}
|
|
@@ -398,14 +398,14 @@ class Constants {
|
|
|
398
398
|
* @default 50
|
|
399
399
|
* @memberof AdvancedUserSettings
|
|
400
400
|
*/
|
|
401
|
-
colorUnselected =
|
|
401
|
+
colorUnselected = "#595959"; // deprecated, todo: find all instances replace with storing old color method
|
|
402
402
|
/**
|
|
403
403
|
* Whether or not we're logging user data. This is off by default, but is used for research purposes.
|
|
404
404
|
* @type {boolean}
|
|
405
405
|
* @default 0
|
|
406
406
|
* @memberof AdvancedUserSettings
|
|
407
407
|
*/
|
|
408
|
-
canTrack =
|
|
408
|
+
canTrack = 1; // 0 / 1, can we track user data
|
|
409
409
|
/**
|
|
410
410
|
* How are we representing braille? like, is it 1:1 with the chart, or do we do some compression and try to represent as accuratly as we can? Not currently in use.
|
|
411
411
|
* @type {boolean}
|
|
@@ -419,33 +419,33 @@ class Constants {
|
|
|
419
419
|
* @default 'assertive'
|
|
420
420
|
* @memberof AdvancedUserSettings
|
|
421
421
|
*/
|
|
422
|
-
ariaMode =
|
|
422
|
+
ariaMode = "assertive";
|
|
423
423
|
|
|
424
424
|
/**
|
|
425
425
|
* Full list of user settings, used internally to save and load settings.
|
|
426
426
|
* @type {string[]}
|
|
427
427
|
*/
|
|
428
428
|
userSettingsKeys = [
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
429
|
+
"vol",
|
|
430
|
+
"autoPlayRate",
|
|
431
|
+
"brailleDisplayLength",
|
|
432
|
+
"colorSelected",
|
|
433
|
+
"MIN_FREQUENCY",
|
|
434
|
+
"MAX_FREQUENCY",
|
|
435
|
+
"AUTOPLAY_DURATION",
|
|
436
|
+
"ariaMode",
|
|
437
|
+
"openAIAuthKey",
|
|
438
|
+
"geminiAuthKey",
|
|
439
|
+
"claudeAuthKey",
|
|
440
|
+
"emailAuthKey",
|
|
441
|
+
"skillLevel",
|
|
442
|
+
"skillLevelOther",
|
|
443
|
+
"LLMModel",
|
|
444
|
+
"LLMPreferences",
|
|
445
|
+
"LLMOpenAiMulti",
|
|
446
|
+
"LLMGeminiMulti",
|
|
447
|
+
"LLMModels",
|
|
448
|
+
"autoInitLLM",
|
|
449
449
|
];
|
|
450
450
|
|
|
451
451
|
// LLM settings
|
|
@@ -486,14 +486,14 @@ class Constants {
|
|
|
486
486
|
* @default 'high'
|
|
487
487
|
* @memberof LLMSettings
|
|
488
488
|
*/
|
|
489
|
-
LLMDetail =
|
|
489
|
+
LLMDetail = "high"; // low (default for testing, like 100 tokens) / high (default for real, like 1000 tokens)
|
|
490
490
|
/**
|
|
491
491
|
* Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'multi'. More to be added.
|
|
492
492
|
* @type {("openai"|"gemini"|"multi")}
|
|
493
493
|
* @default 'openai'
|
|
494
494
|
* @memberof LLMSettings
|
|
495
495
|
*/
|
|
496
|
-
LLMModel =
|
|
496
|
+
LLMModel = "openai";
|
|
497
497
|
/**
|
|
498
498
|
* Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'claude'. More to be added.
|
|
499
499
|
* @type {("openai"|"gemini"|"claude")}
|
|
@@ -508,21 +508,21 @@ class Constants {
|
|
|
508
508
|
* @memberof LLMSettings
|
|
509
509
|
*/
|
|
510
510
|
LLMSystemMessage =
|
|
511
|
-
|
|
511
|
+
"You are a helpful assistant describing the chart to a blind person. ";
|
|
512
512
|
/**
|
|
513
513
|
* The level of skill the user has with statistical charts. Can be 'basic', 'intermediate', 'expert', or 'other'. This is passed to the LLM on the initial message to help it speak correctly to the user. If 'other' is selected, the user can provide a custom skill level.
|
|
514
514
|
* @type {("basic"|"intermediate"|"expert"|"other")}
|
|
515
515
|
* @default 'basic'
|
|
516
516
|
* @memberof LLMSettings
|
|
517
517
|
*/
|
|
518
|
-
skillLevel =
|
|
518
|
+
skillLevel = "basic"; // basic / intermediate / expert
|
|
519
519
|
/**
|
|
520
520
|
* Custom skill level, used if the user selects 'other' as their skill level.
|
|
521
521
|
* @type {string}
|
|
522
522
|
* @default ''
|
|
523
523
|
* @memberof LLMSettings
|
|
524
524
|
*/
|
|
525
|
-
skillLevelOther =
|
|
525
|
+
skillLevelOther = ""; // custom skill level
|
|
526
526
|
/**
|
|
527
527
|
* The LLM can send the first default message containing the chart image on initialization, so when the user opens the chat window the LLM already has an initial response and is ready for a conversation.
|
|
528
528
|
* @type {boolean}
|
|
@@ -536,7 +536,7 @@ class Constants {
|
|
|
536
536
|
* @default ''
|
|
537
537
|
* @memberof LLMSettings
|
|
538
538
|
*/
|
|
539
|
-
verboseText =
|
|
539
|
+
verboseText = "";
|
|
540
540
|
/**
|
|
541
541
|
* An internal variable used to turn the waiting beep on and off.
|
|
542
542
|
* @type {number}
|
|
@@ -584,31 +584,31 @@ class Constants {
|
|
|
584
584
|
* @type {boolean}
|
|
585
585
|
* @memberof PlatformControls
|
|
586
586
|
*/
|
|
587
|
-
isMac = navigator.userAgent.toLowerCase().includes(
|
|
587
|
+
isMac = navigator.userAgent.toLowerCase().includes("mac"); // true if macOS
|
|
588
588
|
/**
|
|
589
589
|
* The control key for the user's platform. Can be 'Cmd' or 'Ctrl'. Used in keyboard shortcut display in help.
|
|
590
590
|
* @type {"Cmd"|"Ctrl"}
|
|
591
591
|
* @memberof PlatformControls
|
|
592
592
|
*/
|
|
593
|
-
control = this.isMac ?
|
|
593
|
+
control = this.isMac ? "Cmd" : "Ctrl";
|
|
594
594
|
/**
|
|
595
595
|
* The alt key for the user's platform. Can be 'option' or 'Alt'. Used in keyboard shortcut display in help.
|
|
596
596
|
* @type {"option"|"Alt"}
|
|
597
597
|
* @memberof PlatformControls
|
|
598
598
|
*/
|
|
599
|
-
alt = this.isMac ?
|
|
599
|
+
alt = this.isMac ? "option" : "Alt";
|
|
600
600
|
/**
|
|
601
601
|
* The home key for the user's platform. Can be 'fn + Left arrow' or 'Home'. Used in keyboard shortcut display in help.
|
|
602
602
|
* @type {"fn + Left arrow"|"Home"}
|
|
603
603
|
* @memberof PlatformControls
|
|
604
604
|
*/
|
|
605
|
-
home = this.isMac ?
|
|
605
|
+
home = this.isMac ? "fn + Left arrow" : "Home";
|
|
606
606
|
/**
|
|
607
607
|
* The end key for the user's platform. Can be 'fn + Right arrow' or 'End'. Used in keyboard shortcut display in help.
|
|
608
608
|
* @type {"fn + Right arrow"|"End"}
|
|
609
609
|
* @memberof PlatformControls
|
|
610
610
|
*/
|
|
611
|
-
end = this.isMac ?
|
|
611
|
+
end = this.isMac ? "fn + Right arrow" : "End";
|
|
612
612
|
/**
|
|
613
613
|
* The interval we wait for an L + X prefix event
|
|
614
614
|
*/
|
|
@@ -704,13 +704,13 @@ class Constants {
|
|
|
704
704
|
*/
|
|
705
705
|
ConvertHexToRGBString(hexColorString) {
|
|
706
706
|
return (
|
|
707
|
-
|
|
707
|
+
"rgb(" +
|
|
708
708
|
parseInt(hexColorString.slice(1, 3), 16) +
|
|
709
|
-
|
|
709
|
+
"," +
|
|
710
710
|
parseInt(hexColorString.slice(3, 5), 16) +
|
|
711
|
-
|
|
711
|
+
"," +
|
|
712
712
|
parseInt(hexColorString.slice(5, 7), 16) +
|
|
713
|
-
|
|
713
|
+
")"
|
|
714
714
|
);
|
|
715
715
|
}
|
|
716
716
|
|
|
@@ -720,12 +720,12 @@ class Constants {
|
|
|
720
720
|
* @returns {string} - hexadecimal color (e.g., "#595959").
|
|
721
721
|
*/
|
|
722
722
|
ConvertRGBStringToHex(rgbColorString) {
|
|
723
|
-
let rgb = rgbColorString.replace(/[^\d,]/g,
|
|
723
|
+
let rgb = rgbColorString.replace(/[^\d,]/g, "").split(",");
|
|
724
724
|
return (
|
|
725
|
-
|
|
726
|
-
rgb[0].toString(16).padStart(2,
|
|
727
|
-
rgb[1].toString(16).padStart(2,
|
|
728
|
-
rgb[2].toString(16).padStart(2,
|
|
725
|
+
"#" +
|
|
726
|
+
rgb[0].toString(16).padStart(2, "0") +
|
|
727
|
+
rgb[1].toString(16).padStart(2, "0") +
|
|
728
|
+
rgb[2].toString(16).padStart(2, "0")
|
|
729
729
|
);
|
|
730
730
|
}
|
|
731
731
|
|
|
@@ -737,11 +737,11 @@ class Constants {
|
|
|
737
737
|
*/
|
|
738
738
|
ColorInvert(color) {
|
|
739
739
|
// invert an rgb color
|
|
740
|
-
let rgb = color.replace(/[^\d,]/g,
|
|
740
|
+
let rgb = color.replace(/[^\d,]/g, "").split(",");
|
|
741
741
|
let r = 255 - rgb[0];
|
|
742
742
|
let g = 255 - rgb[1];
|
|
743
743
|
let b = 255 - rgb[2];
|
|
744
|
-
return
|
|
744
|
+
return "rgb(" + r + "," + g + "," + b + ")";
|
|
745
745
|
}
|
|
746
746
|
|
|
747
747
|
/**
|
|
@@ -750,11 +750,11 @@ class Constants {
|
|
|
750
750
|
* @returns {string} The better color
|
|
751
751
|
*/
|
|
752
752
|
GetBetterColor(oldColor) {
|
|
753
|
-
if (oldColor.indexOf(
|
|
753
|
+
if (oldColor.indexOf("#") !== -1) {
|
|
754
754
|
oldColor = this.ConvertHexToRGBString(oldColor);
|
|
755
755
|
}
|
|
756
756
|
let newColor = this.ColorInvert(oldColor);
|
|
757
|
-
let rgb = newColor.replace(/[^\d,]/g,
|
|
757
|
+
let rgb = newColor.replace(/[^\d,]/g, "").split(",");
|
|
758
758
|
if (
|
|
759
759
|
rgb[1] < rgb[0] + 10 &&
|
|
760
760
|
rgb[1] > rgb[0] - 10 &&
|
|
@@ -776,7 +776,7 @@ class Constants {
|
|
|
776
776
|
*/
|
|
777
777
|
GetStyleArrayFromString(styleString) {
|
|
778
778
|
// Get an array of CSS style attributes and values from a style string
|
|
779
|
-
return styleString.replaceAll(
|
|
779
|
+
return styleString.replaceAll(" ", "").split(/[:;]/);
|
|
780
780
|
}
|
|
781
781
|
|
|
782
782
|
/**
|
|
@@ -786,16 +786,16 @@ class Constants {
|
|
|
786
786
|
*/
|
|
787
787
|
GetStyleStringFromArray(styleArray) {
|
|
788
788
|
// Get CSS style string from an array of style attributes and values
|
|
789
|
-
let styleString =
|
|
789
|
+
let styleString = "";
|
|
790
790
|
for (let i = 0; i < styleArray.length; i++) {
|
|
791
791
|
if (i % 2 === 0) {
|
|
792
792
|
if (i !== styleArray.length - 1) {
|
|
793
|
-
styleString += styleArray[i] +
|
|
793
|
+
styleString += styleArray[i] + ": ";
|
|
794
794
|
} else {
|
|
795
795
|
styleString += styleArray[i];
|
|
796
796
|
}
|
|
797
797
|
} else {
|
|
798
|
-
styleString += styleArray[i] +
|
|
798
|
+
styleString += styleArray[i] + "; ";
|
|
799
799
|
}
|
|
800
800
|
}
|
|
801
801
|
return styleString;
|
|
@@ -808,36 +808,36 @@ class Constants {
|
|
|
808
808
|
class Resources {
|
|
809
809
|
constructor() {}
|
|
810
810
|
|
|
811
|
-
language =
|
|
812
|
-
knowledgeLevel =
|
|
811
|
+
language = "en"; // Current language, 2 char lang code
|
|
812
|
+
knowledgeLevel = "basic"; // basic, intermediate, expert
|
|
813
813
|
|
|
814
814
|
// language strings, per 2 char language code
|
|
815
815
|
strings = {
|
|
816
816
|
en: {
|
|
817
817
|
basic: {
|
|
818
|
-
upper_outlier:
|
|
819
|
-
lower_outlier:
|
|
820
|
-
min:
|
|
821
|
-
max:
|
|
822
|
-
25:
|
|
823
|
-
50:
|
|
824
|
-
75:
|
|
825
|
-
q1:
|
|
826
|
-
q2:
|
|
827
|
-
q3:
|
|
828
|
-
son_on:
|
|
829
|
-
son_off:
|
|
830
|
-
son_des:
|
|
831
|
-
son_comp:
|
|
832
|
-
son_ch:
|
|
833
|
-
son_sep:
|
|
834
|
-
son_same:
|
|
835
|
-
empty:
|
|
836
|
-
openai:
|
|
837
|
-
gemini:
|
|
838
|
-
claude:
|
|
839
|
-
multi:
|
|
840
|
-
processing:
|
|
818
|
+
upper_outlier: "Upper Outlier",
|
|
819
|
+
lower_outlier: "Lower Outlier",
|
|
820
|
+
min: "Minimum",
|
|
821
|
+
max: "Maximum",
|
|
822
|
+
25: "25%",
|
|
823
|
+
50: "50%",
|
|
824
|
+
75: "75%",
|
|
825
|
+
q1: "25%",
|
|
826
|
+
q2: "50%",
|
|
827
|
+
q3: "75%",
|
|
828
|
+
son_on: "Sonification on",
|
|
829
|
+
son_off: "Sonification off",
|
|
830
|
+
son_des: "Sonification descrete",
|
|
831
|
+
son_comp: "Sonification compare",
|
|
832
|
+
son_ch: "Sonification chord",
|
|
833
|
+
son_sep: "Sonification separate",
|
|
834
|
+
son_same: "Sonification combined",
|
|
835
|
+
empty: "Empty",
|
|
836
|
+
openai: "OpenAI Vision",
|
|
837
|
+
gemini: "Gemini Pro Vision",
|
|
838
|
+
claude: "Claude",
|
|
839
|
+
multi: "Multiple AI",
|
|
840
|
+
processing: "Processing Chart...",
|
|
841
841
|
},
|
|
842
842
|
},
|
|
843
843
|
};
|
|
@@ -1007,12 +1007,12 @@ class Menu {
|
|
|
1007
1007
|
<div><fieldset>
|
|
1008
1008
|
<legend>Aria Mode</legend>
|
|
1009
1009
|
<p><input type="radio" id="aria_mode_assertive" name="aria_mode" value="assertive" ${
|
|
1010
|
-
constants.ariaMode ==
|
|
1011
|
-
?
|
|
1012
|
-
:
|
|
1010
|
+
constants.ariaMode == "assertive"
|
|
1011
|
+
? "checked"
|
|
1012
|
+
: ""
|
|
1013
1013
|
}><label for="aria_mode_assertive">Assertive</label></p>
|
|
1014
1014
|
<p><input type="radio" id="aria_mode_polite" name="aria_mode" value="polite" ${
|
|
1015
|
-
constants.ariaMode ==
|
|
1015
|
+
constants.ariaMode == "polite" ? "checked" : ""
|
|
1016
1016
|
}><label for="aria_mode_polite">Polite</label></p>
|
|
1017
1017
|
</fieldset></div>
|
|
1018
1018
|
<p class="hidden">
|
|
@@ -1033,7 +1033,10 @@ class Menu {
|
|
|
1033
1033
|
</fieldset>
|
|
1034
1034
|
</p>
|
|
1035
1035
|
<p id="email_auth_key_container" class="multi_container">
|
|
1036
|
-
<input type="email" size="50" id="email_auth_key"
|
|
1036
|
+
<input type="email" size="50" id="email_auth_key" aria-label="Enter your email address">
|
|
1037
|
+
<button aria-label="Delete Email Address" title="Delete Email Address" id="delete_email_key" class="invis_button">×</button>
|
|
1038
|
+
<label for="gemini_auth_key">Email Authentication</label>
|
|
1039
|
+
<button type="button" id="verify">Verify</button>
|
|
1037
1040
|
</p>
|
|
1038
1041
|
<p id="openai_auth_key_container" class="multi_container hidden">
|
|
1039
1042
|
<span id="openai_multi_container" class="hidden"><input type="checkbox" id="openai_multi" name="openai_multi" aria-label="Use OpenAI in Multi modal mode"></span>
|
|
@@ -1048,7 +1051,7 @@ class Menu {
|
|
|
1048
1051
|
<input type="password" size="50" id="claude_auth_key"><button aria-label="Delete Claude key" title="Delete Claude key" id="delete_claude_key" class="invis_button">×</button><label for="claude_auth_key">Claude Authentication Key</label>
|
|
1049
1052
|
</p>
|
|
1050
1053
|
<p><input type="checkbox" ${
|
|
1051
|
-
constants.autoInitLLM ?
|
|
1054
|
+
constants.autoInitLLM ? "checked" : ""
|
|
1052
1055
|
} id="init_llm_on_load" name="init_llm_on_load"><label for="init_llm_on_load">Start LLM right away</label></p>
|
|
1053
1056
|
<p>
|
|
1054
1057
|
<select id="skill_level">
|
|
@@ -1085,40 +1088,40 @@ class Menu {
|
|
|
1085
1088
|
CreateMenu() {
|
|
1086
1089
|
// menu element creation
|
|
1087
1090
|
document
|
|
1088
|
-
.querySelector(
|
|
1089
|
-
.insertAdjacentHTML(
|
|
1091
|
+
.querySelector("body")
|
|
1092
|
+
.insertAdjacentHTML("beforeend", this.menuHtml);
|
|
1090
1093
|
|
|
1091
1094
|
// menu close events
|
|
1092
|
-
let allClose = document.querySelectorAll(
|
|
1095
|
+
let allClose = document.querySelectorAll("#close_menu, #menu .close");
|
|
1093
1096
|
for (let i = 0; i < allClose.length; i++) {
|
|
1094
1097
|
constants.events.push([
|
|
1095
1098
|
allClose[i],
|
|
1096
|
-
|
|
1099
|
+
"click",
|
|
1097
1100
|
function (e) {
|
|
1098
1101
|
menu.Toggle(false);
|
|
1099
1102
|
},
|
|
1100
1103
|
]);
|
|
1101
1104
|
}
|
|
1102
1105
|
constants.events.push([
|
|
1103
|
-
document.getElementById(
|
|
1104
|
-
|
|
1106
|
+
document.getElementById("save_and_close_menu"),
|
|
1107
|
+
"click",
|
|
1105
1108
|
function (e) {
|
|
1106
1109
|
menu.SaveData();
|
|
1107
1110
|
menu.Toggle(false);
|
|
1108
1111
|
},
|
|
1109
1112
|
]);
|
|
1110
1113
|
constants.events.push([
|
|
1111
|
-
document.getElementById(
|
|
1112
|
-
|
|
1114
|
+
document.getElementById("verify"),
|
|
1115
|
+
"click",
|
|
1113
1116
|
function (e) {
|
|
1114
1117
|
menu.VerifyEmail();
|
|
1115
1118
|
},
|
|
1116
1119
|
]);
|
|
1117
1120
|
constants.events.push([
|
|
1118
|
-
document.getElementById(
|
|
1119
|
-
|
|
1121
|
+
document.getElementById("menu"),
|
|
1122
|
+
"keyup",
|
|
1120
1123
|
function (e) {
|
|
1121
|
-
if (e.key ==
|
|
1124
|
+
if (e.key == "Esc") {
|
|
1122
1125
|
// esc
|
|
1123
1126
|
menu.Toggle(false);
|
|
1124
1127
|
}
|
|
@@ -1128,15 +1131,15 @@ class Menu {
|
|
|
1128
1131
|
// Menu open events
|
|
1129
1132
|
constants.events.push([
|
|
1130
1133
|
document,
|
|
1131
|
-
|
|
1134
|
+
"keyup",
|
|
1132
1135
|
function (e) {
|
|
1133
1136
|
// don't fire on input elements
|
|
1134
1137
|
if (
|
|
1135
|
-
e.target.tagName.toLowerCase() ==
|
|
1136
|
-
e.target.tagName.toLowerCase() ==
|
|
1138
|
+
e.target.tagName.toLowerCase() == "input" ||
|
|
1139
|
+
e.target.tagName.toLowerCase() == "textarea"
|
|
1137
1140
|
) {
|
|
1138
1141
|
return;
|
|
1139
|
-
} else if (e.key ==
|
|
1142
|
+
} else if (e.key == "h") {
|
|
1140
1143
|
menu.Toggle(true);
|
|
1141
1144
|
}
|
|
1142
1145
|
},
|
|
@@ -1144,98 +1147,98 @@ class Menu {
|
|
|
1144
1147
|
|
|
1145
1148
|
// toggle auth key fields
|
|
1146
1149
|
constants.events.push([
|
|
1147
|
-
document.getElementById(
|
|
1148
|
-
|
|
1150
|
+
document.getElementById("LLM_model"),
|
|
1151
|
+
"change",
|
|
1149
1152
|
function (e) {
|
|
1150
|
-
if (e.target.value ==
|
|
1153
|
+
if (e.target.value == "openai") {
|
|
1151
1154
|
document
|
|
1152
|
-
.getElementById(
|
|
1153
|
-
.classList.remove(
|
|
1155
|
+
.getElementById("openai_auth_key_container")
|
|
1156
|
+
.classList.remove("hidden");
|
|
1154
1157
|
document
|
|
1155
|
-
.getElementById(
|
|
1156
|
-
.classList.add(
|
|
1158
|
+
.getElementById("gemini_auth_key_container")
|
|
1159
|
+
.classList.add("hidden");
|
|
1157
1160
|
document
|
|
1158
|
-
.getElementById(
|
|
1159
|
-
.classList.add(
|
|
1161
|
+
.getElementById("openai_multi_container")
|
|
1162
|
+
.classList.add("hidden");
|
|
1160
1163
|
document
|
|
1161
|
-
.getElementById(
|
|
1162
|
-
.classList.add(
|
|
1163
|
-
document.getElementById(
|
|
1164
|
-
document.getElementById(
|
|
1165
|
-
} else if (e.target.value ==
|
|
1164
|
+
.getElementById("gemini_multi_container")
|
|
1165
|
+
.classList.add("hidden");
|
|
1166
|
+
document.getElementById("openai_multi").checked = true;
|
|
1167
|
+
document.getElementById("gemini_multi").checked = false;
|
|
1168
|
+
} else if (e.target.value == "gemini") {
|
|
1166
1169
|
document
|
|
1167
|
-
.getElementById(
|
|
1168
|
-
.classList.add(
|
|
1170
|
+
.getElementById("openai_auth_key_container")
|
|
1171
|
+
.classList.add("hidden");
|
|
1169
1172
|
document
|
|
1170
|
-
.getElementById(
|
|
1171
|
-
.classList.remove(
|
|
1173
|
+
.getElementById("gemini_auth_key_container")
|
|
1174
|
+
.classList.remove("hidden");
|
|
1172
1175
|
document
|
|
1173
|
-
.getElementById(
|
|
1174
|
-
.classList.add(
|
|
1176
|
+
.getElementById("openai_multi_container")
|
|
1177
|
+
.classList.add("hidden");
|
|
1175
1178
|
document
|
|
1176
|
-
.getElementById(
|
|
1177
|
-
.classList.add(
|
|
1178
|
-
document.getElementById(
|
|
1179
|
-
document.getElementById(
|
|
1180
|
-
} else if (e.target.value ==
|
|
1179
|
+
.getElementById("gemini_multi_container")
|
|
1180
|
+
.classList.add("hidden");
|
|
1181
|
+
document.getElementById("openai_multi").checked = false;
|
|
1182
|
+
document.getElementById("gemini_multi").checked = true;
|
|
1183
|
+
} else if (e.target.value == "multi") {
|
|
1181
1184
|
document
|
|
1182
|
-
.getElementById(
|
|
1183
|
-
.classList.remove(
|
|
1185
|
+
.getElementById("openai_auth_key_container")
|
|
1186
|
+
.classList.remove("hidden");
|
|
1184
1187
|
document
|
|
1185
|
-
.getElementById(
|
|
1186
|
-
.classList.remove(
|
|
1188
|
+
.getElementById("gemini_auth_key_container")
|
|
1189
|
+
.classList.remove("hidden");
|
|
1187
1190
|
document
|
|
1188
|
-
.getElementById(
|
|
1189
|
-
.classList.remove(
|
|
1191
|
+
.getElementById("openai_multi_container")
|
|
1192
|
+
.classList.remove("hidden");
|
|
1190
1193
|
document
|
|
1191
|
-
.getElementById(
|
|
1192
|
-
.classList.remove(
|
|
1193
|
-
document.getElementById(
|
|
1194
|
-
document.getElementById(
|
|
1194
|
+
.getElementById("gemini_multi_container")
|
|
1195
|
+
.classList.remove("hidden");
|
|
1196
|
+
document.getElementById("openai_multi").checked = true;
|
|
1197
|
+
document.getElementById("gemini_multi").checked = true;
|
|
1195
1198
|
}
|
|
1196
1199
|
},
|
|
1197
1200
|
]);
|
|
1198
1201
|
|
|
1199
1202
|
constants.events.push([
|
|
1200
|
-
document.getElementById(
|
|
1201
|
-
|
|
1203
|
+
document.getElementById("LLM_model_openai"),
|
|
1204
|
+
"change",
|
|
1202
1205
|
function (e) {
|
|
1203
1206
|
if (e.target.checked) {
|
|
1204
1207
|
document
|
|
1205
|
-
.getElementById(
|
|
1206
|
-
.classList.remove(
|
|
1208
|
+
.getElementById("openai_auth_key_container")
|
|
1209
|
+
.classList.remove("hidden");
|
|
1207
1210
|
} else {
|
|
1208
1211
|
document
|
|
1209
|
-
.getElementById(
|
|
1210
|
-
.classList.add(
|
|
1212
|
+
.getElementById("openai_auth_key_container")
|
|
1213
|
+
.classList.add("hidden");
|
|
1211
1214
|
}
|
|
1212
1215
|
},
|
|
1213
1216
|
]);
|
|
1214
1217
|
|
|
1215
1218
|
constants.events.push([
|
|
1216
|
-
document.getElementById(
|
|
1217
|
-
|
|
1219
|
+
document.getElementById("LLM_model_gemini"),
|
|
1220
|
+
"change",
|
|
1218
1221
|
function (e) {
|
|
1219
1222
|
if (e.target.checked) {
|
|
1220
1223
|
document
|
|
1221
|
-
.getElementById(
|
|
1222
|
-
.classList.remove(
|
|
1224
|
+
.getElementById("gemini_auth_key_container")
|
|
1225
|
+
.classList.remove("hidden");
|
|
1223
1226
|
} else {
|
|
1224
1227
|
document
|
|
1225
|
-
.getElementById(
|
|
1226
|
-
.classList.add(
|
|
1228
|
+
.getElementById("gemini_auth_key_container")
|
|
1229
|
+
.classList.add("hidden");
|
|
1227
1230
|
}
|
|
1228
1231
|
},
|
|
1229
1232
|
]);
|
|
1230
1233
|
|
|
1231
1234
|
constants.events.push([
|
|
1232
|
-
document.getElementById(
|
|
1233
|
-
|
|
1235
|
+
document.getElementById("LLM_model_claude"),
|
|
1236
|
+
"change",
|
|
1234
1237
|
function (e) {
|
|
1235
1238
|
// if (e.target.checked) {
|
|
1236
1239
|
document
|
|
1237
|
-
.getElementById(
|
|
1238
|
-
.classList.add(
|
|
1240
|
+
.getElementById("claude_auth_key_container")
|
|
1241
|
+
.classList.add("hidden");
|
|
1239
1242
|
// } else {
|
|
1240
1243
|
// document
|
|
1241
1244
|
// .getElementById('claude_auth_key_container')
|
|
@@ -1246,17 +1249,17 @@ class Menu {
|
|
|
1246
1249
|
|
|
1247
1250
|
// Skill level other events
|
|
1248
1251
|
constants.events.push([
|
|
1249
|
-
document.getElementById(
|
|
1250
|
-
|
|
1252
|
+
document.getElementById("skill_level"),
|
|
1253
|
+
"change",
|
|
1251
1254
|
function (e) {
|
|
1252
|
-
if (e.target.value ==
|
|
1255
|
+
if (e.target.value == "other") {
|
|
1253
1256
|
document
|
|
1254
|
-
.getElementById(
|
|
1255
|
-
.classList.remove(
|
|
1257
|
+
.getElementById("skill_level_other_container")
|
|
1258
|
+
.classList.remove("hidden");
|
|
1256
1259
|
} else {
|
|
1257
1260
|
document
|
|
1258
|
-
.getElementById(
|
|
1259
|
-
.classList.add(
|
|
1261
|
+
.getElementById("skill_level_other_container")
|
|
1262
|
+
.classList.add("hidden");
|
|
1260
1263
|
}
|
|
1261
1264
|
},
|
|
1262
1265
|
]);
|
|
@@ -1264,16 +1267,16 @@ class Menu {
|
|
|
1264
1267
|
// trigger notification that LLM will be reset
|
|
1265
1268
|
// this is done on change of LLM model, multi settings, or skill level
|
|
1266
1269
|
let LLMResetIds = [
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1270
|
+
"LLM_model",
|
|
1271
|
+
"openai_multi",
|
|
1272
|
+
"gemini_multi",
|
|
1273
|
+
"skill_level",
|
|
1274
|
+
"LLM_preferences",
|
|
1272
1275
|
];
|
|
1273
1276
|
for (let i = 0; i < LLMResetIds.length; i++) {
|
|
1274
1277
|
constants.events.push([
|
|
1275
1278
|
document.getElementById(LLMResetIds[i]),
|
|
1276
|
-
|
|
1279
|
+
"change",
|
|
1277
1280
|
function (e) {
|
|
1278
1281
|
menu.NotifyOfLLMReset();
|
|
1279
1282
|
},
|
|
@@ -1283,13 +1286,13 @@ class Menu {
|
|
|
1283
1286
|
// Limit selections to 2 AI models
|
|
1284
1287
|
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
1285
1288
|
llmCheckboxes.forEach((checkbox) => {
|
|
1286
|
-
checkbox.addEventListener(
|
|
1289
|
+
checkbox.addEventListener("change", () => {
|
|
1287
1290
|
const checked = document.querySelectorAll(
|
|
1288
1291
|
'input[name="LLM_model"]:checked'
|
|
1289
1292
|
);
|
|
1290
1293
|
if (checked.length > 2) {
|
|
1291
1294
|
checkbox.checked = false;
|
|
1292
|
-
alert(
|
|
1295
|
+
alert("You can select up to 2 AI models.");
|
|
1293
1296
|
}
|
|
1294
1297
|
});
|
|
1295
1298
|
});
|
|
@@ -1301,11 +1304,11 @@ class Menu {
|
|
|
1301
1304
|
*/
|
|
1302
1305
|
Destroy() {
|
|
1303
1306
|
// menu element destruction
|
|
1304
|
-
let menu = document.getElementById(
|
|
1307
|
+
let menu = document.getElementById("menu");
|
|
1305
1308
|
if (menu) {
|
|
1306
1309
|
menu.remove();
|
|
1307
1310
|
}
|
|
1308
|
-
let backdrop = document.getElementById(
|
|
1311
|
+
let backdrop = document.getElementById("menu_modal_backdrop");
|
|
1309
1312
|
if (backdrop) {
|
|
1310
1313
|
backdrop.remove();
|
|
1311
1314
|
}
|
|
@@ -1317,16 +1320,16 @@ class Menu {
|
|
|
1317
1320
|
* @return {void}
|
|
1318
1321
|
*/
|
|
1319
1322
|
Toggle(onoff = false) {
|
|
1320
|
-
if (typeof onoff ==
|
|
1321
|
-
if (document.getElementById(
|
|
1323
|
+
if (typeof onoff == "undefined") {
|
|
1324
|
+
if (document.getElementById("menu").classList.contains("hidden")) {
|
|
1322
1325
|
onoff = true;
|
|
1323
1326
|
} else {
|
|
1324
1327
|
onoff = false;
|
|
1325
1328
|
}
|
|
1326
1329
|
}
|
|
1327
1330
|
// don't open if we have another modal open already
|
|
1328
|
-
if (onoff && document.getElementById(
|
|
1329
|
-
if (!document.getElementById(
|
|
1331
|
+
if (onoff && document.getElementById("chatLLM")) {
|
|
1332
|
+
if (!document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
1330
1333
|
return;
|
|
1331
1334
|
}
|
|
1332
1335
|
}
|
|
@@ -1335,13 +1338,13 @@ class Menu {
|
|
|
1335
1338
|
this.whereWasMyFocus = document.activeElement;
|
|
1336
1339
|
this.PopulateData();
|
|
1337
1340
|
constants.tabMovement = 0;
|
|
1338
|
-
document.getElementById(
|
|
1339
|
-
document.getElementById(
|
|
1340
|
-
document.querySelector(
|
|
1341
|
+
document.getElementById("menu").classList.remove("hidden");
|
|
1342
|
+
document.getElementById("menu_modal_backdrop").classList.remove("hidden");
|
|
1343
|
+
document.querySelector("#menu .close").focus();
|
|
1341
1344
|
} else {
|
|
1342
1345
|
// close
|
|
1343
|
-
document.getElementById(
|
|
1344
|
-
document.getElementById(
|
|
1346
|
+
document.getElementById("menu").classList.add("hidden");
|
|
1347
|
+
document.getElementById("menu_modal_backdrop").classList.add("hidden");
|
|
1345
1348
|
this.whereWasMyFocus.focus();
|
|
1346
1349
|
this.whereWasMyFocus = null;
|
|
1347
1350
|
}
|
|
@@ -1352,42 +1355,42 @@ class Menu {
|
|
|
1352
1355
|
* @return {void}
|
|
1353
1356
|
*/
|
|
1354
1357
|
PopulateData() {
|
|
1355
|
-
document.getElementById(
|
|
1356
|
-
document.getElementById(
|
|
1358
|
+
document.getElementById("vol").value = constants.vol;
|
|
1359
|
+
document.getElementById("braille_display_length").value =
|
|
1357
1360
|
constants.brailleDisplayLength;
|
|
1358
|
-
document.getElementById(
|
|
1359
|
-
document.getElementById(
|
|
1360
|
-
document.getElementById(
|
|
1361
|
-
document.getElementById(
|
|
1361
|
+
document.getElementById("color_selected").value = constants.colorSelected;
|
|
1362
|
+
document.getElementById("min_freq").value = constants.MIN_FREQUENCY;
|
|
1363
|
+
document.getElementById("max_freq").value = constants.MAX_FREQUENCY;
|
|
1364
|
+
document.getElementById("AUTOPLAY_DURATION").value =
|
|
1362
1365
|
constants.AUTOPLAY_DURATION;
|
|
1363
|
-
if (typeof constants.openAIAuthKey ==
|
|
1364
|
-
document.getElementById(
|
|
1366
|
+
if (typeof constants.openAIAuthKey == "string") {
|
|
1367
|
+
document.getElementById("openai_auth_key").value =
|
|
1365
1368
|
constants.openAIAuthKey;
|
|
1366
1369
|
}
|
|
1367
|
-
if (typeof constants.emailAuthKey ==
|
|
1368
|
-
document.getElementById(
|
|
1370
|
+
if (typeof constants.emailAuthKey == "string") {
|
|
1371
|
+
document.getElementById("email_auth_key").value = constants.emailAuthKey;
|
|
1369
1372
|
}
|
|
1370
|
-
if (typeof constants.geminiAuthKey ==
|
|
1371
|
-
document.getElementById(
|
|
1373
|
+
if (typeof constants.geminiAuthKey == "string") {
|
|
1374
|
+
document.getElementById("gemini_auth_key").value =
|
|
1372
1375
|
constants.geminiAuthKey;
|
|
1373
1376
|
}
|
|
1374
|
-
if (typeof constants.claudeAuthKey ==
|
|
1375
|
-
document.getElementById(
|
|
1377
|
+
if (typeof constants.claudeAuthKey == "string") {
|
|
1378
|
+
document.getElementById("claude_auth_key").value =
|
|
1376
1379
|
constants.claudeAuthKey;
|
|
1377
1380
|
}
|
|
1378
|
-
document.getElementById(
|
|
1381
|
+
document.getElementById("skill_level").value = constants.skillLevel;
|
|
1379
1382
|
if (constants.skillLevelOther) {
|
|
1380
|
-
document.getElementById(
|
|
1383
|
+
document.getElementById("skill_level_other").value =
|
|
1381
1384
|
constants.skillLevelOther;
|
|
1382
1385
|
}
|
|
1383
1386
|
|
|
1384
1387
|
// aria mode
|
|
1385
|
-
if (constants.ariaMode ==
|
|
1386
|
-
document.getElementById(
|
|
1387
|
-
document.getElementById(
|
|
1388
|
+
if (constants.ariaMode == "assertive") {
|
|
1389
|
+
document.getElementById("aria_mode_assertive").checked = true;
|
|
1390
|
+
document.getElementById("aria_mode_polite").checked = false;
|
|
1388
1391
|
} else {
|
|
1389
|
-
document.getElementById(
|
|
1390
|
-
document.getElementById(
|
|
1392
|
+
document.getElementById("aria_mode_polite").checked = true;
|
|
1393
|
+
document.getElementById("aria_mode_assertive").checked = false;
|
|
1391
1394
|
}
|
|
1392
1395
|
|
|
1393
1396
|
for (let model in constants.LLMModels) {
|
|
@@ -1395,25 +1398,25 @@ class Menu {
|
|
|
1395
1398
|
|
|
1396
1399
|
document
|
|
1397
1400
|
.getElementById(`${model}_auth_key_container`)
|
|
1398
|
-
.classList.remove(
|
|
1401
|
+
.classList.remove("hidden");
|
|
1399
1402
|
}
|
|
1400
1403
|
document
|
|
1401
1404
|
.getElementById(`claude_auth_key_container`)
|
|
1402
|
-
.classList.add(
|
|
1405
|
+
.classList.add("hidden");
|
|
1403
1406
|
|
|
1404
1407
|
// skill level other
|
|
1405
|
-
if (constants.skillLevel ==
|
|
1408
|
+
if (constants.skillLevel == "other") {
|
|
1406
1409
|
document
|
|
1407
|
-
.getElementById(
|
|
1408
|
-
.classList.remove(
|
|
1410
|
+
.getElementById("skill_level_other_container")
|
|
1411
|
+
.classList.remove("hidden");
|
|
1409
1412
|
}
|
|
1410
1413
|
// LLM preferences
|
|
1411
1414
|
if (constants.LLMPreferences) {
|
|
1412
|
-
document.getElementById(
|
|
1415
|
+
document.getElementById("LLM_preferences").value =
|
|
1413
1416
|
constants.LLMPreferences;
|
|
1414
1417
|
}
|
|
1415
|
-
if (document.getElementById(
|
|
1416
|
-
document.getElementById(
|
|
1418
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1419
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1417
1420
|
}
|
|
1418
1421
|
}
|
|
1419
1422
|
|
|
@@ -1424,23 +1427,23 @@ class Menu {
|
|
|
1424
1427
|
SaveData() {
|
|
1425
1428
|
let shouldReset = this.ShouldLLMReset();
|
|
1426
1429
|
|
|
1427
|
-
constants.vol = document.getElementById(
|
|
1430
|
+
constants.vol = document.getElementById("vol").value;
|
|
1428
1431
|
constants.brailleDisplayLength = document.getElementById(
|
|
1429
|
-
|
|
1432
|
+
"braille_display_length"
|
|
1430
1433
|
).value;
|
|
1431
|
-
constants.colorSelected = document.getElementById(
|
|
1432
|
-
constants.MIN_FREQUENCY = document.getElementById(
|
|
1433
|
-
constants.MAX_FREQUENCY = document.getElementById(
|
|
1434
|
+
constants.colorSelected = document.getElementById("color_selected").value;
|
|
1435
|
+
constants.MIN_FREQUENCY = document.getElementById("min_freq").value;
|
|
1436
|
+
constants.MAX_FREQUENCY = document.getElementById("max_freq").value;
|
|
1434
1437
|
constants.AUTOPLAY_DURATION =
|
|
1435
|
-
document.getElementById(
|
|
1438
|
+
document.getElementById("AUTOPLAY_DURATION").value;
|
|
1436
1439
|
|
|
1437
|
-
constants.openAIAuthKey = document.getElementById(
|
|
1438
|
-
constants.geminiAuthKey = document.getElementById(
|
|
1439
|
-
constants.claudeAuthKey = document.getElementById(
|
|
1440
|
-
constants.emailAuthKey = document.getElementById(
|
|
1441
|
-
constants.skillLevel = document.getElementById(
|
|
1440
|
+
constants.openAIAuthKey = document.getElementById("openai_auth_key").value;
|
|
1441
|
+
constants.geminiAuthKey = document.getElementById("gemini_auth_key").value;
|
|
1442
|
+
constants.claudeAuthKey = document.getElementById("claude_auth_key").value;
|
|
1443
|
+
constants.emailAuthKey = document.getElementById("email_auth_key").value;
|
|
1444
|
+
constants.skillLevel = document.getElementById("skill_level").value;
|
|
1442
1445
|
constants.skillLevelOther =
|
|
1443
|
-
document.getElementById(
|
|
1446
|
+
document.getElementById("skill_level_other").value;
|
|
1444
1447
|
// constants.LLMModel = document.getElementById('LLM_model').value;
|
|
1445
1448
|
|
|
1446
1449
|
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
@@ -1452,16 +1455,16 @@ class Menu {
|
|
|
1452
1455
|
}
|
|
1453
1456
|
});
|
|
1454
1457
|
|
|
1455
|
-
constants.LLMPreferences = document.getElementById(
|
|
1456
|
-
constants.LLMOpenAiMulti = document.getElementById(
|
|
1457
|
-
constants.LLMGeminiMulti = document.getElementById(
|
|
1458
|
-
constants.autoInitLLM = document.getElementById(
|
|
1458
|
+
constants.LLMPreferences = document.getElementById("LLM_preferences").value;
|
|
1459
|
+
constants.LLMOpenAiMulti = document.getElementById("openai_multi").checked;
|
|
1460
|
+
constants.LLMGeminiMulti = document.getElementById("gemini_multi").checked;
|
|
1461
|
+
constants.autoInitLLM = document.getElementById("init_llm_on_load").checked;
|
|
1459
1462
|
|
|
1460
1463
|
// aria
|
|
1461
|
-
if (document.getElementById(
|
|
1462
|
-
constants.ariaMode =
|
|
1463
|
-
} else if (document.getElementById(
|
|
1464
|
-
constants.ariaMode =
|
|
1464
|
+
if (document.getElementById("aria_mode_assertive").checked) {
|
|
1465
|
+
constants.ariaMode = "assertive";
|
|
1466
|
+
} else if (document.getElementById("aria_mode_polite").checked) {
|
|
1467
|
+
constants.ariaMode = "polite";
|
|
1465
1468
|
}
|
|
1466
1469
|
|
|
1467
1470
|
this.SaveDataToLocalStorage();
|
|
@@ -1475,8 +1478,8 @@ class Menu {
|
|
|
1475
1478
|
}
|
|
1476
1479
|
|
|
1477
1480
|
VerifyEmail() {
|
|
1478
|
-
let email = document.getElementById(
|
|
1479
|
-
if (email && email.indexOf(
|
|
1481
|
+
let email = document.getElementById("email_auth_key").value;
|
|
1482
|
+
if (email && email.indexOf("@") !== -1) {
|
|
1480
1483
|
let url = `https://maidr-service.azurewebsites.net/api/send_email?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D`;
|
|
1481
1484
|
|
|
1482
1485
|
let requestJson = {
|
|
@@ -1484,9 +1487,9 @@ class Menu {
|
|
|
1484
1487
|
};
|
|
1485
1488
|
|
|
1486
1489
|
fetch(url, {
|
|
1487
|
-
method:
|
|
1490
|
+
method: "POST",
|
|
1488
1491
|
headers: {
|
|
1489
|
-
|
|
1492
|
+
"Content-Type": "application/json",
|
|
1490
1493
|
Authentication: constants.emailAuthKey,
|
|
1491
1494
|
},
|
|
1492
1495
|
body: JSON.stringify(requestJson),
|
|
@@ -1494,7 +1497,7 @@ class Menu {
|
|
|
1494
1497
|
.then((response) => response.json())
|
|
1495
1498
|
.then((data) => {
|
|
1496
1499
|
if (data && data.success) {
|
|
1497
|
-
alert(
|
|
1500
|
+
alert("Link sent to email address: " + email);
|
|
1498
1501
|
} else {
|
|
1499
1502
|
console.log(data);
|
|
1500
1503
|
alert(data.data);
|
|
@@ -1505,7 +1508,7 @@ class Menu {
|
|
|
1505
1508
|
alert(error.data);
|
|
1506
1509
|
});
|
|
1507
1510
|
} else {
|
|
1508
|
-
alert(
|
|
1511
|
+
alert("Please enter a valid email address.");
|
|
1509
1512
|
}
|
|
1510
1513
|
}
|
|
1511
1514
|
|
|
@@ -1515,29 +1518,29 @@ class Menu {
|
|
|
1515
1518
|
*/
|
|
1516
1519
|
UpdateHtml() {
|
|
1517
1520
|
// set aria attributes
|
|
1518
|
-
constants.infoDiv.setAttribute(
|
|
1521
|
+
constants.infoDiv.setAttribute("aria-live", constants.ariaMode);
|
|
1519
1522
|
document
|
|
1520
1523
|
.getElementById(constants.announcement_container_id)
|
|
1521
|
-
.setAttribute(
|
|
1524
|
+
.setAttribute("aria-live", constants.ariaMode);
|
|
1522
1525
|
|
|
1523
|
-
document.getElementById(
|
|
1524
|
-
const scatter = document.getElementsByClassName(
|
|
1525
|
-
const heatmap = document.getElementById(
|
|
1526
|
-
const line = document.getElementById(
|
|
1526
|
+
document.getElementById("init_llm_on_load").checked = constants.autoInitLLM;
|
|
1527
|
+
const scatter = document.getElementsByClassName("highlight_point");
|
|
1528
|
+
const heatmap = document.getElementById("highlight_rect");
|
|
1529
|
+
const line = document.getElementById("highlight_point");
|
|
1527
1530
|
|
|
1528
1531
|
if (scatter !== null && scatter.length > 0) {
|
|
1529
1532
|
for (let i = 0; i < scatter.length; i++) {
|
|
1530
|
-
scatter[i].setAttribute(
|
|
1531
|
-
scatter[i].setAttribute(
|
|
1533
|
+
scatter[i].setAttribute("stroke", constants.colorSelected);
|
|
1534
|
+
scatter[i].setAttribute("fill", constants.colorSelected);
|
|
1532
1535
|
}
|
|
1533
1536
|
}
|
|
1534
1537
|
|
|
1535
1538
|
if (heatmap !== null) {
|
|
1536
|
-
heatmap.setAttribute(
|
|
1539
|
+
heatmap.setAttribute("stroke", constants.colorSelected);
|
|
1537
1540
|
}
|
|
1538
1541
|
|
|
1539
1542
|
if (line !== null) {
|
|
1540
|
-
line.setAttribute(
|
|
1543
|
+
line.setAttribute("stroke", constants.colorSelected);
|
|
1541
1544
|
}
|
|
1542
1545
|
}
|
|
1543
1546
|
|
|
@@ -1549,19 +1552,19 @@ class Menu {
|
|
|
1549
1552
|
let html =
|
|
1550
1553
|
'<p id="LLM_reset_notification">Note: Changes in LLM settings will reset any existing conversation.</p>';
|
|
1551
1554
|
|
|
1552
|
-
if (document.getElementById(
|
|
1553
|
-
document.getElementById(
|
|
1555
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1556
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1554
1557
|
}
|
|
1555
1558
|
document
|
|
1556
|
-
.getElementById(
|
|
1557
|
-
.parentElement.insertAdjacentHTML(
|
|
1559
|
+
.getElementById("save_and_close_menu")
|
|
1560
|
+
.parentElement.insertAdjacentHTML("afterend", html);
|
|
1558
1561
|
|
|
1559
1562
|
// add to aria button text
|
|
1560
1563
|
document
|
|
1561
|
-
.getElementById(
|
|
1564
|
+
.getElementById("save_and_close_menu")
|
|
1562
1565
|
.setAttribute(
|
|
1563
|
-
|
|
1564
|
-
|
|
1566
|
+
"aria-labelledby",
|
|
1567
|
+
"save_and_close_text LLM_reset_notification"
|
|
1565
1568
|
);
|
|
1566
1569
|
}
|
|
1567
1570
|
/**
|
|
@@ -1573,20 +1576,20 @@ class Menu {
|
|
|
1573
1576
|
let shouldReset = false;
|
|
1574
1577
|
if (
|
|
1575
1578
|
!shouldReset &&
|
|
1576
|
-
constants.skillLevel != document.getElementById(
|
|
1579
|
+
constants.skillLevel != document.getElementById("skill_level").value
|
|
1577
1580
|
) {
|
|
1578
1581
|
shouldReset = true;
|
|
1579
1582
|
}
|
|
1580
1583
|
if (
|
|
1581
1584
|
!shouldReset &&
|
|
1582
1585
|
constants.LLMPreferences !=
|
|
1583
|
-
document.getElementById(
|
|
1586
|
+
document.getElementById("LLM_preferences").value
|
|
1584
1587
|
) {
|
|
1585
1588
|
shouldReset = true;
|
|
1586
1589
|
}
|
|
1587
1590
|
if (
|
|
1588
1591
|
!shouldReset &&
|
|
1589
|
-
constants.LLMModel != document.getElementById(
|
|
1592
|
+
constants.LLMModel != document.getElementById("LLM_model").value
|
|
1590
1593
|
) {
|
|
1591
1594
|
shouldReset = true;
|
|
1592
1595
|
}
|
|
@@ -1615,24 +1618,24 @@ class Menu {
|
|
|
1615
1618
|
data[constants.userSettingsKeys[i]] =
|
|
1616
1619
|
constants[constants.userSettingsKeys[i]];
|
|
1617
1620
|
}
|
|
1618
|
-
localStorage.setItem(
|
|
1621
|
+
localStorage.setItem("settings_data", JSON.stringify(data));
|
|
1619
1622
|
|
|
1620
1623
|
// also save to tracking if we're doing that
|
|
1621
1624
|
if (constants.canTrack) {
|
|
1622
1625
|
// but not auth keys
|
|
1623
|
-
data.openAIAuthKey =
|
|
1624
|
-
data.geminiAuthKey =
|
|
1625
|
-
data.claudeAuthKey =
|
|
1626
|
+
data.openAIAuthKey = "hidden";
|
|
1627
|
+
data.geminiAuthKey = "hidden";
|
|
1628
|
+
data.claudeAuthKey = "hidden";
|
|
1626
1629
|
// and need a timestamp
|
|
1627
1630
|
data.timestamp = new Date().toISOString();
|
|
1628
|
-
tracker.SetData(
|
|
1631
|
+
tracker.SetData("settings", data);
|
|
1629
1632
|
}
|
|
1630
1633
|
}
|
|
1631
1634
|
/**
|
|
1632
1635
|
* Loads data from 'settings_data' localStorage, and updates contants variables
|
|
1633
1636
|
*/
|
|
1634
1637
|
LoadDataFromLocalStorage() {
|
|
1635
|
-
let data = JSON.parse(localStorage.getItem(
|
|
1638
|
+
let data = JSON.parse(localStorage.getItem("settings_data"));
|
|
1636
1639
|
if (data) {
|
|
1637
1640
|
for (let i = 0; i < constants.userSettingsKeys.length; i++) {
|
|
1638
1641
|
const key = constants.userSettingsKeys[i];
|
|
@@ -1660,9 +1663,9 @@ class ChatLLM {
|
|
|
1660
1663
|
if (constants.autoInitLLM) {
|
|
1661
1664
|
// only run if we have API keys set
|
|
1662
1665
|
if (
|
|
1663
|
-
(
|
|
1664
|
-
(
|
|
1665
|
-
(
|
|
1666
|
+
("gemini" in constants.LLMModels && constants.geminiAuthKey) ||
|
|
1667
|
+
("openai" in constants.LLMModels && constants.openAIAuthKey) ||
|
|
1668
|
+
("claude" in constants.LLMModels && constants.claudeAuthKey)
|
|
1666
1669
|
) {
|
|
1667
1670
|
this.InitChatMessage();
|
|
1668
1671
|
}
|
|
@@ -1715,7 +1718,7 @@ class ChatLLM {
|
|
|
1715
1718
|
</div>
|
|
1716
1719
|
<div id="chatLLM_modal_backdrop" class="modal-backdrop hidden"></div>
|
|
1717
1720
|
`;
|
|
1718
|
-
document.querySelector(
|
|
1721
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
1719
1722
|
}
|
|
1720
1723
|
|
|
1721
1724
|
/**
|
|
@@ -1724,21 +1727,21 @@ class ChatLLM {
|
|
|
1724
1727
|
*/
|
|
1725
1728
|
SetEvents() {
|
|
1726
1729
|
// chatLLM close events
|
|
1727
|
-
let allClose = document.querySelectorAll(
|
|
1730
|
+
let allClose = document.querySelectorAll("#close_chatLLM, #chatLLM .close");
|
|
1728
1731
|
for (let i = 0; i < allClose.length; i++) {
|
|
1729
1732
|
constants.events.push([
|
|
1730
1733
|
allClose[i],
|
|
1731
|
-
|
|
1734
|
+
"click",
|
|
1732
1735
|
function (e) {
|
|
1733
1736
|
chatLLM.Toggle(false);
|
|
1734
1737
|
},
|
|
1735
1738
|
]);
|
|
1736
1739
|
}
|
|
1737
1740
|
constants.events.push([
|
|
1738
|
-
document.getElementById(
|
|
1739
|
-
|
|
1741
|
+
document.getElementById("chatLLM"),
|
|
1742
|
+
"keyup",
|
|
1740
1743
|
function (e) {
|
|
1741
|
-
if (e.key ==
|
|
1744
|
+
if (e.key == "Esc") {
|
|
1742
1745
|
// esc
|
|
1743
1746
|
chatLLM.Toggle(false);
|
|
1744
1747
|
}
|
|
@@ -1748,9 +1751,9 @@ class ChatLLM {
|
|
|
1748
1751
|
// ChatLLM open/close toggle
|
|
1749
1752
|
constants.events.push([
|
|
1750
1753
|
document,
|
|
1751
|
-
|
|
1754
|
+
"keyup",
|
|
1752
1755
|
function (e) {
|
|
1753
|
-
if ((e.key ==
|
|
1756
|
+
if ((e.key == "?" && (e.ctrlKey || e.metaKey)) || e.key == "¿") {
|
|
1754
1757
|
chatLLM.Toggle();
|
|
1755
1758
|
}
|
|
1756
1759
|
},
|
|
@@ -1758,21 +1761,21 @@ class ChatLLM {
|
|
|
1758
1761
|
|
|
1759
1762
|
// ChatLLM request events
|
|
1760
1763
|
constants.events.push([
|
|
1761
|
-
document.getElementById(
|
|
1762
|
-
|
|
1764
|
+
document.getElementById("chatLLM_submit"),
|
|
1765
|
+
"click",
|
|
1763
1766
|
function (e) {
|
|
1764
|
-
let text = document.getElementById(
|
|
1765
|
-
chatLLM.DisplayChatMessage(
|
|
1767
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1768
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1766
1769
|
chatLLM.Submit(text);
|
|
1767
1770
|
},
|
|
1768
1771
|
]);
|
|
1769
1772
|
constants.events.push([
|
|
1770
|
-
document.getElementById(
|
|
1771
|
-
|
|
1773
|
+
document.getElementById("chatLLM_input"),
|
|
1774
|
+
"keyup",
|
|
1772
1775
|
function (e) {
|
|
1773
|
-
if (e.key ==
|
|
1774
|
-
let text = document.getElementById(
|
|
1775
|
-
chatLLM.DisplayChatMessage(
|
|
1776
|
+
if (e.key == "Enter" && !e.shiftKey) {
|
|
1777
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1778
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1776
1779
|
chatLLM.Submit(text);
|
|
1777
1780
|
}
|
|
1778
1781
|
},
|
|
@@ -1781,15 +1784,15 @@ class ChatLLM {
|
|
|
1781
1784
|
// ChatLLM suggestion events
|
|
1782
1785
|
// actual suggestions:
|
|
1783
1786
|
let suggestions = document.querySelectorAll(
|
|
1784
|
-
|
|
1787
|
+
"#chatLLM .LLM_suggestions button:not(#more_suggestions)"
|
|
1785
1788
|
);
|
|
1786
1789
|
for (let i = 0; i < suggestions.length; i++) {
|
|
1787
1790
|
constants.events.push([
|
|
1788
1791
|
suggestions[i],
|
|
1789
|
-
|
|
1792
|
+
"click",
|
|
1790
1793
|
function (e) {
|
|
1791
1794
|
let text = e.target.innerHTML;
|
|
1792
|
-
chatLLM.DisplayChatMessage(
|
|
1795
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1793
1796
|
chatLLM.Submit(text);
|
|
1794
1797
|
},
|
|
1795
1798
|
]);
|
|
@@ -1797,31 +1800,31 @@ class ChatLLM {
|
|
|
1797
1800
|
|
|
1798
1801
|
// Delete OpenAI and Gemini keys
|
|
1799
1802
|
constants.events.push([
|
|
1800
|
-
document.getElementById(
|
|
1801
|
-
|
|
1803
|
+
document.getElementById("delete_openai_key"),
|
|
1804
|
+
"click",
|
|
1802
1805
|
function (e) {
|
|
1803
|
-
document.getElementById(
|
|
1806
|
+
document.getElementById("openai_auth_key").value = "";
|
|
1804
1807
|
},
|
|
1805
1808
|
]);
|
|
1806
1809
|
constants.events.push([
|
|
1807
|
-
document.getElementById(
|
|
1808
|
-
|
|
1810
|
+
document.getElementById("delete_email_key"),
|
|
1811
|
+
"click",
|
|
1809
1812
|
function (e) {
|
|
1810
|
-
document.getElementById(
|
|
1813
|
+
document.getElementById("email_auth_key").value = "";
|
|
1811
1814
|
},
|
|
1812
1815
|
]);
|
|
1813
1816
|
constants.events.push([
|
|
1814
|
-
document.getElementById(
|
|
1815
|
-
|
|
1817
|
+
document.getElementById("delete_gemini_key"),
|
|
1818
|
+
"click",
|
|
1816
1819
|
function (e) {
|
|
1817
|
-
document.getElementById(
|
|
1820
|
+
document.getElementById("gemini_auth_key").value = "";
|
|
1818
1821
|
},
|
|
1819
1822
|
]);
|
|
1820
1823
|
|
|
1821
1824
|
// Reset chatLLM
|
|
1822
1825
|
constants.events.push([
|
|
1823
|
-
document.getElementById(
|
|
1824
|
-
|
|
1826
|
+
document.getElementById("reset_chatLLM"),
|
|
1827
|
+
"click",
|
|
1825
1828
|
function (e) {
|
|
1826
1829
|
chatLLM.ResetLLM();
|
|
1827
1830
|
},
|
|
@@ -1829,15 +1832,15 @@ class ChatLLM {
|
|
|
1829
1832
|
|
|
1830
1833
|
// copy to clipboard
|
|
1831
1834
|
constants.events.push([
|
|
1832
|
-
document.getElementById(
|
|
1833
|
-
|
|
1835
|
+
document.getElementById("chatLLM"),
|
|
1836
|
+
"click",
|
|
1834
1837
|
function (e) {
|
|
1835
1838
|
chatLLM.CopyChatHistory(e);
|
|
1836
1839
|
},
|
|
1837
1840
|
]);
|
|
1838
1841
|
constants.events.push([
|
|
1839
|
-
document.getElementById(
|
|
1840
|
-
|
|
1842
|
+
document.getElementById("chatLLM"),
|
|
1843
|
+
"keyup",
|
|
1841
1844
|
function (e) {
|
|
1842
1845
|
chatLLM.CopyChatHistory(e);
|
|
1843
1846
|
},
|
|
@@ -1855,96 +1858,96 @@ class ChatLLM {
|
|
|
1855
1858
|
* @param {Event|undefined} e - The event that triggered the copy action. If undefined, the entire chat history is copied.
|
|
1856
1859
|
*/
|
|
1857
1860
|
CopyChatHistory(e) {
|
|
1858
|
-
let text =
|
|
1859
|
-
if (typeof e ==
|
|
1861
|
+
let text = "";
|
|
1862
|
+
if (typeof e == "undefined") {
|
|
1860
1863
|
// check for passthrough
|
|
1861
1864
|
// get html of the full chat history
|
|
1862
|
-
text = document.getElementById(
|
|
1863
|
-
} else if (e.type ==
|
|
1865
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1866
|
+
} else if (e.type == "click") {
|
|
1864
1867
|
// check for buttons
|
|
1865
|
-
if (e.target.id ==
|
|
1868
|
+
if (e.target.id == "chatLLM_copy_all") {
|
|
1866
1869
|
// get html of the full chat history
|
|
1867
|
-
text = document.getElementById(
|
|
1868
|
-
} else if (e.target.classList.contains(
|
|
1870
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1871
|
+
} else if (e.target.classList.contains("chatLLM_message_copy_button")) {
|
|
1869
1872
|
// get the text of the element before the button
|
|
1870
|
-
text = e.target.closest(
|
|
1873
|
+
text = e.target.closest("p").previousElementSibling.innerHTML;
|
|
1871
1874
|
}
|
|
1872
|
-
} else if (e.type ==
|
|
1875
|
+
} else if (e.type == "keyup") {
|
|
1873
1876
|
// check for alt shift c or ctrl shift c
|
|
1874
|
-
if (e.key ==
|
|
1877
|
+
if (e.key == "C" && (e.ctrlKey || e.metaKey || e.altKey) && e.shiftKey) {
|
|
1875
1878
|
e.preventDefault();
|
|
1876
1879
|
// get the last message
|
|
1877
1880
|
let elem = document.querySelector(
|
|
1878
|
-
|
|
1881
|
+
"#chatLLM_chat_history > .chatLLM_message_other:last-of-type"
|
|
1879
1882
|
);
|
|
1880
1883
|
if (elem) {
|
|
1881
1884
|
text = elem.innerHTML;
|
|
1882
1885
|
}
|
|
1883
1886
|
} else if (
|
|
1884
|
-
e.key ==
|
|
1887
|
+
e.key == "A" &&
|
|
1885
1888
|
(e.ctrlKey || e.metaKey || e.altKey) &&
|
|
1886
1889
|
e.shiftKey
|
|
1887
1890
|
) {
|
|
1888
1891
|
e.preventDefault();
|
|
1889
1892
|
// get html of the full chat history
|
|
1890
|
-
text = document.getElementById(
|
|
1893
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1891
1894
|
}
|
|
1892
1895
|
}
|
|
1893
1896
|
|
|
1894
|
-
if (text ==
|
|
1897
|
+
if (text == "") {
|
|
1895
1898
|
return;
|
|
1896
1899
|
} else {
|
|
1897
1900
|
// clear the html, removing buttons etc
|
|
1898
|
-
let cleanElems = document.createElement(
|
|
1901
|
+
let cleanElems = document.createElement("div");
|
|
1899
1902
|
cleanElems.innerHTML = text;
|
|
1900
|
-
let removeThese = cleanElems.querySelectorAll(
|
|
1903
|
+
let removeThese = cleanElems.querySelectorAll(".chatLLM_message_copy");
|
|
1901
1904
|
removeThese.forEach((elem) => elem.remove());
|
|
1902
1905
|
|
|
1903
1906
|
// convert from html to markdown
|
|
1904
1907
|
let markdown = this.htmlToMarkdown(cleanElems);
|
|
1905
1908
|
// this messes up a bit with spacing, so kill more than 2 newlines in a row
|
|
1906
|
-
markdown = markdown.replace(/\n{3,}/g,
|
|
1909
|
+
markdown = markdown.replace(/\n{3,}/g, "\n\n");
|
|
1907
1910
|
|
|
1908
1911
|
try {
|
|
1909
1912
|
navigator.clipboard.writeText(markdown); // note: this fails if you're on the inspector. That's fine as it'll never happen to real users
|
|
1910
1913
|
} catch (err) {
|
|
1911
|
-
console.error(
|
|
1914
|
+
console.error("Failed to copy: ", err);
|
|
1912
1915
|
}
|
|
1913
1916
|
return markdown;
|
|
1914
1917
|
}
|
|
1915
1918
|
}
|
|
1916
1919
|
|
|
1917
1920
|
htmlToMarkdown(element) {
|
|
1918
|
-
let markdown =
|
|
1921
|
+
let markdown = "";
|
|
1919
1922
|
|
|
1920
1923
|
const convertElementToMarkdown = (element) => {
|
|
1921
1924
|
switch (element.tagName) {
|
|
1922
|
-
case
|
|
1925
|
+
case "H1":
|
|
1923
1926
|
return `# ${element.textContent}`;
|
|
1924
|
-
case
|
|
1927
|
+
case "H2":
|
|
1925
1928
|
return `## ${element.textContent}`;
|
|
1926
|
-
case
|
|
1929
|
+
case "H3":
|
|
1927
1930
|
return `### ${element.textContent}`;
|
|
1928
|
-
case
|
|
1931
|
+
case "H4":
|
|
1929
1932
|
return `#### ${element.textContent}`;
|
|
1930
|
-
case
|
|
1933
|
+
case "H5":
|
|
1931
1934
|
return `##### ${element.textContent}`;
|
|
1932
|
-
case
|
|
1935
|
+
case "H6":
|
|
1933
1936
|
return `###### ${element.textContent}`;
|
|
1934
|
-
case
|
|
1937
|
+
case "P":
|
|
1935
1938
|
return element.textContent;
|
|
1936
|
-
case
|
|
1939
|
+
case "DIV":
|
|
1937
1940
|
// For divs, process each child and add newlines as needed
|
|
1938
1941
|
return (
|
|
1939
1942
|
Array.from(element.childNodes)
|
|
1940
1943
|
.map((child) => convertElementToMarkdown(child))
|
|
1941
|
-
.join(
|
|
1944
|
+
.join("\n") + "\n\n"
|
|
1942
1945
|
);
|
|
1943
1946
|
default:
|
|
1944
1947
|
// For any other element, process its children recursively
|
|
1945
1948
|
return Array.from(element.childNodes)
|
|
1946
1949
|
.map((child) => convertElementToMarkdown(child))
|
|
1947
|
-
.join(
|
|
1950
|
+
.join("");
|
|
1948
1951
|
}
|
|
1949
1952
|
};
|
|
1950
1953
|
|
|
@@ -1952,7 +1955,7 @@ class ChatLLM {
|
|
|
1952
1955
|
markdown += convertElementToMarkdown(element);
|
|
1953
1956
|
} else if (
|
|
1954
1957
|
element.nodeType === Node.TEXT_NODE &&
|
|
1955
|
-
element.textContent.trim() !==
|
|
1958
|
+
element.textContent.trim() !== ""
|
|
1956
1959
|
) {
|
|
1957
1960
|
markdown += element.textContent.trim();
|
|
1958
1961
|
}
|
|
@@ -1977,14 +1980,14 @@ class ChatLLM {
|
|
|
1977
1980
|
|
|
1978
1981
|
// if this is the user's first message (or we're gemini, in which case we need to send every time), prepend prompt with user position
|
|
1979
1982
|
if (
|
|
1980
|
-
(this.firstOpen ||
|
|
1983
|
+
(this.firstOpen || "gemini" in constants.LLMModels) &&
|
|
1981
1984
|
!firsttime &&
|
|
1982
1985
|
constants.verboseText.length > 0
|
|
1983
1986
|
) {
|
|
1984
1987
|
text =
|
|
1985
1988
|
"Here is the current position in the chart; no response necessarily needed, use this info only if it's relevant to future questions: " +
|
|
1986
1989
|
constants.verboseText +
|
|
1987
|
-
|
|
1990
|
+
". My question is: " +
|
|
1988
1991
|
text;
|
|
1989
1992
|
|
|
1990
1993
|
this.firstOpen = false;
|
|
@@ -1995,9 +1998,9 @@ class ChatLLM {
|
|
|
1995
1998
|
this.WaitingSound(true);
|
|
1996
1999
|
}
|
|
1997
2000
|
|
|
1998
|
-
if (
|
|
2001
|
+
if ("openai" in constants.LLMModels) {
|
|
1999
2002
|
if (firsttime) {
|
|
2000
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2003
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "openai");
|
|
2001
2004
|
}
|
|
2002
2005
|
if (constants.openAIAuthKey) {
|
|
2003
2006
|
chatLLM.OpenAIPrompt(text, img);
|
|
@@ -2005,9 +2008,9 @@ class ChatLLM {
|
|
|
2005
2008
|
chatLLM.OpenAIPromptAPI(text, img);
|
|
2006
2009
|
}
|
|
2007
2010
|
}
|
|
2008
|
-
if (
|
|
2011
|
+
if ("gemini" in constants.LLMModels) {
|
|
2009
2012
|
if (firsttime) {
|
|
2010
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2013
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "gemini");
|
|
2011
2014
|
}
|
|
2012
2015
|
if (constants.geminiAuthKey) {
|
|
2013
2016
|
chatLLM.GeminiPrompt(text, img);
|
|
@@ -2016,9 +2019,9 @@ class ChatLLM {
|
|
|
2016
2019
|
}
|
|
2017
2020
|
}
|
|
2018
2021
|
|
|
2019
|
-
if (
|
|
2022
|
+
if ("claude" in constants.LLMModels) {
|
|
2020
2023
|
if (firsttime) {
|
|
2021
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2024
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "claude");
|
|
2022
2025
|
}
|
|
2023
2026
|
if (constants.claudeAuthKey) {
|
|
2024
2027
|
chatLLM.ClaudePrompt(text, img);
|
|
@@ -2083,7 +2086,7 @@ class ChatLLM {
|
|
|
2083
2086
|
}, 30000);
|
|
2084
2087
|
|
|
2085
2088
|
// set queue for multi
|
|
2086
|
-
if (constants.LLMModel !=
|
|
2089
|
+
if (constants.LLMModel != "multi") {
|
|
2087
2090
|
constants.waitingQueue = 1;
|
|
2088
2091
|
} else {
|
|
2089
2092
|
constants.waitingQueue = 0;
|
|
@@ -2115,7 +2118,7 @@ class ChatLLM {
|
|
|
2115
2118
|
// get name from resource]
|
|
2116
2119
|
let LLMName = resources.GetString(constants.LLMModel);
|
|
2117
2120
|
this.firstTime = false;
|
|
2118
|
-
this.DisplayChatMessage(LLMName, resources.GetString(
|
|
2121
|
+
this.DisplayChatMessage(LLMName, resources.GetString("processing"), true);
|
|
2119
2122
|
let defaultPrompt = this.GetDefaultPrompt();
|
|
2120
2123
|
this.Submit(defaultPrompt, true);
|
|
2121
2124
|
}
|
|
@@ -2127,47 +2130,47 @@ class ChatLLM {
|
|
|
2127
2130
|
*/
|
|
2128
2131
|
ProcessLLMResponse(data, model) {
|
|
2129
2132
|
chatLLM.WaitingSound(false);
|
|
2130
|
-
let text =
|
|
2133
|
+
let text = "";
|
|
2131
2134
|
let LLMName = resources.GetString(model);
|
|
2132
2135
|
|
|
2133
|
-
if (model ==
|
|
2136
|
+
if (model == "openai") {
|
|
2134
2137
|
text = data.choices[0].message.content;
|
|
2135
2138
|
let i = this.requestJson.messages.length;
|
|
2136
2139
|
this.requestJson.messages[i] = {};
|
|
2137
|
-
this.requestJson.messages[i].role =
|
|
2140
|
+
this.requestJson.messages[i].role = "assistant";
|
|
2138
2141
|
this.requestJson.messages[i].content = text;
|
|
2139
2142
|
|
|
2140
2143
|
if (data.error) {
|
|
2141
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2144
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2142
2145
|
chatLLM.WaitingSound(false);
|
|
2143
2146
|
} else {
|
|
2144
2147
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2145
2148
|
}
|
|
2146
|
-
} else if (model ==
|
|
2149
|
+
} else if (model == "gemini") {
|
|
2147
2150
|
if (data.text()) {
|
|
2148
2151
|
text = data.text();
|
|
2149
2152
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2150
2153
|
} else {
|
|
2151
2154
|
if (!data.error) {
|
|
2152
|
-
data.error =
|
|
2155
|
+
data.error = "Error processing request.";
|
|
2153
2156
|
chatLLM.WaitingSound(false);
|
|
2154
2157
|
}
|
|
2155
2158
|
}
|
|
2156
2159
|
if (data.error) {
|
|
2157
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2160
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2158
2161
|
chatLLM.WaitingSound(false);
|
|
2159
2162
|
} else {
|
|
2160
2163
|
// todo: display actual response
|
|
2161
2164
|
}
|
|
2162
2165
|
}
|
|
2163
|
-
if (model ==
|
|
2164
|
-
console.log(
|
|
2166
|
+
if (model == "claude") {
|
|
2167
|
+
console.log("Claude response: ", data);
|
|
2165
2168
|
if (data.text()) {
|
|
2166
2169
|
text = data.text();
|
|
2167
2170
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2168
2171
|
}
|
|
2169
2172
|
if (data.error) {
|
|
2170
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2173
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2171
2174
|
chatLLM.WaitingSound(false);
|
|
2172
2175
|
}
|
|
2173
2176
|
}
|
|
@@ -2175,7 +2178,7 @@ class ChatLLM {
|
|
|
2175
2178
|
// if we're tracking, log the data
|
|
2176
2179
|
if (constants.canTrack) {
|
|
2177
2180
|
let chatHist = chatLLM.CopyChatHistory();
|
|
2178
|
-
tracker.SetData(
|
|
2181
|
+
tracker.SetData("ChatHistory", chatHist);
|
|
2179
2182
|
}
|
|
2180
2183
|
}
|
|
2181
2184
|
|
|
@@ -2189,11 +2192,11 @@ class ChatLLM {
|
|
|
2189
2192
|
if (this.requestJson.messages.length > 2) {
|
|
2190
2193
|
// subsequent responses
|
|
2191
2194
|
responseText = {
|
|
2192
|
-
id:
|
|
2193
|
-
object:
|
|
2195
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2196
|
+
object: "chat.completion",
|
|
2194
2197
|
created: 1703129508,
|
|
2195
2198
|
//model: 'gpt-4-1106-vision-preview',
|
|
2196
|
-
model:
|
|
2199
|
+
model: "gpt4-o",
|
|
2197
2200
|
usage: {
|
|
2198
2201
|
prompt_tokens: 451,
|
|
2199
2202
|
completion_tokens: 16,
|
|
@@ -2202,10 +2205,10 @@ class ChatLLM {
|
|
|
2202
2205
|
choices: [
|
|
2203
2206
|
{
|
|
2204
2207
|
message: {
|
|
2205
|
-
role:
|
|
2206
|
-
content:
|
|
2208
|
+
role: "assistant",
|
|
2209
|
+
content: "A fake response from the LLM. Nice.",
|
|
2207
2210
|
},
|
|
2208
|
-
finish_reason:
|
|
2211
|
+
finish_reason: "length",
|
|
2209
2212
|
index: 0,
|
|
2210
2213
|
},
|
|
2211
2214
|
],
|
|
@@ -2213,10 +2216,10 @@ class ChatLLM {
|
|
|
2213
2216
|
} else {
|
|
2214
2217
|
// first response
|
|
2215
2218
|
responseText = {
|
|
2216
|
-
id:
|
|
2217
|
-
object:
|
|
2219
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2220
|
+
object: "chat.completion",
|
|
2218
2221
|
created: 1703129508,
|
|
2219
|
-
model:
|
|
2222
|
+
model: "gpt-4-1106-vision-preview",
|
|
2220
2223
|
usage: {
|
|
2221
2224
|
prompt_tokens: 451,
|
|
2222
2225
|
completion_tokens: 16,
|
|
@@ -2225,11 +2228,11 @@ class ChatLLM {
|
|
|
2225
2228
|
choices: [
|
|
2226
2229
|
{
|
|
2227
2230
|
message: {
|
|
2228
|
-
role:
|
|
2231
|
+
role: "assistant",
|
|
2229
2232
|
content:
|
|
2230
|
-
|
|
2233
|
+
"The chart you're referring to is a bar graph titled \"The Number of Diamonds",
|
|
2231
2234
|
},
|
|
2232
|
-
finish_reason:
|
|
2235
|
+
finish_reason: "length",
|
|
2233
2236
|
index: 0,
|
|
2234
2237
|
},
|
|
2235
2238
|
],
|
|
@@ -2240,7 +2243,7 @@ class ChatLLM {
|
|
|
2240
2243
|
}
|
|
2241
2244
|
|
|
2242
2245
|
ClaudeJson(text, img = null) {
|
|
2243
|
-
const anthropicVersion =
|
|
2246
|
+
const anthropicVersion = "vertex-2023-10-16";
|
|
2244
2247
|
const maxTokens = 256;
|
|
2245
2248
|
|
|
2246
2249
|
const payload = {
|
|
@@ -2251,7 +2254,7 @@ class ChatLLM {
|
|
|
2251
2254
|
|
|
2252
2255
|
// Construct the user message object
|
|
2253
2256
|
const userMessage = {
|
|
2254
|
-
role:
|
|
2257
|
+
role: "user",
|
|
2255
2258
|
content: [],
|
|
2256
2259
|
};
|
|
2257
2260
|
|
|
@@ -2259,22 +2262,22 @@ class ChatLLM {
|
|
|
2259
2262
|
if (img) {
|
|
2260
2263
|
userMessage.content.push(
|
|
2261
2264
|
{
|
|
2262
|
-
type:
|
|
2265
|
+
type: "image",
|
|
2263
2266
|
source: {
|
|
2264
|
-
type:
|
|
2265
|
-
media_type:
|
|
2267
|
+
type: "base64",
|
|
2268
|
+
media_type: "image/jpeg", // Update if other formats are supported
|
|
2266
2269
|
data: img,
|
|
2267
2270
|
},
|
|
2268
2271
|
},
|
|
2269
2272
|
{
|
|
2270
|
-
type:
|
|
2273
|
+
type: "text",
|
|
2271
2274
|
text: text,
|
|
2272
2275
|
}
|
|
2273
2276
|
);
|
|
2274
2277
|
} else {
|
|
2275
2278
|
// Add only the text content if no image is provided
|
|
2276
2279
|
userMessage.content.push({
|
|
2277
|
-
type:
|
|
2280
|
+
type: "text",
|
|
2278
2281
|
text: text,
|
|
2279
2282
|
});
|
|
2280
2283
|
}
|
|
@@ -2286,16 +2289,16 @@ class ChatLLM {
|
|
|
2286
2289
|
}
|
|
2287
2290
|
|
|
2288
2291
|
ClaudePromptAPI(text, imgBase64 = null) {
|
|
2289
|
-
console.log(
|
|
2292
|
+
console.log("Claude prompt API");
|
|
2290
2293
|
let url =
|
|
2291
|
-
|
|
2294
|
+
"https://maidr-service.azurewebsites.net/api/claude?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2292
2295
|
|
|
2293
2296
|
// Create the prompt
|
|
2294
2297
|
let prompt = constants.LLMSystemMessage;
|
|
2295
2298
|
if (constants.LLMPreferences) {
|
|
2296
2299
|
prompt += constants.LLMPreferences;
|
|
2297
2300
|
}
|
|
2298
|
-
prompt +=
|
|
2301
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2299
2302
|
|
|
2300
2303
|
if (imgBase64 == null) {
|
|
2301
2304
|
imgBase64 = constants.LLMImage;
|
|
@@ -2307,9 +2310,9 @@ class ChatLLM {
|
|
|
2307
2310
|
let requestJson = chatLLM.ClaudeJson(prompt, imgBase64);
|
|
2308
2311
|
|
|
2309
2312
|
fetch(url, {
|
|
2310
|
-
method:
|
|
2313
|
+
method: "POST",
|
|
2311
2314
|
headers: {
|
|
2312
|
-
|
|
2315
|
+
"Content-Type": "application/json",
|
|
2313
2316
|
Authentication: constants.emailAuthKey,
|
|
2314
2317
|
},
|
|
2315
2318
|
body: JSON.stringify(requestJson),
|
|
@@ -2319,12 +2322,12 @@ class ChatLLM {
|
|
|
2319
2322
|
data.text = function () {
|
|
2320
2323
|
return data.content[0].text;
|
|
2321
2324
|
};
|
|
2322
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2325
|
+
chatLLM.ProcessLLMResponse(data, "claude");
|
|
2323
2326
|
})
|
|
2324
2327
|
.catch((error) => {
|
|
2325
2328
|
chatLLM.WaitingSound(false);
|
|
2326
|
-
console.error(
|
|
2327
|
-
chatLLM.DisplayChatMessage(
|
|
2329
|
+
console.error("Error:", error);
|
|
2330
|
+
chatLLM.DisplayChatMessage("Claude", "Error processing request.", true);
|
|
2328
2331
|
// also todo: handle errors somehow
|
|
2329
2332
|
});
|
|
2330
2333
|
}
|
|
@@ -2338,27 +2341,27 @@ class ChatLLM {
|
|
|
2338
2341
|
*/
|
|
2339
2342
|
OpenAIPrompt(text, img = null) {
|
|
2340
2343
|
// request init
|
|
2341
|
-
let url =
|
|
2344
|
+
let url = "https://api.openai.com/v1/chat/completions";
|
|
2342
2345
|
let auth = constants.openAIAuthKey;
|
|
2343
2346
|
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2344
2347
|
//console.log('LLM request: ', requestJson);
|
|
2345
2348
|
|
|
2346
2349
|
fetch(url, {
|
|
2347
|
-
method:
|
|
2350
|
+
method: "POST",
|
|
2348
2351
|
headers: {
|
|
2349
|
-
|
|
2350
|
-
Authorization:
|
|
2352
|
+
"Content-Type": "application/json",
|
|
2353
|
+
Authorization: "Bearer " + auth,
|
|
2351
2354
|
},
|
|
2352
2355
|
body: JSON.stringify(requestJson),
|
|
2353
2356
|
})
|
|
2354
2357
|
.then((response) => response.json())
|
|
2355
2358
|
.then((data) => {
|
|
2356
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2359
|
+
chatLLM.ProcessLLMResponse(data, "openai");
|
|
2357
2360
|
})
|
|
2358
2361
|
.catch((error) => {
|
|
2359
2362
|
chatLLM.WaitingSound(false);
|
|
2360
|
-
console.error(
|
|
2361
|
-
chatLLM.DisplayChatMessage(
|
|
2363
|
+
console.error("Error:", error);
|
|
2364
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2362
2365
|
// also todo: handle errors somehow
|
|
2363
2366
|
});
|
|
2364
2367
|
}
|
|
@@ -2366,27 +2369,27 @@ class ChatLLM {
|
|
|
2366
2369
|
OpenAIPromptAPI(text, img = null) {
|
|
2367
2370
|
// request init
|
|
2368
2371
|
let url =
|
|
2369
|
-
|
|
2372
|
+
"https://maidr-service.azurewebsites.net/api/openai?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2370
2373
|
let auth = constants.openAIAuthKey;
|
|
2371
2374
|
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2372
|
-
console.log(
|
|
2375
|
+
console.log("LLM request: ", requestJson);
|
|
2373
2376
|
|
|
2374
2377
|
fetch(url, {
|
|
2375
|
-
method:
|
|
2378
|
+
method: "POST",
|
|
2376
2379
|
headers: {
|
|
2377
|
-
|
|
2380
|
+
"Content-Type": "application/json",
|
|
2378
2381
|
Authentication: constants.emailAuthKey,
|
|
2379
2382
|
},
|
|
2380
2383
|
body: JSON.stringify(requestJson),
|
|
2381
2384
|
})
|
|
2382
2385
|
.then((response) => response.json())
|
|
2383
2386
|
.then((data) => {
|
|
2384
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2387
|
+
chatLLM.ProcessLLMResponse(data, "openai");
|
|
2385
2388
|
})
|
|
2386
2389
|
.catch((error) => {
|
|
2387
2390
|
chatLLM.WaitingSound(false);
|
|
2388
|
-
console.error(
|
|
2389
|
-
chatLLM.DisplayChatMessage(
|
|
2391
|
+
console.error("Error:", error);
|
|
2392
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2390
2393
|
// also todo: handle errors somehow
|
|
2391
2394
|
});
|
|
2392
2395
|
}
|
|
@@ -2394,22 +2397,22 @@ class ChatLLM {
|
|
|
2394
2397
|
OpenAIJson(text, img = null) {
|
|
2395
2398
|
let sysMessage = constants.LLMSystemMessage;
|
|
2396
2399
|
let backupMessage =
|
|
2397
|
-
|
|
2400
|
+
"Describe " + singleMaidr.type + " charts to a blind person";
|
|
2398
2401
|
// headers and sys message
|
|
2399
2402
|
if (!this.requestJson) {
|
|
2400
2403
|
this.requestJson = {};
|
|
2401
2404
|
//this.requestJson.model = 'gpt-4-vision-preview';
|
|
2402
|
-
this.requestJson.model =
|
|
2405
|
+
this.requestJson.model = "gpt-4o-2024-11-20";
|
|
2403
2406
|
this.requestJson.max_tokens = constants.LLMmaxResponseTokens; // note: if this is too short (tested with less than 200), the response gets cut off
|
|
2404
2407
|
|
|
2405
2408
|
// sys message
|
|
2406
2409
|
this.requestJson.messages = [];
|
|
2407
2410
|
this.requestJson.messages[0] = {};
|
|
2408
|
-
this.requestJson.messages[0].role =
|
|
2411
|
+
this.requestJson.messages[0].role = "system";
|
|
2409
2412
|
this.requestJson.messages[0].content = sysMessage;
|
|
2410
2413
|
if (constants.LLMPreferences) {
|
|
2411
2414
|
this.requestJson.messages[1] = {};
|
|
2412
|
-
this.requestJson.messages[1].role =
|
|
2415
|
+
this.requestJson.messages[1].role = "system";
|
|
2413
2416
|
this.requestJson.messages[1].content = constants.LLMPreferences;
|
|
2414
2417
|
}
|
|
2415
2418
|
}
|
|
@@ -2418,16 +2421,16 @@ class ChatLLM {
|
|
|
2418
2421
|
// if we have an image (first time only), send the image and the text, otherwise just the text
|
|
2419
2422
|
let i = this.requestJson.messages.length;
|
|
2420
2423
|
this.requestJson.messages[i] = {};
|
|
2421
|
-
this.requestJson.messages[i].role =
|
|
2424
|
+
this.requestJson.messages[i].role = "user";
|
|
2422
2425
|
if (img) {
|
|
2423
2426
|
// first message, include the img
|
|
2424
2427
|
this.requestJson.messages[i].content = [
|
|
2425
2428
|
{
|
|
2426
|
-
type:
|
|
2429
|
+
type: "text",
|
|
2427
2430
|
text: text,
|
|
2428
2431
|
},
|
|
2429
2432
|
{
|
|
2430
|
-
type:
|
|
2433
|
+
type: "image_url",
|
|
2431
2434
|
image_url: { url: img },
|
|
2432
2435
|
},
|
|
2433
2436
|
];
|
|
@@ -2442,7 +2445,7 @@ class ChatLLM {
|
|
|
2442
2445
|
GeminiJson(text, img = null) {
|
|
2443
2446
|
let sysMessage = constants.LLMSystemMessage;
|
|
2444
2447
|
let backupMessage =
|
|
2445
|
-
|
|
2448
|
+
"Describe " + singleMaidr.type + " charts to a blind person";
|
|
2446
2449
|
|
|
2447
2450
|
let payload = {
|
|
2448
2451
|
generationConfig: {},
|
|
@@ -2452,7 +2455,7 @@ class ChatLLM {
|
|
|
2452
2455
|
|
|
2453
2456
|
// System message as the initial "role" and "text" content for context
|
|
2454
2457
|
let sysContent = {
|
|
2455
|
-
role:
|
|
2458
|
+
role: "user",
|
|
2456
2459
|
parts: [
|
|
2457
2460
|
{
|
|
2458
2461
|
text: sysMessage || backupMessage, // Fallback if sysMessage is unavailable
|
|
@@ -2471,7 +2474,7 @@ class ChatLLM {
|
|
|
2471
2474
|
|
|
2472
2475
|
// Add user input content, including image if available
|
|
2473
2476
|
let userContent = {
|
|
2474
|
-
role:
|
|
2477
|
+
role: "user",
|
|
2475
2478
|
parts: [],
|
|
2476
2479
|
};
|
|
2477
2480
|
|
|
@@ -2484,7 +2487,7 @@ class ChatLLM {
|
|
|
2484
2487
|
{
|
|
2485
2488
|
inlineData: {
|
|
2486
2489
|
data: img, // Expecting base64-encoded image data
|
|
2487
|
-
mimeType:
|
|
2490
|
+
mimeType: "image/png", // Adjust if different image formats are possible
|
|
2488
2491
|
},
|
|
2489
2492
|
}
|
|
2490
2493
|
);
|
|
@@ -2503,14 +2506,14 @@ class ChatLLM {
|
|
|
2503
2506
|
|
|
2504
2507
|
async GeminiPromptAPI(text, imgBase64 = null) {
|
|
2505
2508
|
let url =
|
|
2506
|
-
|
|
2509
|
+
"https://maidr-service.azurewebsites.net/api/gemini?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2507
2510
|
|
|
2508
2511
|
// Create the prompt
|
|
2509
2512
|
let prompt = constants.LLMSystemMessage;
|
|
2510
2513
|
if (constants.LLMPreferences) {
|
|
2511
2514
|
prompt += constants.LLMPreferences;
|
|
2512
2515
|
}
|
|
2513
|
-
prompt +=
|
|
2516
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2514
2517
|
|
|
2515
2518
|
if (imgBase64 == null) {
|
|
2516
2519
|
imgBase64 = constants.LLMImage;
|
|
@@ -2522,9 +2525,9 @@ class ChatLLM {
|
|
|
2522
2525
|
let requestJson = chatLLM.GeminiJson(prompt, imgBase64);
|
|
2523
2526
|
|
|
2524
2527
|
const response = await fetch(url, {
|
|
2525
|
-
method:
|
|
2528
|
+
method: "POST",
|
|
2526
2529
|
headers: {
|
|
2527
|
-
|
|
2530
|
+
"Content-Type": "application/json",
|
|
2528
2531
|
Authentication: constants.emailAuthKey,
|
|
2529
2532
|
},
|
|
2530
2533
|
body: JSON.stringify(requestJson),
|
|
@@ -2534,11 +2537,11 @@ class ChatLLM {
|
|
|
2534
2537
|
responseJson.text = () => {
|
|
2535
2538
|
return responseJson.candidates[0].content.parts[0].text;
|
|
2536
2539
|
};
|
|
2537
|
-
chatLLM.ProcessLLMResponse(responseJson,
|
|
2540
|
+
chatLLM.ProcessLLMResponse(responseJson, "gemini");
|
|
2538
2541
|
} else {
|
|
2539
2542
|
chatLLM.WaitingSound(false);
|
|
2540
|
-
console.error(
|
|
2541
|
-
chatLLM.DisplayChatMessage(
|
|
2543
|
+
console.error("Error:", error);
|
|
2544
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2542
2545
|
// also todo: handle errors somehow
|
|
2543
2546
|
}
|
|
2544
2547
|
}
|
|
@@ -2556,12 +2559,12 @@ class ChatLLM {
|
|
|
2556
2559
|
|
|
2557
2560
|
// Import the module
|
|
2558
2561
|
const { GoogleGenerativeAI } = await import(
|
|
2559
|
-
|
|
2562
|
+
"https://esm.run/@google/generative-ai"
|
|
2560
2563
|
);
|
|
2561
2564
|
const API_KEY = constants.geminiAuthKey;
|
|
2562
2565
|
const genAI = new GoogleGenerativeAI(API_KEY);
|
|
2563
2566
|
const model = genAI.getGenerativeModel({
|
|
2564
|
-
model:
|
|
2567
|
+
model: "gemini-1.5-pro-latest",
|
|
2565
2568
|
}); // old model was 'gemini-pro-vision'
|
|
2566
2569
|
|
|
2567
2570
|
// Create the prompt
|
|
@@ -2569,11 +2572,11 @@ class ChatLLM {
|
|
|
2569
2572
|
if (constants.LLMPreferences) {
|
|
2570
2573
|
prompt += constants.LLMPreferences;
|
|
2571
2574
|
}
|
|
2572
|
-
prompt +=
|
|
2575
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2573
2576
|
const image = {
|
|
2574
2577
|
inlineData: {
|
|
2575
2578
|
data: imgBase64, // Use the base64 image string
|
|
2576
|
-
mimeType:
|
|
2579
|
+
mimeType: "image/png", // Or the appropriate mime type of your image
|
|
2577
2580
|
},
|
|
2578
2581
|
};
|
|
2579
2582
|
|
|
@@ -2583,11 +2586,11 @@ class ChatLLM {
|
|
|
2583
2586
|
//console.log(result.response.text());
|
|
2584
2587
|
|
|
2585
2588
|
// Process the response
|
|
2586
|
-
chatLLM.ProcessLLMResponse(result.response,
|
|
2589
|
+
chatLLM.ProcessLLMResponse(result.response, "gemini");
|
|
2587
2590
|
} catch (error) {
|
|
2588
2591
|
chatLLM.WaitingSound(false);
|
|
2589
|
-
chatLLM.DisplayChatMessage(
|
|
2590
|
-
console.error(
|
|
2592
|
+
chatLLM.DisplayChatMessage("Gemini", "Error processing request.", true);
|
|
2593
|
+
console.error("Error in GeminiPrompt:", error);
|
|
2591
2594
|
throw error; // Rethrow the error for further handling if necessary
|
|
2592
2595
|
}
|
|
2593
2596
|
}
|
|
@@ -2599,11 +2602,11 @@ class ChatLLM {
|
|
|
2599
2602
|
* @memberof module:constants
|
|
2600
2603
|
* @returns {void}
|
|
2601
2604
|
*/
|
|
2602
|
-
DisplayChatMessage(user =
|
|
2603
|
-
let hLevel =
|
|
2604
|
-
if (!isSystem && constants.LLMModel ==
|
|
2605
|
+
DisplayChatMessage(user = "User", text = "", isSystem = false) {
|
|
2606
|
+
let hLevel = "h3";
|
|
2607
|
+
if (!isSystem && constants.LLMModel == "multi" && user != "User") {
|
|
2605
2608
|
if (this.firstMulti) {
|
|
2606
|
-
let multiAIName = resources.GetString(
|
|
2609
|
+
let multiAIName = resources.GetString("multi");
|
|
2607
2610
|
let titleHtml = `
|
|
2608
2611
|
<div class="chatLLM_message chatLLM_message_other">
|
|
2609
2612
|
<h3 class="chatLLM_message_user">${multiAIName} Responses</h3>
|
|
@@ -2612,20 +2615,20 @@ class ChatLLM {
|
|
|
2612
2615
|
this.RenderChatMessage(titleHtml);
|
|
2613
2616
|
this.firstMulti = false;
|
|
2614
2617
|
}
|
|
2615
|
-
hLevel =
|
|
2618
|
+
hLevel = "h4";
|
|
2616
2619
|
}
|
|
2617
2620
|
let html = `
|
|
2618
2621
|
<div class="chatLLM_message ${
|
|
2619
|
-
user ==
|
|
2622
|
+
user == "User" ? "chatLLM_message_self" : "chatLLM_message_other"
|
|
2620
2623
|
}">`;
|
|
2621
|
-
if (text != resources.GetString(
|
|
2624
|
+
if (text != resources.GetString("processing")) {
|
|
2622
2625
|
html += `<${hLevel} class="chatLLM_message_user">${user}</${hLevel}>`;
|
|
2623
2626
|
}
|
|
2624
2627
|
html += `<p class="chatLLM_message_text">${text}</p>
|
|
2625
2628
|
</div>
|
|
2626
2629
|
`;
|
|
2627
2630
|
// add a copy button to actual messages
|
|
2628
|
-
if (user !=
|
|
2631
|
+
if (user != "User" && text != resources.GetString("processing")) {
|
|
2629
2632
|
html += `
|
|
2630
2633
|
<p class="chatLLM_message_copy"><button class="chatLLM_message_copy_button">Copy</button></p>
|
|
2631
2634
|
`;
|
|
@@ -2635,13 +2638,13 @@ class ChatLLM {
|
|
|
2635
2638
|
}
|
|
2636
2639
|
RenderChatMessage(html) {
|
|
2637
2640
|
document
|
|
2638
|
-
.getElementById(
|
|
2639
|
-
.insertAdjacentHTML(
|
|
2640
|
-
document.getElementById(
|
|
2641
|
+
.getElementById("chatLLM_chat_history")
|
|
2642
|
+
.insertAdjacentHTML("beforeend", html);
|
|
2643
|
+
document.getElementById("chatLLM_input").value = "";
|
|
2641
2644
|
|
|
2642
2645
|
// scroll to bottom
|
|
2643
|
-
document.getElementById(
|
|
2644
|
-
document.getElementById(
|
|
2646
|
+
document.getElementById("chatLLM_chat_history").scrollTop =
|
|
2647
|
+
document.getElementById("chatLLM_chat_history").scrollHeight;
|
|
2645
2648
|
}
|
|
2646
2649
|
|
|
2647
2650
|
/**
|
|
@@ -2649,7 +2652,7 @@ class ChatLLM {
|
|
|
2649
2652
|
*/
|
|
2650
2653
|
ResetLLM() {
|
|
2651
2654
|
// clear the main chat history
|
|
2652
|
-
document.getElementById(
|
|
2655
|
+
document.getElementById("chatLLM_chat_history").innerHTML = "";
|
|
2653
2656
|
|
|
2654
2657
|
// reset the data
|
|
2655
2658
|
this.requestJson = null;
|
|
@@ -2670,11 +2673,11 @@ class ChatLLM {
|
|
|
2670
2673
|
*/
|
|
2671
2674
|
Destroy() {
|
|
2672
2675
|
// chatLLM element destruction
|
|
2673
|
-
let chatLLM = document.getElementById(
|
|
2676
|
+
let chatLLM = document.getElementById("chatLLM");
|
|
2674
2677
|
if (chatLLM) {
|
|
2675
2678
|
chatLLM.remove();
|
|
2676
2679
|
}
|
|
2677
|
-
let backdrop = document.getElementById(
|
|
2680
|
+
let backdrop = document.getElementById("chatLLM_modal_backdrop");
|
|
2678
2681
|
if (backdrop) {
|
|
2679
2682
|
backdrop.remove();
|
|
2680
2683
|
}
|
|
@@ -2685,8 +2688,8 @@ class ChatLLM {
|
|
|
2685
2688
|
* @param {boolean} [onoff=false] - Whether to turn the chatLLM on or off. Defaults to false (close).
|
|
2686
2689
|
*/
|
|
2687
2690
|
Toggle(onoff) {
|
|
2688
|
-
if (typeof onoff ==
|
|
2689
|
-
if (document.getElementById(
|
|
2691
|
+
if (typeof onoff == "undefined") {
|
|
2692
|
+
if (document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
2690
2693
|
onoff = true;
|
|
2691
2694
|
} else {
|
|
2692
2695
|
onoff = false;
|
|
@@ -2697,19 +2700,19 @@ class ChatLLM {
|
|
|
2697
2700
|
// open
|
|
2698
2701
|
this.whereWasMyFocus = document.activeElement;
|
|
2699
2702
|
constants.tabMovement = 0;
|
|
2700
|
-
document.getElementById(
|
|
2703
|
+
document.getElementById("chatLLM").classList.remove("hidden");
|
|
2701
2704
|
document
|
|
2702
|
-
.getElementById(
|
|
2703
|
-
.classList.remove(
|
|
2704
|
-
document.querySelector(
|
|
2705
|
+
.getElementById("chatLLM_modal_backdrop")
|
|
2706
|
+
.classList.remove("hidden");
|
|
2707
|
+
document.querySelector("#chatLLM .close").focus();
|
|
2705
2708
|
|
|
2706
2709
|
if (this.firstTime) {
|
|
2707
2710
|
this.InitChatMessage();
|
|
2708
2711
|
}
|
|
2709
2712
|
} else {
|
|
2710
2713
|
// close
|
|
2711
|
-
document.getElementById(
|
|
2712
|
-
document.getElementById(
|
|
2714
|
+
document.getElementById("chatLLM").classList.add("hidden");
|
|
2715
|
+
document.getElementById("chatLLM_modal_backdrop").classList.add("hidden");
|
|
2713
2716
|
this.whereWasMyFocus.focus();
|
|
2714
2717
|
this.whereWasMyFocus = null;
|
|
2715
2718
|
this.firstOpen = true;
|
|
@@ -2723,11 +2726,11 @@ class ChatLLM {
|
|
|
2723
2726
|
async ConvertSVGtoJPG(id, model) {
|
|
2724
2727
|
let svgElement = document.getElementById(id);
|
|
2725
2728
|
return new Promise((resolve, reject) => {
|
|
2726
|
-
var canvas = document.createElement(
|
|
2727
|
-
var ctx = canvas.getContext(
|
|
2729
|
+
var canvas = document.createElement("canvas");
|
|
2730
|
+
var ctx = canvas.getContext("2d");
|
|
2728
2731
|
|
|
2729
2732
|
var svgData = new XMLSerializer().serializeToString(svgElement);
|
|
2730
|
-
if (!svgData.startsWith(
|
|
2733
|
+
if (!svgData.startsWith("<svg xmlns")) {
|
|
2731
2734
|
svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
|
|
2732
2735
|
}
|
|
2733
2736
|
|
|
@@ -2739,11 +2742,11 @@ class ChatLLM {
|
|
|
2739
2742
|
var img = new Image();
|
|
2740
2743
|
img.onload = function () {
|
|
2741
2744
|
ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
|
|
2742
|
-
var jpegData = canvas.toDataURL(
|
|
2743
|
-
if (model ==
|
|
2745
|
+
var jpegData = canvas.toDataURL("image/jpeg", 0.9); // 0.9 is the quality parameter
|
|
2746
|
+
if (model == "openai") {
|
|
2744
2747
|
resolve(jpegData);
|
|
2745
|
-
} else if (model ==
|
|
2746
|
-
let base64Data = jpegData.split(
|
|
2748
|
+
} else if (model == "gemini" || model == "claude") {
|
|
2749
|
+
let base64Data = jpegData.split(",")[1];
|
|
2747
2750
|
resolve(base64Data);
|
|
2748
2751
|
//resolve(jpegData);
|
|
2749
2752
|
}
|
|
@@ -2751,11 +2754,11 @@ class ChatLLM {
|
|
|
2751
2754
|
};
|
|
2752
2755
|
|
|
2753
2756
|
img.onerror = function () {
|
|
2754
|
-
reject(new Error(
|
|
2757
|
+
reject(new Error("Error loading SVG"));
|
|
2755
2758
|
};
|
|
2756
2759
|
|
|
2757
2760
|
var svgBlob = new Blob([svgData], {
|
|
2758
|
-
type:
|
|
2761
|
+
type: "image/svg+xml;charset=utf-8",
|
|
2759
2762
|
});
|
|
2760
2763
|
var url = URL.createObjectURL(svgBlob);
|
|
2761
2764
|
img.src = url;
|
|
@@ -2768,25 +2771,25 @@ class ChatLLM {
|
|
|
2768
2771
|
* The prompt includes information about the blind person's skill level and the chart's image and raw data, if available.
|
|
2769
2772
|
*/
|
|
2770
2773
|
GetDefaultPrompt() {
|
|
2771
|
-
let text =
|
|
2774
|
+
let text = "Describe this chart to a blind person";
|
|
2772
2775
|
if (constants.skillLevel) {
|
|
2773
|
-
if (constants.skillLevel ==
|
|
2776
|
+
if (constants.skillLevel == "other" && constants.skillLevelOther) {
|
|
2774
2777
|
text +=
|
|
2775
|
-
|
|
2778
|
+
" who has a " +
|
|
2776
2779
|
constants.skillLevelOther +
|
|
2777
|
-
|
|
2780
|
+
" understanding of statistical charts. ";
|
|
2778
2781
|
} else {
|
|
2779
2782
|
text +=
|
|
2780
|
-
|
|
2783
|
+
" who has a " +
|
|
2781
2784
|
constants.skillLevel +
|
|
2782
|
-
|
|
2785
|
+
" understanding of statistical charts. ";
|
|
2783
2786
|
}
|
|
2784
2787
|
} else {
|
|
2785
|
-
text +=
|
|
2788
|
+
text += " who has a basic understanding of statistical charts. ";
|
|
2786
2789
|
}
|
|
2787
|
-
text +=
|
|
2790
|
+
text += "Here is a chart in image format";
|
|
2788
2791
|
if (singleMaidr) {
|
|
2789
|
-
text +=
|
|
2792
|
+
text += " and raw data in json format: \n";
|
|
2790
2793
|
text += JSON.stringify(singleMaidr);
|
|
2791
2794
|
}
|
|
2792
2795
|
|
|
@@ -2841,26 +2844,26 @@ class Description {
|
|
|
2841
2844
|
|
|
2842
2845
|
`;
|
|
2843
2846
|
|
|
2844
|
-
document.querySelector(
|
|
2847
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
2845
2848
|
|
|
2846
2849
|
// close events
|
|
2847
2850
|
let allClose = document.querySelectorAll(
|
|
2848
|
-
|
|
2851
|
+
"#close_desc, #description .close"
|
|
2849
2852
|
);
|
|
2850
2853
|
for (let i = 0; i < allClose.length; i++) {
|
|
2851
2854
|
constants.events.push([
|
|
2852
2855
|
allClose[i],
|
|
2853
|
-
|
|
2856
|
+
"click",
|
|
2854
2857
|
function (e) {
|
|
2855
2858
|
description.Toggle(false);
|
|
2856
2859
|
},
|
|
2857
2860
|
]);
|
|
2858
2861
|
}
|
|
2859
2862
|
constants.events.push([
|
|
2860
|
-
document.getElementById(
|
|
2861
|
-
|
|
2863
|
+
document.getElementById("description"),
|
|
2864
|
+
"keyup",
|
|
2862
2865
|
function (e) {
|
|
2863
|
-
if (e.key ==
|
|
2866
|
+
if (e.key == "Esc") {
|
|
2864
2867
|
// esc
|
|
2865
2868
|
description.Toggle(false);
|
|
2866
2869
|
}
|
|
@@ -2870,9 +2873,9 @@ class Description {
|
|
|
2870
2873
|
// open events
|
|
2871
2874
|
constants.events.push([
|
|
2872
2875
|
document,
|
|
2873
|
-
|
|
2876
|
+
"keyup",
|
|
2874
2877
|
function (e) {
|
|
2875
|
-
if (e.key ==
|
|
2878
|
+
if (e.key == "d") {
|
|
2876
2879
|
description.Toggle(true);
|
|
2877
2880
|
}
|
|
2878
2881
|
},
|
|
@@ -2884,11 +2887,11 @@ class Description {
|
|
|
2884
2887
|
*/
|
|
2885
2888
|
Destroy() {
|
|
2886
2889
|
// description element destruction
|
|
2887
|
-
let description = document.getElementById(
|
|
2890
|
+
let description = document.getElementById("menu");
|
|
2888
2891
|
if (description) {
|
|
2889
2892
|
description.remove();
|
|
2890
2893
|
}
|
|
2891
|
-
let backdrop = document.getElementById(
|
|
2894
|
+
let backdrop = document.getElementById("desc_modal_backdrop");
|
|
2892
2895
|
if (backdrop) {
|
|
2893
2896
|
backdrop.remove();
|
|
2894
2897
|
}
|
|
@@ -2899,8 +2902,8 @@ class Description {
|
|
|
2899
2902
|
* @param {boolean} [onoff=false] - Whether to turn the description element on or off.
|
|
2900
2903
|
*/
|
|
2901
2904
|
Toggle(onoff = false) {
|
|
2902
|
-
if (typeof onoff ==
|
|
2903
|
-
if (document.getElementById(
|
|
2905
|
+
if (typeof onoff == "undefined") {
|
|
2906
|
+
if (document.getElementById("description").classList.contains("hidden")) {
|
|
2904
2907
|
onoff = true;
|
|
2905
2908
|
} else {
|
|
2906
2909
|
onoff = false;
|
|
@@ -2911,13 +2914,13 @@ class Description {
|
|
|
2911
2914
|
this.whereWasMyFocus = document.activeElement;
|
|
2912
2915
|
constants.tabMovement = 0;
|
|
2913
2916
|
this.PopulateData();
|
|
2914
|
-
document.getElementById(
|
|
2915
|
-
document.getElementById(
|
|
2916
|
-
document.querySelector(
|
|
2917
|
+
document.getElementById("description").classList.remove("hidden");
|
|
2918
|
+
document.getElementById("desc_modal_backdrop").classList.remove("hidden");
|
|
2919
|
+
document.querySelector("#description .close").focus();
|
|
2917
2920
|
} else {
|
|
2918
2921
|
// close
|
|
2919
|
-
document.getElementById(
|
|
2920
|
-
document.getElementById(
|
|
2922
|
+
document.getElementById("description").classList.add("hidden");
|
|
2923
|
+
document.getElementById("desc_modal_backdrop").classList.add("hidden");
|
|
2921
2924
|
this.whereWasMyFocus.focus();
|
|
2922
2925
|
this.whereWasMyFocus = null;
|
|
2923
2926
|
}
|
|
@@ -2927,22 +2930,22 @@ class Description {
|
|
|
2927
2930
|
* Populates the data for the chart and table based on the chart type and plot data.
|
|
2928
2931
|
*/
|
|
2929
2932
|
PopulateData() {
|
|
2930
|
-
let descHtml =
|
|
2933
|
+
let descHtml = "";
|
|
2931
2934
|
|
|
2932
2935
|
// chart labels and descriptions
|
|
2933
|
-
let descType =
|
|
2934
|
-
if (constants.chartType ==
|
|
2935
|
-
descType =
|
|
2936
|
-
} else if (constants.chartType ==
|
|
2937
|
-
descType =
|
|
2938
|
-
} else if (constants.chartType ==
|
|
2939
|
-
descType =
|
|
2940
|
-
} else if (constants.chartType ==
|
|
2941
|
-
descType =
|
|
2942
|
-
} else if (constants.chartType ==
|
|
2943
|
-
descType =
|
|
2944
|
-
} else if (constants.chartType ==
|
|
2945
|
-
descType =
|
|
2936
|
+
let descType = "";
|
|
2937
|
+
if (constants.chartType == "bar") {
|
|
2938
|
+
descType = "Bar chart";
|
|
2939
|
+
} else if (constants.chartType == "heat") {
|
|
2940
|
+
descType = "Heatmap";
|
|
2941
|
+
} else if (constants.chartType == "box") {
|
|
2942
|
+
descType = "Box plot";
|
|
2943
|
+
} else if (constants.chartType == "scatter") {
|
|
2944
|
+
descType = "Scatter plot";
|
|
2945
|
+
} else if (constants.chartType == "line") {
|
|
2946
|
+
descType = "Line chart";
|
|
2947
|
+
} else if (constants.chartType == "hist") {
|
|
2948
|
+
descType = "Histogram";
|
|
2946
2949
|
}
|
|
2947
2950
|
|
|
2948
2951
|
if (descType) {
|
|
@@ -2959,7 +2962,7 @@ class Description {
|
|
|
2959
2962
|
}
|
|
2960
2963
|
|
|
2961
2964
|
// table of data, prep
|
|
2962
|
-
let descTableHtml =
|
|
2965
|
+
let descTableHtml = "";
|
|
2963
2966
|
let descLabelX = null;
|
|
2964
2967
|
let descLabelY = null;
|
|
2965
2968
|
let descTickX = null;
|
|
@@ -2969,7 +2972,7 @@ class Description {
|
|
|
2969
2972
|
let descNumColsWithLabels = 0;
|
|
2970
2973
|
let descNumRows = 0;
|
|
2971
2974
|
let descNumRowsWithLabels = 0;
|
|
2972
|
-
if (constants.chartType ==
|
|
2975
|
+
if (constants.chartType == "bar") {
|
|
2973
2976
|
if (plot.plotLegend.x != null) {
|
|
2974
2977
|
descLabelX = plot.plotLegend.x;
|
|
2975
2978
|
descNumColsWithLabels += 1;
|
|
@@ -2994,43 +2997,43 @@ class Description {
|
|
|
2994
2997
|
|
|
2995
2998
|
// table of data, create
|
|
2996
2999
|
if (descData != null) {
|
|
2997
|
-
descTableHtml +=
|
|
3000
|
+
descTableHtml += "<table>";
|
|
2998
3001
|
|
|
2999
3002
|
// header rows
|
|
3000
3003
|
if (descLabelX != null || descTickX != null) {
|
|
3001
|
-
descTableHtml +=
|
|
3004
|
+
descTableHtml += "<thead>";
|
|
3002
3005
|
if (descLabelX != null) {
|
|
3003
|
-
descTableHtml +=
|
|
3006
|
+
descTableHtml += "<tr>";
|
|
3004
3007
|
if (descLabelY != null) {
|
|
3005
|
-
descTableHtml +=
|
|
3008
|
+
descTableHtml += "<td></td>";
|
|
3006
3009
|
}
|
|
3007
3010
|
if (descTickY != null) {
|
|
3008
|
-
descTableHtml +=
|
|
3011
|
+
descTableHtml += "<td></td>";
|
|
3009
3012
|
}
|
|
3010
3013
|
descTableHtml += `<th scope="col" colspan="${descNumCols}">${descLabelX}</th>`;
|
|
3011
|
-
descTableHtml +=
|
|
3014
|
+
descTableHtml += "</tr>";
|
|
3012
3015
|
}
|
|
3013
3016
|
if (descTickX != null) {
|
|
3014
|
-
descTableHtml +=
|
|
3017
|
+
descTableHtml += "<tr>";
|
|
3015
3018
|
if (descLabelY != null) {
|
|
3016
|
-
descTableHtml +=
|
|
3019
|
+
descTableHtml += "<td></td>";
|
|
3017
3020
|
}
|
|
3018
3021
|
if (descTickY != null) {
|
|
3019
|
-
descTableHtml +=
|
|
3022
|
+
descTableHtml += "<td></td>";
|
|
3020
3023
|
}
|
|
3021
3024
|
for (let i = 0; i < descNumCols; i++) {
|
|
3022
3025
|
descTableHtml += `<th scope="col">${descTickX[i]}</th>`;
|
|
3023
3026
|
}
|
|
3024
|
-
descTableHtml +=
|
|
3027
|
+
descTableHtml += "</tr>";
|
|
3025
3028
|
}
|
|
3026
|
-
descTableHtml +=
|
|
3029
|
+
descTableHtml += "</thead>";
|
|
3027
3030
|
}
|
|
3028
3031
|
|
|
3029
3032
|
// body rows
|
|
3030
3033
|
if (descNumRows > 0) {
|
|
3031
|
-
descTableHtml +=
|
|
3034
|
+
descTableHtml += "<tbody>";
|
|
3032
3035
|
for (let i = 0; i < descNumRows; i++) {
|
|
3033
|
-
descTableHtml +=
|
|
3036
|
+
descTableHtml += "<tr>";
|
|
3034
3037
|
if (descLabelY != null && i == 0) {
|
|
3035
3038
|
descTableHtml += `<th scope="row" rowspan="${descNumRows}">${descLabelY}</th>`;
|
|
3036
3039
|
}
|
|
@@ -3040,19 +3043,19 @@ class Description {
|
|
|
3040
3043
|
for (let j = 0; j < descNumCols; j++) {
|
|
3041
3044
|
descTableHtml += `<td>${descData[i][j]}</td>`;
|
|
3042
3045
|
}
|
|
3043
|
-
descTableHtml +=
|
|
3046
|
+
descTableHtml += "</tr>";
|
|
3044
3047
|
}
|
|
3045
|
-
descTableHtml +=
|
|
3048
|
+
descTableHtml += "</tbody>";
|
|
3046
3049
|
}
|
|
3047
3050
|
|
|
3048
|
-
descTableHtml +=
|
|
3051
|
+
descTableHtml += "</table>";
|
|
3049
3052
|
}
|
|
3050
3053
|
|
|
3051
3054
|
// bar: don't need colspan or rowspan stuff, put legendX and Y as headers
|
|
3052
3055
|
|
|
3053
|
-
document.getElementById(
|
|
3054
|
-
document.getElementById(
|
|
3055
|
-
document.getElementById(
|
|
3056
|
+
document.getElementById("desc_title").innerHTML = descType + " description";
|
|
3057
|
+
document.getElementById("desc_content").innerHTML = descHtml;
|
|
3058
|
+
document.getElementById("desc_table").innerHTML = descTableHtml;
|
|
3056
3059
|
}
|
|
3057
3060
|
}
|
|
3058
3061
|
|
|
@@ -3094,7 +3097,7 @@ class Helper {
|
|
|
3094
3097
|
class Tracker {
|
|
3095
3098
|
// URL
|
|
3096
3099
|
logUrl =
|
|
3097
|
-
|
|
3100
|
+
"https://maidr-service.azurewebsites.net/api/log?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D"; // TODO Replace
|
|
3098
3101
|
isLocal = false;
|
|
3099
3102
|
|
|
3100
3103
|
constructor() {
|
|
@@ -3113,7 +3116,7 @@ class Tracker {
|
|
|
3113
3116
|
data.language = Object.assign(navigator.language);
|
|
3114
3117
|
data.platform = Object.assign(navigator.platform);
|
|
3115
3118
|
data.geolocation = Object.assign(navigator.geolocation);
|
|
3116
|
-
data.log_type =
|
|
3119
|
+
data.log_type = "system_data";
|
|
3117
3120
|
data.events = [];
|
|
3118
3121
|
data.settings = [];
|
|
3119
3122
|
|
|
@@ -3126,11 +3129,11 @@ class Tracker {
|
|
|
3126
3129
|
* Downloads the tracker data as a JSON file.
|
|
3127
3130
|
*/
|
|
3128
3131
|
DownloadTrackerData() {
|
|
3129
|
-
let link = document.createElement(
|
|
3132
|
+
let link = document.createElement("a");
|
|
3130
3133
|
let data = this.GetTrackerData();
|
|
3131
|
-
let fileStr = new Blob([JSON.stringify(data)], { type:
|
|
3134
|
+
let fileStr = new Blob([JSON.stringify(data)], { type: "text/plain" });
|
|
3132
3135
|
link.href = URL.createObjectURL(fileStr);
|
|
3133
|
-
link.download =
|
|
3136
|
+
link.download = "tracking.json";
|
|
3134
3137
|
link.click();
|
|
3135
3138
|
}
|
|
3136
3139
|
|
|
@@ -3139,16 +3142,16 @@ class Tracker {
|
|
|
3139
3142
|
* @param {Object} data - The data to be saved.
|
|
3140
3143
|
*/
|
|
3141
3144
|
async SaveTrackerData(data) {
|
|
3142
|
-
console.log(
|
|
3145
|
+
console.log("about to save data", data);
|
|
3143
3146
|
if (this.isLocal) {
|
|
3144
3147
|
localStorage.setItem(constants.project_id, JSON.stringify(data));
|
|
3145
3148
|
} else {
|
|
3146
3149
|
// test this first
|
|
3147
3150
|
try {
|
|
3148
3151
|
const response = await fetch(this.logUrl, {
|
|
3149
|
-
method:
|
|
3152
|
+
method: "POST",
|
|
3150
3153
|
headers: {
|
|
3151
|
-
|
|
3154
|
+
"Content-Type": "application/json",
|
|
3152
3155
|
},
|
|
3153
3156
|
body: JSON.stringify(data),
|
|
3154
3157
|
});
|
|
@@ -3158,10 +3161,10 @@ class Tracker {
|
|
|
3158
3161
|
}
|
|
3159
3162
|
|
|
3160
3163
|
const result = await response.json();
|
|
3161
|
-
console.log(
|
|
3164
|
+
console.log("Data saved successfully:", result);
|
|
3162
3165
|
return result;
|
|
3163
3166
|
} catch (error) {
|
|
3164
|
-
console.error(
|
|
3167
|
+
console.error("Error saving data:", error);
|
|
3165
3168
|
return null;
|
|
3166
3169
|
}
|
|
3167
3170
|
}
|
|
@@ -3184,7 +3187,7 @@ class Tracker {
|
|
|
3184
3187
|
this.data = null;
|
|
3185
3188
|
|
|
3186
3189
|
if (constants.debugLevel > 0) {
|
|
3187
|
-
console.log(
|
|
3190
|
+
console.log("tracking data cleared");
|
|
3188
3191
|
}
|
|
3189
3192
|
|
|
3190
3193
|
this.DataSetup();
|
|
@@ -3192,16 +3195,16 @@ class Tracker {
|
|
|
3192
3195
|
|
|
3193
3196
|
SaveSettings() {
|
|
3194
3197
|
// fetch all settings, push to data.settings
|
|
3195
|
-
let settings = JSON.parse(localStorage.getItem(
|
|
3198
|
+
let settings = JSON.parse(localStorage.getItem("settings_data"));
|
|
3196
3199
|
if (settings) {
|
|
3197
3200
|
// don't store their auth keys
|
|
3198
|
-
settings.openAIAuthKey =
|
|
3199
|
-
settings.geminiAuthKey =
|
|
3201
|
+
settings.openAIAuthKey = "hidden";
|
|
3202
|
+
settings.geminiAuthKey = "hidden";
|
|
3200
3203
|
if (constants.emailAuthKey) {
|
|
3201
3204
|
settings.username = constants.emailAuthKey;
|
|
3202
3205
|
}
|
|
3203
3206
|
settings;
|
|
3204
|
-
this.SetData(
|
|
3207
|
+
this.SetData("settings", settings);
|
|
3205
3208
|
}
|
|
3206
3209
|
}
|
|
3207
3210
|
|
|
@@ -3298,7 +3301,7 @@ class Tracker {
|
|
|
3298
3301
|
}
|
|
3299
3302
|
if (!this.isUndefinedOrNull(constants.infoDiv.innerHTML)) {
|
|
3300
3303
|
let textDisplay = Object.assign(constants.infoDiv.innerHTML);
|
|
3301
|
-
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm,
|
|
3304
|
+
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm, "");
|
|
3302
3305
|
eventToLog.text_display = textDisplay;
|
|
3303
3306
|
}
|
|
3304
3307
|
if (!this.isUndefinedOrNull(location.href)) {
|
|
@@ -3306,13 +3309,13 @@ class Tracker {
|
|
|
3306
3309
|
}
|
|
3307
3310
|
|
|
3308
3311
|
// chart specific values
|
|
3309
|
-
let x_tickmark =
|
|
3310
|
-
let y_tickmark =
|
|
3311
|
-
let x_label =
|
|
3312
|
-
let y_label =
|
|
3313
|
-
let value =
|
|
3314
|
-
let fill_value =
|
|
3315
|
-
if (constants.chartType ==
|
|
3312
|
+
let x_tickmark = "";
|
|
3313
|
+
let y_tickmark = "";
|
|
3314
|
+
let x_label = "";
|
|
3315
|
+
let y_label = "";
|
|
3316
|
+
let value = "";
|
|
3317
|
+
let fill_value = "";
|
|
3318
|
+
if (constants.chartType == "bar") {
|
|
3316
3319
|
if (!this.isUndefinedOrNull(plot.columnLabels[position.x])) {
|
|
3317
3320
|
x_tickmark = plot.columnLabels[position.x];
|
|
3318
3321
|
}
|
|
@@ -3325,7 +3328,7 @@ class Tracker {
|
|
|
3325
3328
|
if (!this.isUndefinedOrNull(plot.plotData[position.x])) {
|
|
3326
3329
|
value = plot.plotData[position.x];
|
|
3327
3330
|
}
|
|
3328
|
-
} else if (constants.chartType ==
|
|
3331
|
+
} else if (constants.chartType == "heat") {
|
|
3329
3332
|
if (!this.isUndefinedOrNull(plot.x_labels[position.x])) {
|
|
3330
3333
|
x_tickmark = plot.x_labels[position.x].trim();
|
|
3331
3334
|
}
|
|
@@ -3346,11 +3349,11 @@ class Tracker {
|
|
|
3346
3349
|
if (!this.isUndefinedOrNull(plot.group_labels[2])) {
|
|
3347
3350
|
fill_value = plot.group_labels[2];
|
|
3348
3351
|
}
|
|
3349
|
-
} else if (constants.chartType ==
|
|
3352
|
+
} else if (constants.chartType == "box") {
|
|
3350
3353
|
let plotPos =
|
|
3351
|
-
constants.plotOrientation ==
|
|
3354
|
+
constants.plotOrientation == "vert" ? position.x : position.y;
|
|
3352
3355
|
let sectionPos =
|
|
3353
|
-
constants.plotOrientation ==
|
|
3356
|
+
constants.plotOrientation == "vert" ? position.y : position.x;
|
|
3354
3357
|
let sectionLabel = plot.sections[sectionPos];
|
|
3355
3358
|
|
|
3356
3359
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
@@ -3359,7 +3362,7 @@ class Tracker {
|
|
|
3359
3362
|
if (!this.isUndefinedOrNull(plot.y_group_label)) {
|
|
3360
3363
|
y_label = plot.y_group_label;
|
|
3361
3364
|
}
|
|
3362
|
-
if (constants.plotOrientation ==
|
|
3365
|
+
if (constants.plotOrientation == "vert") {
|
|
3363
3366
|
if (plotPos > -1 && sectionPos > -1) {
|
|
3364
3367
|
if (!this.isUndefinedOrNull(sectionLabel)) {
|
|
3365
3368
|
y_tickmark = sectionLabel;
|
|
@@ -3384,7 +3387,7 @@ class Tracker {
|
|
|
3384
3387
|
}
|
|
3385
3388
|
}
|
|
3386
3389
|
}
|
|
3387
|
-
} else if (constants.chartType ==
|
|
3390
|
+
} else if (constants.chartType == "point") {
|
|
3388
3391
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
3389
3392
|
x_label = plot.x_group_label;
|
|
3390
3393
|
}
|
|
@@ -3411,7 +3414,7 @@ class Tracker {
|
|
|
3411
3414
|
|
|
3412
3415
|
//console.log("x_tickmark: '", x_tickmark, "', y_tickmark: '", y_tickmark, "', x_label: '", x_label, "', y_label: '", y_label, "', value: '", value, "', fill_value: '", fill_value);
|
|
3413
3416
|
|
|
3414
|
-
this.SetData(
|
|
3417
|
+
this.SetData("events", eventToLog);
|
|
3415
3418
|
//console.log('logged an event');
|
|
3416
3419
|
}
|
|
3417
3420
|
|
|
@@ -3424,7 +3427,7 @@ class Tracker {
|
|
|
3424
3427
|
SetData(key, value) {
|
|
3425
3428
|
if (this.isLocal) {
|
|
3426
3429
|
let data = this.GetTrackerData();
|
|
3427
|
-
let arrayKeys = [
|
|
3430
|
+
let arrayKeys = ["events", "ChatHistory", "settings"];
|
|
3428
3431
|
if (!arrayKeys.includes(key)) {
|
|
3429
3432
|
data[key] = value;
|
|
3430
3433
|
} else {
|
|
@@ -3435,7 +3438,7 @@ class Tracker {
|
|
|
3435
3438
|
}
|
|
3436
3439
|
this.SaveTrackerData(data);
|
|
3437
3440
|
} else {
|
|
3438
|
-
value[
|
|
3441
|
+
value["log_type"] = key;
|
|
3439
3442
|
this.SaveTrackerData(value);
|
|
3440
3443
|
}
|
|
3441
3444
|
}
|
|
@@ -3469,20 +3472,20 @@ class Review {
|
|
|
3469
3472
|
// true means on or show
|
|
3470
3473
|
if (onoff) {
|
|
3471
3474
|
constants.reviewSaveSpot = document.activeElement;
|
|
3472
|
-
constants.review_container.classList.remove(
|
|
3475
|
+
constants.review_container.classList.remove("hidden");
|
|
3473
3476
|
constants.reviewSaveBrailleMode = constants.brailleMode;
|
|
3474
3477
|
constants.review.focus();
|
|
3475
3478
|
|
|
3476
|
-
display.announceText(
|
|
3479
|
+
display.announceText("Review on");
|
|
3477
3480
|
} else {
|
|
3478
|
-
constants.review_container.classList.add(
|
|
3479
|
-
if (constants.reviewSaveBrailleMode ==
|
|
3481
|
+
constants.review_container.classList.add("hidden");
|
|
3482
|
+
if (constants.reviewSaveBrailleMode == "on") {
|
|
3480
3483
|
// we have to turn braille mode back on
|
|
3481
|
-
display.toggleBrailleMode(
|
|
3484
|
+
display.toggleBrailleMode("on");
|
|
3482
3485
|
} else {
|
|
3483
3486
|
constants.reviewSaveSpot.focus();
|
|
3484
3487
|
}
|
|
3485
|
-
display.announceText(
|
|
3488
|
+
display.announceText("Review off");
|
|
3486
3489
|
}
|
|
3487
3490
|
}
|
|
3488
3491
|
}
|
|
@@ -3499,7 +3502,7 @@ class LogError {
|
|
|
3499
3502
|
* @param {string} a - The absent element to log.
|
|
3500
3503
|
*/
|
|
3501
3504
|
LogAbsentElement(a) {
|
|
3502
|
-
console.log(a,
|
|
3505
|
+
console.log(a, "not found. Visual highlighting is turned off.");
|
|
3503
3506
|
}
|
|
3504
3507
|
|
|
3505
3508
|
/**
|
|
@@ -3507,7 +3510,7 @@ class LogError {
|
|
|
3507
3510
|
* @param {string} a - The critical element to log.
|
|
3508
3511
|
*/
|
|
3509
3512
|
LogCriticalElement(a) {
|
|
3510
|
-
consolelog(a,
|
|
3513
|
+
consolelog(a, "is critical. MAIDR unable to run");
|
|
3511
3514
|
}
|
|
3512
3515
|
|
|
3513
3516
|
/**
|
|
@@ -3518,9 +3521,9 @@ class LogError {
|
|
|
3518
3521
|
LogDifferentLengths(a, b) {
|
|
3519
3522
|
console.log(
|
|
3520
3523
|
a,
|
|
3521
|
-
|
|
3524
|
+
"and",
|
|
3522
3525
|
b,
|
|
3523
|
-
|
|
3526
|
+
"do not have the same length. Visual highlighting is turned off."
|
|
3524
3527
|
);
|
|
3525
3528
|
}
|
|
3526
3529
|
|
|
@@ -3531,11 +3534,11 @@ class LogError {
|
|
|
3531
3534
|
*/
|
|
3532
3535
|
LogTooManyElements(a, b) {
|
|
3533
3536
|
console.log(
|
|
3534
|
-
|
|
3537
|
+
"Too many",
|
|
3535
3538
|
a,
|
|
3536
|
-
|
|
3539
|
+
"elements. Only the first",
|
|
3537
3540
|
b,
|
|
3538
|
-
|
|
3541
|
+
"will be highlighted."
|
|
3539
3542
|
);
|
|
3540
3543
|
}
|
|
3541
3544
|
|
|
@@ -3544,7 +3547,7 @@ class LogError {
|
|
|
3544
3547
|
* @param {*} a - The parameter that is not an array.
|
|
3545
3548
|
*/
|
|
3546
3549
|
LogNotArray(a) {
|
|
3547
|
-
console.log(a,
|
|
3550
|
+
console.log(a, "is not an array. Visual highlighting is turned off.");
|
|
3548
3551
|
}
|
|
3549
3552
|
}
|
|
3550
3553
|
|