Spaces:
Running
Running
Update index.html
Browse files- index.html +84 -224
index.html
CHANGED
|
@@ -560,12 +560,27 @@
|
|
| 560 |
<!-- PDF.js library for PDF support -->
|
| 561 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
| 562 |
|
| 563 |
-
<!-- Mammoth library for Word document support -->
|
| 564 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.2/mammoth.browser.min.js"></script>
|
| 565 |
-
|
| 566 |
<script>
|
| 567 |
document.addEventListener('DOMContentLoaded', () => {
|
| 568 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
const apiKeyInput = document.getElementById('apiKey');
|
| 570 |
const saveKeyBtn = document.getElementById('saveKeyBtn');
|
| 571 |
const uploadBtn = document.getElementById('uploadBtn');
|
|
@@ -591,7 +606,7 @@
|
|
| 591 |
const readingProgress = document.getElementById('readingProgress');
|
| 592 |
const currentPositionMarker = document.getElementById('currentPositionMarker');
|
| 593 |
|
| 594 |
-
// New feature elements
|
| 595 |
const darkModeToggle = document.getElementById('darkModeToggle');
|
| 596 |
const addBookmarkBtn = document.getElementById('addBookmarkBtn');
|
| 597 |
const showBookmarksBtn = document.getElementById('showBookmarksBtn');
|
|
@@ -605,7 +620,7 @@
|
|
| 605 |
let wordsPerMinute = 150; // Average reading speed
|
| 606 |
let isBookmarkPanelOpen = false;
|
| 607 |
|
| 608 |
-
//
|
| 609 |
function formatFileSize(bytes) {
|
| 610 |
if (bytes === 0) return '0 Bytes';
|
| 611 |
const k = 1024;
|
|
@@ -614,32 +629,6 @@
|
|
| 614 |
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
| 615 |
}
|
| 616 |
|
| 617 |
-
function updateBookmarkCount() {
|
| 618 |
-
if (bookmarkCount) {
|
| 619 |
-
bookmarkCount.textContent = bookmarks.length.toString();
|
| 620 |
-
}
|
| 621 |
-
}
|
| 622 |
-
|
| 623 |
-
function removeBookmark(id) {
|
| 624 |
-
bookmarks = bookmarks.filter(b => b.id !== id);
|
| 625 |
-
localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
|
| 626 |
-
renderBookmarks();
|
| 627 |
-
updateBookmarkCount();
|
| 628 |
-
showToast('Bookmark removed', 'success', 1000);
|
| 629 |
-
}
|
| 630 |
-
|
| 631 |
-
// Voice preset functions (needed for onclick handlers)
|
| 632 |
-
window.voicePresets = {
|
| 633 |
-
loadPreset: function(id) {
|
| 634 |
-
console.log('Voice preset loading not yet implemented');
|
| 635 |
-
showToast('Voice presets feature coming soon', 'info');
|
| 636 |
-
},
|
| 637 |
-
deletePreset: function(id) {
|
| 638 |
-
console.log('Voice preset deletion not yet implemented');
|
| 639 |
-
showToast('Voice presets feature coming soon', 'info');
|
| 640 |
-
}
|
| 641 |
-
};
|
| 642 |
-
|
| 643 |
// Caching & Smart Processing System
|
| 644 |
class TTSCache {
|
| 645 |
constructor() {
|
|
@@ -1488,168 +1477,51 @@
|
|
| 1488 |
// Download functionality
|
| 1489 |
initDownloadFeature();
|
| 1490 |
|
| 1491 |
-
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
-
|
| 1495 |
-
|
| 1496 |
-
|
| 1497 |
-
|
| 1498 |
-
|
| 1499 |
-
|
| 1500 |
-
|
| 1501 |
-
|
| 1502 |
-
|
| 1503 |
-
|
| 1504 |
-
|
| 1505 |
-
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.worker.min.js';
|
| 1506 |
-
}
|
| 1507 |
-
|
| 1508 |
-
// Initialize AudioContext on user interaction
|
| 1509 |
-
document.addEventListener('click', initAudioContext, { once: true });
|
| 1510 |
-
|
| 1511 |
-
// API Key visibility toggle
|
| 1512 |
-
const toggleKeyVisibility = document.getElementById('toggleKeyVisibility');
|
| 1513 |
-
const eyeIcon = document.getElementById('eyeIcon');
|
| 1514 |
-
|
| 1515 |
-
if (toggleKeyVisibility && eyeIcon && apiKeyInput) {
|
| 1516 |
-
toggleKeyVisibility.addEventListener('click', () => {
|
| 1517 |
-
if (apiKeyInput.type === 'password') {
|
| 1518 |
-
apiKeyInput.type = 'text';
|
| 1519 |
-
eyeIcon.className = 'fas fa-eye-slash';
|
| 1520 |
-
} else {
|
| 1521 |
-
apiKeyInput.type = 'password';
|
| 1522 |
-
eyeIcon.className = 'fas fa-eye';
|
| 1523 |
-
}
|
| 1524 |
-
});
|
| 1525 |
-
}
|
| 1526 |
-
|
| 1527 |
-
// Dark mode initialization
|
| 1528 |
-
if (darkModeToggle) {
|
| 1529 |
-
initDarkMode();
|
| 1530 |
-
}
|
| 1531 |
-
|
| 1532 |
-
// Keyboard shortcuts
|
| 1533 |
-
initKeyboardShortcuts();
|
| 1534 |
-
|
| 1535 |
-
// Bookmark system
|
| 1536 |
-
if (addBookmarkBtn && showBookmarksBtn) {
|
| 1537 |
-
initBookmarkSystem();
|
| 1538 |
-
}
|
| 1539 |
-
|
| 1540 |
-
// Progress indicator
|
| 1541 |
-
if (progressContainer) {
|
| 1542 |
-
initProgressIndicator();
|
| 1543 |
-
}
|
| 1544 |
-
|
| 1545 |
-
// Download functionality
|
| 1546 |
-
if (downloadBtn) {
|
| 1547 |
-
initDownloadFeature();
|
| 1548 |
-
}
|
| 1549 |
-
|
| 1550 |
-
// Initialize Audio Library
|
| 1551 |
-
const openLibraryBtn = document.getElementById('openLibraryBtn');
|
| 1552 |
-
const closeAudioLibrary = document.getElementById('closeAudioLibrary');
|
| 1553 |
-
const saveToLibraryBtn = document.getElementById('saveToLibraryBtn');
|
| 1554 |
-
const clearLibraryBtn = document.getElementById('clearLibraryBtn');
|
| 1555 |
-
const exportLibraryBtn = document.getElementById('exportLibraryBtn');
|
| 1556 |
-
|
| 1557 |
-
if (openLibraryBtn) {
|
| 1558 |
-
openLibraryBtn.addEventListener('click', () => {
|
| 1559 |
-
const panel = document.getElementById('audioLibraryPanel');
|
| 1560 |
-
if (panel) panel.classList.add('open');
|
| 1561 |
-
});
|
| 1562 |
-
}
|
| 1563 |
-
|
| 1564 |
-
if (closeAudioLibrary) {
|
| 1565 |
-
closeAudioLibrary.addEventListener('click', () => {
|
| 1566 |
-
const panel = document.getElementById('audioLibraryPanel');
|
| 1567 |
-
if (panel) panel.classList.remove('open');
|
| 1568 |
-
});
|
| 1569 |
-
}
|
| 1570 |
-
|
| 1571 |
-
if (saveToLibraryBtn) {
|
| 1572 |
-
saveToLibraryBtn.addEventListener('click', saveToLibrary);
|
| 1573 |
-
}
|
| 1574 |
-
|
| 1575 |
-
if (clearLibraryBtn) {
|
| 1576 |
-
clearLibraryBtn.addEventListener('click', () => {
|
| 1577 |
-
if (confirm('Clear entire audio library? This cannot be undone.')) {
|
| 1578 |
-
audioLibrary.clearLibrary();
|
| 1579 |
-
showToast('Library cleared', 'success');
|
| 1580 |
-
}
|
| 1581 |
-
});
|
| 1582 |
-
}
|
| 1583 |
-
|
| 1584 |
-
if (exportLibraryBtn) {
|
| 1585 |
-
exportLibraryBtn.addEventListener('click', () => {
|
| 1586 |
-
audioLibrary.exportLibrary();
|
| 1587 |
-
});
|
| 1588 |
-
}
|
| 1589 |
-
|
| 1590 |
-
// Initialize Budget System
|
| 1591 |
-
const openBudgetBtn = document.getElementById('openBudgetBtn');
|
| 1592 |
-
const closeBudgetPanel = document.getElementById('closeBudgetPanel');
|
| 1593 |
-
const monthlyBudget = document.getElementById('monthlyBudget');
|
| 1594 |
-
const alertThreshold = document.getElementById('alertThreshold');
|
| 1595 |
-
|
| 1596 |
-
if (openBudgetBtn) {
|
| 1597 |
-
openBudgetBtn.addEventListener('click', () => {
|
| 1598 |
-
const panel = document.getElementById('costBudgetPanel');
|
| 1599 |
-
if (panel) {
|
| 1600 |
-
panel.classList.add('open');
|
| 1601 |
-
budgetManager.updateBudgetDisplay();
|
| 1602 |
-
}
|
| 1603 |
-
});
|
| 1604 |
-
}
|
| 1605 |
-
|
| 1606 |
-
if (closeBudgetPanel) {
|
| 1607 |
-
closeBudgetPanel.addEventListener('click', () => {
|
| 1608 |
-
const panel = document.getElementById('costBudgetPanel');
|
| 1609 |
-
if (panel) panel.classList.remove('open');
|
| 1610 |
-
});
|
| 1611 |
-
}
|
| 1612 |
-
|
| 1613 |
-
if (monthlyBudget) {
|
| 1614 |
-
monthlyBudget.addEventListener('change', (e) => {
|
| 1615 |
-
budgetManager.setMonthlyBudget(parseFloat(e.target.value) || 0);
|
| 1616 |
-
});
|
| 1617 |
-
}
|
| 1618 |
-
|
| 1619 |
-
if (alertThreshold) {
|
| 1620 |
-
alertThreshold.addEventListener('input', (e) => {
|
| 1621 |
-
budgetManager.setAlertThreshold(parseInt(e.target.value));
|
| 1622 |
-
const thresholdValue = document.getElementById('alertThresholdValue');
|
| 1623 |
-
if (thresholdValue) {
|
| 1624 |
-
thresholdValue.textContent = `${e.target.value}%`;
|
| 1625 |
-
}
|
| 1626 |
-
});
|
| 1627 |
-
}
|
| 1628 |
-
|
| 1629 |
-
// Initialize cache system
|
| 1630 |
-
if (typeof ttsCache !== 'undefined') {
|
| 1631 |
-
ttsCache.init();
|
| 1632 |
-
}
|
| 1633 |
-
|
| 1634 |
-
// Update library display
|
| 1635 |
-
if (typeof audioLibrary !== 'undefined') {
|
| 1636 |
-
audioLibrary.updateLibraryDisplay();
|
| 1637 |
-
}
|
| 1638 |
-
|
| 1639 |
-
// Update bookmark count
|
| 1640 |
-
updateBookmarkCount();
|
| 1641 |
-
|
| 1642 |
-
// Cost breakdown modal
|
| 1643 |
-
const showCostBreakdown = document.getElementById('showCostBreakdown');
|
| 1644 |
-
if (showCostBreakdown) {
|
| 1645 |
-
showCostBreakdown.addEventListener('click', showCostBreakdownModal);
|
| 1646 |
}
|
| 1647 |
-
|
| 1648 |
-
|
| 1649 |
-
|
| 1650 |
-
|
| 1651 |
-
}
|
| 1652 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1653 |
}
|
| 1654 |
|
| 1655 |
// Dark Mode Implementation
|
|
@@ -1918,6 +1790,9 @@
|
|
| 1918 |
showToast('Bookmark removed', 'success', 1000);
|
| 1919 |
}
|
| 1920 |
|
|
|
|
|
|
|
|
|
|
| 1921 |
function updateBookmarkCount() {
|
| 1922 |
bookmarkCount.textContent = bookmarks.length.toString();
|
| 1923 |
}
|
|
@@ -2105,7 +1980,7 @@
|
|
| 2105 |
}
|
| 2106 |
}
|
| 2107 |
|
| 2108 |
-
// Toast notifications
|
| 2109 |
function showToast(message, type = 'success', duration = 3000) {
|
| 2110 |
const toast = document.createElement('div');
|
| 2111 |
toast.className = `toast ${type}`;
|
|
@@ -2118,17 +1993,14 @@
|
|
| 2118 |
}, duration);
|
| 2119 |
}
|
| 2120 |
|
| 2121 |
-
// Add slideOut animation
|
| 2122 |
-
|
| 2123 |
-
|
| 2124 |
-
|
| 2125 |
-
style.textContent = '@keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }';
|
| 2126 |
-
document.head.appendChild(style);
|
| 2127 |
-
}
|
| 2128 |
|
| 2129 |
-
// API Key Management
|
| 2130 |
saveKeyBtn.addEventListener('click', async () => {
|
| 2131 |
-
const key = apiKeyInput.value.trim();
|
| 2132 |
if (key) {
|
| 2133 |
// Show loading state
|
| 2134 |
saveKeyBtn.innerHTML = '<div class="loading-spinner inline-block w-4 h-4 mr-2"></div>Validating...';
|
|
@@ -2310,7 +2182,10 @@
|
|
| 2310 |
const languageCode = languageSelect.value;
|
| 2311 |
|
| 2312 |
// Clean and validate API key
|
| 2313 |
-
const cleanApiKey = apiKey.trim();
|
|
|
|
|
|
|
|
|
|
| 2314 |
|
| 2315 |
// Method 1: Try with API key in header (preferred)
|
| 2316 |
let response;
|
|
@@ -2971,20 +2846,12 @@
|
|
| 2971 |
|
| 2972 |
// Word document reader (.doc/.docx)
|
| 2973 |
function readWordDocument(file) {
|
| 2974 |
-
// Check if mammoth library is available
|
| 2975 |
-
if (typeof mammoth === 'undefined') {
|
| 2976 |
-
showToast('Word document support not available. Mammoth library not loaded.', 'error');
|
| 2977 |
-
return;
|
| 2978 |
-
}
|
| 2979 |
-
|
| 2980 |
const reader = new FileReader();
|
| 2981 |
reader.onload = async (e) => {
|
| 2982 |
try {
|
| 2983 |
// Use mammoth to convert docx to text
|
| 2984 |
const result = await mammoth.extractRawText({arrayBuffer: e.target.result});
|
| 2985 |
setDocumentContent(result.value);
|
| 2986 |
-
showFileProgress(file.name, 'success');
|
| 2987 |
-
showToast(`Loaded Word document: ${formatFileSize(file.size)}`, 'success');
|
| 2988 |
|
| 2989 |
if (result.messages.length > 0) {
|
| 2990 |
console.warn('Word processing warnings:', result.messages);
|
|
@@ -2992,12 +2859,10 @@
|
|
| 2992 |
} catch (error) {
|
| 2993 |
console.error('Error reading Word document:', error);
|
| 2994 |
showToast('Error reading Word document. Please try saving as a different format.', 'error');
|
| 2995 |
-
showFileProgress(file.name, 'error');
|
| 2996 |
}
|
| 2997 |
};
|
| 2998 |
reader.onerror = () => {
|
| 2999 |
showToast('Error reading Word document', 'error');
|
| 3000 |
-
showFileProgress(file.name, 'error');
|
| 3001 |
};
|
| 3002 |
reader.readAsArrayBuffer(file);
|
| 3003 |
}
|
|
@@ -3458,17 +3323,12 @@
|
|
| 3458 |
return SmartTextProcessor.optimizeChunks(text, maxChunkSize);
|
| 3459 |
}
|
| 3460 |
|
| 3461 |
-
// Event listeners
|
| 3462 |
-
|
| 3463 |
-
|
| 3464 |
|
| 3465 |
-
// Initialize
|
| 3466 |
-
|
| 3467 |
-
document.addEventListener('DOMContentLoaded', init);
|
| 3468 |
-
} else {
|
| 3469 |
-
// DOM is already loaded
|
| 3470 |
-
init();
|
| 3471 |
-
}
|
| 3472 |
});
|
| 3473 |
</script>
|
| 3474 |
</body>
|
|
|
|
| 560 |
<!-- PDF.js library for PDF support -->
|
| 561 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script>
|
| 562 |
|
|
|
|
|
|
|
|
|
|
| 563 |
<script>
|
| 564 |
document.addEventListener('DOMContentLoaded', () => {
|
| 565 |
+
// Global error handler
|
| 566 |
+
window.addEventListener('error', (e) => {
|
| 567 |
+
console.error('Global error caught:', e.error);
|
| 568 |
+
console.error('Error stack:', e.error?.stack);
|
| 569 |
+
|
| 570 |
+
// Don't show toast for every error, just log them
|
| 571 |
+
if (e.error?.message?.includes('currentText') ||
|
| 572 |
+
e.error?.message?.includes('formatFileSize') ||
|
| 573 |
+
e.error?.message?.includes('apikey.trim')) {
|
| 574 |
+
console.error('Handled error:', e.error.message);
|
| 575 |
+
}
|
| 576 |
+
});
|
| 577 |
+
|
| 578 |
+
// Global unhandled promise rejection handler
|
| 579 |
+
window.addEventListener('unhandledrejection', (e) => {
|
| 580 |
+
console.error('Unhandled promise rejection:', e.reason);
|
| 581 |
+
e.preventDefault(); // Prevent default browser error logging
|
| 582 |
+
});
|
| 583 |
+
// Enhanced DOM Elements
|
| 584 |
const apiKeyInput = document.getElementById('apiKey');
|
| 585 |
const saveKeyBtn = document.getElementById('saveKeyBtn');
|
| 586 |
const uploadBtn = document.getElementById('uploadBtn');
|
|
|
|
| 606 |
const readingProgress = document.getElementById('readingProgress');
|
| 607 |
const currentPositionMarker = document.getElementById('currentPositionMarker');
|
| 608 |
|
| 609 |
+
// New feature elements
|
| 610 |
const darkModeToggle = document.getElementById('darkModeToggle');
|
| 611 |
const addBookmarkBtn = document.getElementById('addBookmarkBtn');
|
| 612 |
const showBookmarksBtn = document.getElementById('showBookmarksBtn');
|
|
|
|
| 620 |
let wordsPerMinute = 150; // Average reading speed
|
| 621 |
let isBookmarkPanelOpen = false;
|
| 622 |
|
| 623 |
+
// Utility function for file size formatting
|
| 624 |
function formatFileSize(bytes) {
|
| 625 |
if (bytes === 0) return '0 Bytes';
|
| 626 |
const k = 1024;
|
|
|
|
| 629 |
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
| 630 |
}
|
| 631 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 632 |
// Caching & Smart Processing System
|
| 633 |
class TTSCache {
|
| 634 |
constructor() {
|
|
|
|
| 1477 |
// Download functionality
|
| 1478 |
initDownloadFeature();
|
| 1479 |
|
| 1480 |
+
// Initialize Audio Library
|
| 1481 |
+
document.getElementById('openLibraryBtn').addEventListener('click', () => {
|
| 1482 |
+
document.getElementById('audioLibraryPanel').classList.add('open');
|
| 1483 |
+
});
|
| 1484 |
+
|
| 1485 |
+
document.getElementById('closeAudioLibrary').addEventListener('click', () => {
|
| 1486 |
+
document.getElementById('audioLibraryPanel').classList.remove('open');
|
| 1487 |
+
});
|
| 1488 |
+
|
| 1489 |
+
document.getElementById('saveToLibraryBtn').addEventListener('click', saveToLibrary);
|
| 1490 |
+
document.getElementById('clearLibraryBtn').addEventListener('click', () => {
|
| 1491 |
+
if (confirm('Clear entire audio library? This cannot be undone.')) {
|
| 1492 |
+
audioLibrary.clearLibrary();
|
| 1493 |
+
showToast('Library cleared', 'success');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1494 |
}
|
| 1495 |
+
});
|
| 1496 |
+
|
| 1497 |
+
document.getElementById('exportLibraryBtn').addEventListener('click', () => {
|
| 1498 |
+
audioLibrary.exportLibrary();
|
| 1499 |
+
});
|
| 1500 |
+
|
| 1501 |
+
// Initialize Budget System
|
| 1502 |
+
document.getElementById('openBudgetBtn').addEventListener('click', () => {
|
| 1503 |
+
document.getElementById('costBudgetPanel').classList.add('open');
|
| 1504 |
+
budgetManager.updateBudgetDisplay();
|
| 1505 |
+
});
|
| 1506 |
+
|
| 1507 |
+
document.getElementById('closeBudgetPanel').addEventListener('click', () => {
|
| 1508 |
+
document.getElementById('costBudgetPanel').classList.remove('open');
|
| 1509 |
+
});
|
| 1510 |
+
|
| 1511 |
+
document.getElementById('monthlyBudget').addEventListener('change', (e) => {
|
| 1512 |
+
budgetManager.setMonthlyBudget(parseFloat(e.target.value) || 0);
|
| 1513 |
+
});
|
| 1514 |
+
|
| 1515 |
+
document.getElementById('alertThreshold').addEventListener('input', (e) => {
|
| 1516 |
+
budgetManager.setAlertThreshold(parseInt(e.target.value));
|
| 1517 |
+
document.getElementById('alertThresholdValue').textContent = `${e.target.value}%`;
|
| 1518 |
+
});
|
| 1519 |
+
|
| 1520 |
+
// Initialize cache system
|
| 1521 |
+
ttsCache.init();
|
| 1522 |
+
|
| 1523 |
+
// Update library display
|
| 1524 |
+
audioLibrary.updateLibraryDisplay();
|
| 1525 |
}
|
| 1526 |
|
| 1527 |
// Dark Mode Implementation
|
|
|
|
| 1790 |
showToast('Bookmark removed', 'success', 1000);
|
| 1791 |
}
|
| 1792 |
|
| 1793 |
+
// Make removeBookmark globally accessible
|
| 1794 |
+
window.removeBookmark = removeBookmark;
|
| 1795 |
+
|
| 1796 |
function updateBookmarkCount() {
|
| 1797 |
bookmarkCount.textContent = bookmarks.length.toString();
|
| 1798 |
}
|
|
|
|
| 1980 |
}
|
| 1981 |
}
|
| 1982 |
|
| 1983 |
+
// Toast notifications
|
| 1984 |
function showToast(message, type = 'success', duration = 3000) {
|
| 1985 |
const toast = document.createElement('div');
|
| 1986 |
toast.className = `toast ${type}`;
|
|
|
|
| 1993 |
}, duration);
|
| 1994 |
}
|
| 1995 |
|
| 1996 |
+
// Add slideOut animation
|
| 1997 |
+
const style = document.createElement('style');
|
| 1998 |
+
style.textContent = '@keyframes slideOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(100%); opacity: 0; } }';
|
| 1999 |
+
document.head.appendChild(style);
|
|
|
|
|
|
|
|
|
|
| 2000 |
|
| 2001 |
+
// API Key Management
|
| 2002 |
saveKeyBtn.addEventListener('click', async () => {
|
| 2003 |
+
const key = apiKeyInput.value ? apiKeyInput.value.trim() : '';
|
| 2004 |
if (key) {
|
| 2005 |
// Show loading state
|
| 2006 |
saveKeyBtn.innerHTML = '<div class="loading-spinner inline-block w-4 h-4 mr-2"></div>Validating...';
|
|
|
|
| 2182 |
const languageCode = languageSelect.value;
|
| 2183 |
|
| 2184 |
// Clean and validate API key
|
| 2185 |
+
const cleanApiKey = apiKey && apiKey.trim ? apiKey.trim() : (apiKey || '');
|
| 2186 |
+
if (!cleanApiKey) {
|
| 2187 |
+
throw new Error('API key is empty or invalid');
|
| 2188 |
+
}
|
| 2189 |
|
| 2190 |
// Method 1: Try with API key in header (preferred)
|
| 2191 |
let response;
|
|
|
|
| 2846 |
|
| 2847 |
// Word document reader (.doc/.docx)
|
| 2848 |
function readWordDocument(file) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2849 |
const reader = new FileReader();
|
| 2850 |
reader.onload = async (e) => {
|
| 2851 |
try {
|
| 2852 |
// Use mammoth to convert docx to text
|
| 2853 |
const result = await mammoth.extractRawText({arrayBuffer: e.target.result});
|
| 2854 |
setDocumentContent(result.value);
|
|
|
|
|
|
|
| 2855 |
|
| 2856 |
if (result.messages.length > 0) {
|
| 2857 |
console.warn('Word processing warnings:', result.messages);
|
|
|
|
| 2859 |
} catch (error) {
|
| 2860 |
console.error('Error reading Word document:', error);
|
| 2861 |
showToast('Error reading Word document. Please try saving as a different format.', 'error');
|
|
|
|
| 2862 |
}
|
| 2863 |
};
|
| 2864 |
reader.onerror = () => {
|
| 2865 |
showToast('Error reading Word document', 'error');
|
|
|
|
| 2866 |
};
|
| 2867 |
reader.readAsArrayBuffer(file);
|
| 2868 |
}
|
|
|
|
| 3323 |
return SmartTextProcessor.optimizeChunks(text, maxChunkSize);
|
| 3324 |
}
|
| 3325 |
|
| 3326 |
+
// Event listeners
|
| 3327 |
+
refreshVoicesBtn.addEventListener('click', loadVoices);
|
| 3328 |
+
languageSelect.addEventListener('change', loadVoices);
|
| 3329 |
|
| 3330 |
+
// Initialize the application
|
| 3331 |
+
init();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3332 |
});
|
| 3333 |
</script>
|
| 3334 |
</body>
|