seawolf2357 commited on
Commit
a5cf5de
·
verified ·
1 Parent(s): db999b8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +198 -141
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 => tab.classList.remove('active'));
 
 
 
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).classList.add('active');
 
 
 
 
874
 
875
  // Add active class to clicked button
876
- event.target.classList.add('active');
 
 
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
- sendButton.style.display = 'block';
 
 
 
 
 
 
 
 
 
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