maidr 2.24.0 → 2.25.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 +93 -58
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/dist/maidr.js
CHANGED
|
@@ -810,6 +810,51 @@ class Constants {
|
|
|
810
810
|
}
|
|
811
811
|
return styleString;
|
|
812
812
|
}
|
|
813
|
+
/**
|
|
814
|
+
* Converts the active chart to a jpg image.
|
|
815
|
+
* @id {string} - The html ID of the chart to convert.
|
|
816
|
+
*/
|
|
817
|
+
async ConvertSVGtoJPG(id, model) {
|
|
818
|
+
let svgElement = document.getElementById(id);
|
|
819
|
+
return new Promise((resolve, reject) => {
|
|
820
|
+
var canvas = document.createElement('canvas');
|
|
821
|
+
var ctx = canvas.getContext('2d');
|
|
822
|
+
|
|
823
|
+
var svgData = new XMLSerializer().serializeToString(svgElement);
|
|
824
|
+
if (!svgData.startsWith('<svg xmlns')) {
|
|
825
|
+
svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
var svgSize =
|
|
829
|
+
svgElement.viewBox.baseVal || svgElement.getBoundingClientRect();
|
|
830
|
+
canvas.width = svgSize.width;
|
|
831
|
+
canvas.height = svgSize.height;
|
|
832
|
+
|
|
833
|
+
var img = new Image();
|
|
834
|
+
img.onload = function () {
|
|
835
|
+
ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
|
|
836
|
+
var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
|
|
837
|
+
if (model == 'openai') {
|
|
838
|
+
resolve(jpegData);
|
|
839
|
+
} else if (model == 'gemini' || model == 'claude') {
|
|
840
|
+
let base64Data = jpegData.split(',')[1];
|
|
841
|
+
resolve(base64Data);
|
|
842
|
+
//resolve(jpegData);
|
|
843
|
+
}
|
|
844
|
+
URL.revokeObjectURL(url);
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
img.onerror = function () {
|
|
848
|
+
reject(new Error('Error loading SVG'));
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
var svgBlob = new Blob([svgData], {
|
|
852
|
+
type: 'image/svg+xml;charset=utf-8',
|
|
853
|
+
});
|
|
854
|
+
var url = URL.createObjectURL(svgBlob);
|
|
855
|
+
img.src = url;
|
|
856
|
+
});
|
|
857
|
+
}
|
|
813
858
|
}
|
|
814
859
|
|
|
815
860
|
/**
|
|
@@ -1962,6 +2007,7 @@ class ChatLLM {
|
|
|
1962
2007
|
*/
|
|
1963
2008
|
CopyChatHistory(e) {
|
|
1964
2009
|
let text = '';
|
|
2010
|
+
let notificationText = '';
|
|
1965
2011
|
if (typeof e == 'undefined') {
|
|
1966
2012
|
// check for passthrough
|
|
1967
2013
|
// get html of the full chat history
|
|
@@ -1971,9 +2017,11 @@ class ChatLLM {
|
|
|
1971
2017
|
if (e.target.id == 'chatLLM_copy_all') {
|
|
1972
2018
|
// get html of the full chat history
|
|
1973
2019
|
text = document.getElementById('chatLLM_chat_history').innerHTML;
|
|
2020
|
+
notificationText = 'Copied All.';
|
|
1974
2021
|
} else if (e.target.classList.contains('chatLLM_message_copy_button')) {
|
|
1975
2022
|
// get the text of the element before the button
|
|
1976
2023
|
text = e.target.closest('p').previousElementSibling.innerHTML;
|
|
2024
|
+
notificationText = 'Copied.';
|
|
1977
2025
|
}
|
|
1978
2026
|
} else if (e.type == 'keyup') {
|
|
1979
2027
|
// check for alt shift c or ctrl shift c
|
|
@@ -1985,6 +2033,7 @@ class ChatLLM {
|
|
|
1985
2033
|
);
|
|
1986
2034
|
if (elem) {
|
|
1987
2035
|
text = elem.innerHTML;
|
|
2036
|
+
notificationText = 'Copied.';
|
|
1988
2037
|
}
|
|
1989
2038
|
} else if (
|
|
1990
2039
|
e.key == 'A' &&
|
|
@@ -1994,6 +2043,7 @@ class ChatLLM {
|
|
|
1994
2043
|
e.preventDefault();
|
|
1995
2044
|
// get html of the full chat history
|
|
1996
2045
|
text = document.getElementById('chatLLM_chat_history').innerHTML;
|
|
2046
|
+
notificationText = 'Copied All.';
|
|
1997
2047
|
}
|
|
1998
2048
|
}
|
|
1999
2049
|
|
|
@@ -2011,6 +2061,12 @@ class ChatLLM {
|
|
|
2011
2061
|
// this messes up a bit with spacing, so kill more than 2 newlines in a row
|
|
2012
2062
|
markdown = markdown.replace(/\n{3,}/g, '\n\n');
|
|
2013
2063
|
|
|
2064
|
+
if (notificationText != '') {
|
|
2065
|
+
if (display) {
|
|
2066
|
+
display.announceText(notificationText);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2014
2070
|
try {
|
|
2015
2071
|
navigator.clipboard.writeText(markdown); // note: this fails if you're on the inspector. That's fine as it'll never happen to real users
|
|
2016
2072
|
} catch (err) {
|
|
@@ -2103,7 +2159,7 @@ class ChatLLM {
|
|
|
2103
2159
|
|
|
2104
2160
|
if ('openai' in constants.LLMModels) {
|
|
2105
2161
|
if (firsttime) {
|
|
2106
|
-
img = await
|
|
2162
|
+
img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'openai');
|
|
2107
2163
|
}
|
|
2108
2164
|
if (constants.emailAuthKey) {
|
|
2109
2165
|
chatLLM.OpenAIPromptAPI(text, img);
|
|
@@ -2113,7 +2169,7 @@ class ChatLLM {
|
|
|
2113
2169
|
}
|
|
2114
2170
|
if ('gemini' in constants.LLMModels) {
|
|
2115
2171
|
if (firsttime) {
|
|
2116
|
-
img = await
|
|
2172
|
+
img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
|
|
2117
2173
|
}
|
|
2118
2174
|
if (constants.emailAuthKey) {
|
|
2119
2175
|
chatLLM.GeminiPromptAPI(text, img);
|
|
@@ -2124,7 +2180,7 @@ class ChatLLM {
|
|
|
2124
2180
|
|
|
2125
2181
|
if ('claude' in constants.LLMModels) {
|
|
2126
2182
|
if (firsttime) {
|
|
2127
|
-
img = await
|
|
2183
|
+
img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'claude');
|
|
2128
2184
|
}
|
|
2129
2185
|
if (constants.emailAuthKey) {
|
|
2130
2186
|
chatLLM.ClaudePromptAPI(text, img);
|
|
@@ -2271,8 +2327,7 @@ class ChatLLM {
|
|
|
2271
2327
|
if (data.text()) {
|
|
2272
2328
|
text = data.text();
|
|
2273
2329
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2274
|
-
}
|
|
2275
|
-
if (data.error) {
|
|
2330
|
+
} else if (data.error) {
|
|
2276
2331
|
chatLLM.DisplayChatMessage(LLMName, 'Error processing request.', true);
|
|
2277
2332
|
chatLLM.WaitingSound(false);
|
|
2278
2333
|
}
|
|
@@ -2281,7 +2336,10 @@ class ChatLLM {
|
|
|
2281
2336
|
// if we're tracking, log the data
|
|
2282
2337
|
if (constants.canTrack) {
|
|
2283
2338
|
let chatHist = chatLLM.CopyChatHistory();
|
|
2284
|
-
|
|
2339
|
+
let data = {};
|
|
2340
|
+
data.chatHistory = chatHist;
|
|
2341
|
+
if (constants.emailAuthKey) data.username = constants.emailAuthKey;
|
|
2342
|
+
tracker.SetData('ChatHistory', data);
|
|
2285
2343
|
}
|
|
2286
2344
|
}
|
|
2287
2345
|
|
|
@@ -2818,52 +2876,6 @@ class ChatLLM {
|
|
|
2818
2876
|
}
|
|
2819
2877
|
}
|
|
2820
2878
|
|
|
2821
|
-
/**
|
|
2822
|
-
* Converts the active chart to a jpg image.
|
|
2823
|
-
* @id {string} - The html ID of the chart to convert.
|
|
2824
|
-
*/
|
|
2825
|
-
async ConvertSVGtoJPG(id, model) {
|
|
2826
|
-
let svgElement = document.getElementById(id);
|
|
2827
|
-
return new Promise((resolve, reject) => {
|
|
2828
|
-
var canvas = document.createElement('canvas');
|
|
2829
|
-
var ctx = canvas.getContext('2d');
|
|
2830
|
-
|
|
2831
|
-
var svgData = new XMLSerializer().serializeToString(svgElement);
|
|
2832
|
-
if (!svgData.startsWith('<svg xmlns')) {
|
|
2833
|
-
svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
|
|
2834
|
-
}
|
|
2835
|
-
|
|
2836
|
-
var svgSize =
|
|
2837
|
-
svgElement.viewBox.baseVal || svgElement.getBoundingClientRect();
|
|
2838
|
-
canvas.width = svgSize.width;
|
|
2839
|
-
canvas.height = svgSize.height;
|
|
2840
|
-
|
|
2841
|
-
var img = new Image();
|
|
2842
|
-
img.onload = function () {
|
|
2843
|
-
ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
|
|
2844
|
-
var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
|
|
2845
|
-
if (model == 'openai') {
|
|
2846
|
-
resolve(jpegData);
|
|
2847
|
-
} else if (model == 'gemini' || model == 'claude') {
|
|
2848
|
-
let base64Data = jpegData.split(',')[1];
|
|
2849
|
-
resolve(base64Data);
|
|
2850
|
-
//resolve(jpegData);
|
|
2851
|
-
}
|
|
2852
|
-
URL.revokeObjectURL(url);
|
|
2853
|
-
};
|
|
2854
|
-
|
|
2855
|
-
img.onerror = function () {
|
|
2856
|
-
reject(new Error('Error loading SVG'));
|
|
2857
|
-
};
|
|
2858
|
-
|
|
2859
|
-
var svgBlob = new Blob([svgData], {
|
|
2860
|
-
type: 'image/svg+xml;charset=utf-8',
|
|
2861
|
-
});
|
|
2862
|
-
var url = URL.createObjectURL(svgBlob);
|
|
2863
|
-
img.src = url;
|
|
2864
|
-
});
|
|
2865
|
-
}
|
|
2866
|
-
|
|
2867
2879
|
/**
|
|
2868
2880
|
* GetDefaultPrompt is an asynchronous function that generates a prompt for describing a chart to a blind person.
|
|
2869
2881
|
* It converts the chart to a JPG image using the ConvertSVGtoJPG method and then submits the prompt to the chatLLM function.
|
|
@@ -3205,7 +3217,7 @@ class Tracker {
|
|
|
3205
3217
|
/**
|
|
3206
3218
|
* Sets up the tracker data by checking if previous data exists and creating new data if it doesn't.
|
|
3207
3219
|
*/
|
|
3208
|
-
DataSetup() {
|
|
3220
|
+
async DataSetup() {
|
|
3209
3221
|
let prevData = this.GetTrackerData();
|
|
3210
3222
|
if (!this.isLocal || !prevData) {
|
|
3211
3223
|
let data = {};
|
|
@@ -3214,6 +3226,10 @@ class Tracker {
|
|
|
3214
3226
|
data.language = Object.assign(navigator.language);
|
|
3215
3227
|
data.platform = Object.assign(navigator.platform);
|
|
3216
3228
|
data.geolocation = Object.assign(navigator.geolocation);
|
|
3229
|
+
data.imageBase64 = await constants.ConvertSVGtoJPG(
|
|
3230
|
+
singleMaidr.id,
|
|
3231
|
+
'gemini'
|
|
3232
|
+
);
|
|
3217
3233
|
data.log_type = 'system_data';
|
|
3218
3234
|
data.events = [];
|
|
3219
3235
|
data.settings = [];
|
|
@@ -3659,9 +3675,20 @@ class LogError {
|
|
|
3659
3675
|
*/
|
|
3660
3676
|
class Audio {
|
|
3661
3677
|
constructor() {
|
|
3662
|
-
this.
|
|
3663
|
-
|
|
3664
|
-
|
|
3678
|
+
this.fixAudioContext();
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
fixAudioContext() {
|
|
3682
|
+
if (!this.audioContext) {
|
|
3683
|
+
this.AudioContext =
|
|
3684
|
+
window['AudioContext'] || window['webkitAudioContext'];
|
|
3685
|
+
this.audioContext = new AudioContext();
|
|
3686
|
+
this.compressor = this.compressorSetup(this.audioContext);
|
|
3687
|
+
} else if (this.audioContext.state === 'suspended') {
|
|
3688
|
+
this.audioContext.resume().then(() => {
|
|
3689
|
+
console.log('AudioContext resumed');
|
|
3690
|
+
});
|
|
3691
|
+
}
|
|
3665
3692
|
}
|
|
3666
3693
|
|
|
3667
3694
|
/**
|
|
@@ -4408,6 +4435,10 @@ class Display {
|
|
|
4408
4435
|
this.announceText(resources.GetString('son_off'));
|
|
4409
4436
|
}
|
|
4410
4437
|
}
|
|
4438
|
+
|
|
4439
|
+
if (constants.sonifMode != 'off') {
|
|
4440
|
+
audio.fixAudioContext();
|
|
4441
|
+
}
|
|
4411
4442
|
}
|
|
4412
4443
|
|
|
4413
4444
|
/**
|
|
@@ -9019,15 +9050,19 @@ class Control {
|
|
|
9019
9050
|
// we lock the selection while we're changing stuff so it doesn't loop
|
|
9020
9051
|
constants.lockSelection = true;
|
|
9021
9052
|
|
|
9022
|
-
// exception: don't let users click the seperator char
|
|
9053
|
+
// exception: don't let users click the seperator char, so make them click just before
|
|
9023
9054
|
let seperatorPositions = constants.brailleInput.value
|
|
9024
9055
|
.split('')
|
|
9025
9056
|
.reduce((positions, char, index) => {
|
|
9026
9057
|
if (char === '⠳') positions.push(index);
|
|
9027
9058
|
return positions;
|
|
9028
9059
|
}, []);
|
|
9060
|
+
console.log('seperatorPositions', seperatorPositions);
|
|
9061
|
+
console.log('pos', pos);
|
|
9029
9062
|
if (seperatorPositions.includes(pos)) {
|
|
9030
|
-
|
|
9063
|
+
if (pos > 0) {
|
|
9064
|
+
pos += -1;
|
|
9065
|
+
}
|
|
9031
9066
|
}
|
|
9032
9067
|
|
|
9033
9068
|
// we're using braille cursor, update the selection from what was clicked
|