Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -167,10 +167,10 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
167 |
display: none;
|
168 |
flex-grow: 1;
|
169 |
overflow: hidden;
|
|
|
170 |
}
|
171 |
.tab-content.active {
|
172 |
display: flex;
|
173 |
-
flex-direction: column;
|
174 |
}
|
175 |
.main-content {
|
176 |
display: flex;
|
@@ -861,19 +861,31 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
861 |
<script>
|
862 |
// Tab switching functionality
|
863 |
function switchTab(event, tabName) {
|
|
|
|
|
|
|
864 |
// Hide all tabs
|
865 |
const tabs = document.querySelectorAll('.tab-content');
|
866 |
-
tabs.forEach(tab =>
|
|
|
|
|
|
|
867 |
|
868 |
// Remove active class from all buttons
|
869 |
const buttons = document.querySelectorAll('.tab-button');
|
870 |
buttons.forEach(btn => btn.classList.remove('active'));
|
871 |
|
872 |
// Show selected tab
|
873 |
-
document.getElementById(tabName)
|
|
|
|
|
|
|
|
|
874 |
|
875 |
// Add active class to clicked button
|
876 |
-
event.target
|
|
|
|
|
877 |
}
|
878 |
|
879 |
// Original voice chat variables and functions
|
@@ -882,16 +894,6 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
882 |
let webSearchEnabled = false;
|
883 |
let selectedLanguage = "";
|
884 |
let systemPrompt = "You are a helpful assistant. Respond in a friendly and professional manner.";
|
885 |
-
const audioOutput = document.getElementById('audio-output');
|
886 |
-
const startButton = document.getElementById('start-button');
|
887 |
-
const sendButton = document.getElementById('send-button');
|
888 |
-
const chatMessages = document.getElementById('chat-messages');
|
889 |
-
const statusDot = document.getElementById('status-dot');
|
890 |
-
const statusText = document.getElementById('status-text');
|
891 |
-
const searchToggle = document.getElementById('search-toggle');
|
892 |
-
const languageSelect = document.getElementById('language-select');
|
893 |
-
const systemPromptInput = document.getElementById('system-prompt');
|
894 |
-
const textInput = document.getElementById('text-input');
|
895 |
let audioLevel = 0;
|
896 |
let animationFrame;
|
897 |
let audioContext, analyser, audioSource;
|
@@ -905,35 +907,9 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
905 |
let isRealtimeRecording = false;
|
906 |
let realtimeStream = null;
|
907 |
|
908 |
-
// Web search toggle functionality
|
909 |
-
searchToggle.addEventListener('click', () => {
|
910 |
-
webSearchEnabled = !webSearchEnabled;
|
911 |
-
searchToggle.classList.toggle('active', webSearchEnabled);
|
912 |
-
console.log('Web search enabled:', webSearchEnabled);
|
913 |
-
});
|
914 |
-
|
915 |
-
// Language selection
|
916 |
-
languageSelect.addEventListener('change', () => {
|
917 |
-
selectedLanguage = languageSelect.value;
|
918 |
-
console.log('Selected language:', selectedLanguage);
|
919 |
-
});
|
920 |
-
|
921 |
-
// System prompt update
|
922 |
-
systemPromptInput.addEventListener('input', () => {
|
923 |
-
systemPrompt = systemPromptInput.value || "You are a helpful assistant. Respond in a friendly and professional manner.";
|
924 |
-
});
|
925 |
-
|
926 |
-
// Text input handling
|
927 |
-
textInput.addEventListener('keypress', (e) => {
|
928 |
-
if (e.key === 'Enter' && !e.shiftKey) {
|
929 |
-
e.preventDefault();
|
930 |
-
sendTextMessage();
|
931 |
-
}
|
932 |
-
});
|
933 |
-
|
934 |
-
sendButton.addEventListener('click', sendTextMessage);
|
935 |
-
|
936 |
async function sendTextMessage() {
|
|
|
|
|
937 |
const message = textInput.value.trim();
|
938 |
if (!message) return;
|
939 |
|
@@ -987,17 +963,21 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
987 |
}
|
988 |
|
989 |
function updateStatus(state) {
|
|
|
|
|
|
|
|
|
990 |
statusDot.className = 'status-dot ' + state;
|
991 |
if (state === 'connected') {
|
992 |
statusText.textContent = '연결됨';
|
993 |
-
sendButton.style.display = 'block';
|
994 |
isVoiceActive = true;
|
995 |
} else if (state === 'connecting') {
|
996 |
statusText.textContent = '연결 중...';
|
997 |
-
sendButton.style.display = 'none';
|
998 |
} else {
|
999 |
statusText.textContent = '연결 대기 중';
|
1000 |
-
sendButton.style.display = 'block'; // Show send button even when disconnected for text chat
|
1001 |
isVoiceActive = false;
|
1002 |
}
|
1003 |
}
|
@@ -1088,6 +1068,7 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
1088 |
}
|
1089 |
|
1090 |
async function setupWebRTC() {
|
|
|
1091 |
const config = __RTC_CONFIGURATION__;
|
1092 |
peerConnection = new RTCPeerConnection(config);
|
1093 |
const timeoutId = setTimeout(() => {
|
@@ -1198,6 +1179,7 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
1198 |
}
|
1199 |
|
1200 |
function addMessage(role, content) {
|
|
|
1201 |
const messageDiv = document.createElement('div');
|
1202 |
messageDiv.classList.add('message', role);
|
1203 |
|
@@ -1287,103 +1269,8 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
1287 |
}
|
1288 |
}
|
1289 |
|
1290 |
-
startButton.addEventListener('click', () => {
|
1291 |
-
console.log('clicked');
|
1292 |
-
console.log(peerConnection, peerConnection?.connectionState);
|
1293 |
-
if (!peerConnection || peerConnection.connectionState !== 'connected') {
|
1294 |
-
setupWebRTC();
|
1295 |
-
} else {
|
1296 |
-
console.log('stopping');
|
1297 |
-
stop();
|
1298 |
-
}
|
1299 |
-
});
|
1300 |
-
|
1301 |
// Whisper Tab Functions
|
1302 |
|
1303 |
-
// Microphone recording
|
1304 |
-
async function toggleMicRecording() {
|
1305 |
-
const btn = document.getElementById('mic-record-btn');
|
1306 |
-
const status = document.getElementById('mic-status');
|
1307 |
-
|
1308 |
-
if (!isRecording) {
|
1309 |
-
try {
|
1310 |
-
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
1311 |
-
micRecorder = new MediaRecorder(stream);
|
1312 |
-
const chunks = [];
|
1313 |
-
|
1314 |
-
micRecorder.ondataavailable = (e) => chunks.push(e.data);
|
1315 |
-
micRecorder.onstop = async () => {
|
1316 |
-
const blob = new Blob(chunks, { type: 'audio/webm' });
|
1317 |
-
await processAudioBlob(blob, 'mic');
|
1318 |
-
stream.getTracks().forEach(track => track.stop());
|
1319 |
-
};
|
1320 |
-
|
1321 |
-
micRecorder.start();
|
1322 |
-
isRecording = true;
|
1323 |
-
btn.textContent = '녹음 중지';
|
1324 |
-
status.innerHTML = '<div class="recording-indicator"><div class="recording-dot"></div>녹음 중...</div>';
|
1325 |
-
} catch (err) {
|
1326 |
-
showError('마이크 접근 권한이 필요합니다.');
|
1327 |
-
}
|
1328 |
-
} else {
|
1329 |
-
micRecorder.stop();
|
1330 |
-
isRecording = false;
|
1331 |
-
btn.textContent = '녹음 시작';
|
1332 |
-
status.textContent = '처리 중...';
|
1333 |
-
}
|
1334 |
-
}
|
1335 |
-
|
1336 |
-
// File upload handlers
|
1337 |
-
document.getElementById('audio-upload-area').addEventListener('click', () => {
|
1338 |
-
document.getElementById('audio-file-input').click();
|
1339 |
-
});
|
1340 |
-
|
1341 |
-
document.getElementById('video-upload-area').addEventListener('click', () => {
|
1342 |
-
document.getElementById('video-file-input').click();
|
1343 |
-
});
|
1344 |
-
|
1345 |
-
document.getElementById('pdf-upload-area').addEventListener('click', () => {
|
1346 |
-
document.getElementById('pdf-file-input').click();
|
1347 |
-
});
|
1348 |
-
|
1349 |
-
// Drag and drop handlers
|
1350 |
-
['audio', 'video', 'pdf'].forEach(type => {
|
1351 |
-
const area = document.getElementById(`${type}-upload-area`);
|
1352 |
-
|
1353 |
-
area.addEventListener('dragover', (e) => {
|
1354 |
-
e.preventDefault();
|
1355 |
-
area.classList.add('drag-over');
|
1356 |
-
});
|
1357 |
-
|
1358 |
-
area.addEventListener('dragleave', () => {
|
1359 |
-
area.classList.remove('drag-over');
|
1360 |
-
});
|
1361 |
-
|
1362 |
-
area.addEventListener('drop', (e) => {
|
1363 |
-
e.preventDefault();
|
1364 |
-
area.classList.remove('drag-over');
|
1365 |
-
const file = e.dataTransfer.files[0];
|
1366 |
-
if (file) {
|
1367 |
-
if (type === 'audio') processAudioFile(file);
|
1368 |
-
else if (type === 'video') processVideoFile(file);
|
1369 |
-
else if (type === 'pdf') processPDFFile(file);
|
1370 |
-
}
|
1371 |
-
});
|
1372 |
-
});
|
1373 |
-
|
1374 |
-
// File input change handlers
|
1375 |
-
document.getElementById('audio-file-input').addEventListener('change', (e) => {
|
1376 |
-
if (e.target.files[0]) processAudioFile(e.target.files[0]);
|
1377 |
-
});
|
1378 |
-
|
1379 |
-
document.getElementById('video-file-input').addEventListener('change', (e) => {
|
1380 |
-
if (e.target.files[0]) processVideoFile(e.target.files[0]);
|
1381 |
-
});
|
1382 |
-
|
1383 |
-
document.getElementById('pdf-file-input').addEventListener('change', (e) => {
|
1384 |
-
if (e.target.files[0]) processPDFFile(e.target.files[0]);
|
1385 |
-
});
|
1386 |
-
|
1387 |
// Process audio blob (for microphone recording)
|
1388 |
async function processAudioBlob(blob, type) {
|
1389 |
const formData = new FormData();
|
@@ -1614,8 +1501,178 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
1614 |
|
1615 |
// Initialize on page load
|
1616 |
window.addEventListener('DOMContentLoaded', () => {
|
1617 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1618 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1619 |
</script>
|
1620 |
</body>
|
1621 |
|
|
|
167 |
display: none;
|
168 |
flex-grow: 1;
|
169 |
overflow: hidden;
|
170 |
+
flex-direction: column;
|
171 |
}
|
172 |
.tab-content.active {
|
173 |
display: flex;
|
|
|
174 |
}
|
175 |
.main-content {
|
176 |
display: flex;
|
|
|
861 |
<script>
|
862 |
// Tab switching functionality
|
863 |
function switchTab(event, tabName) {
|
864 |
+
// Prevent default button behavior
|
865 |
+
event.preventDefault();
|
866 |
+
|
867 |
// Hide all tabs
|
868 |
const tabs = document.querySelectorAll('.tab-content');
|
869 |
+
tabs.forEach(tab => {
|
870 |
+
tab.classList.remove('active');
|
871 |
+
tab.style.display = 'none';
|
872 |
+
});
|
873 |
|
874 |
// Remove active class from all buttons
|
875 |
const buttons = document.querySelectorAll('.tab-button');
|
876 |
buttons.forEach(btn => btn.classList.remove('active'));
|
877 |
|
878 |
// Show selected tab
|
879 |
+
const selectedTab = document.getElementById(tabName);
|
880 |
+
if (selectedTab) {
|
881 |
+
selectedTab.classList.add('active');
|
882 |
+
selectedTab.style.display = 'flex';
|
883 |
+
}
|
884 |
|
885 |
// Add active class to clicked button
|
886 |
+
if (event.target) {
|
887 |
+
event.target.classList.add('active');
|
888 |
+
}
|
889 |
}
|
890 |
|
891 |
// Original voice chat variables and functions
|
|
|
894 |
let webSearchEnabled = false;
|
895 |
let selectedLanguage = "";
|
896 |
let systemPrompt = "You are a helpful assistant. Respond in a friendly and professional manner.";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
897 |
let audioLevel = 0;
|
898 |
let animationFrame;
|
899 |
let audioContext, analyser, audioSource;
|
|
|
907 |
let isRealtimeRecording = false;
|
908 |
let realtimeStream = null;
|
909 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
910 |
async function sendTextMessage() {
|
911 |
+
const textInput = document.getElementById('text-input');
|
912 |
+
const chatMessages = document.getElementById('chat-messages');
|
913 |
const message = textInput.value.trim();
|
914 |
if (!message) return;
|
915 |
|
|
|
963 |
}
|
964 |
|
965 |
function updateStatus(state) {
|
966 |
+
const statusDot = document.getElementById('status-dot');
|
967 |
+
const statusText = document.getElementById('status-text');
|
968 |
+
const sendButton = document.getElementById('send-button');
|
969 |
+
|
970 |
statusDot.className = 'status-dot ' + state;
|
971 |
if (state === 'connected') {
|
972 |
statusText.textContent = '연결됨';
|
973 |
+
if (sendButton) sendButton.style.display = 'block';
|
974 |
isVoiceActive = true;
|
975 |
} else if (state === 'connecting') {
|
976 |
statusText.textContent = '연결 중...';
|
977 |
+
if (sendButton) sendButton.style.display = 'none';
|
978 |
} else {
|
979 |
statusText.textContent = '연결 대기 중';
|
980 |
+
if (sendButton) sendButton.style.display = 'block'; // Show send button even when disconnected for text chat
|
981 |
isVoiceActive = false;
|
982 |
}
|
983 |
}
|
|
|
1068 |
}
|
1069 |
|
1070 |
async function setupWebRTC() {
|
1071 |
+
const audioOutput = document.getElementById('audio-output');
|
1072 |
const config = __RTC_CONFIGURATION__;
|
1073 |
peerConnection = new RTCPeerConnection(config);
|
1074 |
const timeoutId = setTimeout(() => {
|
|
|
1179 |
}
|
1180 |
|
1181 |
function addMessage(role, content) {
|
1182 |
+
const chatMessages = document.getElementById('chat-messages');
|
1183 |
const messageDiv = document.createElement('div');
|
1184 |
messageDiv.classList.add('message', role);
|
1185 |
|
|
|
1269 |
}
|
1270 |
}
|
1271 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1272 |
// Whisper Tab Functions
|
1273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1274 |
// Process audio blob (for microphone recording)
|
1275 |
async function processAudioBlob(blob, type) {
|
1276 |
const formData = new FormData();
|
|
|
1501 |
|
1502 |
// Initialize on page load
|
1503 |
window.addEventListener('DOMContentLoaded', () => {
|
1504 |
+
console.log('DOM loaded, initializing...');
|
1505 |
+
|
1506 |
+
// Initialize voice chat tab elements
|
1507 |
+
initializeVoiceChatTab();
|
1508 |
+
|
1509 |
+
// Initialize tab functionality
|
1510 |
+
initializeTabs();
|
1511 |
+
|
1512 |
+
// Initialize Whisper tabs
|
1513 |
+
initializeWhisperTabs();
|
1514 |
});
|
1515 |
+
|
1516 |
+
function initializeVoiceChatTab() {
|
1517 |
+
// Initialize send button
|
1518 |
+
const sendBtn = document.getElementById('send-button');
|
1519 |
+
if (sendBtn) {
|
1520 |
+
sendBtn.style.display = 'block';
|
1521 |
+
sendBtn.addEventListener('click', sendTextMessage);
|
1522 |
+
console.log('Send button initialized');
|
1523 |
+
}
|
1524 |
+
|
1525 |
+
// Text input handling
|
1526 |
+
const textInputEl = document.getElementById('text-input');
|
1527 |
+
if (textInputEl) {
|
1528 |
+
textInputEl.addEventListener('keypress', (e) => {
|
1529 |
+
if (e.key === 'Enter' && !e.shiftKey) {
|
1530 |
+
e.preventDefault();
|
1531 |
+
sendTextMessage();
|
1532 |
+
}
|
1533 |
+
});
|
1534 |
+
console.log('Text input initialized');
|
1535 |
+
}
|
1536 |
+
|
1537 |
+
// Web search toggle
|
1538 |
+
const searchToggleBtn = document.getElementById('search-toggle');
|
1539 |
+
if (searchToggleBtn) {
|
1540 |
+
searchToggleBtn.addEventListener('click', function() {
|
1541 |
+
webSearchEnabled = !webSearchEnabled;
|
1542 |
+
this.classList.toggle('active', webSearchEnabled);
|
1543 |
+
console.log('Web search toggled:', webSearchEnabled);
|
1544 |
+
});
|
1545 |
+
console.log('Search toggle initialized');
|
1546 |
+
}
|
1547 |
+
|
1548 |
+
// Language selection
|
1549 |
+
const languageSelectEl = document.getElementById('language-select');
|
1550 |
+
if (languageSelectEl) {
|
1551 |
+
languageSelectEl.addEventListener('change', function() {
|
1552 |
+
selectedLanguage = this.value;
|
1553 |
+
console.log('Language selected:', selectedLanguage);
|
1554 |
+
});
|
1555 |
+
console.log('Language select initialized');
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
// System prompt
|
1559 |
+
const systemPromptEl = document.getElementById('system-prompt');
|
1560 |
+
if (systemPromptEl) {
|
1561 |
+
systemPromptEl.addEventListener('input', function() {
|
1562 |
+
systemPrompt = this.value || "You are a helpful assistant. Respond in a friendly and professional manner.";
|
1563 |
+
});
|
1564 |
+
console.log('System prompt initialized');
|
1565 |
+
}
|
1566 |
+
|
1567 |
+
// Start button
|
1568 |
+
const startBtn = document.getElementById('start-button');
|
1569 |
+
if (startBtn) {
|
1570 |
+
startBtn.addEventListener('click', () => {
|
1571 |
+
console.log('Start button clicked');
|
1572 |
+
if (!peerConnection || peerConnection.connectionState !== 'connected') {
|
1573 |
+
setupWebRTC();
|
1574 |
+
} else {
|
1575 |
+
stop();
|
1576 |
+
}
|
1577 |
+
});
|
1578 |
+
console.log('Start button initialized');
|
1579 |
+
}
|
1580 |
+
}
|
1581 |
+
|
1582 |
+
function initializeTabs() {
|
1583 |
+
// Ensure first tab is visible
|
1584 |
+
const firstTab = document.getElementById('voice-chat');
|
1585 |
+
if (firstTab) {
|
1586 |
+
firstTab.style.display = 'flex';
|
1587 |
+
firstTab.classList.add('active');
|
1588 |
+
console.log('First tab made visible');
|
1589 |
+
}
|
1590 |
+
|
1591 |
+
// Add click handlers to all tab buttons
|
1592 |
+
const tabButtons = document.querySelectorAll('.tab-button');
|
1593 |
+
tabButtons.forEach(button => {
|
1594 |
+
button.addEventListener('click', function(e) {
|
1595 |
+
const tabName = this.getAttribute('onclick').match(/'([^']+)'/)[1];
|
1596 |
+
switchTab(e, tabName);
|
1597 |
+
});
|
1598 |
+
});
|
1599 |
+
console.log('Tab buttons initialized:', tabButtons.length);
|
1600 |
+
}
|
1601 |
+
|
1602 |
+
function initializeWhisperTabs() {
|
1603 |
+
// Initialize file upload areas and other Whisper functionality
|
1604 |
+
console.log('Initializing Whisper tabs...');
|
1605 |
+
|
1606 |
+
// File upload handlers
|
1607 |
+
const audioUploadArea = document.getElementById('audio-upload-area');
|
1608 |
+
if (audioUploadArea) {
|
1609 |
+
audioUploadArea.addEventListener('click', () => {
|
1610 |
+
document.getElementById('audio-file-input').click();
|
1611 |
+
});
|
1612 |
+
}
|
1613 |
+
|
1614 |
+
const videoUploadArea = document.getElementById('video-upload-area');
|
1615 |
+
if (videoUploadArea) {
|
1616 |
+
videoUploadArea.addEventListener('click', () => {
|
1617 |
+
document.getElementById('video-file-input').click();
|
1618 |
+
});
|
1619 |
+
}
|
1620 |
+
|
1621 |
+
const pdfUploadArea = document.getElementById('pdf-upload-area');
|
1622 |
+
if (pdfUploadArea) {
|
1623 |
+
pdfUploadArea.addEventListener('click', () => {
|
1624 |
+
document.getElementById('pdf-file-input').click();
|
1625 |
+
});
|
1626 |
+
}
|
1627 |
+
|
1628 |
+
// Drag and drop handlers
|
1629 |
+
['audio', 'video', 'pdf'].forEach(type => {
|
1630 |
+
const area = document.getElementById(`${type}-upload-area`);
|
1631 |
+
if (!area) return;
|
1632 |
+
|
1633 |
+
area.addEventListener('dragover', (e) => {
|
1634 |
+
e.preventDefault();
|
1635 |
+
area.classList.add('drag-over');
|
1636 |
+
});
|
1637 |
+
|
1638 |
+
area.addEventListener('dragleave', () => {
|
1639 |
+
area.classList.remove('drag-over');
|
1640 |
+
});
|
1641 |
+
|
1642 |
+
area.addEventListener('drop', (e) => {
|
1643 |
+
e.preventDefault();
|
1644 |
+
area.classList.remove('drag-over');
|
1645 |
+
const file = e.dataTransfer.files[0];
|
1646 |
+
if (file) {
|
1647 |
+
if (type === 'audio') processAudioFile(file);
|
1648 |
+
else if (type === 'video') processVideoFile(file);
|
1649 |
+
else if (type === 'pdf') processPDFFile(file);
|
1650 |
+
}
|
1651 |
+
});
|
1652 |
+
});
|
1653 |
+
|
1654 |
+
// File input change handlers
|
1655 |
+
const audioFileInput = document.getElementById('audio-file-input');
|
1656 |
+
if (audioFileInput) {
|
1657 |
+
audioFileInput.addEventListener('change', (e) => {
|
1658 |
+
if (e.target.files[0]) processAudioFile(e.target.files[0]);
|
1659 |
+
});
|
1660 |
+
}
|
1661 |
+
|
1662 |
+
const videoFileInput = document.getElementById('video-file-input');
|
1663 |
+
if (videoFileInput) {
|
1664 |
+
videoFileInput.addEventListener('change', (e) => {
|
1665 |
+
if (e.target.files[0]) processVideoFile(e.target.files[0]);
|
1666 |
+
});
|
1667 |
+
}
|
1668 |
+
|
1669 |
+
const pdfFileInput = document.getElementById('pdf-file-input');
|
1670 |
+
if (pdfFileInput) {
|
1671 |
+
pdfFileInput.addEventListener('change', (e) => {
|
1672 |
+
if (e.target.files[0]) processPDFFile(e.target.files[0]);
|
1673 |
+
});
|
1674 |
+
}
|
1675 |
+
}
|
1676 |
</script>
|
1677 |
</body>
|
1678 |
|