maidr 2.24.1 → 2.25.1

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 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
  /**
@@ -1177,7 +1222,7 @@ class Menu {
1177
1222
  document
1178
1223
  .getElementById('gemini_multi_container')
1179
1224
  .classList.add('hidden');
1180
- document.getElementById('openai_multi').checked = true;
1225
+ document.getElementById('openai_multi').checked = true; // refactor note: this hidden checkbox stuff is stupid and should be removed. We're sorta replacing with the visible checkboxes.
1181
1226
  document.getElementById('gemini_multi').checked = false;
1182
1227
  } else if (e.target.value == 'gemini') {
1183
1228
  document
@@ -1521,8 +1566,12 @@ class Menu {
1521
1566
  });
1522
1567
 
1523
1568
  constants.LLMPreferences = document.getElementById('LLM_preferences').value;
1524
- constants.LLMOpenAiMulti = document.getElementById('openai_multi').checked;
1525
- constants.LLMGeminiMulti = document.getElementById('gemini_multi').checked;
1569
+ constants.LLMOpenAiMulti =
1570
+ document.getElementById('LLM_model_openai').checked;
1571
+ constants.LLMGeminiMulti =
1572
+ document.getElementById('LLM_model_gemini').checked;
1573
+ constants.LLMClaudeMulti =
1574
+ document.getElementById('LLM_model_claude').checked;
1526
1575
  constants.autoInitLLM = document.getElementById('init_llm_on_load').checked;
1527
1576
 
1528
1577
  // aria
@@ -1752,6 +1801,7 @@ class ChatLLM {
1752
1801
  this.firstMulti = true;
1753
1802
  this.firstOpen = true;
1754
1803
  this.shown = false;
1804
+ this.awaitingNumChats = 0;
1755
1805
  this.CreateComponent();
1756
1806
  this.SetEvents();
1757
1807
  if (constants.autoInitLLM) {
@@ -1960,8 +2010,9 @@ class ChatLLM {
1960
2010
  *
1961
2011
  * @param {Event|undefined} e - The event that triggered the copy action. If undefined, the entire chat history is copied.
1962
2012
  */
1963
- CopyChatHistory(e) {
2013
+ CopyChatHistory(e, actuallyCopy = true) {
1964
2014
  let text = '';
2015
+ let notificationText = '';
1965
2016
  if (typeof e == 'undefined') {
1966
2017
  // check for passthrough
1967
2018
  // get html of the full chat history
@@ -1971,9 +2022,11 @@ class ChatLLM {
1971
2022
  if (e.target.id == 'chatLLM_copy_all') {
1972
2023
  // get html of the full chat history
1973
2024
  text = document.getElementById('chatLLM_chat_history').innerHTML;
2025
+ notificationText = 'Copied All.';
1974
2026
  } else if (e.target.classList.contains('chatLLM_message_copy_button')) {
1975
2027
  // get the text of the element before the button
1976
2028
  text = e.target.closest('p').previousElementSibling.innerHTML;
2029
+ notificationText = 'Copied.';
1977
2030
  }
1978
2031
  } else if (e.type == 'keyup') {
1979
2032
  // check for alt shift c or ctrl shift c
@@ -1985,6 +2038,7 @@ class ChatLLM {
1985
2038
  );
1986
2039
  if (elem) {
1987
2040
  text = elem.innerHTML;
2041
+ notificationText = 'Copied.';
1988
2042
  }
1989
2043
  } else if (
1990
2044
  e.key == 'A' &&
@@ -1994,6 +2048,7 @@ class ChatLLM {
1994
2048
  e.preventDefault();
1995
2049
  // get html of the full chat history
1996
2050
  text = document.getElementById('chatLLM_chat_history').innerHTML;
2051
+ notificationText = 'Copied All.';
1997
2052
  }
1998
2053
  }
1999
2054
 
@@ -2011,10 +2066,18 @@ class ChatLLM {
2011
2066
  // this messes up a bit with spacing, so kill more than 2 newlines in a row
2012
2067
  markdown = markdown.replace(/\n{3,}/g, '\n\n');
2013
2068
 
2014
- try {
2015
- 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
- } catch (err) {
2017
- console.error('Failed to copy: ', err);
2069
+ if (notificationText != '') {
2070
+ if (display) {
2071
+ display.announceText(notificationText);
2072
+ }
2073
+ }
2074
+
2075
+ if (actuallyCopy) {
2076
+ try {
2077
+ navigator.clipboard.writeText(markdown); // note: this fails if you're on the inspector. That's fine as it'll never happen to real users
2078
+ } catch (err) {
2079
+ console.error('Failed to copy: ', err);
2080
+ }
2018
2081
  }
2019
2082
  return markdown;
2020
2083
  }
@@ -2103,7 +2166,7 @@ class ChatLLM {
2103
2166
 
2104
2167
  if ('openai' in constants.LLMModels) {
2105
2168
  if (firsttime) {
2106
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'openai');
2169
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'openai');
2107
2170
  }
2108
2171
  if (constants.emailAuthKey) {
2109
2172
  chatLLM.OpenAIPromptAPI(text, img);
@@ -2113,7 +2176,7 @@ class ChatLLM {
2113
2176
  }
2114
2177
  if ('gemini' in constants.LLMModels) {
2115
2178
  if (firsttime) {
2116
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
2179
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
2117
2180
  }
2118
2181
  if (constants.emailAuthKey) {
2119
2182
  chatLLM.GeminiPromptAPI(text, img);
@@ -2124,7 +2187,7 @@ class ChatLLM {
2124
2187
 
2125
2188
  if ('claude' in constants.LLMModels) {
2126
2189
  if (firsttime) {
2127
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'claude');
2190
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'claude');
2128
2191
  }
2129
2192
  if (constants.emailAuthKey) {
2130
2193
  chatLLM.ClaudePromptAPI(text, img);
@@ -2148,7 +2211,7 @@ class ChatLLM {
2148
2211
  let inprogressFreq = freq * 2;
2149
2212
 
2150
2213
  if (onoff) {
2151
- // if turning on, clear old intervals and timeouts
2214
+ // if turning on clear old intervals and timeouts
2152
2215
  if (constants.waitingInterval) {
2153
2216
  // destroy old waiting sound
2154
2217
  clearInterval(constants.waitingInterval);
@@ -2199,6 +2262,9 @@ class ChatLLM {
2199
2262
  if (constants.LLMOpenAiMulti) {
2200
2263
  constants.waitingQueue++;
2201
2264
  }
2265
+ if (constants.LLMClaudeMulti) {
2266
+ constants.waitingQueue++;
2267
+ }
2202
2268
  }
2203
2269
  }
2204
2270
  }
@@ -2279,8 +2345,11 @@ class ChatLLM {
2279
2345
 
2280
2346
  // if we're tracking, log the data
2281
2347
  if (constants.canTrack) {
2282
- let chatHist = chatLLM.CopyChatHistory();
2283
- tracker.SetData('ChatHistory', { chatHistory: chatHist });
2348
+ let chatHist = chatLLM.CopyChatHistory(undefined, false);
2349
+ let data = {};
2350
+ data.chatHistory = chatHist;
2351
+ if (constants.emailAuthKey) data.username = constants.emailAuthKey;
2352
+ tracker.SetData('ChatHistory', data);
2284
2353
  }
2285
2354
  }
2286
2355
 
@@ -2817,52 +2886,6 @@ class ChatLLM {
2817
2886
  }
2818
2887
  }
2819
2888
 
2820
- /**
2821
- * Converts the active chart to a jpg image.
2822
- * @id {string} - The html ID of the chart to convert.
2823
- */
2824
- async ConvertSVGtoJPG(id, model) {
2825
- let svgElement = document.getElementById(id);
2826
- return new Promise((resolve, reject) => {
2827
- var canvas = document.createElement('canvas');
2828
- var ctx = canvas.getContext('2d');
2829
-
2830
- var svgData = new XMLSerializer().serializeToString(svgElement);
2831
- if (!svgData.startsWith('<svg xmlns')) {
2832
- svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
2833
- }
2834
-
2835
- var svgSize =
2836
- svgElement.viewBox.baseVal || svgElement.getBoundingClientRect();
2837
- canvas.width = svgSize.width;
2838
- canvas.height = svgSize.height;
2839
-
2840
- var img = new Image();
2841
- img.onload = function () {
2842
- ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
2843
- var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
2844
- if (model == 'openai') {
2845
- resolve(jpegData);
2846
- } else if (model == 'gemini' || model == 'claude') {
2847
- let base64Data = jpegData.split(',')[1];
2848
- resolve(base64Data);
2849
- //resolve(jpegData);
2850
- }
2851
- URL.revokeObjectURL(url);
2852
- };
2853
-
2854
- img.onerror = function () {
2855
- reject(new Error('Error loading SVG'));
2856
- };
2857
-
2858
- var svgBlob = new Blob([svgData], {
2859
- type: 'image/svg+xml;charset=utf-8',
2860
- });
2861
- var url = URL.createObjectURL(svgBlob);
2862
- img.src = url;
2863
- });
2864
- }
2865
-
2866
2889
  /**
2867
2890
  * GetDefaultPrompt is an asynchronous function that generates a prompt for describing a chart to a blind person.
2868
2891
  * It converts the chart to a JPG image using the ConvertSVGtoJPG method and then submits the prompt to the chatLLM function.
@@ -3204,7 +3227,7 @@ class Tracker {
3204
3227
  /**
3205
3228
  * Sets up the tracker data by checking if previous data exists and creating new data if it doesn't.
3206
3229
  */
3207
- DataSetup() {
3230
+ async DataSetup() {
3208
3231
  let prevData = this.GetTrackerData();
3209
3232
  if (!this.isLocal || !prevData) {
3210
3233
  let data = {};
@@ -3213,6 +3236,10 @@ class Tracker {
3213
3236
  data.language = Object.assign(navigator.language);
3214
3237
  data.platform = Object.assign(navigator.platform);
3215
3238
  data.geolocation = Object.assign(navigator.geolocation);
3239
+ data.imageBase64 = await constants.ConvertSVGtoJPG(
3240
+ singleMaidr.id,
3241
+ 'gemini'
3242
+ );
3216
3243
  data.log_type = 'system_data';
3217
3244
  data.events = [];
3218
3245
  data.settings = [];
@@ -3239,7 +3266,7 @@ class Tracker {
3239
3266
  * @param {Object} data - The data to be saved.
3240
3267
  */
3241
3268
  async SaveTrackerData(data) {
3242
- console.log('about to save data', data);
3269
+ //console.log('about to save data', data);
3243
3270
  if (this.isLocal) {
3244
3271
  localStorage.setItem(constants.project_id, JSON.stringify(data));
3245
3272
  } else {
@@ -3258,7 +3285,7 @@ class Tracker {
3258
3285
  }
3259
3286
 
3260
3287
  const result = await response.json();
3261
- console.log('Data saved successfully:', result);
3288
+ //console.log('Data saved successfully:', result);
3262
3289
  return result;
3263
3290
  } catch (error) {
3264
3291
  console.error('Error saving data:', error);