maidr 2.20.0 → 2.22.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 +552 -131
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/dist/maidr.js
CHANGED
|
@@ -406,13 +406,6 @@ class Constants {
|
|
|
406
406
|
* @memberof AdvancedUserSettings
|
|
407
407
|
*/
|
|
408
408
|
canTrack = 0; // 0 / 1, can we track user data
|
|
409
|
-
/**
|
|
410
|
-
* Whether or not we're currently tracking user data.
|
|
411
|
-
* @type {boolean}
|
|
412
|
-
* @default 1
|
|
413
|
-
* @memberof AdvancedUserSettings
|
|
414
|
-
*/
|
|
415
|
-
isTracking = 0;
|
|
416
409
|
/**
|
|
417
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.
|
|
418
411
|
* @type {boolean}
|
|
@@ -443,12 +436,15 @@ class Constants {
|
|
|
443
436
|
'ariaMode',
|
|
444
437
|
'openAIAuthKey',
|
|
445
438
|
'geminiAuthKey',
|
|
439
|
+
'claudeAuthKey',
|
|
440
|
+
'emailAuthKey',
|
|
446
441
|
'skillLevel',
|
|
447
442
|
'skillLevelOther',
|
|
448
443
|
'LLMModel',
|
|
449
444
|
'LLMPreferences',
|
|
450
445
|
'LLMOpenAiMulti',
|
|
451
446
|
'LLMGeminiMulti',
|
|
447
|
+
'LLMModels',
|
|
452
448
|
'autoInitLLM',
|
|
453
449
|
];
|
|
454
450
|
|
|
@@ -498,6 +494,13 @@ class Constants {
|
|
|
498
494
|
* @memberof LLMSettings
|
|
499
495
|
*/
|
|
500
496
|
LLMModel = 'openai';
|
|
497
|
+
/**
|
|
498
|
+
* Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'claude'. More to be added.
|
|
499
|
+
* @type {("openai"|"gemini"|"claude")}
|
|
500
|
+
* @default 'openai'
|
|
501
|
+
* @memberof LLMSettings
|
|
502
|
+
*/
|
|
503
|
+
LLMModels = { openai: true };
|
|
501
504
|
/**
|
|
502
505
|
* The default system message for the LLM. Helps the LLM understand the context of the chart and its role.
|
|
503
506
|
* @type {string}
|
|
@@ -832,6 +835,7 @@ class Resources {
|
|
|
832
835
|
empty: 'Empty',
|
|
833
836
|
openai: 'OpenAI Vision',
|
|
834
837
|
gemini: 'Gemini Pro Vision',
|
|
838
|
+
claude: 'Claude',
|
|
835
839
|
multi: 'Multiple AI',
|
|
836
840
|
processing: 'Processing Chart...',
|
|
837
841
|
},
|
|
@@ -1011,8 +1015,7 @@ class Menu {
|
|
|
1011
1015
|
constants.ariaMode == 'polite' ? 'checked' : ''
|
|
1012
1016
|
}><label for="aria_mode_polite">Polite</label></p>
|
|
1013
1017
|
</fieldset></div>
|
|
1014
|
-
<
|
|
1015
|
-
<p>
|
|
1018
|
+
<p class="hidden">
|
|
1016
1019
|
<select id="LLM_model">
|
|
1017
1020
|
<option value="openai">OpenAI Vision</option>
|
|
1018
1021
|
<option value="gemini">Gemini Pro Vision</option>
|
|
@@ -1020,6 +1023,18 @@ class Menu {
|
|
|
1020
1023
|
</select>
|
|
1021
1024
|
<label for="LLM_model">LLM Model</label>
|
|
1022
1025
|
</p>
|
|
1026
|
+
<h5 class="modal-title">LLM Settings</h5>
|
|
1027
|
+
<p>
|
|
1028
|
+
<fieldset>
|
|
1029
|
+
<legend>LLM Models (select up to 2)</legend>
|
|
1030
|
+
<p><input type="checkbox" id="LLM_model_openai" name="LLM_model" value="openai"><label for="LLM_model_openai">OpenAI Vision</label></p>
|
|
1031
|
+
<p><input type="checkbox" id="LLM_model_gemini" name="LLM_model" value="gemini"><label for="LLM_model_gemini">Gemini Pro Vision</label></p>
|
|
1032
|
+
<p><input type="checkbox" id="LLM_model_claude" name="LLM_model" value="claude"><label for="LLM_model_claude">Claude</label></p>
|
|
1033
|
+
</fieldset>
|
|
1034
|
+
</p>
|
|
1035
|
+
<p id="email_auth_key_container" class="multi_container">
|
|
1036
|
+
<input type="email" size="50" id="email_auth_key"><button aria-label="Delete Email Address" title="Delete Email Address" id="delete_email_key" class="invis_button">×</button><label for="gemini_auth_key">Email Authentication</label><button type="button" id="verify">Verify</button>
|
|
1037
|
+
</p>
|
|
1023
1038
|
<p id="openai_auth_key_container" class="multi_container hidden">
|
|
1024
1039
|
<span id="openai_multi_container" class="hidden"><input type="checkbox" id="openai_multi" name="openai_multi" aria-label="Use OpenAI in Multi modal mode"></span>
|
|
1025
1040
|
<input type="password" size="50" id="openai_auth_key"><button aria-label="Delete OpenAI key" title="Delete OpenAI key" id="delete_openai_key" class="invis_button">×</button><label for="openai_auth_key">OpenAI Authentication Key</label>
|
|
@@ -1027,10 +1042,14 @@ class Menu {
|
|
|
1027
1042
|
<p id="gemini_auth_key_container" class="multi_container hidden">
|
|
1028
1043
|
<span id="gemini_multi_container" class="hidden"><input type="checkbox" id="gemini_multi" name="gemini_multi" aria-label="Use Gemini in Multi modal mode"></span>
|
|
1029
1044
|
<input type="password" size="50" id="gemini_auth_key"><button aria-label="Delete Gemini key" title="Delete Gemini key" id="delete_gemini_key" class="invis_button">×</button><label for="gemini_auth_key">Gemini Authentication Key</label>
|
|
1045
|
+
</p>
|
|
1046
|
+
<p id="claude_auth_key_container" class="multi_container hidden">
|
|
1047
|
+
<span id="claude_multi_container" class="hidden"><input type="checkbox" id="claude_multi" name="claude_multi" aria-label="Use Claude in Multi modal mode"></span>
|
|
1048
|
+
<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>
|
|
1030
1049
|
</p>
|
|
1031
1050
|
<p><input type="checkbox" ${
|
|
1032
1051
|
constants.autoInitLLM ? 'checked' : ''
|
|
1033
|
-
} id="init_llm_on_load" name="init_llm_on_load"><label for="init_llm_on_load">Start
|
|
1052
|
+
} id="init_llm_on_load" name="init_llm_on_load"><label for="init_llm_on_load">Start LLM right away</label></p>
|
|
1034
1053
|
<p>
|
|
1035
1054
|
<select id="skill_level">
|
|
1036
1055
|
<option value="basic">Basic</option>
|
|
@@ -1088,6 +1107,13 @@ class Menu {
|
|
|
1088
1107
|
menu.Toggle(false);
|
|
1089
1108
|
},
|
|
1090
1109
|
]);
|
|
1110
|
+
constants.events.push([
|
|
1111
|
+
document.getElementById('verify'),
|
|
1112
|
+
'click',
|
|
1113
|
+
function (e) {
|
|
1114
|
+
menu.VerifyEmail();
|
|
1115
|
+
},
|
|
1116
|
+
]);
|
|
1091
1117
|
constants.events.push([
|
|
1092
1118
|
document.getElementById('menu'),
|
|
1093
1119
|
'keyup',
|
|
@@ -1170,6 +1196,54 @@ class Menu {
|
|
|
1170
1196
|
},
|
|
1171
1197
|
]);
|
|
1172
1198
|
|
|
1199
|
+
constants.events.push([
|
|
1200
|
+
document.getElementById('LLM_model_openai'),
|
|
1201
|
+
'change',
|
|
1202
|
+
function (e) {
|
|
1203
|
+
if (e.target.checked) {
|
|
1204
|
+
document
|
|
1205
|
+
.getElementById('openai_auth_key_container')
|
|
1206
|
+
.classList.remove('hidden');
|
|
1207
|
+
} else {
|
|
1208
|
+
document
|
|
1209
|
+
.getElementById('openai_auth_key_container')
|
|
1210
|
+
.classList.add('hidden');
|
|
1211
|
+
}
|
|
1212
|
+
},
|
|
1213
|
+
]);
|
|
1214
|
+
|
|
1215
|
+
constants.events.push([
|
|
1216
|
+
document.getElementById('LLM_model_gemini'),
|
|
1217
|
+
'change',
|
|
1218
|
+
function (e) {
|
|
1219
|
+
if (e.target.checked) {
|
|
1220
|
+
document
|
|
1221
|
+
.getElementById('gemini_auth_key_container')
|
|
1222
|
+
.classList.remove('hidden');
|
|
1223
|
+
} else {
|
|
1224
|
+
document
|
|
1225
|
+
.getElementById('gemini_auth_key_container')
|
|
1226
|
+
.classList.add('hidden');
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
]);
|
|
1230
|
+
|
|
1231
|
+
constants.events.push([
|
|
1232
|
+
document.getElementById('LLM_model_claude'),
|
|
1233
|
+
'change',
|
|
1234
|
+
function (e) {
|
|
1235
|
+
// if (e.target.checked) {
|
|
1236
|
+
document
|
|
1237
|
+
.getElementById('claude_auth_key_container')
|
|
1238
|
+
.classList.add('hidden');
|
|
1239
|
+
// } else {
|
|
1240
|
+
// document
|
|
1241
|
+
// .getElementById('claude_auth_key_container')
|
|
1242
|
+
// .classList.add('hidden');
|
|
1243
|
+
// }
|
|
1244
|
+
},
|
|
1245
|
+
]);
|
|
1246
|
+
|
|
1173
1247
|
// Skill level other events
|
|
1174
1248
|
constants.events.push([
|
|
1175
1249
|
document.getElementById('skill_level'),
|
|
@@ -1205,6 +1279,20 @@ class Menu {
|
|
|
1205
1279
|
},
|
|
1206
1280
|
]);
|
|
1207
1281
|
}
|
|
1282
|
+
|
|
1283
|
+
// Limit selections to 2 AI models
|
|
1284
|
+
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
1285
|
+
llmCheckboxes.forEach((checkbox) => {
|
|
1286
|
+
checkbox.addEventListener('change', () => {
|
|
1287
|
+
const checked = document.querySelectorAll(
|
|
1288
|
+
'input[name="LLM_model"]:checked'
|
|
1289
|
+
);
|
|
1290
|
+
if (checked.length > 2) {
|
|
1291
|
+
checkbox.checked = false;
|
|
1292
|
+
alert('You can select up to 2 AI models.');
|
|
1293
|
+
}
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1208
1296
|
}
|
|
1209
1297
|
|
|
1210
1298
|
/**
|
|
@@ -1276,16 +1364,22 @@ class Menu {
|
|
|
1276
1364
|
document.getElementById('openai_auth_key').value =
|
|
1277
1365
|
constants.openAIAuthKey;
|
|
1278
1366
|
}
|
|
1367
|
+
if (typeof constants.emailAuthKey == 'string') {
|
|
1368
|
+
document.getElementById('email_auth_key').value = constants.emailAuthKey;
|
|
1369
|
+
}
|
|
1279
1370
|
if (typeof constants.geminiAuthKey == 'string') {
|
|
1280
1371
|
document.getElementById('gemini_auth_key').value =
|
|
1281
1372
|
constants.geminiAuthKey;
|
|
1282
1373
|
}
|
|
1374
|
+
if (typeof constants.claudeAuthKey == 'string') {
|
|
1375
|
+
document.getElementById('claude_auth_key').value =
|
|
1376
|
+
constants.claudeAuthKey;
|
|
1377
|
+
}
|
|
1283
1378
|
document.getElementById('skill_level').value = constants.skillLevel;
|
|
1284
1379
|
if (constants.skillLevelOther) {
|
|
1285
1380
|
document.getElementById('skill_level_other').value =
|
|
1286
1381
|
constants.skillLevelOther;
|
|
1287
1382
|
}
|
|
1288
|
-
document.getElementById('LLM_model').value = constants.LLMModel;
|
|
1289
1383
|
|
|
1290
1384
|
// aria mode
|
|
1291
1385
|
if (constants.ariaMode == 'assertive') {
|
|
@@ -1295,44 +1389,18 @@ class Menu {
|
|
|
1295
1389
|
document.getElementById('aria_mode_polite').checked = true;
|
|
1296
1390
|
document.getElementById('aria_mode_assertive').checked = false;
|
|
1297
1391
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
document
|
|
1301
|
-
|
|
1302
|
-
.classList.remove('hidden');
|
|
1303
|
-
document
|
|
1304
|
-
.getElementById('gemini_auth_key_container')
|
|
1305
|
-
.classList.add('hidden');
|
|
1306
|
-
} else if (constants.LLMModel == 'gemini') {
|
|
1307
|
-
document
|
|
1308
|
-
.getElementById('openai_auth_key_container')
|
|
1309
|
-
.classList.add('hidden');
|
|
1310
|
-
document
|
|
1311
|
-
.getElementById('gemini_auth_key_container')
|
|
1312
|
-
.classList.remove('hidden');
|
|
1313
|
-
} else if (constants.LLMModel == 'multi') {
|
|
1314
|
-
// multi LLM mode
|
|
1315
|
-
document
|
|
1316
|
-
.getElementById('openai_auth_key_container')
|
|
1317
|
-
.classList.remove('hidden');
|
|
1318
|
-
document
|
|
1319
|
-
.getElementById('gemini_auth_key_container')
|
|
1320
|
-
.classList.remove('hidden');
|
|
1321
|
-
document
|
|
1322
|
-
.getElementById('openai_multi_container')
|
|
1323
|
-
.classList.remove('hidden');
|
|
1392
|
+
|
|
1393
|
+
for (let model in constants.LLMModels) {
|
|
1394
|
+
document.getElementById(`LLM_model_${model}`).checked = true;
|
|
1395
|
+
|
|
1324
1396
|
document
|
|
1325
|
-
.getElementById(
|
|
1397
|
+
.getElementById(`${model}_auth_key_container`)
|
|
1326
1398
|
.classList.remove('hidden');
|
|
1327
|
-
document.getElementById('openai_multi').checked = false;
|
|
1328
|
-
if (constants.LLMOpenAiMulti) {
|
|
1329
|
-
document.getElementById('openai_multi').checked = true;
|
|
1330
|
-
}
|
|
1331
|
-
document.getElementById('gemini_multi').checked = false;
|
|
1332
|
-
if (constants.LLMGeminiMulti) {
|
|
1333
|
-
document.getElementById('gemini_multi').checked = true;
|
|
1334
|
-
}
|
|
1335
1399
|
}
|
|
1400
|
+
document
|
|
1401
|
+
.getElementById(`claude_auth_key_container`)
|
|
1402
|
+
.classList.add('hidden');
|
|
1403
|
+
|
|
1336
1404
|
// skill level other
|
|
1337
1405
|
if (constants.skillLevel == 'other') {
|
|
1338
1406
|
document
|
|
@@ -1368,10 +1436,22 @@ class Menu {
|
|
|
1368
1436
|
|
|
1369
1437
|
constants.openAIAuthKey = document.getElementById('openai_auth_key').value;
|
|
1370
1438
|
constants.geminiAuthKey = document.getElementById('gemini_auth_key').value;
|
|
1439
|
+
constants.claudeAuthKey = document.getElementById('claude_auth_key').value;
|
|
1440
|
+
constants.emailAuthKey = document.getElementById('email_auth_key').value;
|
|
1371
1441
|
constants.skillLevel = document.getElementById('skill_level').value;
|
|
1372
1442
|
constants.skillLevelOther =
|
|
1373
1443
|
document.getElementById('skill_level_other').value;
|
|
1374
|
-
constants.LLMModel = document.getElementById('LLM_model').value;
|
|
1444
|
+
// constants.LLMModel = document.getElementById('LLM_model').value;
|
|
1445
|
+
|
|
1446
|
+
const llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
1447
|
+
llmCheckboxes.forEach((checkbox) => {
|
|
1448
|
+
if (checkbox.checked) {
|
|
1449
|
+
constants.LLMModels[checkbox.value] = true;
|
|
1450
|
+
} else {
|
|
1451
|
+
delete constants.LLMModels[checkbox.value];
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1375
1455
|
constants.LLMPreferences = document.getElementById('LLM_preferences').value;
|
|
1376
1456
|
constants.LLMOpenAiMulti = document.getElementById('openai_multi').checked;
|
|
1377
1457
|
constants.LLMGeminiMulti = document.getElementById('gemini_multi').checked;
|
|
@@ -1394,6 +1474,41 @@ class Menu {
|
|
|
1394
1474
|
}
|
|
1395
1475
|
}
|
|
1396
1476
|
|
|
1477
|
+
VerifyEmail() {
|
|
1478
|
+
let email = document.getElementById('email_auth_key').value;
|
|
1479
|
+
if (email && email.indexOf('@') !== -1) {
|
|
1480
|
+
let url = `https://maidr-service.azurewebsites.net/api/send_email?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D`;
|
|
1481
|
+
|
|
1482
|
+
let requestJson = {
|
|
1483
|
+
email: email,
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
fetch(url, {
|
|
1487
|
+
method: 'POST',
|
|
1488
|
+
headers: {
|
|
1489
|
+
'Content-Type': 'application/json',
|
|
1490
|
+
Authentication: constants.emailAuthKey,
|
|
1491
|
+
},
|
|
1492
|
+
body: JSON.stringify(requestJson),
|
|
1493
|
+
})
|
|
1494
|
+
.then((response) => response.json())
|
|
1495
|
+
.then((data) => {
|
|
1496
|
+
if (data && data.success) {
|
|
1497
|
+
alert('Link sent to email address: ' + email);
|
|
1498
|
+
} else {
|
|
1499
|
+
console.log(data);
|
|
1500
|
+
alert(data.data);
|
|
1501
|
+
}
|
|
1502
|
+
})
|
|
1503
|
+
.catch((error) => {
|
|
1504
|
+
console.log(error);
|
|
1505
|
+
alert(error.data);
|
|
1506
|
+
});
|
|
1507
|
+
} else {
|
|
1508
|
+
alert('Please enter a valid email address.');
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1397
1512
|
/**
|
|
1398
1513
|
* Sets the aria attributes on the HTML elements in the menu
|
|
1399
1514
|
* @returns {void}
|
|
@@ -1475,14 +1590,16 @@ class Menu {
|
|
|
1475
1590
|
) {
|
|
1476
1591
|
shouldReset = true;
|
|
1477
1592
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1593
|
+
|
|
1594
|
+
// check if LLMModels have changed
|
|
1595
|
+
let llmCheckboxes = document.querySelectorAll('input[name="LLM_model"]');
|
|
1596
|
+
for (let i = 0; i < llmCheckboxes.length; i++) {
|
|
1597
|
+
if (
|
|
1598
|
+
!shouldReset &&
|
|
1599
|
+
constants.LLMModels[llmCheckboxes[i].value] != llmCheckboxes[i].checked
|
|
1600
|
+
) {
|
|
1601
|
+
shouldReset = true;
|
|
1602
|
+
}
|
|
1486
1603
|
}
|
|
1487
1604
|
|
|
1488
1605
|
return shouldReset;
|
|
@@ -1501,10 +1618,11 @@ class Menu {
|
|
|
1501
1618
|
localStorage.setItem('settings_data', JSON.stringify(data));
|
|
1502
1619
|
|
|
1503
1620
|
// also save to tracking if we're doing that
|
|
1504
|
-
if (constants.
|
|
1621
|
+
if (constants.canTrack) {
|
|
1505
1622
|
// but not auth keys
|
|
1506
1623
|
data.openAIAuthKey = 'hidden';
|
|
1507
1624
|
data.geminiAuthKey = 'hidden';
|
|
1625
|
+
data.claudeAuthKey = 'hidden';
|
|
1508
1626
|
// and need a timestamp
|
|
1509
1627
|
data.timestamp = new Date().toISOString();
|
|
1510
1628
|
tracker.SetData('settings', data);
|
|
@@ -1517,9 +1635,10 @@ class Menu {
|
|
|
1517
1635
|
let data = JSON.parse(localStorage.getItem('settings_data'));
|
|
1518
1636
|
if (data) {
|
|
1519
1637
|
for (let i = 0; i < constants.userSettingsKeys.length; i++) {
|
|
1520
|
-
constants
|
|
1521
|
-
|
|
1522
|
-
constants[
|
|
1638
|
+
const key = constants.userSettingsKeys[i];
|
|
1639
|
+
if (key in data) {
|
|
1640
|
+
constants[key] = data[key];
|
|
1641
|
+
}
|
|
1523
1642
|
}
|
|
1524
1643
|
}
|
|
1525
1644
|
this.PopulateData();
|
|
@@ -1541,11 +1660,9 @@ class ChatLLM {
|
|
|
1541
1660
|
if (constants.autoInitLLM) {
|
|
1542
1661
|
// only run if we have API keys set
|
|
1543
1662
|
if (
|
|
1544
|
-
(constants.
|
|
1545
|
-
(constants.
|
|
1546
|
-
(constants.
|
|
1547
|
-
constants.openAIAuthKey &&
|
|
1548
|
-
constants.geminiAuthKey)
|
|
1663
|
+
('gemini' in constants.LLMModels && constants.geminiAuthKey) ||
|
|
1664
|
+
('openai' in constants.LLMModels && constants.openAIAuthKey) ||
|
|
1665
|
+
('claude' in constants.LLMModels && constants.claudeAuthKey)
|
|
1549
1666
|
) {
|
|
1550
1667
|
this.InitChatMessage();
|
|
1551
1668
|
}
|
|
@@ -1686,6 +1803,13 @@ class ChatLLM {
|
|
|
1686
1803
|
document.getElementById('openai_auth_key').value = '';
|
|
1687
1804
|
},
|
|
1688
1805
|
]);
|
|
1806
|
+
constants.events.push([
|
|
1807
|
+
document.getElementById('delete_email_key'),
|
|
1808
|
+
'click',
|
|
1809
|
+
function (e) {
|
|
1810
|
+
document.getElementById('email_auth_key').value = '';
|
|
1811
|
+
},
|
|
1812
|
+
]);
|
|
1689
1813
|
constants.events.push([
|
|
1690
1814
|
document.getElementById('delete_gemini_key'),
|
|
1691
1815
|
'click',
|
|
@@ -1853,7 +1977,7 @@ class ChatLLM {
|
|
|
1853
1977
|
|
|
1854
1978
|
// 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
|
|
1855
1979
|
if (
|
|
1856
|
-
(this.firstOpen ||
|
|
1980
|
+
(this.firstOpen || 'gemini' in constants.LLMModels) &&
|
|
1857
1981
|
!firsttime &&
|
|
1858
1982
|
constants.verboseText.length > 0
|
|
1859
1983
|
) {
|
|
@@ -1871,17 +1995,36 @@ class ChatLLM {
|
|
|
1871
1995
|
this.WaitingSound(true);
|
|
1872
1996
|
}
|
|
1873
1997
|
|
|
1874
|
-
if (
|
|
1998
|
+
if ('openai' in constants.LLMModels) {
|
|
1875
1999
|
if (firsttime) {
|
|
1876
2000
|
img = await this.ConvertSVGtoJPG(singleMaidr.id, 'openai');
|
|
1877
2001
|
}
|
|
1878
|
-
|
|
2002
|
+
if (constants.openAIAuthKey) {
|
|
2003
|
+
chatLLM.OpenAIPrompt(text, img);
|
|
2004
|
+
} else {
|
|
2005
|
+
chatLLM.OpenAIPromptAPI(text, img);
|
|
2006
|
+
}
|
|
1879
2007
|
}
|
|
1880
|
-
if (
|
|
2008
|
+
if ('gemini' in constants.LLMModels) {
|
|
1881
2009
|
if (firsttime) {
|
|
1882
2010
|
img = await this.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
|
|
1883
2011
|
}
|
|
1884
|
-
|
|
2012
|
+
if (constants.geminiAuthKey) {
|
|
2013
|
+
chatLLM.GeminiPrompt(text, img);
|
|
2014
|
+
} else {
|
|
2015
|
+
chatLLM.GeminiPromptAPI(text, img);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
if ('claude' in constants.LLMModels) {
|
|
2020
|
+
if (firsttime) {
|
|
2021
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, 'claude');
|
|
2022
|
+
}
|
|
2023
|
+
if (constants.claudeAuthKey) {
|
|
2024
|
+
chatLLM.ClaudePrompt(text, img);
|
|
2025
|
+
} else {
|
|
2026
|
+
chatLLM.ClaudePromptAPI(text, img);
|
|
2027
|
+
}
|
|
1885
2028
|
}
|
|
1886
2029
|
}
|
|
1887
2030
|
|
|
@@ -1969,7 +2112,7 @@ class ChatLLM {
|
|
|
1969
2112
|
}
|
|
1970
2113
|
|
|
1971
2114
|
InitChatMessage() {
|
|
1972
|
-
// get name from resource
|
|
2115
|
+
// get name from resource]
|
|
1973
2116
|
let LLMName = resources.GetString(constants.LLMModel);
|
|
1974
2117
|
this.firstTime = false;
|
|
1975
2118
|
this.DisplayChatMessage(LLMName, resources.GetString('processing'), true);
|
|
@@ -1984,7 +2127,6 @@ class ChatLLM {
|
|
|
1984
2127
|
*/
|
|
1985
2128
|
ProcessLLMResponse(data, model) {
|
|
1986
2129
|
chatLLM.WaitingSound(false);
|
|
1987
|
-
//console.log('LLM response: ', data);
|
|
1988
2130
|
let text = '';
|
|
1989
2131
|
let LLMName = resources.GetString(model);
|
|
1990
2132
|
|
|
@@ -2018,9 +2160,20 @@ class ChatLLM {
|
|
|
2018
2160
|
// todo: display actual response
|
|
2019
2161
|
}
|
|
2020
2162
|
}
|
|
2163
|
+
if (model == 'claude') {
|
|
2164
|
+
console.log('Claude response: ', data);
|
|
2165
|
+
if (data.text()) {
|
|
2166
|
+
text = data.text();
|
|
2167
|
+
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2168
|
+
}
|
|
2169
|
+
if (data.error) {
|
|
2170
|
+
chatLLM.DisplayChatMessage(LLMName, 'Error processing request.', true);
|
|
2171
|
+
chatLLM.WaitingSound(false);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2021
2174
|
|
|
2022
2175
|
// if we're tracking, log the data
|
|
2023
|
-
if (constants.
|
|
2176
|
+
if (constants.canTrack) {
|
|
2024
2177
|
let chatHist = chatLLM.CopyChatHistory();
|
|
2025
2178
|
tracker.SetData('ChatHistory', chatHist);
|
|
2026
2179
|
}
|
|
@@ -2086,6 +2239,96 @@ class ChatLLM {
|
|
|
2086
2239
|
return responseText;
|
|
2087
2240
|
}
|
|
2088
2241
|
|
|
2242
|
+
ClaudeJson(text, img = null) {
|
|
2243
|
+
const anthropicVersion = 'vertex-2023-10-16';
|
|
2244
|
+
const maxTokens = 256;
|
|
2245
|
+
|
|
2246
|
+
const payload = {
|
|
2247
|
+
anthropic_version: anthropicVersion,
|
|
2248
|
+
max_tokens: maxTokens,
|
|
2249
|
+
messages: [],
|
|
2250
|
+
};
|
|
2251
|
+
|
|
2252
|
+
// Construct the user message object
|
|
2253
|
+
const userMessage = {
|
|
2254
|
+
role: 'user',
|
|
2255
|
+
content: [],
|
|
2256
|
+
};
|
|
2257
|
+
|
|
2258
|
+
// Add the image content if provided
|
|
2259
|
+
if (img) {
|
|
2260
|
+
userMessage.content.push(
|
|
2261
|
+
{
|
|
2262
|
+
type: 'image',
|
|
2263
|
+
source: {
|
|
2264
|
+
type: 'base64',
|
|
2265
|
+
media_type: 'image/jpeg', // Update if other formats are supported
|
|
2266
|
+
data: img,
|
|
2267
|
+
},
|
|
2268
|
+
},
|
|
2269
|
+
{
|
|
2270
|
+
type: 'text',
|
|
2271
|
+
text: text,
|
|
2272
|
+
}
|
|
2273
|
+
);
|
|
2274
|
+
} else {
|
|
2275
|
+
// Add only the text content if no image is provided
|
|
2276
|
+
userMessage.content.push({
|
|
2277
|
+
type: 'text',
|
|
2278
|
+
text: text,
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
// Add the user message to the messages array
|
|
2283
|
+
payload.messages.push(userMessage);
|
|
2284
|
+
|
|
2285
|
+
return payload;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
ClaudePromptAPI(text, imgBase64 = null) {
|
|
2289
|
+
console.log('Claude prompt API');
|
|
2290
|
+
let url =
|
|
2291
|
+
'https://maidr-service.azurewebsites.net/api/claude?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D';
|
|
2292
|
+
|
|
2293
|
+
// Create the prompt
|
|
2294
|
+
let prompt = constants.LLMSystemMessage;
|
|
2295
|
+
if (constants.LLMPreferences) {
|
|
2296
|
+
prompt += constants.LLMPreferences;
|
|
2297
|
+
}
|
|
2298
|
+
prompt += '\n\n' + text; // Use the text parameter as the prompt
|
|
2299
|
+
|
|
2300
|
+
if (imgBase64 == null) {
|
|
2301
|
+
imgBase64 = constants.LLMImage;
|
|
2302
|
+
} else {
|
|
2303
|
+
constants.LLMImage = imgBase64;
|
|
2304
|
+
}
|
|
2305
|
+
constants.LLMImage = imgBase64;
|
|
2306
|
+
|
|
2307
|
+
let requestJson = chatLLM.ClaudeJson(prompt, imgBase64);
|
|
2308
|
+
|
|
2309
|
+
fetch(url, {
|
|
2310
|
+
method: 'POST',
|
|
2311
|
+
headers: {
|
|
2312
|
+
'Content-Type': 'application/json',
|
|
2313
|
+
Authentication: constants.emailAuthKey,
|
|
2314
|
+
},
|
|
2315
|
+
body: JSON.stringify(requestJson),
|
|
2316
|
+
})
|
|
2317
|
+
.then((response) => response.json())
|
|
2318
|
+
.then((data) => {
|
|
2319
|
+
data.text = function () {
|
|
2320
|
+
return data.content[0].text;
|
|
2321
|
+
};
|
|
2322
|
+
chatLLM.ProcessLLMResponse(data, 'claude');
|
|
2323
|
+
})
|
|
2324
|
+
.catch((error) => {
|
|
2325
|
+
chatLLM.WaitingSound(false);
|
|
2326
|
+
console.error('Error:', error);
|
|
2327
|
+
chatLLM.DisplayChatMessage('Claude', 'Error processing request.', true);
|
|
2328
|
+
// also todo: handle errors somehow
|
|
2329
|
+
});
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2089
2332
|
/**
|
|
2090
2333
|
* Gets running prompt info, appends the latest request, and packages it into a JSON object for the LLM.
|
|
2091
2334
|
* @function
|
|
@@ -2119,6 +2362,35 @@ class ChatLLM {
|
|
|
2119
2362
|
// also todo: handle errors somehow
|
|
2120
2363
|
});
|
|
2121
2364
|
}
|
|
2365
|
+
|
|
2366
|
+
OpenAIPromptAPI(text, img = null) {
|
|
2367
|
+
// request init
|
|
2368
|
+
let url =
|
|
2369
|
+
'https://maidr-service.azurewebsites.net/api/openai?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D';
|
|
2370
|
+
let auth = constants.openAIAuthKey;
|
|
2371
|
+
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2372
|
+
console.log('LLM request: ', requestJson);
|
|
2373
|
+
|
|
2374
|
+
fetch(url, {
|
|
2375
|
+
method: 'POST',
|
|
2376
|
+
headers: {
|
|
2377
|
+
'Content-Type': 'application/json',
|
|
2378
|
+
Authentication: constants.emailAuthKey,
|
|
2379
|
+
},
|
|
2380
|
+
body: JSON.stringify(requestJson),
|
|
2381
|
+
})
|
|
2382
|
+
.then((response) => response.json())
|
|
2383
|
+
.then((data) => {
|
|
2384
|
+
chatLLM.ProcessLLMResponse(data, 'openai');
|
|
2385
|
+
})
|
|
2386
|
+
.catch((error) => {
|
|
2387
|
+
chatLLM.WaitingSound(false);
|
|
2388
|
+
console.error('Error:', error);
|
|
2389
|
+
chatLLM.DisplayChatMessage('OpenAI', 'Error processing request.', true);
|
|
2390
|
+
// also todo: handle errors somehow
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2122
2394
|
OpenAIJson(text, img = null) {
|
|
2123
2395
|
let sysMessage = constants.LLMSystemMessage;
|
|
2124
2396
|
let backupMessage =
|
|
@@ -2167,6 +2439,110 @@ class ChatLLM {
|
|
|
2167
2439
|
return this.requestJson;
|
|
2168
2440
|
}
|
|
2169
2441
|
|
|
2442
|
+
GeminiJson(text, img = null) {
|
|
2443
|
+
let sysMessage = constants.LLMSystemMessage;
|
|
2444
|
+
let backupMessage =
|
|
2445
|
+
'Describe ' + singleMaidr.type + ' charts to a blind person';
|
|
2446
|
+
|
|
2447
|
+
let payload = {
|
|
2448
|
+
generationConfig: {},
|
|
2449
|
+
safetySettings: [],
|
|
2450
|
+
contents: [],
|
|
2451
|
+
};
|
|
2452
|
+
|
|
2453
|
+
// System message as the initial "role" and "text" content for context
|
|
2454
|
+
let sysContent = {
|
|
2455
|
+
role: 'user',
|
|
2456
|
+
parts: [
|
|
2457
|
+
{
|
|
2458
|
+
text: sysMessage || backupMessage, // Fallback if sysMessage is unavailable
|
|
2459
|
+
},
|
|
2460
|
+
],
|
|
2461
|
+
};
|
|
2462
|
+
|
|
2463
|
+
// Add preferences if available
|
|
2464
|
+
if (constants.LLMPreferences) {
|
|
2465
|
+
sysContent.parts.push({
|
|
2466
|
+
text: constants.LLMPreferences,
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
payload.contents.push(sysContent);
|
|
2471
|
+
|
|
2472
|
+
// Add user input content, including image if available
|
|
2473
|
+
let userContent = {
|
|
2474
|
+
role: 'user',
|
|
2475
|
+
parts: [],
|
|
2476
|
+
};
|
|
2477
|
+
|
|
2478
|
+
if (img) {
|
|
2479
|
+
// If there’s an image, add both text and image data
|
|
2480
|
+
userContent.parts.push(
|
|
2481
|
+
{
|
|
2482
|
+
text: text,
|
|
2483
|
+
},
|
|
2484
|
+
{
|
|
2485
|
+
inlineData: {
|
|
2486
|
+
data: img, // Expecting base64-encoded image data
|
|
2487
|
+
mimeType: 'image/png', // Adjust if different image formats are possible
|
|
2488
|
+
},
|
|
2489
|
+
}
|
|
2490
|
+
);
|
|
2491
|
+
} else {
|
|
2492
|
+
// If no image, only add the text
|
|
2493
|
+
userContent.parts.push({
|
|
2494
|
+
text: text,
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// Add user content to the contents array
|
|
2499
|
+
payload.contents.push(userContent);
|
|
2500
|
+
|
|
2501
|
+
return payload;
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
async GeminiPromptAPI(text, imgBase64 = null) {
|
|
2505
|
+
let url =
|
|
2506
|
+
'https://maidr-service.azurewebsites.net/api/gemini?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D';
|
|
2507
|
+
|
|
2508
|
+
// Create the prompt
|
|
2509
|
+
let prompt = constants.LLMSystemMessage;
|
|
2510
|
+
if (constants.LLMPreferences) {
|
|
2511
|
+
prompt += constants.LLMPreferences;
|
|
2512
|
+
}
|
|
2513
|
+
prompt += '\n\n' + text; // Use the text parameter as the prompt
|
|
2514
|
+
|
|
2515
|
+
if (imgBase64 == null) {
|
|
2516
|
+
imgBase64 = constants.LLMImage;
|
|
2517
|
+
} else {
|
|
2518
|
+
constants.LLMImage = imgBase64;
|
|
2519
|
+
}
|
|
2520
|
+
constants.LLMImage = imgBase64;
|
|
2521
|
+
|
|
2522
|
+
let requestJson = chatLLM.GeminiJson(prompt, imgBase64);
|
|
2523
|
+
|
|
2524
|
+
const response = await fetch(url, {
|
|
2525
|
+
method: 'POST',
|
|
2526
|
+
headers: {
|
|
2527
|
+
'Content-Type': 'application/json',
|
|
2528
|
+
Authentication: constants.emailAuthKey,
|
|
2529
|
+
},
|
|
2530
|
+
body: JSON.stringify(requestJson),
|
|
2531
|
+
});
|
|
2532
|
+
if (response.ok) {
|
|
2533
|
+
const responseJson = await response.json();
|
|
2534
|
+
responseJson.text = () => {
|
|
2535
|
+
return responseJson.candidates[0].content.parts[0].text;
|
|
2536
|
+
};
|
|
2537
|
+
chatLLM.ProcessLLMResponse(responseJson, 'gemini');
|
|
2538
|
+
} else {
|
|
2539
|
+
chatLLM.WaitingSound(false);
|
|
2540
|
+
console.error('Error:', error);
|
|
2541
|
+
chatLLM.DisplayChatMessage('OpenAI', 'Error processing request.', true);
|
|
2542
|
+
// also todo: handle errors somehow
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2170
2546
|
async GeminiPrompt(text, imgBase64 = null) {
|
|
2171
2547
|
// https://ai.google.dev/docs/gemini_api_overview#node.js
|
|
2172
2548
|
try {
|
|
@@ -2366,7 +2742,7 @@ class ChatLLM {
|
|
|
2366
2742
|
var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
|
|
2367
2743
|
if (model == 'openai') {
|
|
2368
2744
|
resolve(jpegData);
|
|
2369
|
-
} else if (model == 'gemini') {
|
|
2745
|
+
} else if (model == 'gemini' || model == 'claude') {
|
|
2370
2746
|
let base64Data = jpegData.split(',')[1];
|
|
2371
2747
|
resolve(base64Data);
|
|
2372
2748
|
//resolve(jpegData);
|
|
@@ -2716,9 +3092,13 @@ class Helper {
|
|
|
2716
3092
|
* @class
|
|
2717
3093
|
*/
|
|
2718
3094
|
class Tracker {
|
|
3095
|
+
// URL
|
|
3096
|
+
logUrl =
|
|
3097
|
+
'https://maidr-service.azurewebsites.net/api/log?code=I8Aa2PlPspjQ8Hks0QzGyszP8_i2-XJ3bq7Xh8-ykEe4AzFuYn_QWA%3D%3D'; // TODO Replace
|
|
3098
|
+
isLocal = false;
|
|
3099
|
+
|
|
2719
3100
|
constructor() {
|
|
2720
3101
|
this.DataSetup();
|
|
2721
|
-
constants.isTracking = true;
|
|
2722
3102
|
}
|
|
2723
3103
|
|
|
2724
3104
|
/**
|
|
@@ -2726,14 +3106,14 @@ class Tracker {
|
|
|
2726
3106
|
*/
|
|
2727
3107
|
DataSetup() {
|
|
2728
3108
|
let prevData = this.GetTrackerData();
|
|
2729
|
-
if (prevData) {
|
|
2730
|
-
// good to go already, do nothing, but make sure we have our containers
|
|
2731
|
-
} else {
|
|
3109
|
+
if (!this.isLocal || !prevData) {
|
|
2732
3110
|
let data = {};
|
|
2733
3111
|
data.userAgent = Object.assign(navigator.userAgent);
|
|
2734
3112
|
data.vendor = Object.assign(navigator.vendor);
|
|
2735
3113
|
data.language = Object.assign(navigator.language);
|
|
2736
3114
|
data.platform = Object.assign(navigator.platform);
|
|
3115
|
+
data.geolocation = Object.assign(navigator.geolocation);
|
|
3116
|
+
data.log_type = 'system_data';
|
|
2737
3117
|
data.events = [];
|
|
2738
3118
|
data.settings = [];
|
|
2739
3119
|
|
|
@@ -2758,8 +3138,33 @@ class Tracker {
|
|
|
2758
3138
|
* Saves the tracker data to local storage.
|
|
2759
3139
|
* @param {Object} data - The data to be saved.
|
|
2760
3140
|
*/
|
|
2761
|
-
SaveTrackerData(data) {
|
|
2762
|
-
|
|
3141
|
+
async SaveTrackerData(data) {
|
|
3142
|
+
console.log('about to save data', data);
|
|
3143
|
+
if (this.isLocal) {
|
|
3144
|
+
localStorage.setItem(constants.project_id, JSON.stringify(data));
|
|
3145
|
+
} else {
|
|
3146
|
+
// test this first
|
|
3147
|
+
try {
|
|
3148
|
+
const response = await fetch(this.logUrl, {
|
|
3149
|
+
method: 'POST',
|
|
3150
|
+
headers: {
|
|
3151
|
+
'Content-Type': 'application/json',
|
|
3152
|
+
},
|
|
3153
|
+
body: JSON.stringify(data),
|
|
3154
|
+
});
|
|
3155
|
+
|
|
3156
|
+
if (!response.ok) {
|
|
3157
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
const result = await response.json();
|
|
3161
|
+
console.log('Data saved successfully:', result);
|
|
3162
|
+
return result;
|
|
3163
|
+
} catch (error) {
|
|
3164
|
+
console.error('Error saving data:', error);
|
|
3165
|
+
return null;
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
2763
3168
|
}
|
|
2764
3169
|
|
|
2765
3170
|
/**
|
|
@@ -2792,6 +3197,10 @@ class Tracker {
|
|
|
2792
3197
|
// don't store their auth keys
|
|
2793
3198
|
settings.openAIAuthKey = 'hidden';
|
|
2794
3199
|
settings.geminiAuthKey = 'hidden';
|
|
3200
|
+
if (constants.emailAuthKey) {
|
|
3201
|
+
settings.username = constants.emailAuthKey;
|
|
3202
|
+
}
|
|
3203
|
+
settings;
|
|
2795
3204
|
this.SetData('settings', settings);
|
|
2796
3205
|
}
|
|
2797
3206
|
}
|
|
@@ -2810,6 +3219,9 @@ class Tracker {
|
|
|
2810
3219
|
eventToLog.altKey = Object.assign(e.altKey);
|
|
2811
3220
|
eventToLog.ctrlKey = Object.assign(e.ctrlKey);
|
|
2812
3221
|
eventToLog.shiftKey = Object.assign(e.shiftKey);
|
|
3222
|
+
if (constants.emailAuthKey) {
|
|
3223
|
+
eventToLog.username = Object.assign(constants.emailAuthKey);
|
|
3224
|
+
}
|
|
2813
3225
|
if (e.path) {
|
|
2814
3226
|
eventToLog.focus = Object.assign(e.path[0].tagName);
|
|
2815
3227
|
}
|
|
@@ -3003,18 +3415,29 @@ class Tracker {
|
|
|
3003
3415
|
//console.log('logged an event');
|
|
3004
3416
|
}
|
|
3005
3417
|
|
|
3418
|
+
/**
|
|
3419
|
+
* Saves data to the server using a POST request.
|
|
3420
|
+
* @param {Object} logData - The data to be saved.
|
|
3421
|
+
* @returns {Promise<Object>} The result of the save operation.
|
|
3422
|
+
*/
|
|
3423
|
+
|
|
3006
3424
|
SetData(key, value) {
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
data[key]
|
|
3425
|
+
if (this.isLocal) {
|
|
3426
|
+
let data = this.GetTrackerData();
|
|
3427
|
+
let arrayKeys = ['events', 'ChatHistory', 'settings'];
|
|
3428
|
+
if (!arrayKeys.includes(key)) {
|
|
3429
|
+
data[key] = value;
|
|
3430
|
+
} else {
|
|
3431
|
+
if (!data[key]) {
|
|
3432
|
+
data[key] = [];
|
|
3433
|
+
}
|
|
3434
|
+
data[key].push(value);
|
|
3014
3435
|
}
|
|
3015
|
-
|
|
3436
|
+
this.SaveTrackerData(data);
|
|
3437
|
+
} else {
|
|
3438
|
+
value['log_type'] = key;
|
|
3439
|
+
this.SaveTrackerData(value);
|
|
3016
3440
|
}
|
|
3017
|
-
this.SaveTrackerData(data);
|
|
3018
3441
|
}
|
|
3019
3442
|
|
|
3020
3443
|
/**
|
|
@@ -11121,47 +11544,6 @@ document.addEventListener('DOMContentLoaded', function (e) {
|
|
|
11121
11544
|
|
|
11122
11545
|
// init components like alt text on just the first chart
|
|
11123
11546
|
CreateChartComponents(firstMaidr, true);
|
|
11124
|
-
|
|
11125
|
-
// events etc for user study page
|
|
11126
|
-
// run tracker stuff only on user study page
|
|
11127
|
-
if (constants.canTrack) {
|
|
11128
|
-
window.tracker = new Tracker();
|
|
11129
|
-
if (document.getElementById('download_data_trigger')) {
|
|
11130
|
-
// we're on the intro page, so enable the download data button
|
|
11131
|
-
document
|
|
11132
|
-
.getElementById('download_data_trigger')
|
|
11133
|
-
.addEventListener('click', function (e) {
|
|
11134
|
-
tracker.DownloadTrackerData();
|
|
11135
|
-
});
|
|
11136
|
-
}
|
|
11137
|
-
|
|
11138
|
-
// general events
|
|
11139
|
-
document.addEventListener('keydown', function (e) {
|
|
11140
|
-
// reset tracking with Ctrl + F5 / command + F5, and Ctrl + Shift + R / command + Shift + R
|
|
11141
|
-
// future todo: this should probably be a button with a confirmation. This is dangerous
|
|
11142
|
-
if (
|
|
11143
|
-
(e.key == 'F5' && (constants.isMac ? e.metaKey : e.ctrlKey)) ||
|
|
11144
|
-
(e.key == 'R' && (constants.isMac ? e.metaKey : e.ctrlKey))
|
|
11145
|
-
) {
|
|
11146
|
-
e.preventDefault();
|
|
11147
|
-
tracker.Delete();
|
|
11148
|
-
location.reload(true);
|
|
11149
|
-
}
|
|
11150
|
-
|
|
11151
|
-
// main event tracker, built for individual charts
|
|
11152
|
-
if (e.key == 'F10') {
|
|
11153
|
-
tracker.DownloadTrackerData();
|
|
11154
|
-
} else {
|
|
11155
|
-
if (plot) {
|
|
11156
|
-
tracker.LogEvent(e);
|
|
11157
|
-
}
|
|
11158
|
-
}
|
|
11159
|
-
|
|
11160
|
-
// Stuff to only run if we're on a chart (so check if the info div exists?)
|
|
11161
|
-
if (document.getElementById('info')) {
|
|
11162
|
-
}
|
|
11163
|
-
});
|
|
11164
|
-
}
|
|
11165
11547
|
});
|
|
11166
11548
|
|
|
11167
11549
|
/**
|
|
@@ -11181,6 +11563,7 @@ function InitMaidr(thisMaidr) {
|
|
|
11181
11563
|
}
|
|
11182
11564
|
DestroyChartComponents(); // destroy so that we start fresh, in case we've created on the wrong chart
|
|
11183
11565
|
CreateChartComponents(singleMaidr);
|
|
11566
|
+
InitTracker();
|
|
11184
11567
|
|
|
11185
11568
|
window.menu = new Menu();
|
|
11186
11569
|
window.chatLLM = new ChatLLM();
|
|
@@ -11239,7 +11622,7 @@ function InitMaidr(thisMaidr) {
|
|
|
11239
11622
|
Array.isArray(singleMaidr.type) && singleMaidr.type.length > 1;
|
|
11240
11623
|
|
|
11241
11624
|
// Construct the final announceText string
|
|
11242
|
-
let announceText = `${plotTypeString} plot of ${title}: Use Arrows to navigate data points. ${
|
|
11625
|
+
let announceText = `${plotTypeString} plot of ${title}: Click to activate. Use Arrows to navigate data points. ${
|
|
11243
11626
|
isMultiLayered ? multiLayerInstruction : ' '
|
|
11244
11627
|
}Toggle B for Braille, T for Text, S for Sonification, and R for Review mode. Use H for Help.`;
|
|
11245
11628
|
|
|
@@ -11575,7 +11958,7 @@ function CreateChartComponents(thisMaidr, chartOnly = false) {
|
|
|
11575
11958
|
Array.isArray(thisMaidr.type) && thisMaidr.type.length > 1;
|
|
11576
11959
|
|
|
11577
11960
|
// Construct the final announceText string
|
|
11578
|
-
altText = `${plotTypeString} plot of ${title}: Use Arrows to navigate data points. ${
|
|
11961
|
+
altText = `${plotTypeString} plot of ${title}: Click to activate. Use Arrows to navigate data points. ${
|
|
11579
11962
|
isMultiLayered ? multiLayerInstruction : ' '
|
|
11580
11963
|
}Toggle B for Braille, T for Text, S for Sonification, and R for Review mode. Use H for Help.`;
|
|
11581
11964
|
}
|
|
@@ -11586,6 +11969,44 @@ function CreateChartComponents(thisMaidr, chartOnly = false) {
|
|
|
11586
11969
|
}
|
|
11587
11970
|
}
|
|
11588
11971
|
|
|
11972
|
+
function InitTracker() {
|
|
11973
|
+
// events etc for user study page
|
|
11974
|
+
// run tracker stuff only on user study page
|
|
11975
|
+
if (constants.canTrack) {
|
|
11976
|
+
window.tracker = new Tracker();
|
|
11977
|
+
if (document.getElementById('download_data_trigger')) {
|
|
11978
|
+
// we're on the intro page, so enable the download data button
|
|
11979
|
+
document
|
|
11980
|
+
.getElementById('download_data_trigger')
|
|
11981
|
+
.addEventListener('click', function (e) {
|
|
11982
|
+
tracker.DownloadTrackerData();
|
|
11983
|
+
});
|
|
11984
|
+
}
|
|
11985
|
+
|
|
11986
|
+
// general events
|
|
11987
|
+
document.addEventListener('keydown', function (e) {
|
|
11988
|
+
// reset tracking with Ctrl + F5 / command + F5, and Ctrl + Shift + R / command + Shift + R
|
|
11989
|
+
// future todo: this should probably be a button with a confirmation. This is dangerous
|
|
11990
|
+
if (
|
|
11991
|
+
(e.key == 'F5' && (constants.isMac ? e.metaKey : e.ctrlKey)) ||
|
|
11992
|
+
(e.key == 'R' && (constants.isMac ? e.metaKey : e.ctrlKey))
|
|
11993
|
+
) {
|
|
11994
|
+
e.preventDefault();
|
|
11995
|
+
tracker.Delete();
|
|
11996
|
+
location.reload(true);
|
|
11997
|
+
}
|
|
11998
|
+
|
|
11999
|
+
// main event tracker, built for individual charts
|
|
12000
|
+
if (e.key == 'F10') {
|
|
12001
|
+
tracker.DownloadTrackerData();
|
|
12002
|
+
} else {
|
|
12003
|
+
if (plot) {
|
|
12004
|
+
tracker.LogEvent(e);
|
|
12005
|
+
}
|
|
12006
|
+
}
|
|
12007
|
+
});
|
|
12008
|
+
}
|
|
12009
|
+
}
|
|
11589
12010
|
/**
|
|
11590
12011
|
* Removes all chart components from the DOM and resets related variables to null.
|
|
11591
12012
|
* @function
|