maidr 2.22.1 → 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 +569 -569
- 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">
|
|
@@ -1051,7 +1051,7 @@ class Menu {
|
|
|
1051
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>
|
|
1052
1052
|
</p>
|
|
1053
1053
|
<p><input type="checkbox" ${
|
|
1054
|
-
constants.autoInitLLM ?
|
|
1054
|
+
constants.autoInitLLM ? "checked" : ""
|
|
1055
1055
|
} id="init_llm_on_load" name="init_llm_on_load"><label for="init_llm_on_load">Start LLM right away</label></p>
|
|
1056
1056
|
<p>
|
|
1057
1057
|
<select id="skill_level">
|
|
@@ -1088,40 +1088,40 @@ class Menu {
|
|
|
1088
1088
|
CreateMenu() {
|
|
1089
1089
|
// menu element creation
|
|
1090
1090
|
document
|
|
1091
|
-
.querySelector(
|
|
1092
|
-
.insertAdjacentHTML(
|
|
1091
|
+
.querySelector("body")
|
|
1092
|
+
.insertAdjacentHTML("beforeend", this.menuHtml);
|
|
1093
1093
|
|
|
1094
1094
|
// menu close events
|
|
1095
|
-
let allClose = document.querySelectorAll(
|
|
1095
|
+
let allClose = document.querySelectorAll("#close_menu, #menu .close");
|
|
1096
1096
|
for (let i = 0; i < allClose.length; i++) {
|
|
1097
1097
|
constants.events.push([
|
|
1098
1098
|
allClose[i],
|
|
1099
|
-
|
|
1099
|
+
"click",
|
|
1100
1100
|
function (e) {
|
|
1101
1101
|
menu.Toggle(false);
|
|
1102
1102
|
},
|
|
1103
1103
|
]);
|
|
1104
1104
|
}
|
|
1105
1105
|
constants.events.push([
|
|
1106
|
-
document.getElementById(
|
|
1107
|
-
|
|
1106
|
+
document.getElementById("save_and_close_menu"),
|
|
1107
|
+
"click",
|
|
1108
1108
|
function (e) {
|
|
1109
1109
|
menu.SaveData();
|
|
1110
1110
|
menu.Toggle(false);
|
|
1111
1111
|
},
|
|
1112
1112
|
]);
|
|
1113
1113
|
constants.events.push([
|
|
1114
|
-
document.getElementById(
|
|
1115
|
-
|
|
1114
|
+
document.getElementById("verify"),
|
|
1115
|
+
"click",
|
|
1116
1116
|
function (e) {
|
|
1117
1117
|
menu.VerifyEmail();
|
|
1118
1118
|
},
|
|
1119
1119
|
]);
|
|
1120
1120
|
constants.events.push([
|
|
1121
|
-
document.getElementById(
|
|
1122
|
-
|
|
1121
|
+
document.getElementById("menu"),
|
|
1122
|
+
"keyup",
|
|
1123
1123
|
function (e) {
|
|
1124
|
-
if (e.key ==
|
|
1124
|
+
if (e.key == "Esc") {
|
|
1125
1125
|
// esc
|
|
1126
1126
|
menu.Toggle(false);
|
|
1127
1127
|
}
|
|
@@ -1131,15 +1131,15 @@ class Menu {
|
|
|
1131
1131
|
// Menu open events
|
|
1132
1132
|
constants.events.push([
|
|
1133
1133
|
document,
|
|
1134
|
-
|
|
1134
|
+
"keyup",
|
|
1135
1135
|
function (e) {
|
|
1136
1136
|
// don't fire on input elements
|
|
1137
1137
|
if (
|
|
1138
|
-
e.target.tagName.toLowerCase() ==
|
|
1139
|
-
e.target.tagName.toLowerCase() ==
|
|
1138
|
+
e.target.tagName.toLowerCase() == "input" ||
|
|
1139
|
+
e.target.tagName.toLowerCase() == "textarea"
|
|
1140
1140
|
) {
|
|
1141
1141
|
return;
|
|
1142
|
-
} else if (e.key ==
|
|
1142
|
+
} else if (e.key == "h") {
|
|
1143
1143
|
menu.Toggle(true);
|
|
1144
1144
|
}
|
|
1145
1145
|
},
|
|
@@ -1147,98 +1147,98 @@ class Menu {
|
|
|
1147
1147
|
|
|
1148
1148
|
// toggle auth key fields
|
|
1149
1149
|
constants.events.push([
|
|
1150
|
-
document.getElementById(
|
|
1151
|
-
|
|
1150
|
+
document.getElementById("LLM_model"),
|
|
1151
|
+
"change",
|
|
1152
1152
|
function (e) {
|
|
1153
|
-
if (e.target.value ==
|
|
1153
|
+
if (e.target.value == "openai") {
|
|
1154
1154
|
document
|
|
1155
|
-
.getElementById(
|
|
1156
|
-
.classList.remove(
|
|
1155
|
+
.getElementById("openai_auth_key_container")
|
|
1156
|
+
.classList.remove("hidden");
|
|
1157
1157
|
document
|
|
1158
|
-
.getElementById(
|
|
1159
|
-
.classList.add(
|
|
1158
|
+
.getElementById("gemini_auth_key_container")
|
|
1159
|
+
.classList.add("hidden");
|
|
1160
1160
|
document
|
|
1161
|
-
.getElementById(
|
|
1162
|
-
.classList.add(
|
|
1161
|
+
.getElementById("openai_multi_container")
|
|
1162
|
+
.classList.add("hidden");
|
|
1163
1163
|
document
|
|
1164
|
-
.getElementById(
|
|
1165
|
-
.classList.add(
|
|
1166
|
-
document.getElementById(
|
|
1167
|
-
document.getElementById(
|
|
1168
|
-
} 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") {
|
|
1169
1169
|
document
|
|
1170
|
-
.getElementById(
|
|
1171
|
-
.classList.add(
|
|
1170
|
+
.getElementById("openai_auth_key_container")
|
|
1171
|
+
.classList.add("hidden");
|
|
1172
1172
|
document
|
|
1173
|
-
.getElementById(
|
|
1174
|
-
.classList.remove(
|
|
1173
|
+
.getElementById("gemini_auth_key_container")
|
|
1174
|
+
.classList.remove("hidden");
|
|
1175
1175
|
document
|
|
1176
|
-
.getElementById(
|
|
1177
|
-
.classList.add(
|
|
1176
|
+
.getElementById("openai_multi_container")
|
|
1177
|
+
.classList.add("hidden");
|
|
1178
1178
|
document
|
|
1179
|
-
.getElementById(
|
|
1180
|
-
.classList.add(
|
|
1181
|
-
document.getElementById(
|
|
1182
|
-
document.getElementById(
|
|
1183
|
-
} 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") {
|
|
1184
1184
|
document
|
|
1185
|
-
.getElementById(
|
|
1186
|
-
.classList.remove(
|
|
1185
|
+
.getElementById("openai_auth_key_container")
|
|
1186
|
+
.classList.remove("hidden");
|
|
1187
1187
|
document
|
|
1188
|
-
.getElementById(
|
|
1189
|
-
.classList.remove(
|
|
1188
|
+
.getElementById("gemini_auth_key_container")
|
|
1189
|
+
.classList.remove("hidden");
|
|
1190
1190
|
document
|
|
1191
|
-
.getElementById(
|
|
1192
|
-
.classList.remove(
|
|
1191
|
+
.getElementById("openai_multi_container")
|
|
1192
|
+
.classList.remove("hidden");
|
|
1193
1193
|
document
|
|
1194
|
-
.getElementById(
|
|
1195
|
-
.classList.remove(
|
|
1196
|
-
document.getElementById(
|
|
1197
|
-
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;
|
|
1198
1198
|
}
|
|
1199
1199
|
},
|
|
1200
1200
|
]);
|
|
1201
1201
|
|
|
1202
1202
|
constants.events.push([
|
|
1203
|
-
document.getElementById(
|
|
1204
|
-
|
|
1203
|
+
document.getElementById("LLM_model_openai"),
|
|
1204
|
+
"change",
|
|
1205
1205
|
function (e) {
|
|
1206
1206
|
if (e.target.checked) {
|
|
1207
1207
|
document
|
|
1208
|
-
.getElementById(
|
|
1209
|
-
.classList.remove(
|
|
1208
|
+
.getElementById("openai_auth_key_container")
|
|
1209
|
+
.classList.remove("hidden");
|
|
1210
1210
|
} else {
|
|
1211
1211
|
document
|
|
1212
|
-
.getElementById(
|
|
1213
|
-
.classList.add(
|
|
1212
|
+
.getElementById("openai_auth_key_container")
|
|
1213
|
+
.classList.add("hidden");
|
|
1214
1214
|
}
|
|
1215
1215
|
},
|
|
1216
1216
|
]);
|
|
1217
1217
|
|
|
1218
1218
|
constants.events.push([
|
|
1219
|
-
document.getElementById(
|
|
1220
|
-
|
|
1219
|
+
document.getElementById("LLM_model_gemini"),
|
|
1220
|
+
"change",
|
|
1221
1221
|
function (e) {
|
|
1222
1222
|
if (e.target.checked) {
|
|
1223
1223
|
document
|
|
1224
|
-
.getElementById(
|
|
1225
|
-
.classList.remove(
|
|
1224
|
+
.getElementById("gemini_auth_key_container")
|
|
1225
|
+
.classList.remove("hidden");
|
|
1226
1226
|
} else {
|
|
1227
1227
|
document
|
|
1228
|
-
.getElementById(
|
|
1229
|
-
.classList.add(
|
|
1228
|
+
.getElementById("gemini_auth_key_container")
|
|
1229
|
+
.classList.add("hidden");
|
|
1230
1230
|
}
|
|
1231
1231
|
},
|
|
1232
1232
|
]);
|
|
1233
1233
|
|
|
1234
1234
|
constants.events.push([
|
|
1235
|
-
document.getElementById(
|
|
1236
|
-
|
|
1235
|
+
document.getElementById("LLM_model_claude"),
|
|
1236
|
+
"change",
|
|
1237
1237
|
function (e) {
|
|
1238
1238
|
// if (e.target.checked) {
|
|
1239
1239
|
document
|
|
1240
|
-
.getElementById(
|
|
1241
|
-
.classList.add(
|
|
1240
|
+
.getElementById("claude_auth_key_container")
|
|
1241
|
+
.classList.add("hidden");
|
|
1242
1242
|
// } else {
|
|
1243
1243
|
// document
|
|
1244
1244
|
// .getElementById('claude_auth_key_container')
|
|
@@ -1249,17 +1249,17 @@ class Menu {
|
|
|
1249
1249
|
|
|
1250
1250
|
// Skill level other events
|
|
1251
1251
|
constants.events.push([
|
|
1252
|
-
document.getElementById(
|
|
1253
|
-
|
|
1252
|
+
document.getElementById("skill_level"),
|
|
1253
|
+
"change",
|
|
1254
1254
|
function (e) {
|
|
1255
|
-
if (e.target.value ==
|
|
1255
|
+
if (e.target.value == "other") {
|
|
1256
1256
|
document
|
|
1257
|
-
.getElementById(
|
|
1258
|
-
.classList.remove(
|
|
1257
|
+
.getElementById("skill_level_other_container")
|
|
1258
|
+
.classList.remove("hidden");
|
|
1259
1259
|
} else {
|
|
1260
1260
|
document
|
|
1261
|
-
.getElementById(
|
|
1262
|
-
.classList.add(
|
|
1261
|
+
.getElementById("skill_level_other_container")
|
|
1262
|
+
.classList.add("hidden");
|
|
1263
1263
|
}
|
|
1264
1264
|
},
|
|
1265
1265
|
]);
|
|
@@ -1267,16 +1267,16 @@ class Menu {
|
|
|
1267
1267
|
// trigger notification that LLM will be reset
|
|
1268
1268
|
// this is done on change of LLM model, multi settings, or skill level
|
|
1269
1269
|
let LLMResetIds = [
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1270
|
+
"LLM_model",
|
|
1271
|
+
"openai_multi",
|
|
1272
|
+
"gemini_multi",
|
|
1273
|
+
"skill_level",
|
|
1274
|
+
"LLM_preferences",
|
|
1275
1275
|
];
|
|
1276
1276
|
for (let i = 0; i < LLMResetIds.length; i++) {
|
|
1277
1277
|
constants.events.push([
|
|
1278
1278
|
document.getElementById(LLMResetIds[i]),
|
|
1279
|
-
|
|
1279
|
+
"change",
|
|
1280
1280
|
function (e) {
|
|
1281
1281
|
menu.NotifyOfLLMReset();
|
|
1282
1282
|
},
|
|
@@ -1286,13 +1286,13 @@ class Menu {
|
|
|
1286
1286
|
// Limit selections to 2 AI models
|
|
1287
1287
|
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
1288
1288
|
llmCheckboxes.forEach((checkbox) => {
|
|
1289
|
-
checkbox.addEventListener(
|
|
1289
|
+
checkbox.addEventListener("change", () => {
|
|
1290
1290
|
const checked = document.querySelectorAll(
|
|
1291
1291
|
'input[name="LLM_model"]:checked'
|
|
1292
1292
|
);
|
|
1293
1293
|
if (checked.length > 2) {
|
|
1294
1294
|
checkbox.checked = false;
|
|
1295
|
-
alert(
|
|
1295
|
+
alert("You can select up to 2 AI models.");
|
|
1296
1296
|
}
|
|
1297
1297
|
});
|
|
1298
1298
|
});
|
|
@@ -1304,11 +1304,11 @@ class Menu {
|
|
|
1304
1304
|
*/
|
|
1305
1305
|
Destroy() {
|
|
1306
1306
|
// menu element destruction
|
|
1307
|
-
let menu = document.getElementById(
|
|
1307
|
+
let menu = document.getElementById("menu");
|
|
1308
1308
|
if (menu) {
|
|
1309
1309
|
menu.remove();
|
|
1310
1310
|
}
|
|
1311
|
-
let backdrop = document.getElementById(
|
|
1311
|
+
let backdrop = document.getElementById("menu_modal_backdrop");
|
|
1312
1312
|
if (backdrop) {
|
|
1313
1313
|
backdrop.remove();
|
|
1314
1314
|
}
|
|
@@ -1320,16 +1320,16 @@ class Menu {
|
|
|
1320
1320
|
* @return {void}
|
|
1321
1321
|
*/
|
|
1322
1322
|
Toggle(onoff = false) {
|
|
1323
|
-
if (typeof onoff ==
|
|
1324
|
-
if (document.getElementById(
|
|
1323
|
+
if (typeof onoff == "undefined") {
|
|
1324
|
+
if (document.getElementById("menu").classList.contains("hidden")) {
|
|
1325
1325
|
onoff = true;
|
|
1326
1326
|
} else {
|
|
1327
1327
|
onoff = false;
|
|
1328
1328
|
}
|
|
1329
1329
|
}
|
|
1330
1330
|
// don't open if we have another modal open already
|
|
1331
|
-
if (onoff && document.getElementById(
|
|
1332
|
-
if (!document.getElementById(
|
|
1331
|
+
if (onoff && document.getElementById("chatLLM")) {
|
|
1332
|
+
if (!document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
1333
1333
|
return;
|
|
1334
1334
|
}
|
|
1335
1335
|
}
|
|
@@ -1338,13 +1338,13 @@ class Menu {
|
|
|
1338
1338
|
this.whereWasMyFocus = document.activeElement;
|
|
1339
1339
|
this.PopulateData();
|
|
1340
1340
|
constants.tabMovement = 0;
|
|
1341
|
-
document.getElementById(
|
|
1342
|
-
document.getElementById(
|
|
1343
|
-
document.querySelector(
|
|
1341
|
+
document.getElementById("menu").classList.remove("hidden");
|
|
1342
|
+
document.getElementById("menu_modal_backdrop").classList.remove("hidden");
|
|
1343
|
+
document.querySelector("#menu .close").focus();
|
|
1344
1344
|
} else {
|
|
1345
1345
|
// close
|
|
1346
|
-
document.getElementById(
|
|
1347
|
-
document.getElementById(
|
|
1346
|
+
document.getElementById("menu").classList.add("hidden");
|
|
1347
|
+
document.getElementById("menu_modal_backdrop").classList.add("hidden");
|
|
1348
1348
|
this.whereWasMyFocus.focus();
|
|
1349
1349
|
this.whereWasMyFocus = null;
|
|
1350
1350
|
}
|
|
@@ -1355,42 +1355,42 @@ class Menu {
|
|
|
1355
1355
|
* @return {void}
|
|
1356
1356
|
*/
|
|
1357
1357
|
PopulateData() {
|
|
1358
|
-
document.getElementById(
|
|
1359
|
-
document.getElementById(
|
|
1358
|
+
document.getElementById("vol").value = constants.vol;
|
|
1359
|
+
document.getElementById("braille_display_length").value =
|
|
1360
1360
|
constants.brailleDisplayLength;
|
|
1361
|
-
document.getElementById(
|
|
1362
|
-
document.getElementById(
|
|
1363
|
-
document.getElementById(
|
|
1364
|
-
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 =
|
|
1365
1365
|
constants.AUTOPLAY_DURATION;
|
|
1366
|
-
if (typeof constants.openAIAuthKey ==
|
|
1367
|
-
document.getElementById(
|
|
1366
|
+
if (typeof constants.openAIAuthKey == "string") {
|
|
1367
|
+
document.getElementById("openai_auth_key").value =
|
|
1368
1368
|
constants.openAIAuthKey;
|
|
1369
1369
|
}
|
|
1370
|
-
if (typeof constants.emailAuthKey ==
|
|
1371
|
-
document.getElementById(
|
|
1370
|
+
if (typeof constants.emailAuthKey == "string") {
|
|
1371
|
+
document.getElementById("email_auth_key").value = constants.emailAuthKey;
|
|
1372
1372
|
}
|
|
1373
|
-
if (typeof constants.geminiAuthKey ==
|
|
1374
|
-
document.getElementById(
|
|
1373
|
+
if (typeof constants.geminiAuthKey == "string") {
|
|
1374
|
+
document.getElementById("gemini_auth_key").value =
|
|
1375
1375
|
constants.geminiAuthKey;
|
|
1376
1376
|
}
|
|
1377
|
-
if (typeof constants.claudeAuthKey ==
|
|
1378
|
-
document.getElementById(
|
|
1377
|
+
if (typeof constants.claudeAuthKey == "string") {
|
|
1378
|
+
document.getElementById("claude_auth_key").value =
|
|
1379
1379
|
constants.claudeAuthKey;
|
|
1380
1380
|
}
|
|
1381
|
-
document.getElementById(
|
|
1381
|
+
document.getElementById("skill_level").value = constants.skillLevel;
|
|
1382
1382
|
if (constants.skillLevelOther) {
|
|
1383
|
-
document.getElementById(
|
|
1383
|
+
document.getElementById("skill_level_other").value =
|
|
1384
1384
|
constants.skillLevelOther;
|
|
1385
1385
|
}
|
|
1386
1386
|
|
|
1387
1387
|
// aria mode
|
|
1388
|
-
if (constants.ariaMode ==
|
|
1389
|
-
document.getElementById(
|
|
1390
|
-
document.getElementById(
|
|
1388
|
+
if (constants.ariaMode == "assertive") {
|
|
1389
|
+
document.getElementById("aria_mode_assertive").checked = true;
|
|
1390
|
+
document.getElementById("aria_mode_polite").checked = false;
|
|
1391
1391
|
} else {
|
|
1392
|
-
document.getElementById(
|
|
1393
|
-
document.getElementById(
|
|
1392
|
+
document.getElementById("aria_mode_polite").checked = true;
|
|
1393
|
+
document.getElementById("aria_mode_assertive").checked = false;
|
|
1394
1394
|
}
|
|
1395
1395
|
|
|
1396
1396
|
for (let model in constants.LLMModels) {
|
|
@@ -1398,25 +1398,25 @@ class Menu {
|
|
|
1398
1398
|
|
|
1399
1399
|
document
|
|
1400
1400
|
.getElementById(`${model}_auth_key_container`)
|
|
1401
|
-
.classList.remove(
|
|
1401
|
+
.classList.remove("hidden");
|
|
1402
1402
|
}
|
|
1403
1403
|
document
|
|
1404
1404
|
.getElementById(`claude_auth_key_container`)
|
|
1405
|
-
.classList.add(
|
|
1405
|
+
.classList.add("hidden");
|
|
1406
1406
|
|
|
1407
1407
|
// skill level other
|
|
1408
|
-
if (constants.skillLevel ==
|
|
1408
|
+
if (constants.skillLevel == "other") {
|
|
1409
1409
|
document
|
|
1410
|
-
.getElementById(
|
|
1411
|
-
.classList.remove(
|
|
1410
|
+
.getElementById("skill_level_other_container")
|
|
1411
|
+
.classList.remove("hidden");
|
|
1412
1412
|
}
|
|
1413
1413
|
// LLM preferences
|
|
1414
1414
|
if (constants.LLMPreferences) {
|
|
1415
|
-
document.getElementById(
|
|
1415
|
+
document.getElementById("LLM_preferences").value =
|
|
1416
1416
|
constants.LLMPreferences;
|
|
1417
1417
|
}
|
|
1418
|
-
if (document.getElementById(
|
|
1419
|
-
document.getElementById(
|
|
1418
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1419
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1420
1420
|
}
|
|
1421
1421
|
}
|
|
1422
1422
|
|
|
@@ -1427,23 +1427,23 @@ class Menu {
|
|
|
1427
1427
|
SaveData() {
|
|
1428
1428
|
let shouldReset = this.ShouldLLMReset();
|
|
1429
1429
|
|
|
1430
|
-
constants.vol = document.getElementById(
|
|
1430
|
+
constants.vol = document.getElementById("vol").value;
|
|
1431
1431
|
constants.brailleDisplayLength = document.getElementById(
|
|
1432
|
-
|
|
1432
|
+
"braille_display_length"
|
|
1433
1433
|
).value;
|
|
1434
|
-
constants.colorSelected = document.getElementById(
|
|
1435
|
-
constants.MIN_FREQUENCY = document.getElementById(
|
|
1436
|
-
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;
|
|
1437
1437
|
constants.AUTOPLAY_DURATION =
|
|
1438
|
-
document.getElementById(
|
|
1438
|
+
document.getElementById("AUTOPLAY_DURATION").value;
|
|
1439
1439
|
|
|
1440
|
-
constants.openAIAuthKey = document.getElementById(
|
|
1441
|
-
constants.geminiAuthKey = document.getElementById(
|
|
1442
|
-
constants.claudeAuthKey = document.getElementById(
|
|
1443
|
-
constants.emailAuthKey = document.getElementById(
|
|
1444
|
-
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;
|
|
1445
1445
|
constants.skillLevelOther =
|
|
1446
|
-
document.getElementById(
|
|
1446
|
+
document.getElementById("skill_level_other").value;
|
|
1447
1447
|
// constants.LLMModel = document.getElementById('LLM_model').value;
|
|
1448
1448
|
|
|
1449
1449
|
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
@@ -1455,16 +1455,16 @@ class Menu {
|
|
|
1455
1455
|
}
|
|
1456
1456
|
});
|
|
1457
1457
|
|
|
1458
|
-
constants.LLMPreferences = document.getElementById(
|
|
1459
|
-
constants.LLMOpenAiMulti = document.getElementById(
|
|
1460
|
-
constants.LLMGeminiMulti = document.getElementById(
|
|
1461
|
-
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;
|
|
1462
1462
|
|
|
1463
1463
|
// aria
|
|
1464
|
-
if (document.getElementById(
|
|
1465
|
-
constants.ariaMode =
|
|
1466
|
-
} else if (document.getElementById(
|
|
1467
|
-
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";
|
|
1468
1468
|
}
|
|
1469
1469
|
|
|
1470
1470
|
this.SaveDataToLocalStorage();
|
|
@@ -1478,8 +1478,8 @@ class Menu {
|
|
|
1478
1478
|
}
|
|
1479
1479
|
|
|
1480
1480
|
VerifyEmail() {
|
|
1481
|
-
let email = document.getElementById(
|
|
1482
|
-
if (email && email.indexOf(
|
|
1481
|
+
let email = document.getElementById("email_auth_key").value;
|
|
1482
|
+
if (email && email.indexOf("@") !== -1) {
|
|
1483
1483
|
let url = `https://maidr-service.azurewebsites.net/api/send_email?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D`;
|
|
1484
1484
|
|
|
1485
1485
|
let requestJson = {
|
|
@@ -1487,9 +1487,9 @@ class Menu {
|
|
|
1487
1487
|
};
|
|
1488
1488
|
|
|
1489
1489
|
fetch(url, {
|
|
1490
|
-
method:
|
|
1490
|
+
method: "POST",
|
|
1491
1491
|
headers: {
|
|
1492
|
-
|
|
1492
|
+
"Content-Type": "application/json",
|
|
1493
1493
|
Authentication: constants.emailAuthKey,
|
|
1494
1494
|
},
|
|
1495
1495
|
body: JSON.stringify(requestJson),
|
|
@@ -1497,7 +1497,7 @@ class Menu {
|
|
|
1497
1497
|
.then((response) => response.json())
|
|
1498
1498
|
.then((data) => {
|
|
1499
1499
|
if (data && data.success) {
|
|
1500
|
-
alert(
|
|
1500
|
+
alert("Link sent to email address: " + email);
|
|
1501
1501
|
} else {
|
|
1502
1502
|
console.log(data);
|
|
1503
1503
|
alert(data.data);
|
|
@@ -1508,7 +1508,7 @@ class Menu {
|
|
|
1508
1508
|
alert(error.data);
|
|
1509
1509
|
});
|
|
1510
1510
|
} else {
|
|
1511
|
-
alert(
|
|
1511
|
+
alert("Please enter a valid email address.");
|
|
1512
1512
|
}
|
|
1513
1513
|
}
|
|
1514
1514
|
|
|
@@ -1518,29 +1518,29 @@ class Menu {
|
|
|
1518
1518
|
*/
|
|
1519
1519
|
UpdateHtml() {
|
|
1520
1520
|
// set aria attributes
|
|
1521
|
-
constants.infoDiv.setAttribute(
|
|
1521
|
+
constants.infoDiv.setAttribute("aria-live", constants.ariaMode);
|
|
1522
1522
|
document
|
|
1523
1523
|
.getElementById(constants.announcement_container_id)
|
|
1524
|
-
.setAttribute(
|
|
1524
|
+
.setAttribute("aria-live", constants.ariaMode);
|
|
1525
1525
|
|
|
1526
|
-
document.getElementById(
|
|
1527
|
-
const scatter = document.getElementsByClassName(
|
|
1528
|
-
const heatmap = document.getElementById(
|
|
1529
|
-
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");
|
|
1530
1530
|
|
|
1531
1531
|
if (scatter !== null && scatter.length > 0) {
|
|
1532
1532
|
for (let i = 0; i < scatter.length; i++) {
|
|
1533
|
-
scatter[i].setAttribute(
|
|
1534
|
-
scatter[i].setAttribute(
|
|
1533
|
+
scatter[i].setAttribute("stroke", constants.colorSelected);
|
|
1534
|
+
scatter[i].setAttribute("fill", constants.colorSelected);
|
|
1535
1535
|
}
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
1538
|
if (heatmap !== null) {
|
|
1539
|
-
heatmap.setAttribute(
|
|
1539
|
+
heatmap.setAttribute("stroke", constants.colorSelected);
|
|
1540
1540
|
}
|
|
1541
1541
|
|
|
1542
1542
|
if (line !== null) {
|
|
1543
|
-
line.setAttribute(
|
|
1543
|
+
line.setAttribute("stroke", constants.colorSelected);
|
|
1544
1544
|
}
|
|
1545
1545
|
}
|
|
1546
1546
|
|
|
@@ -1552,19 +1552,19 @@ class Menu {
|
|
|
1552
1552
|
let html =
|
|
1553
1553
|
'<p id="LLM_reset_notification">Note: Changes in LLM settings will reset any existing conversation.</p>';
|
|
1554
1554
|
|
|
1555
|
-
if (document.getElementById(
|
|
1556
|
-
document.getElementById(
|
|
1555
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1556
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1557
1557
|
}
|
|
1558
1558
|
document
|
|
1559
|
-
.getElementById(
|
|
1560
|
-
.parentElement.insertAdjacentHTML(
|
|
1559
|
+
.getElementById("save_and_close_menu")
|
|
1560
|
+
.parentElement.insertAdjacentHTML("afterend", html);
|
|
1561
1561
|
|
|
1562
1562
|
// add to aria button text
|
|
1563
1563
|
document
|
|
1564
|
-
.getElementById(
|
|
1564
|
+
.getElementById("save_and_close_menu")
|
|
1565
1565
|
.setAttribute(
|
|
1566
|
-
|
|
1567
|
-
|
|
1566
|
+
"aria-labelledby",
|
|
1567
|
+
"save_and_close_text LLM_reset_notification"
|
|
1568
1568
|
);
|
|
1569
1569
|
}
|
|
1570
1570
|
/**
|
|
@@ -1576,20 +1576,20 @@ class Menu {
|
|
|
1576
1576
|
let shouldReset = false;
|
|
1577
1577
|
if (
|
|
1578
1578
|
!shouldReset &&
|
|
1579
|
-
constants.skillLevel != document.getElementById(
|
|
1579
|
+
constants.skillLevel != document.getElementById("skill_level").value
|
|
1580
1580
|
) {
|
|
1581
1581
|
shouldReset = true;
|
|
1582
1582
|
}
|
|
1583
1583
|
if (
|
|
1584
1584
|
!shouldReset &&
|
|
1585
1585
|
constants.LLMPreferences !=
|
|
1586
|
-
document.getElementById(
|
|
1586
|
+
document.getElementById("LLM_preferences").value
|
|
1587
1587
|
) {
|
|
1588
1588
|
shouldReset = true;
|
|
1589
1589
|
}
|
|
1590
1590
|
if (
|
|
1591
1591
|
!shouldReset &&
|
|
1592
|
-
constants.LLMModel != document.getElementById(
|
|
1592
|
+
constants.LLMModel != document.getElementById("LLM_model").value
|
|
1593
1593
|
) {
|
|
1594
1594
|
shouldReset = true;
|
|
1595
1595
|
}
|
|
@@ -1618,24 +1618,24 @@ class Menu {
|
|
|
1618
1618
|
data[constants.userSettingsKeys[i]] =
|
|
1619
1619
|
constants[constants.userSettingsKeys[i]];
|
|
1620
1620
|
}
|
|
1621
|
-
localStorage.setItem(
|
|
1621
|
+
localStorage.setItem("settings_data", JSON.stringify(data));
|
|
1622
1622
|
|
|
1623
1623
|
// also save to tracking if we're doing that
|
|
1624
1624
|
if (constants.canTrack) {
|
|
1625
1625
|
// but not auth keys
|
|
1626
|
-
data.openAIAuthKey =
|
|
1627
|
-
data.geminiAuthKey =
|
|
1628
|
-
data.claudeAuthKey =
|
|
1626
|
+
data.openAIAuthKey = "hidden";
|
|
1627
|
+
data.geminiAuthKey = "hidden";
|
|
1628
|
+
data.claudeAuthKey = "hidden";
|
|
1629
1629
|
// and need a timestamp
|
|
1630
1630
|
data.timestamp = new Date().toISOString();
|
|
1631
|
-
tracker.SetData(
|
|
1631
|
+
tracker.SetData("settings", data);
|
|
1632
1632
|
}
|
|
1633
1633
|
}
|
|
1634
1634
|
/**
|
|
1635
1635
|
* Loads data from 'settings_data' localStorage, and updates contants variables
|
|
1636
1636
|
*/
|
|
1637
1637
|
LoadDataFromLocalStorage() {
|
|
1638
|
-
let data = JSON.parse(localStorage.getItem(
|
|
1638
|
+
let data = JSON.parse(localStorage.getItem("settings_data"));
|
|
1639
1639
|
if (data) {
|
|
1640
1640
|
for (let i = 0; i < constants.userSettingsKeys.length; i++) {
|
|
1641
1641
|
const key = constants.userSettingsKeys[i];
|
|
@@ -1663,9 +1663,9 @@ class ChatLLM {
|
|
|
1663
1663
|
if (constants.autoInitLLM) {
|
|
1664
1664
|
// only run if we have API keys set
|
|
1665
1665
|
if (
|
|
1666
|
-
(
|
|
1667
|
-
(
|
|
1668
|
-
(
|
|
1666
|
+
("gemini" in constants.LLMModels && constants.geminiAuthKey) ||
|
|
1667
|
+
("openai" in constants.LLMModels && constants.openAIAuthKey) ||
|
|
1668
|
+
("claude" in constants.LLMModels && constants.claudeAuthKey)
|
|
1669
1669
|
) {
|
|
1670
1670
|
this.InitChatMessage();
|
|
1671
1671
|
}
|
|
@@ -1718,7 +1718,7 @@ class ChatLLM {
|
|
|
1718
1718
|
</div>
|
|
1719
1719
|
<div id="chatLLM_modal_backdrop" class="modal-backdrop hidden"></div>
|
|
1720
1720
|
`;
|
|
1721
|
-
document.querySelector(
|
|
1721
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
1722
1722
|
}
|
|
1723
1723
|
|
|
1724
1724
|
/**
|
|
@@ -1727,21 +1727,21 @@ class ChatLLM {
|
|
|
1727
1727
|
*/
|
|
1728
1728
|
SetEvents() {
|
|
1729
1729
|
// chatLLM close events
|
|
1730
|
-
let allClose = document.querySelectorAll(
|
|
1730
|
+
let allClose = document.querySelectorAll("#close_chatLLM, #chatLLM .close");
|
|
1731
1731
|
for (let i = 0; i < allClose.length; i++) {
|
|
1732
1732
|
constants.events.push([
|
|
1733
1733
|
allClose[i],
|
|
1734
|
-
|
|
1734
|
+
"click",
|
|
1735
1735
|
function (e) {
|
|
1736
1736
|
chatLLM.Toggle(false);
|
|
1737
1737
|
},
|
|
1738
1738
|
]);
|
|
1739
1739
|
}
|
|
1740
1740
|
constants.events.push([
|
|
1741
|
-
document.getElementById(
|
|
1742
|
-
|
|
1741
|
+
document.getElementById("chatLLM"),
|
|
1742
|
+
"keyup",
|
|
1743
1743
|
function (e) {
|
|
1744
|
-
if (e.key ==
|
|
1744
|
+
if (e.key == "Esc") {
|
|
1745
1745
|
// esc
|
|
1746
1746
|
chatLLM.Toggle(false);
|
|
1747
1747
|
}
|
|
@@ -1751,9 +1751,9 @@ class ChatLLM {
|
|
|
1751
1751
|
// ChatLLM open/close toggle
|
|
1752
1752
|
constants.events.push([
|
|
1753
1753
|
document,
|
|
1754
|
-
|
|
1754
|
+
"keyup",
|
|
1755
1755
|
function (e) {
|
|
1756
|
-
if ((e.key ==
|
|
1756
|
+
if ((e.key == "?" && (e.ctrlKey || e.metaKey)) || e.key == "¿") {
|
|
1757
1757
|
chatLLM.Toggle();
|
|
1758
1758
|
}
|
|
1759
1759
|
},
|
|
@@ -1761,21 +1761,21 @@ class ChatLLM {
|
|
|
1761
1761
|
|
|
1762
1762
|
// ChatLLM request events
|
|
1763
1763
|
constants.events.push([
|
|
1764
|
-
document.getElementById(
|
|
1765
|
-
|
|
1764
|
+
document.getElementById("chatLLM_submit"),
|
|
1765
|
+
"click",
|
|
1766
1766
|
function (e) {
|
|
1767
|
-
let text = document.getElementById(
|
|
1768
|
-
chatLLM.DisplayChatMessage(
|
|
1767
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1768
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1769
1769
|
chatLLM.Submit(text);
|
|
1770
1770
|
},
|
|
1771
1771
|
]);
|
|
1772
1772
|
constants.events.push([
|
|
1773
|
-
document.getElementById(
|
|
1774
|
-
|
|
1773
|
+
document.getElementById("chatLLM_input"),
|
|
1774
|
+
"keyup",
|
|
1775
1775
|
function (e) {
|
|
1776
|
-
if (e.key ==
|
|
1777
|
-
let text = document.getElementById(
|
|
1778
|
-
chatLLM.DisplayChatMessage(
|
|
1776
|
+
if (e.key == "Enter" && !e.shiftKey) {
|
|
1777
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1778
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1779
1779
|
chatLLM.Submit(text);
|
|
1780
1780
|
}
|
|
1781
1781
|
},
|
|
@@ -1784,15 +1784,15 @@ class ChatLLM {
|
|
|
1784
1784
|
// ChatLLM suggestion events
|
|
1785
1785
|
// actual suggestions:
|
|
1786
1786
|
let suggestions = document.querySelectorAll(
|
|
1787
|
-
|
|
1787
|
+
"#chatLLM .LLM_suggestions button:not(#more_suggestions)"
|
|
1788
1788
|
);
|
|
1789
1789
|
for (let i = 0; i < suggestions.length; i++) {
|
|
1790
1790
|
constants.events.push([
|
|
1791
1791
|
suggestions[i],
|
|
1792
|
-
|
|
1792
|
+
"click",
|
|
1793
1793
|
function (e) {
|
|
1794
1794
|
let text = e.target.innerHTML;
|
|
1795
|
-
chatLLM.DisplayChatMessage(
|
|
1795
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1796
1796
|
chatLLM.Submit(text);
|
|
1797
1797
|
},
|
|
1798
1798
|
]);
|
|
@@ -1800,31 +1800,31 @@ class ChatLLM {
|
|
|
1800
1800
|
|
|
1801
1801
|
// Delete OpenAI and Gemini keys
|
|
1802
1802
|
constants.events.push([
|
|
1803
|
-
document.getElementById(
|
|
1804
|
-
|
|
1803
|
+
document.getElementById("delete_openai_key"),
|
|
1804
|
+
"click",
|
|
1805
1805
|
function (e) {
|
|
1806
|
-
document.getElementById(
|
|
1806
|
+
document.getElementById("openai_auth_key").value = "";
|
|
1807
1807
|
},
|
|
1808
1808
|
]);
|
|
1809
1809
|
constants.events.push([
|
|
1810
|
-
document.getElementById(
|
|
1811
|
-
|
|
1810
|
+
document.getElementById("delete_email_key"),
|
|
1811
|
+
"click",
|
|
1812
1812
|
function (e) {
|
|
1813
|
-
document.getElementById(
|
|
1813
|
+
document.getElementById("email_auth_key").value = "";
|
|
1814
1814
|
},
|
|
1815
1815
|
]);
|
|
1816
1816
|
constants.events.push([
|
|
1817
|
-
document.getElementById(
|
|
1818
|
-
|
|
1817
|
+
document.getElementById("delete_gemini_key"),
|
|
1818
|
+
"click",
|
|
1819
1819
|
function (e) {
|
|
1820
|
-
document.getElementById(
|
|
1820
|
+
document.getElementById("gemini_auth_key").value = "";
|
|
1821
1821
|
},
|
|
1822
1822
|
]);
|
|
1823
1823
|
|
|
1824
1824
|
// Reset chatLLM
|
|
1825
1825
|
constants.events.push([
|
|
1826
|
-
document.getElementById(
|
|
1827
|
-
|
|
1826
|
+
document.getElementById("reset_chatLLM"),
|
|
1827
|
+
"click",
|
|
1828
1828
|
function (e) {
|
|
1829
1829
|
chatLLM.ResetLLM();
|
|
1830
1830
|
},
|
|
@@ -1832,15 +1832,15 @@ class ChatLLM {
|
|
|
1832
1832
|
|
|
1833
1833
|
// copy to clipboard
|
|
1834
1834
|
constants.events.push([
|
|
1835
|
-
document.getElementById(
|
|
1836
|
-
|
|
1835
|
+
document.getElementById("chatLLM"),
|
|
1836
|
+
"click",
|
|
1837
1837
|
function (e) {
|
|
1838
1838
|
chatLLM.CopyChatHistory(e);
|
|
1839
1839
|
},
|
|
1840
1840
|
]);
|
|
1841
1841
|
constants.events.push([
|
|
1842
|
-
document.getElementById(
|
|
1843
|
-
|
|
1842
|
+
document.getElementById("chatLLM"),
|
|
1843
|
+
"keyup",
|
|
1844
1844
|
function (e) {
|
|
1845
1845
|
chatLLM.CopyChatHistory(e);
|
|
1846
1846
|
},
|
|
@@ -1858,96 +1858,96 @@ class ChatLLM {
|
|
|
1858
1858
|
* @param {Event|undefined} e - The event that triggered the copy action. If undefined, the entire chat history is copied.
|
|
1859
1859
|
*/
|
|
1860
1860
|
CopyChatHistory(e) {
|
|
1861
|
-
let text =
|
|
1862
|
-
if (typeof e ==
|
|
1861
|
+
let text = "";
|
|
1862
|
+
if (typeof e == "undefined") {
|
|
1863
1863
|
// check for passthrough
|
|
1864
1864
|
// get html of the full chat history
|
|
1865
|
-
text = document.getElementById(
|
|
1866
|
-
} else if (e.type ==
|
|
1865
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1866
|
+
} else if (e.type == "click") {
|
|
1867
1867
|
// check for buttons
|
|
1868
|
-
if (e.target.id ==
|
|
1868
|
+
if (e.target.id == "chatLLM_copy_all") {
|
|
1869
1869
|
// get html of the full chat history
|
|
1870
|
-
text = document.getElementById(
|
|
1871
|
-
} 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")) {
|
|
1872
1872
|
// get the text of the element before the button
|
|
1873
|
-
text = e.target.closest(
|
|
1873
|
+
text = e.target.closest("p").previousElementSibling.innerHTML;
|
|
1874
1874
|
}
|
|
1875
|
-
} else if (e.type ==
|
|
1875
|
+
} else if (e.type == "keyup") {
|
|
1876
1876
|
// check for alt shift c or ctrl shift c
|
|
1877
|
-
if (e.key ==
|
|
1877
|
+
if (e.key == "C" && (e.ctrlKey || e.metaKey || e.altKey) && e.shiftKey) {
|
|
1878
1878
|
e.preventDefault();
|
|
1879
1879
|
// get the last message
|
|
1880
1880
|
let elem = document.querySelector(
|
|
1881
|
-
|
|
1881
|
+
"#chatLLM_chat_history > .chatLLM_message_other:last-of-type"
|
|
1882
1882
|
);
|
|
1883
1883
|
if (elem) {
|
|
1884
1884
|
text = elem.innerHTML;
|
|
1885
1885
|
}
|
|
1886
1886
|
} else if (
|
|
1887
|
-
e.key ==
|
|
1887
|
+
e.key == "A" &&
|
|
1888
1888
|
(e.ctrlKey || e.metaKey || e.altKey) &&
|
|
1889
1889
|
e.shiftKey
|
|
1890
1890
|
) {
|
|
1891
1891
|
e.preventDefault();
|
|
1892
1892
|
// get html of the full chat history
|
|
1893
|
-
text = document.getElementById(
|
|
1893
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1894
1894
|
}
|
|
1895
1895
|
}
|
|
1896
1896
|
|
|
1897
|
-
if (text ==
|
|
1897
|
+
if (text == "") {
|
|
1898
1898
|
return;
|
|
1899
1899
|
} else {
|
|
1900
1900
|
// clear the html, removing buttons etc
|
|
1901
|
-
let cleanElems = document.createElement(
|
|
1901
|
+
let cleanElems = document.createElement("div");
|
|
1902
1902
|
cleanElems.innerHTML = text;
|
|
1903
|
-
let removeThese = cleanElems.querySelectorAll(
|
|
1903
|
+
let removeThese = cleanElems.querySelectorAll(".chatLLM_message_copy");
|
|
1904
1904
|
removeThese.forEach((elem) => elem.remove());
|
|
1905
1905
|
|
|
1906
1906
|
// convert from html to markdown
|
|
1907
1907
|
let markdown = this.htmlToMarkdown(cleanElems);
|
|
1908
1908
|
// this messes up a bit with spacing, so kill more than 2 newlines in a row
|
|
1909
|
-
markdown = markdown.replace(/\n{3,}/g,
|
|
1909
|
+
markdown = markdown.replace(/\n{3,}/g, "\n\n");
|
|
1910
1910
|
|
|
1911
1911
|
try {
|
|
1912
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
|
|
1913
1913
|
} catch (err) {
|
|
1914
|
-
console.error(
|
|
1914
|
+
console.error("Failed to copy: ", err);
|
|
1915
1915
|
}
|
|
1916
1916
|
return markdown;
|
|
1917
1917
|
}
|
|
1918
1918
|
}
|
|
1919
1919
|
|
|
1920
1920
|
htmlToMarkdown(element) {
|
|
1921
|
-
let markdown =
|
|
1921
|
+
let markdown = "";
|
|
1922
1922
|
|
|
1923
1923
|
const convertElementToMarkdown = (element) => {
|
|
1924
1924
|
switch (element.tagName) {
|
|
1925
|
-
case
|
|
1925
|
+
case "H1":
|
|
1926
1926
|
return `# ${element.textContent}`;
|
|
1927
|
-
case
|
|
1927
|
+
case "H2":
|
|
1928
1928
|
return `## ${element.textContent}`;
|
|
1929
|
-
case
|
|
1929
|
+
case "H3":
|
|
1930
1930
|
return `### ${element.textContent}`;
|
|
1931
|
-
case
|
|
1931
|
+
case "H4":
|
|
1932
1932
|
return `#### ${element.textContent}`;
|
|
1933
|
-
case
|
|
1933
|
+
case "H5":
|
|
1934
1934
|
return `##### ${element.textContent}`;
|
|
1935
|
-
case
|
|
1935
|
+
case "H6":
|
|
1936
1936
|
return `###### ${element.textContent}`;
|
|
1937
|
-
case
|
|
1937
|
+
case "P":
|
|
1938
1938
|
return element.textContent;
|
|
1939
|
-
case
|
|
1939
|
+
case "DIV":
|
|
1940
1940
|
// For divs, process each child and add newlines as needed
|
|
1941
1941
|
return (
|
|
1942
1942
|
Array.from(element.childNodes)
|
|
1943
1943
|
.map((child) => convertElementToMarkdown(child))
|
|
1944
|
-
.join(
|
|
1944
|
+
.join("\n") + "\n\n"
|
|
1945
1945
|
);
|
|
1946
1946
|
default:
|
|
1947
1947
|
// For any other element, process its children recursively
|
|
1948
1948
|
return Array.from(element.childNodes)
|
|
1949
1949
|
.map((child) => convertElementToMarkdown(child))
|
|
1950
|
-
.join(
|
|
1950
|
+
.join("");
|
|
1951
1951
|
}
|
|
1952
1952
|
};
|
|
1953
1953
|
|
|
@@ -1955,7 +1955,7 @@ class ChatLLM {
|
|
|
1955
1955
|
markdown += convertElementToMarkdown(element);
|
|
1956
1956
|
} else if (
|
|
1957
1957
|
element.nodeType === Node.TEXT_NODE &&
|
|
1958
|
-
element.textContent.trim() !==
|
|
1958
|
+
element.textContent.trim() !== ""
|
|
1959
1959
|
) {
|
|
1960
1960
|
markdown += element.textContent.trim();
|
|
1961
1961
|
}
|
|
@@ -1980,14 +1980,14 @@ class ChatLLM {
|
|
|
1980
1980
|
|
|
1981
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
|
|
1982
1982
|
if (
|
|
1983
|
-
(this.firstOpen ||
|
|
1983
|
+
(this.firstOpen || "gemini" in constants.LLMModels) &&
|
|
1984
1984
|
!firsttime &&
|
|
1985
1985
|
constants.verboseText.length > 0
|
|
1986
1986
|
) {
|
|
1987
1987
|
text =
|
|
1988
1988
|
"Here is the current position in the chart; no response necessarily needed, use this info only if it's relevant to future questions: " +
|
|
1989
1989
|
constants.verboseText +
|
|
1990
|
-
|
|
1990
|
+
". My question is: " +
|
|
1991
1991
|
text;
|
|
1992
1992
|
|
|
1993
1993
|
this.firstOpen = false;
|
|
@@ -1998,9 +1998,9 @@ class ChatLLM {
|
|
|
1998
1998
|
this.WaitingSound(true);
|
|
1999
1999
|
}
|
|
2000
2000
|
|
|
2001
|
-
if (
|
|
2001
|
+
if ("openai" in constants.LLMModels) {
|
|
2002
2002
|
if (firsttime) {
|
|
2003
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2003
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "openai");
|
|
2004
2004
|
}
|
|
2005
2005
|
if (constants.openAIAuthKey) {
|
|
2006
2006
|
chatLLM.OpenAIPrompt(text, img);
|
|
@@ -2008,9 +2008,9 @@ class ChatLLM {
|
|
|
2008
2008
|
chatLLM.OpenAIPromptAPI(text, img);
|
|
2009
2009
|
}
|
|
2010
2010
|
}
|
|
2011
|
-
if (
|
|
2011
|
+
if ("gemini" in constants.LLMModels) {
|
|
2012
2012
|
if (firsttime) {
|
|
2013
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2013
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "gemini");
|
|
2014
2014
|
}
|
|
2015
2015
|
if (constants.geminiAuthKey) {
|
|
2016
2016
|
chatLLM.GeminiPrompt(text, img);
|
|
@@ -2019,9 +2019,9 @@ class ChatLLM {
|
|
|
2019
2019
|
}
|
|
2020
2020
|
}
|
|
2021
2021
|
|
|
2022
|
-
if (
|
|
2022
|
+
if ("claude" in constants.LLMModels) {
|
|
2023
2023
|
if (firsttime) {
|
|
2024
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
2024
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "claude");
|
|
2025
2025
|
}
|
|
2026
2026
|
if (constants.claudeAuthKey) {
|
|
2027
2027
|
chatLLM.ClaudePrompt(text, img);
|
|
@@ -2086,7 +2086,7 @@ class ChatLLM {
|
|
|
2086
2086
|
}, 30000);
|
|
2087
2087
|
|
|
2088
2088
|
// set queue for multi
|
|
2089
|
-
if (constants.LLMModel !=
|
|
2089
|
+
if (constants.LLMModel != "multi") {
|
|
2090
2090
|
constants.waitingQueue = 1;
|
|
2091
2091
|
} else {
|
|
2092
2092
|
constants.waitingQueue = 0;
|
|
@@ -2118,7 +2118,7 @@ class ChatLLM {
|
|
|
2118
2118
|
// get name from resource]
|
|
2119
2119
|
let LLMName = resources.GetString(constants.LLMModel);
|
|
2120
2120
|
this.firstTime = false;
|
|
2121
|
-
this.DisplayChatMessage(LLMName, resources.GetString(
|
|
2121
|
+
this.DisplayChatMessage(LLMName, resources.GetString("processing"), true);
|
|
2122
2122
|
let defaultPrompt = this.GetDefaultPrompt();
|
|
2123
2123
|
this.Submit(defaultPrompt, true);
|
|
2124
2124
|
}
|
|
@@ -2130,47 +2130,47 @@ class ChatLLM {
|
|
|
2130
2130
|
*/
|
|
2131
2131
|
ProcessLLMResponse(data, model) {
|
|
2132
2132
|
chatLLM.WaitingSound(false);
|
|
2133
|
-
let text =
|
|
2133
|
+
let text = "";
|
|
2134
2134
|
let LLMName = resources.GetString(model);
|
|
2135
2135
|
|
|
2136
|
-
if (model ==
|
|
2136
|
+
if (model == "openai") {
|
|
2137
2137
|
text = data.choices[0].message.content;
|
|
2138
2138
|
let i = this.requestJson.messages.length;
|
|
2139
2139
|
this.requestJson.messages[i] = {};
|
|
2140
|
-
this.requestJson.messages[i].role =
|
|
2140
|
+
this.requestJson.messages[i].role = "assistant";
|
|
2141
2141
|
this.requestJson.messages[i].content = text;
|
|
2142
2142
|
|
|
2143
2143
|
if (data.error) {
|
|
2144
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2144
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2145
2145
|
chatLLM.WaitingSound(false);
|
|
2146
2146
|
} else {
|
|
2147
2147
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2148
2148
|
}
|
|
2149
|
-
} else if (model ==
|
|
2149
|
+
} else if (model == "gemini") {
|
|
2150
2150
|
if (data.text()) {
|
|
2151
2151
|
text = data.text();
|
|
2152
2152
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2153
2153
|
} else {
|
|
2154
2154
|
if (!data.error) {
|
|
2155
|
-
data.error =
|
|
2155
|
+
data.error = "Error processing request.";
|
|
2156
2156
|
chatLLM.WaitingSound(false);
|
|
2157
2157
|
}
|
|
2158
2158
|
}
|
|
2159
2159
|
if (data.error) {
|
|
2160
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2160
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2161
2161
|
chatLLM.WaitingSound(false);
|
|
2162
2162
|
} else {
|
|
2163
2163
|
// todo: display actual response
|
|
2164
2164
|
}
|
|
2165
2165
|
}
|
|
2166
|
-
if (model ==
|
|
2167
|
-
console.log(
|
|
2166
|
+
if (model == "claude") {
|
|
2167
|
+
console.log("Claude response: ", data);
|
|
2168
2168
|
if (data.text()) {
|
|
2169
2169
|
text = data.text();
|
|
2170
2170
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2171
2171
|
}
|
|
2172
2172
|
if (data.error) {
|
|
2173
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2173
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2174
2174
|
chatLLM.WaitingSound(false);
|
|
2175
2175
|
}
|
|
2176
2176
|
}
|
|
@@ -2178,7 +2178,7 @@ class ChatLLM {
|
|
|
2178
2178
|
// if we're tracking, log the data
|
|
2179
2179
|
if (constants.canTrack) {
|
|
2180
2180
|
let chatHist = chatLLM.CopyChatHistory();
|
|
2181
|
-
tracker.SetData(
|
|
2181
|
+
tracker.SetData("ChatHistory", chatHist);
|
|
2182
2182
|
}
|
|
2183
2183
|
}
|
|
2184
2184
|
|
|
@@ -2192,11 +2192,11 @@ class ChatLLM {
|
|
|
2192
2192
|
if (this.requestJson.messages.length > 2) {
|
|
2193
2193
|
// subsequent responses
|
|
2194
2194
|
responseText = {
|
|
2195
|
-
id:
|
|
2196
|
-
object:
|
|
2195
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2196
|
+
object: "chat.completion",
|
|
2197
2197
|
created: 1703129508,
|
|
2198
2198
|
//model: 'gpt-4-1106-vision-preview',
|
|
2199
|
-
model:
|
|
2199
|
+
model: "gpt4-o",
|
|
2200
2200
|
usage: {
|
|
2201
2201
|
prompt_tokens: 451,
|
|
2202
2202
|
completion_tokens: 16,
|
|
@@ -2205,10 +2205,10 @@ class ChatLLM {
|
|
|
2205
2205
|
choices: [
|
|
2206
2206
|
{
|
|
2207
2207
|
message: {
|
|
2208
|
-
role:
|
|
2209
|
-
content:
|
|
2208
|
+
role: "assistant",
|
|
2209
|
+
content: "A fake response from the LLM. Nice.",
|
|
2210
2210
|
},
|
|
2211
|
-
finish_reason:
|
|
2211
|
+
finish_reason: "length",
|
|
2212
2212
|
index: 0,
|
|
2213
2213
|
},
|
|
2214
2214
|
],
|
|
@@ -2216,10 +2216,10 @@ class ChatLLM {
|
|
|
2216
2216
|
} else {
|
|
2217
2217
|
// first response
|
|
2218
2218
|
responseText = {
|
|
2219
|
-
id:
|
|
2220
|
-
object:
|
|
2219
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2220
|
+
object: "chat.completion",
|
|
2221
2221
|
created: 1703129508,
|
|
2222
|
-
model:
|
|
2222
|
+
model: "gpt-4-1106-vision-preview",
|
|
2223
2223
|
usage: {
|
|
2224
2224
|
prompt_tokens: 451,
|
|
2225
2225
|
completion_tokens: 16,
|
|
@@ -2228,11 +2228,11 @@ class ChatLLM {
|
|
|
2228
2228
|
choices: [
|
|
2229
2229
|
{
|
|
2230
2230
|
message: {
|
|
2231
|
-
role:
|
|
2231
|
+
role: "assistant",
|
|
2232
2232
|
content:
|
|
2233
|
-
|
|
2233
|
+
"The chart you're referring to is a bar graph titled \"The Number of Diamonds",
|
|
2234
2234
|
},
|
|
2235
|
-
finish_reason:
|
|
2235
|
+
finish_reason: "length",
|
|
2236
2236
|
index: 0,
|
|
2237
2237
|
},
|
|
2238
2238
|
],
|
|
@@ -2243,7 +2243,7 @@ class ChatLLM {
|
|
|
2243
2243
|
}
|
|
2244
2244
|
|
|
2245
2245
|
ClaudeJson(text, img = null) {
|
|
2246
|
-
const anthropicVersion =
|
|
2246
|
+
const anthropicVersion = "vertex-2023-10-16";
|
|
2247
2247
|
const maxTokens = 256;
|
|
2248
2248
|
|
|
2249
2249
|
const payload = {
|
|
@@ -2254,7 +2254,7 @@ class ChatLLM {
|
|
|
2254
2254
|
|
|
2255
2255
|
// Construct the user message object
|
|
2256
2256
|
const userMessage = {
|
|
2257
|
-
role:
|
|
2257
|
+
role: "user",
|
|
2258
2258
|
content: [],
|
|
2259
2259
|
};
|
|
2260
2260
|
|
|
@@ -2262,22 +2262,22 @@ class ChatLLM {
|
|
|
2262
2262
|
if (img) {
|
|
2263
2263
|
userMessage.content.push(
|
|
2264
2264
|
{
|
|
2265
|
-
type:
|
|
2265
|
+
type: "image",
|
|
2266
2266
|
source: {
|
|
2267
|
-
type:
|
|
2268
|
-
media_type:
|
|
2267
|
+
type: "base64",
|
|
2268
|
+
media_type: "image/jpeg", // Update if other formats are supported
|
|
2269
2269
|
data: img,
|
|
2270
2270
|
},
|
|
2271
2271
|
},
|
|
2272
2272
|
{
|
|
2273
|
-
type:
|
|
2273
|
+
type: "text",
|
|
2274
2274
|
text: text,
|
|
2275
2275
|
}
|
|
2276
2276
|
);
|
|
2277
2277
|
} else {
|
|
2278
2278
|
// Add only the text content if no image is provided
|
|
2279
2279
|
userMessage.content.push({
|
|
2280
|
-
type:
|
|
2280
|
+
type: "text",
|
|
2281
2281
|
text: text,
|
|
2282
2282
|
});
|
|
2283
2283
|
}
|
|
@@ -2289,16 +2289,16 @@ class ChatLLM {
|
|
|
2289
2289
|
}
|
|
2290
2290
|
|
|
2291
2291
|
ClaudePromptAPI(text, imgBase64 = null) {
|
|
2292
|
-
console.log(
|
|
2292
|
+
console.log("Claude prompt API");
|
|
2293
2293
|
let url =
|
|
2294
|
-
|
|
2294
|
+
"https://maidr-service.azurewebsites.net/api/claude?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2295
2295
|
|
|
2296
2296
|
// Create the prompt
|
|
2297
2297
|
let prompt = constants.LLMSystemMessage;
|
|
2298
2298
|
if (constants.LLMPreferences) {
|
|
2299
2299
|
prompt += constants.LLMPreferences;
|
|
2300
2300
|
}
|
|
2301
|
-
prompt +=
|
|
2301
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2302
2302
|
|
|
2303
2303
|
if (imgBase64 == null) {
|
|
2304
2304
|
imgBase64 = constants.LLMImage;
|
|
@@ -2310,9 +2310,9 @@ class ChatLLM {
|
|
|
2310
2310
|
let requestJson = chatLLM.ClaudeJson(prompt, imgBase64);
|
|
2311
2311
|
|
|
2312
2312
|
fetch(url, {
|
|
2313
|
-
method:
|
|
2313
|
+
method: "POST",
|
|
2314
2314
|
headers: {
|
|
2315
|
-
|
|
2315
|
+
"Content-Type": "application/json",
|
|
2316
2316
|
Authentication: constants.emailAuthKey,
|
|
2317
2317
|
},
|
|
2318
2318
|
body: JSON.stringify(requestJson),
|
|
@@ -2322,12 +2322,12 @@ class ChatLLM {
|
|
|
2322
2322
|
data.text = function () {
|
|
2323
2323
|
return data.content[0].text;
|
|
2324
2324
|
};
|
|
2325
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2325
|
+
chatLLM.ProcessLLMResponse(data, "claude");
|
|
2326
2326
|
})
|
|
2327
2327
|
.catch((error) => {
|
|
2328
2328
|
chatLLM.WaitingSound(false);
|
|
2329
|
-
console.error(
|
|
2330
|
-
chatLLM.DisplayChatMessage(
|
|
2329
|
+
console.error("Error:", error);
|
|
2330
|
+
chatLLM.DisplayChatMessage("Claude", "Error processing request.", true);
|
|
2331
2331
|
// also todo: handle errors somehow
|
|
2332
2332
|
});
|
|
2333
2333
|
}
|
|
@@ -2341,27 +2341,27 @@ class ChatLLM {
|
|
|
2341
2341
|
*/
|
|
2342
2342
|
OpenAIPrompt(text, img = null) {
|
|
2343
2343
|
// request init
|
|
2344
|
-
let url =
|
|
2344
|
+
let url = "https://api.openai.com/v1/chat/completions";
|
|
2345
2345
|
let auth = constants.openAIAuthKey;
|
|
2346
2346
|
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2347
2347
|
//console.log('LLM request: ', requestJson);
|
|
2348
2348
|
|
|
2349
2349
|
fetch(url, {
|
|
2350
|
-
method:
|
|
2350
|
+
method: "POST",
|
|
2351
2351
|
headers: {
|
|
2352
|
-
|
|
2353
|
-
Authorization:
|
|
2352
|
+
"Content-Type": "application/json",
|
|
2353
|
+
Authorization: "Bearer " + auth,
|
|
2354
2354
|
},
|
|
2355
2355
|
body: JSON.stringify(requestJson),
|
|
2356
2356
|
})
|
|
2357
2357
|
.then((response) => response.json())
|
|
2358
2358
|
.then((data) => {
|
|
2359
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2359
|
+
chatLLM.ProcessLLMResponse(data, "openai");
|
|
2360
2360
|
})
|
|
2361
2361
|
.catch((error) => {
|
|
2362
2362
|
chatLLM.WaitingSound(false);
|
|
2363
|
-
console.error(
|
|
2364
|
-
chatLLM.DisplayChatMessage(
|
|
2363
|
+
console.error("Error:", error);
|
|
2364
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2365
2365
|
// also todo: handle errors somehow
|
|
2366
2366
|
});
|
|
2367
2367
|
}
|
|
@@ -2369,27 +2369,27 @@ class ChatLLM {
|
|
|
2369
2369
|
OpenAIPromptAPI(text, img = null) {
|
|
2370
2370
|
// request init
|
|
2371
2371
|
let url =
|
|
2372
|
-
|
|
2372
|
+
"https://maidr-service.azurewebsites.net/api/openai?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2373
2373
|
let auth = constants.openAIAuthKey;
|
|
2374
2374
|
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2375
|
-
console.log(
|
|
2375
|
+
console.log("LLM request: ", requestJson);
|
|
2376
2376
|
|
|
2377
2377
|
fetch(url, {
|
|
2378
|
-
method:
|
|
2378
|
+
method: "POST",
|
|
2379
2379
|
headers: {
|
|
2380
|
-
|
|
2380
|
+
"Content-Type": "application/json",
|
|
2381
2381
|
Authentication: constants.emailAuthKey,
|
|
2382
2382
|
},
|
|
2383
2383
|
body: JSON.stringify(requestJson),
|
|
2384
2384
|
})
|
|
2385
2385
|
.then((response) => response.json())
|
|
2386
2386
|
.then((data) => {
|
|
2387
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2387
|
+
chatLLM.ProcessLLMResponse(data, "openai");
|
|
2388
2388
|
})
|
|
2389
2389
|
.catch((error) => {
|
|
2390
2390
|
chatLLM.WaitingSound(false);
|
|
2391
|
-
console.error(
|
|
2392
|
-
chatLLM.DisplayChatMessage(
|
|
2391
|
+
console.error("Error:", error);
|
|
2392
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2393
2393
|
// also todo: handle errors somehow
|
|
2394
2394
|
});
|
|
2395
2395
|
}
|
|
@@ -2397,22 +2397,22 @@ class ChatLLM {
|
|
|
2397
2397
|
OpenAIJson(text, img = null) {
|
|
2398
2398
|
let sysMessage = constants.LLMSystemMessage;
|
|
2399
2399
|
let backupMessage =
|
|
2400
|
-
|
|
2400
|
+
"Describe " + singleMaidr.type + " charts to a blind person";
|
|
2401
2401
|
// headers and sys message
|
|
2402
2402
|
if (!this.requestJson) {
|
|
2403
2403
|
this.requestJson = {};
|
|
2404
2404
|
//this.requestJson.model = 'gpt-4-vision-preview';
|
|
2405
|
-
this.requestJson.model =
|
|
2405
|
+
this.requestJson.model = "gpt-4o-2024-11-20";
|
|
2406
2406
|
this.requestJson.max_tokens = constants.LLMmaxResponseTokens; // note: if this is too short (tested with less than 200), the response gets cut off
|
|
2407
2407
|
|
|
2408
2408
|
// sys message
|
|
2409
2409
|
this.requestJson.messages = [];
|
|
2410
2410
|
this.requestJson.messages[0] = {};
|
|
2411
|
-
this.requestJson.messages[0].role =
|
|
2411
|
+
this.requestJson.messages[0].role = "system";
|
|
2412
2412
|
this.requestJson.messages[0].content = sysMessage;
|
|
2413
2413
|
if (constants.LLMPreferences) {
|
|
2414
2414
|
this.requestJson.messages[1] = {};
|
|
2415
|
-
this.requestJson.messages[1].role =
|
|
2415
|
+
this.requestJson.messages[1].role = "system";
|
|
2416
2416
|
this.requestJson.messages[1].content = constants.LLMPreferences;
|
|
2417
2417
|
}
|
|
2418
2418
|
}
|
|
@@ -2421,16 +2421,16 @@ class ChatLLM {
|
|
|
2421
2421
|
// if we have an image (first time only), send the image and the text, otherwise just the text
|
|
2422
2422
|
let i = this.requestJson.messages.length;
|
|
2423
2423
|
this.requestJson.messages[i] = {};
|
|
2424
|
-
this.requestJson.messages[i].role =
|
|
2424
|
+
this.requestJson.messages[i].role = "user";
|
|
2425
2425
|
if (img) {
|
|
2426
2426
|
// first message, include the img
|
|
2427
2427
|
this.requestJson.messages[i].content = [
|
|
2428
2428
|
{
|
|
2429
|
-
type:
|
|
2429
|
+
type: "text",
|
|
2430
2430
|
text: text,
|
|
2431
2431
|
},
|
|
2432
2432
|
{
|
|
2433
|
-
type:
|
|
2433
|
+
type: "image_url",
|
|
2434
2434
|
image_url: { url: img },
|
|
2435
2435
|
},
|
|
2436
2436
|
];
|
|
@@ -2445,7 +2445,7 @@ class ChatLLM {
|
|
|
2445
2445
|
GeminiJson(text, img = null) {
|
|
2446
2446
|
let sysMessage = constants.LLMSystemMessage;
|
|
2447
2447
|
let backupMessage =
|
|
2448
|
-
|
|
2448
|
+
"Describe " + singleMaidr.type + " charts to a blind person";
|
|
2449
2449
|
|
|
2450
2450
|
let payload = {
|
|
2451
2451
|
generationConfig: {},
|
|
@@ -2455,7 +2455,7 @@ class ChatLLM {
|
|
|
2455
2455
|
|
|
2456
2456
|
// System message as the initial "role" and "text" content for context
|
|
2457
2457
|
let sysContent = {
|
|
2458
|
-
role:
|
|
2458
|
+
role: "user",
|
|
2459
2459
|
parts: [
|
|
2460
2460
|
{
|
|
2461
2461
|
text: sysMessage || backupMessage, // Fallback if sysMessage is unavailable
|
|
@@ -2474,7 +2474,7 @@ class ChatLLM {
|
|
|
2474
2474
|
|
|
2475
2475
|
// Add user input content, including image if available
|
|
2476
2476
|
let userContent = {
|
|
2477
|
-
role:
|
|
2477
|
+
role: "user",
|
|
2478
2478
|
parts: [],
|
|
2479
2479
|
};
|
|
2480
2480
|
|
|
@@ -2487,7 +2487,7 @@ class ChatLLM {
|
|
|
2487
2487
|
{
|
|
2488
2488
|
inlineData: {
|
|
2489
2489
|
data: img, // Expecting base64-encoded image data
|
|
2490
|
-
mimeType:
|
|
2490
|
+
mimeType: "image/png", // Adjust if different image formats are possible
|
|
2491
2491
|
},
|
|
2492
2492
|
}
|
|
2493
2493
|
);
|
|
@@ -2506,14 +2506,14 @@ class ChatLLM {
|
|
|
2506
2506
|
|
|
2507
2507
|
async GeminiPromptAPI(text, imgBase64 = null) {
|
|
2508
2508
|
let url =
|
|
2509
|
-
|
|
2509
|
+
"https://maidr-service.azurewebsites.net/api/gemini?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D";
|
|
2510
2510
|
|
|
2511
2511
|
// Create the prompt
|
|
2512
2512
|
let prompt = constants.LLMSystemMessage;
|
|
2513
2513
|
if (constants.LLMPreferences) {
|
|
2514
2514
|
prompt += constants.LLMPreferences;
|
|
2515
2515
|
}
|
|
2516
|
-
prompt +=
|
|
2516
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2517
2517
|
|
|
2518
2518
|
if (imgBase64 == null) {
|
|
2519
2519
|
imgBase64 = constants.LLMImage;
|
|
@@ -2525,9 +2525,9 @@ class ChatLLM {
|
|
|
2525
2525
|
let requestJson = chatLLM.GeminiJson(prompt, imgBase64);
|
|
2526
2526
|
|
|
2527
2527
|
const response = await fetch(url, {
|
|
2528
|
-
method:
|
|
2528
|
+
method: "POST",
|
|
2529
2529
|
headers: {
|
|
2530
|
-
|
|
2530
|
+
"Content-Type": "application/json",
|
|
2531
2531
|
Authentication: constants.emailAuthKey,
|
|
2532
2532
|
},
|
|
2533
2533
|
body: JSON.stringify(requestJson),
|
|
@@ -2537,11 +2537,11 @@ class ChatLLM {
|
|
|
2537
2537
|
responseJson.text = () => {
|
|
2538
2538
|
return responseJson.candidates[0].content.parts[0].text;
|
|
2539
2539
|
};
|
|
2540
|
-
chatLLM.ProcessLLMResponse(responseJson,
|
|
2540
|
+
chatLLM.ProcessLLMResponse(responseJson, "gemini");
|
|
2541
2541
|
} else {
|
|
2542
2542
|
chatLLM.WaitingSound(false);
|
|
2543
|
-
console.error(
|
|
2544
|
-
chatLLM.DisplayChatMessage(
|
|
2543
|
+
console.error("Error:", error);
|
|
2544
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2545
2545
|
// also todo: handle errors somehow
|
|
2546
2546
|
}
|
|
2547
2547
|
}
|
|
@@ -2559,12 +2559,12 @@ class ChatLLM {
|
|
|
2559
2559
|
|
|
2560
2560
|
// Import the module
|
|
2561
2561
|
const { GoogleGenerativeAI } = await import(
|
|
2562
|
-
|
|
2562
|
+
"https://esm.run/@google/generative-ai"
|
|
2563
2563
|
);
|
|
2564
2564
|
const API_KEY = constants.geminiAuthKey;
|
|
2565
2565
|
const genAI = new GoogleGenerativeAI(API_KEY);
|
|
2566
2566
|
const model = genAI.getGenerativeModel({
|
|
2567
|
-
model:
|
|
2567
|
+
model: "gemini-1.5-pro-latest",
|
|
2568
2568
|
}); // old model was 'gemini-pro-vision'
|
|
2569
2569
|
|
|
2570
2570
|
// Create the prompt
|
|
@@ -2572,11 +2572,11 @@ class ChatLLM {
|
|
|
2572
2572
|
if (constants.LLMPreferences) {
|
|
2573
2573
|
prompt += constants.LLMPreferences;
|
|
2574
2574
|
}
|
|
2575
|
-
prompt +=
|
|
2575
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2576
2576
|
const image = {
|
|
2577
2577
|
inlineData: {
|
|
2578
2578
|
data: imgBase64, // Use the base64 image string
|
|
2579
|
-
mimeType:
|
|
2579
|
+
mimeType: "image/png", // Or the appropriate mime type of your image
|
|
2580
2580
|
},
|
|
2581
2581
|
};
|
|
2582
2582
|
|
|
@@ -2586,11 +2586,11 @@ class ChatLLM {
|
|
|
2586
2586
|
//console.log(result.response.text());
|
|
2587
2587
|
|
|
2588
2588
|
// Process the response
|
|
2589
|
-
chatLLM.ProcessLLMResponse(result.response,
|
|
2589
|
+
chatLLM.ProcessLLMResponse(result.response, "gemini");
|
|
2590
2590
|
} catch (error) {
|
|
2591
2591
|
chatLLM.WaitingSound(false);
|
|
2592
|
-
chatLLM.DisplayChatMessage(
|
|
2593
|
-
console.error(
|
|
2592
|
+
chatLLM.DisplayChatMessage("Gemini", "Error processing request.", true);
|
|
2593
|
+
console.error("Error in GeminiPrompt:", error);
|
|
2594
2594
|
throw error; // Rethrow the error for further handling if necessary
|
|
2595
2595
|
}
|
|
2596
2596
|
}
|
|
@@ -2602,11 +2602,11 @@ class ChatLLM {
|
|
|
2602
2602
|
* @memberof module:constants
|
|
2603
2603
|
* @returns {void}
|
|
2604
2604
|
*/
|
|
2605
|
-
DisplayChatMessage(user =
|
|
2606
|
-
let hLevel =
|
|
2607
|
-
if (!isSystem && constants.LLMModel ==
|
|
2605
|
+
DisplayChatMessage(user = "User", text = "", isSystem = false) {
|
|
2606
|
+
let hLevel = "h3";
|
|
2607
|
+
if (!isSystem && constants.LLMModel == "multi" && user != "User") {
|
|
2608
2608
|
if (this.firstMulti) {
|
|
2609
|
-
let multiAIName = resources.GetString(
|
|
2609
|
+
let multiAIName = resources.GetString("multi");
|
|
2610
2610
|
let titleHtml = `
|
|
2611
2611
|
<div class="chatLLM_message chatLLM_message_other">
|
|
2612
2612
|
<h3 class="chatLLM_message_user">${multiAIName} Responses</h3>
|
|
@@ -2615,20 +2615,20 @@ class ChatLLM {
|
|
|
2615
2615
|
this.RenderChatMessage(titleHtml);
|
|
2616
2616
|
this.firstMulti = false;
|
|
2617
2617
|
}
|
|
2618
|
-
hLevel =
|
|
2618
|
+
hLevel = "h4";
|
|
2619
2619
|
}
|
|
2620
2620
|
let html = `
|
|
2621
2621
|
<div class="chatLLM_message ${
|
|
2622
|
-
user ==
|
|
2622
|
+
user == "User" ? "chatLLM_message_self" : "chatLLM_message_other"
|
|
2623
2623
|
}">`;
|
|
2624
|
-
if (text != resources.GetString(
|
|
2624
|
+
if (text != resources.GetString("processing")) {
|
|
2625
2625
|
html += `<${hLevel} class="chatLLM_message_user">${user}</${hLevel}>`;
|
|
2626
2626
|
}
|
|
2627
2627
|
html += `<p class="chatLLM_message_text">${text}</p>
|
|
2628
2628
|
</div>
|
|
2629
2629
|
`;
|
|
2630
2630
|
// add a copy button to actual messages
|
|
2631
|
-
if (user !=
|
|
2631
|
+
if (user != "User" && text != resources.GetString("processing")) {
|
|
2632
2632
|
html += `
|
|
2633
2633
|
<p class="chatLLM_message_copy"><button class="chatLLM_message_copy_button">Copy</button></p>
|
|
2634
2634
|
`;
|
|
@@ -2638,13 +2638,13 @@ class ChatLLM {
|
|
|
2638
2638
|
}
|
|
2639
2639
|
RenderChatMessage(html) {
|
|
2640
2640
|
document
|
|
2641
|
-
.getElementById(
|
|
2642
|
-
.insertAdjacentHTML(
|
|
2643
|
-
document.getElementById(
|
|
2641
|
+
.getElementById("chatLLM_chat_history")
|
|
2642
|
+
.insertAdjacentHTML("beforeend", html);
|
|
2643
|
+
document.getElementById("chatLLM_input").value = "";
|
|
2644
2644
|
|
|
2645
2645
|
// scroll to bottom
|
|
2646
|
-
document.getElementById(
|
|
2647
|
-
document.getElementById(
|
|
2646
|
+
document.getElementById("chatLLM_chat_history").scrollTop =
|
|
2647
|
+
document.getElementById("chatLLM_chat_history").scrollHeight;
|
|
2648
2648
|
}
|
|
2649
2649
|
|
|
2650
2650
|
/**
|
|
@@ -2652,7 +2652,7 @@ class ChatLLM {
|
|
|
2652
2652
|
*/
|
|
2653
2653
|
ResetLLM() {
|
|
2654
2654
|
// clear the main chat history
|
|
2655
|
-
document.getElementById(
|
|
2655
|
+
document.getElementById("chatLLM_chat_history").innerHTML = "";
|
|
2656
2656
|
|
|
2657
2657
|
// reset the data
|
|
2658
2658
|
this.requestJson = null;
|
|
@@ -2673,11 +2673,11 @@ class ChatLLM {
|
|
|
2673
2673
|
*/
|
|
2674
2674
|
Destroy() {
|
|
2675
2675
|
// chatLLM element destruction
|
|
2676
|
-
let chatLLM = document.getElementById(
|
|
2676
|
+
let chatLLM = document.getElementById("chatLLM");
|
|
2677
2677
|
if (chatLLM) {
|
|
2678
2678
|
chatLLM.remove();
|
|
2679
2679
|
}
|
|
2680
|
-
let backdrop = document.getElementById(
|
|
2680
|
+
let backdrop = document.getElementById("chatLLM_modal_backdrop");
|
|
2681
2681
|
if (backdrop) {
|
|
2682
2682
|
backdrop.remove();
|
|
2683
2683
|
}
|
|
@@ -2688,8 +2688,8 @@ class ChatLLM {
|
|
|
2688
2688
|
* @param {boolean} [onoff=false] - Whether to turn the chatLLM on or off. Defaults to false (close).
|
|
2689
2689
|
*/
|
|
2690
2690
|
Toggle(onoff) {
|
|
2691
|
-
if (typeof onoff ==
|
|
2692
|
-
if (document.getElementById(
|
|
2691
|
+
if (typeof onoff == "undefined") {
|
|
2692
|
+
if (document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
2693
2693
|
onoff = true;
|
|
2694
2694
|
} else {
|
|
2695
2695
|
onoff = false;
|
|
@@ -2700,19 +2700,19 @@ class ChatLLM {
|
|
|
2700
2700
|
// open
|
|
2701
2701
|
this.whereWasMyFocus = document.activeElement;
|
|
2702
2702
|
constants.tabMovement = 0;
|
|
2703
|
-
document.getElementById(
|
|
2703
|
+
document.getElementById("chatLLM").classList.remove("hidden");
|
|
2704
2704
|
document
|
|
2705
|
-
.getElementById(
|
|
2706
|
-
.classList.remove(
|
|
2707
|
-
document.querySelector(
|
|
2705
|
+
.getElementById("chatLLM_modal_backdrop")
|
|
2706
|
+
.classList.remove("hidden");
|
|
2707
|
+
document.querySelector("#chatLLM .close").focus();
|
|
2708
2708
|
|
|
2709
2709
|
if (this.firstTime) {
|
|
2710
2710
|
this.InitChatMessage();
|
|
2711
2711
|
}
|
|
2712
2712
|
} else {
|
|
2713
2713
|
// close
|
|
2714
|
-
document.getElementById(
|
|
2715
|
-
document.getElementById(
|
|
2714
|
+
document.getElementById("chatLLM").classList.add("hidden");
|
|
2715
|
+
document.getElementById("chatLLM_modal_backdrop").classList.add("hidden");
|
|
2716
2716
|
this.whereWasMyFocus.focus();
|
|
2717
2717
|
this.whereWasMyFocus = null;
|
|
2718
2718
|
this.firstOpen = true;
|
|
@@ -2726,11 +2726,11 @@ class ChatLLM {
|
|
|
2726
2726
|
async ConvertSVGtoJPG(id, model) {
|
|
2727
2727
|
let svgElement = document.getElementById(id);
|
|
2728
2728
|
return new Promise((resolve, reject) => {
|
|
2729
|
-
var canvas = document.createElement(
|
|
2730
|
-
var ctx = canvas.getContext(
|
|
2729
|
+
var canvas = document.createElement("canvas");
|
|
2730
|
+
var ctx = canvas.getContext("2d");
|
|
2731
2731
|
|
|
2732
2732
|
var svgData = new XMLSerializer().serializeToString(svgElement);
|
|
2733
|
-
if (!svgData.startsWith(
|
|
2733
|
+
if (!svgData.startsWith("<svg xmlns")) {
|
|
2734
2734
|
svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
|
|
2735
2735
|
}
|
|
2736
2736
|
|
|
@@ -2742,11 +2742,11 @@ class ChatLLM {
|
|
|
2742
2742
|
var img = new Image();
|
|
2743
2743
|
img.onload = function () {
|
|
2744
2744
|
ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
|
|
2745
|
-
var jpegData = canvas.toDataURL(
|
|
2746
|
-
if (model ==
|
|
2745
|
+
var jpegData = canvas.toDataURL("image/jpeg", 0.9); // 0.9 is the quality parameter
|
|
2746
|
+
if (model == "openai") {
|
|
2747
2747
|
resolve(jpegData);
|
|
2748
|
-
} else if (model ==
|
|
2749
|
-
let base64Data = jpegData.split(
|
|
2748
|
+
} else if (model == "gemini" || model == "claude") {
|
|
2749
|
+
let base64Data = jpegData.split(",")[1];
|
|
2750
2750
|
resolve(base64Data);
|
|
2751
2751
|
//resolve(jpegData);
|
|
2752
2752
|
}
|
|
@@ -2754,11 +2754,11 @@ class ChatLLM {
|
|
|
2754
2754
|
};
|
|
2755
2755
|
|
|
2756
2756
|
img.onerror = function () {
|
|
2757
|
-
reject(new Error(
|
|
2757
|
+
reject(new Error("Error loading SVG"));
|
|
2758
2758
|
};
|
|
2759
2759
|
|
|
2760
2760
|
var svgBlob = new Blob([svgData], {
|
|
2761
|
-
type:
|
|
2761
|
+
type: "image/svg+xml;charset=utf-8",
|
|
2762
2762
|
});
|
|
2763
2763
|
var url = URL.createObjectURL(svgBlob);
|
|
2764
2764
|
img.src = url;
|
|
@@ -2771,25 +2771,25 @@ class ChatLLM {
|
|
|
2771
2771
|
* The prompt includes information about the blind person's skill level and the chart's image and raw data, if available.
|
|
2772
2772
|
*/
|
|
2773
2773
|
GetDefaultPrompt() {
|
|
2774
|
-
let text =
|
|
2774
|
+
let text = "Describe this chart to a blind person";
|
|
2775
2775
|
if (constants.skillLevel) {
|
|
2776
|
-
if (constants.skillLevel ==
|
|
2776
|
+
if (constants.skillLevel == "other" && constants.skillLevelOther) {
|
|
2777
2777
|
text +=
|
|
2778
|
-
|
|
2778
|
+
" who has a " +
|
|
2779
2779
|
constants.skillLevelOther +
|
|
2780
|
-
|
|
2780
|
+
" understanding of statistical charts. ";
|
|
2781
2781
|
} else {
|
|
2782
2782
|
text +=
|
|
2783
|
-
|
|
2783
|
+
" who has a " +
|
|
2784
2784
|
constants.skillLevel +
|
|
2785
|
-
|
|
2785
|
+
" understanding of statistical charts. ";
|
|
2786
2786
|
}
|
|
2787
2787
|
} else {
|
|
2788
|
-
text +=
|
|
2788
|
+
text += " who has a basic understanding of statistical charts. ";
|
|
2789
2789
|
}
|
|
2790
|
-
text +=
|
|
2790
|
+
text += "Here is a chart in image format";
|
|
2791
2791
|
if (singleMaidr) {
|
|
2792
|
-
text +=
|
|
2792
|
+
text += " and raw data in json format: \n";
|
|
2793
2793
|
text += JSON.stringify(singleMaidr);
|
|
2794
2794
|
}
|
|
2795
2795
|
|
|
@@ -2844,26 +2844,26 @@ class Description {
|
|
|
2844
2844
|
|
|
2845
2845
|
`;
|
|
2846
2846
|
|
|
2847
|
-
document.querySelector(
|
|
2847
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
2848
2848
|
|
|
2849
2849
|
// close events
|
|
2850
2850
|
let allClose = document.querySelectorAll(
|
|
2851
|
-
|
|
2851
|
+
"#close_desc, #description .close"
|
|
2852
2852
|
);
|
|
2853
2853
|
for (let i = 0; i < allClose.length; i++) {
|
|
2854
2854
|
constants.events.push([
|
|
2855
2855
|
allClose[i],
|
|
2856
|
-
|
|
2856
|
+
"click",
|
|
2857
2857
|
function (e) {
|
|
2858
2858
|
description.Toggle(false);
|
|
2859
2859
|
},
|
|
2860
2860
|
]);
|
|
2861
2861
|
}
|
|
2862
2862
|
constants.events.push([
|
|
2863
|
-
document.getElementById(
|
|
2864
|
-
|
|
2863
|
+
document.getElementById("description"),
|
|
2864
|
+
"keyup",
|
|
2865
2865
|
function (e) {
|
|
2866
|
-
if (e.key ==
|
|
2866
|
+
if (e.key == "Esc") {
|
|
2867
2867
|
// esc
|
|
2868
2868
|
description.Toggle(false);
|
|
2869
2869
|
}
|
|
@@ -2873,9 +2873,9 @@ class Description {
|
|
|
2873
2873
|
// open events
|
|
2874
2874
|
constants.events.push([
|
|
2875
2875
|
document,
|
|
2876
|
-
|
|
2876
|
+
"keyup",
|
|
2877
2877
|
function (e) {
|
|
2878
|
-
if (e.key ==
|
|
2878
|
+
if (e.key == "d") {
|
|
2879
2879
|
description.Toggle(true);
|
|
2880
2880
|
}
|
|
2881
2881
|
},
|
|
@@ -2887,11 +2887,11 @@ class Description {
|
|
|
2887
2887
|
*/
|
|
2888
2888
|
Destroy() {
|
|
2889
2889
|
// description element destruction
|
|
2890
|
-
let description = document.getElementById(
|
|
2890
|
+
let description = document.getElementById("menu");
|
|
2891
2891
|
if (description) {
|
|
2892
2892
|
description.remove();
|
|
2893
2893
|
}
|
|
2894
|
-
let backdrop = document.getElementById(
|
|
2894
|
+
let backdrop = document.getElementById("desc_modal_backdrop");
|
|
2895
2895
|
if (backdrop) {
|
|
2896
2896
|
backdrop.remove();
|
|
2897
2897
|
}
|
|
@@ -2902,8 +2902,8 @@ class Description {
|
|
|
2902
2902
|
* @param {boolean} [onoff=false] - Whether to turn the description element on or off.
|
|
2903
2903
|
*/
|
|
2904
2904
|
Toggle(onoff = false) {
|
|
2905
|
-
if (typeof onoff ==
|
|
2906
|
-
if (document.getElementById(
|
|
2905
|
+
if (typeof onoff == "undefined") {
|
|
2906
|
+
if (document.getElementById("description").classList.contains("hidden")) {
|
|
2907
2907
|
onoff = true;
|
|
2908
2908
|
} else {
|
|
2909
2909
|
onoff = false;
|
|
@@ -2914,13 +2914,13 @@ class Description {
|
|
|
2914
2914
|
this.whereWasMyFocus = document.activeElement;
|
|
2915
2915
|
constants.tabMovement = 0;
|
|
2916
2916
|
this.PopulateData();
|
|
2917
|
-
document.getElementById(
|
|
2918
|
-
document.getElementById(
|
|
2919
|
-
document.querySelector(
|
|
2917
|
+
document.getElementById("description").classList.remove("hidden");
|
|
2918
|
+
document.getElementById("desc_modal_backdrop").classList.remove("hidden");
|
|
2919
|
+
document.querySelector("#description .close").focus();
|
|
2920
2920
|
} else {
|
|
2921
2921
|
// close
|
|
2922
|
-
document.getElementById(
|
|
2923
|
-
document.getElementById(
|
|
2922
|
+
document.getElementById("description").classList.add("hidden");
|
|
2923
|
+
document.getElementById("desc_modal_backdrop").classList.add("hidden");
|
|
2924
2924
|
this.whereWasMyFocus.focus();
|
|
2925
2925
|
this.whereWasMyFocus = null;
|
|
2926
2926
|
}
|
|
@@ -2930,22 +2930,22 @@ class Description {
|
|
|
2930
2930
|
* Populates the data for the chart and table based on the chart type and plot data.
|
|
2931
2931
|
*/
|
|
2932
2932
|
PopulateData() {
|
|
2933
|
-
let descHtml =
|
|
2933
|
+
let descHtml = "";
|
|
2934
2934
|
|
|
2935
2935
|
// chart labels and descriptions
|
|
2936
|
-
let descType =
|
|
2937
|
-
if (constants.chartType ==
|
|
2938
|
-
descType =
|
|
2939
|
-
} else if (constants.chartType ==
|
|
2940
|
-
descType =
|
|
2941
|
-
} else if (constants.chartType ==
|
|
2942
|
-
descType =
|
|
2943
|
-
} else if (constants.chartType ==
|
|
2944
|
-
descType =
|
|
2945
|
-
} else if (constants.chartType ==
|
|
2946
|
-
descType =
|
|
2947
|
-
} else if (constants.chartType ==
|
|
2948
|
-
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";
|
|
2949
2949
|
}
|
|
2950
2950
|
|
|
2951
2951
|
if (descType) {
|
|
@@ -2962,7 +2962,7 @@ class Description {
|
|
|
2962
2962
|
}
|
|
2963
2963
|
|
|
2964
2964
|
// table of data, prep
|
|
2965
|
-
let descTableHtml =
|
|
2965
|
+
let descTableHtml = "";
|
|
2966
2966
|
let descLabelX = null;
|
|
2967
2967
|
let descLabelY = null;
|
|
2968
2968
|
let descTickX = null;
|
|
@@ -2972,7 +2972,7 @@ class Description {
|
|
|
2972
2972
|
let descNumColsWithLabels = 0;
|
|
2973
2973
|
let descNumRows = 0;
|
|
2974
2974
|
let descNumRowsWithLabels = 0;
|
|
2975
|
-
if (constants.chartType ==
|
|
2975
|
+
if (constants.chartType == "bar") {
|
|
2976
2976
|
if (plot.plotLegend.x != null) {
|
|
2977
2977
|
descLabelX = plot.plotLegend.x;
|
|
2978
2978
|
descNumColsWithLabels += 1;
|
|
@@ -2997,43 +2997,43 @@ class Description {
|
|
|
2997
2997
|
|
|
2998
2998
|
// table of data, create
|
|
2999
2999
|
if (descData != null) {
|
|
3000
|
-
descTableHtml +=
|
|
3000
|
+
descTableHtml += "<table>";
|
|
3001
3001
|
|
|
3002
3002
|
// header rows
|
|
3003
3003
|
if (descLabelX != null || descTickX != null) {
|
|
3004
|
-
descTableHtml +=
|
|
3004
|
+
descTableHtml += "<thead>";
|
|
3005
3005
|
if (descLabelX != null) {
|
|
3006
|
-
descTableHtml +=
|
|
3006
|
+
descTableHtml += "<tr>";
|
|
3007
3007
|
if (descLabelY != null) {
|
|
3008
|
-
descTableHtml +=
|
|
3008
|
+
descTableHtml += "<td></td>";
|
|
3009
3009
|
}
|
|
3010
3010
|
if (descTickY != null) {
|
|
3011
|
-
descTableHtml +=
|
|
3011
|
+
descTableHtml += "<td></td>";
|
|
3012
3012
|
}
|
|
3013
3013
|
descTableHtml += `<th scope="col" colspan="${descNumCols}">${descLabelX}</th>`;
|
|
3014
|
-
descTableHtml +=
|
|
3014
|
+
descTableHtml += "</tr>";
|
|
3015
3015
|
}
|
|
3016
3016
|
if (descTickX != null) {
|
|
3017
|
-
descTableHtml +=
|
|
3017
|
+
descTableHtml += "<tr>";
|
|
3018
3018
|
if (descLabelY != null) {
|
|
3019
|
-
descTableHtml +=
|
|
3019
|
+
descTableHtml += "<td></td>";
|
|
3020
3020
|
}
|
|
3021
3021
|
if (descTickY != null) {
|
|
3022
|
-
descTableHtml +=
|
|
3022
|
+
descTableHtml += "<td></td>";
|
|
3023
3023
|
}
|
|
3024
3024
|
for (let i = 0; i < descNumCols; i++) {
|
|
3025
3025
|
descTableHtml += `<th scope="col">${descTickX[i]}</th>`;
|
|
3026
3026
|
}
|
|
3027
|
-
descTableHtml +=
|
|
3027
|
+
descTableHtml += "</tr>";
|
|
3028
3028
|
}
|
|
3029
|
-
descTableHtml +=
|
|
3029
|
+
descTableHtml += "</thead>";
|
|
3030
3030
|
}
|
|
3031
3031
|
|
|
3032
3032
|
// body rows
|
|
3033
3033
|
if (descNumRows > 0) {
|
|
3034
|
-
descTableHtml +=
|
|
3034
|
+
descTableHtml += "<tbody>";
|
|
3035
3035
|
for (let i = 0; i < descNumRows; i++) {
|
|
3036
|
-
descTableHtml +=
|
|
3036
|
+
descTableHtml += "<tr>";
|
|
3037
3037
|
if (descLabelY != null && i == 0) {
|
|
3038
3038
|
descTableHtml += `<th scope="row" rowspan="${descNumRows}">${descLabelY}</th>`;
|
|
3039
3039
|
}
|
|
@@ -3043,19 +3043,19 @@ class Description {
|
|
|
3043
3043
|
for (let j = 0; j < descNumCols; j++) {
|
|
3044
3044
|
descTableHtml += `<td>${descData[i][j]}</td>`;
|
|
3045
3045
|
}
|
|
3046
|
-
descTableHtml +=
|
|
3046
|
+
descTableHtml += "</tr>";
|
|
3047
3047
|
}
|
|
3048
|
-
descTableHtml +=
|
|
3048
|
+
descTableHtml += "</tbody>";
|
|
3049
3049
|
}
|
|
3050
3050
|
|
|
3051
|
-
descTableHtml +=
|
|
3051
|
+
descTableHtml += "</table>";
|
|
3052
3052
|
}
|
|
3053
3053
|
|
|
3054
3054
|
// bar: don't need colspan or rowspan stuff, put legendX and Y as headers
|
|
3055
3055
|
|
|
3056
|
-
document.getElementById(
|
|
3057
|
-
document.getElementById(
|
|
3058
|
-
document.getElementById(
|
|
3056
|
+
document.getElementById("desc_title").innerHTML = descType + " description";
|
|
3057
|
+
document.getElementById("desc_content").innerHTML = descHtml;
|
|
3058
|
+
document.getElementById("desc_table").innerHTML = descTableHtml;
|
|
3059
3059
|
}
|
|
3060
3060
|
}
|
|
3061
3061
|
|
|
@@ -3097,7 +3097,7 @@ class Helper {
|
|
|
3097
3097
|
class Tracker {
|
|
3098
3098
|
// URL
|
|
3099
3099
|
logUrl =
|
|
3100
|
-
|
|
3100
|
+
"https://maidr-service.azurewebsites.net/api/log?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D"; // TODO Replace
|
|
3101
3101
|
isLocal = false;
|
|
3102
3102
|
|
|
3103
3103
|
constructor() {
|
|
@@ -3116,7 +3116,7 @@ class Tracker {
|
|
|
3116
3116
|
data.language = Object.assign(navigator.language);
|
|
3117
3117
|
data.platform = Object.assign(navigator.platform);
|
|
3118
3118
|
data.geolocation = Object.assign(navigator.geolocation);
|
|
3119
|
-
data.log_type =
|
|
3119
|
+
data.log_type = "system_data";
|
|
3120
3120
|
data.events = [];
|
|
3121
3121
|
data.settings = [];
|
|
3122
3122
|
|
|
@@ -3129,11 +3129,11 @@ class Tracker {
|
|
|
3129
3129
|
* Downloads the tracker data as a JSON file.
|
|
3130
3130
|
*/
|
|
3131
3131
|
DownloadTrackerData() {
|
|
3132
|
-
let link = document.createElement(
|
|
3132
|
+
let link = document.createElement("a");
|
|
3133
3133
|
let data = this.GetTrackerData();
|
|
3134
|
-
let fileStr = new Blob([JSON.stringify(data)], { type:
|
|
3134
|
+
let fileStr = new Blob([JSON.stringify(data)], { type: "text/plain" });
|
|
3135
3135
|
link.href = URL.createObjectURL(fileStr);
|
|
3136
|
-
link.download =
|
|
3136
|
+
link.download = "tracking.json";
|
|
3137
3137
|
link.click();
|
|
3138
3138
|
}
|
|
3139
3139
|
|
|
@@ -3142,16 +3142,16 @@ class Tracker {
|
|
|
3142
3142
|
* @param {Object} data - The data to be saved.
|
|
3143
3143
|
*/
|
|
3144
3144
|
async SaveTrackerData(data) {
|
|
3145
|
-
console.log(
|
|
3145
|
+
console.log("about to save data", data);
|
|
3146
3146
|
if (this.isLocal) {
|
|
3147
3147
|
localStorage.setItem(constants.project_id, JSON.stringify(data));
|
|
3148
3148
|
} else {
|
|
3149
3149
|
// test this first
|
|
3150
3150
|
try {
|
|
3151
3151
|
const response = await fetch(this.logUrl, {
|
|
3152
|
-
method:
|
|
3152
|
+
method: "POST",
|
|
3153
3153
|
headers: {
|
|
3154
|
-
|
|
3154
|
+
"Content-Type": "application/json",
|
|
3155
3155
|
},
|
|
3156
3156
|
body: JSON.stringify(data),
|
|
3157
3157
|
});
|
|
@@ -3161,10 +3161,10 @@ class Tracker {
|
|
|
3161
3161
|
}
|
|
3162
3162
|
|
|
3163
3163
|
const result = await response.json();
|
|
3164
|
-
console.log(
|
|
3164
|
+
console.log("Data saved successfully:", result);
|
|
3165
3165
|
return result;
|
|
3166
3166
|
} catch (error) {
|
|
3167
|
-
console.error(
|
|
3167
|
+
console.error("Error saving data:", error);
|
|
3168
3168
|
return null;
|
|
3169
3169
|
}
|
|
3170
3170
|
}
|
|
@@ -3187,7 +3187,7 @@ class Tracker {
|
|
|
3187
3187
|
this.data = null;
|
|
3188
3188
|
|
|
3189
3189
|
if (constants.debugLevel > 0) {
|
|
3190
|
-
console.log(
|
|
3190
|
+
console.log("tracking data cleared");
|
|
3191
3191
|
}
|
|
3192
3192
|
|
|
3193
3193
|
this.DataSetup();
|
|
@@ -3195,16 +3195,16 @@ class Tracker {
|
|
|
3195
3195
|
|
|
3196
3196
|
SaveSettings() {
|
|
3197
3197
|
// fetch all settings, push to data.settings
|
|
3198
|
-
let settings = JSON.parse(localStorage.getItem(
|
|
3198
|
+
let settings = JSON.parse(localStorage.getItem("settings_data"));
|
|
3199
3199
|
if (settings) {
|
|
3200
3200
|
// don't store their auth keys
|
|
3201
|
-
settings.openAIAuthKey =
|
|
3202
|
-
settings.geminiAuthKey =
|
|
3201
|
+
settings.openAIAuthKey = "hidden";
|
|
3202
|
+
settings.geminiAuthKey = "hidden";
|
|
3203
3203
|
if (constants.emailAuthKey) {
|
|
3204
3204
|
settings.username = constants.emailAuthKey;
|
|
3205
3205
|
}
|
|
3206
3206
|
settings;
|
|
3207
|
-
this.SetData(
|
|
3207
|
+
this.SetData("settings", settings);
|
|
3208
3208
|
}
|
|
3209
3209
|
}
|
|
3210
3210
|
|
|
@@ -3301,7 +3301,7 @@ class Tracker {
|
|
|
3301
3301
|
}
|
|
3302
3302
|
if (!this.isUndefinedOrNull(constants.infoDiv.innerHTML)) {
|
|
3303
3303
|
let textDisplay = Object.assign(constants.infoDiv.innerHTML);
|
|
3304
|
-
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm,
|
|
3304
|
+
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm, "");
|
|
3305
3305
|
eventToLog.text_display = textDisplay;
|
|
3306
3306
|
}
|
|
3307
3307
|
if (!this.isUndefinedOrNull(location.href)) {
|
|
@@ -3309,13 +3309,13 @@ class Tracker {
|
|
|
3309
3309
|
}
|
|
3310
3310
|
|
|
3311
3311
|
// chart specific values
|
|
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 ==
|
|
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") {
|
|
3319
3319
|
if (!this.isUndefinedOrNull(plot.columnLabels[position.x])) {
|
|
3320
3320
|
x_tickmark = plot.columnLabels[position.x];
|
|
3321
3321
|
}
|
|
@@ -3328,7 +3328,7 @@ class Tracker {
|
|
|
3328
3328
|
if (!this.isUndefinedOrNull(plot.plotData[position.x])) {
|
|
3329
3329
|
value = plot.plotData[position.x];
|
|
3330
3330
|
}
|
|
3331
|
-
} else if (constants.chartType ==
|
|
3331
|
+
} else if (constants.chartType == "heat") {
|
|
3332
3332
|
if (!this.isUndefinedOrNull(plot.x_labels[position.x])) {
|
|
3333
3333
|
x_tickmark = plot.x_labels[position.x].trim();
|
|
3334
3334
|
}
|
|
@@ -3349,11 +3349,11 @@ class Tracker {
|
|
|
3349
3349
|
if (!this.isUndefinedOrNull(plot.group_labels[2])) {
|
|
3350
3350
|
fill_value = plot.group_labels[2];
|
|
3351
3351
|
}
|
|
3352
|
-
} else if (constants.chartType ==
|
|
3352
|
+
} else if (constants.chartType == "box") {
|
|
3353
3353
|
let plotPos =
|
|
3354
|
-
constants.plotOrientation ==
|
|
3354
|
+
constants.plotOrientation == "vert" ? position.x : position.y;
|
|
3355
3355
|
let sectionPos =
|
|
3356
|
-
constants.plotOrientation ==
|
|
3356
|
+
constants.plotOrientation == "vert" ? position.y : position.x;
|
|
3357
3357
|
let sectionLabel = plot.sections[sectionPos];
|
|
3358
3358
|
|
|
3359
3359
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
@@ -3362,7 +3362,7 @@ class Tracker {
|
|
|
3362
3362
|
if (!this.isUndefinedOrNull(plot.y_group_label)) {
|
|
3363
3363
|
y_label = plot.y_group_label;
|
|
3364
3364
|
}
|
|
3365
|
-
if (constants.plotOrientation ==
|
|
3365
|
+
if (constants.plotOrientation == "vert") {
|
|
3366
3366
|
if (plotPos > -1 && sectionPos > -1) {
|
|
3367
3367
|
if (!this.isUndefinedOrNull(sectionLabel)) {
|
|
3368
3368
|
y_tickmark = sectionLabel;
|
|
@@ -3387,7 +3387,7 @@ class Tracker {
|
|
|
3387
3387
|
}
|
|
3388
3388
|
}
|
|
3389
3389
|
}
|
|
3390
|
-
} else if (constants.chartType ==
|
|
3390
|
+
} else if (constants.chartType == "point") {
|
|
3391
3391
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
3392
3392
|
x_label = plot.x_group_label;
|
|
3393
3393
|
}
|
|
@@ -3414,7 +3414,7 @@ class Tracker {
|
|
|
3414
3414
|
|
|
3415
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);
|
|
3416
3416
|
|
|
3417
|
-
this.SetData(
|
|
3417
|
+
this.SetData("events", eventToLog);
|
|
3418
3418
|
//console.log('logged an event');
|
|
3419
3419
|
}
|
|
3420
3420
|
|
|
@@ -3427,7 +3427,7 @@ class Tracker {
|
|
|
3427
3427
|
SetData(key, value) {
|
|
3428
3428
|
if (this.isLocal) {
|
|
3429
3429
|
let data = this.GetTrackerData();
|
|
3430
|
-
let arrayKeys = [
|
|
3430
|
+
let arrayKeys = ["events", "ChatHistory", "settings"];
|
|
3431
3431
|
if (!arrayKeys.includes(key)) {
|
|
3432
3432
|
data[key] = value;
|
|
3433
3433
|
} else {
|
|
@@ -3438,7 +3438,7 @@ class Tracker {
|
|
|
3438
3438
|
}
|
|
3439
3439
|
this.SaveTrackerData(data);
|
|
3440
3440
|
} else {
|
|
3441
|
-
value[
|
|
3441
|
+
value["log_type"] = key;
|
|
3442
3442
|
this.SaveTrackerData(value);
|
|
3443
3443
|
}
|
|
3444
3444
|
}
|
|
@@ -3472,20 +3472,20 @@ class Review {
|
|
|
3472
3472
|
// true means on or show
|
|
3473
3473
|
if (onoff) {
|
|
3474
3474
|
constants.reviewSaveSpot = document.activeElement;
|
|
3475
|
-
constants.review_container.classList.remove(
|
|
3475
|
+
constants.review_container.classList.remove("hidden");
|
|
3476
3476
|
constants.reviewSaveBrailleMode = constants.brailleMode;
|
|
3477
3477
|
constants.review.focus();
|
|
3478
3478
|
|
|
3479
|
-
display.announceText(
|
|
3479
|
+
display.announceText("Review on");
|
|
3480
3480
|
} else {
|
|
3481
|
-
constants.review_container.classList.add(
|
|
3482
|
-
if (constants.reviewSaveBrailleMode ==
|
|
3481
|
+
constants.review_container.classList.add("hidden");
|
|
3482
|
+
if (constants.reviewSaveBrailleMode == "on") {
|
|
3483
3483
|
// we have to turn braille mode back on
|
|
3484
|
-
display.toggleBrailleMode(
|
|
3484
|
+
display.toggleBrailleMode("on");
|
|
3485
3485
|
} else {
|
|
3486
3486
|
constants.reviewSaveSpot.focus();
|
|
3487
3487
|
}
|
|
3488
|
-
display.announceText(
|
|
3488
|
+
display.announceText("Review off");
|
|
3489
3489
|
}
|
|
3490
3490
|
}
|
|
3491
3491
|
}
|
|
@@ -3502,7 +3502,7 @@ class LogError {
|
|
|
3502
3502
|
* @param {string} a - The absent element to log.
|
|
3503
3503
|
*/
|
|
3504
3504
|
LogAbsentElement(a) {
|
|
3505
|
-
console.log(a,
|
|
3505
|
+
console.log(a, "not found. Visual highlighting is turned off.");
|
|
3506
3506
|
}
|
|
3507
3507
|
|
|
3508
3508
|
/**
|
|
@@ -3510,7 +3510,7 @@ class LogError {
|
|
|
3510
3510
|
* @param {string} a - The critical element to log.
|
|
3511
3511
|
*/
|
|
3512
3512
|
LogCriticalElement(a) {
|
|
3513
|
-
consolelog(a,
|
|
3513
|
+
consolelog(a, "is critical. MAIDR unable to run");
|
|
3514
3514
|
}
|
|
3515
3515
|
|
|
3516
3516
|
/**
|
|
@@ -3521,9 +3521,9 @@ class LogError {
|
|
|
3521
3521
|
LogDifferentLengths(a, b) {
|
|
3522
3522
|
console.log(
|
|
3523
3523
|
a,
|
|
3524
|
-
|
|
3524
|
+
"and",
|
|
3525
3525
|
b,
|
|
3526
|
-
|
|
3526
|
+
"do not have the same length. Visual highlighting is turned off."
|
|
3527
3527
|
);
|
|
3528
3528
|
}
|
|
3529
3529
|
|
|
@@ -3534,11 +3534,11 @@ class LogError {
|
|
|
3534
3534
|
*/
|
|
3535
3535
|
LogTooManyElements(a, b) {
|
|
3536
3536
|
console.log(
|
|
3537
|
-
|
|
3537
|
+
"Too many",
|
|
3538
3538
|
a,
|
|
3539
|
-
|
|
3539
|
+
"elements. Only the first",
|
|
3540
3540
|
b,
|
|
3541
|
-
|
|
3541
|
+
"will be highlighted."
|
|
3542
3542
|
);
|
|
3543
3543
|
}
|
|
3544
3544
|
|
|
@@ -3547,7 +3547,7 @@ class LogError {
|
|
|
3547
3547
|
* @param {*} a - The parameter that is not an array.
|
|
3548
3548
|
*/
|
|
3549
3549
|
LogNotArray(a) {
|
|
3550
|
-
console.log(a,
|
|
3550
|
+
console.log(a, "is not an array. Visual highlighting is turned off.");
|
|
3551
3551
|
}
|
|
3552
3552
|
}
|
|
3553
3553
|
|