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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +138 -165
app.py CHANGED
@@ -666,12 +666,12 @@ HTML_CONTENT = """<!DOCTYPE html>
666
  </div>
667
 
668
  <div class="tabs-container">
669
- <button class="tab-button active" onclick="switchTab(event, 'voice-chat')">음성 채팅</button>
670
- <button class="tab-button" onclick="switchTab(event, 'mic-whisper')">마이크 전사</button>
671
- <button class="tab-button" onclick="switchTab(event, 'audio-whisper')">오디오 파일</button>
672
- <button class="tab-button" onclick="switchTab(event, 'video-whisper')">비디오 파일</button>
673
- <button class="tab-button" onclick="switchTab(event, 'pdf-whisper')">PDF 번역</button>
674
- <button class="tab-button" onclick="switchTab(event, 'realtime-whisper')">실시간 통역</button>
675
  </div>
676
 
677
  <!-- Voice Chat Tab (Original) -->
@@ -859,48 +859,49 @@ HTML_CONTENT = """<!DOCTYPE html>
859
  <audio id="audio-output"></audio>
860
 
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
892
- let peerConnection;
893
- let webrtc_id;
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;
 
 
900
  let dataChannel = null;
901
  let isVoiceActive = false;
902
 
903
- // Whisper-related variables
904
  let micRecorder = null;
905
  let isRecording = false;
906
  let realtimeRecorder = null;
@@ -1069,7 +1070,7 @@ HTML_CONTENT = """<!DOCTYPE html>
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(() => {
1075
  const toast = document.getElementById('error-toast');
@@ -1271,6 +1272,39 @@ HTML_CONTENT = """<!DOCTYPE html>
1271
 
1272
  // Whisper Tab Functions
1273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1274
  // Process audio blob (for microphone recording)
1275
  async function processAudioBlob(blob, type) {
1276
  const formData = new FormData();
@@ -1499,180 +1533,119 @@ HTML_CONTENT = """<!DOCTYPE html>
1499
  processor.connect(audioContext.destination);
1500
  }
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
 
 
666
  </div>
667
 
668
  <div class="tabs-container">
669
+ <button class="tab-button active" onclick="switchTab('voice-chat')">음성 채팅</button>
670
+ <button class="tab-button" onclick="switchTab('mic-whisper')">마이크 전사</button>
671
+ <button class="tab-button" onclick="switchTab('audio-whisper')">오디오 파일</button>
672
+ <button class="tab-button" onclick="switchTab('video-whisper')">비디오 파일</button>
673
+ <button class="tab-button" onclick="switchTab('pdf-whisper')">PDF 번역</button>
674
+ <button class="tab-button" onclick="switchTab('realtime-whisper')">실시간 통역</button>
675
  </div>
676
 
677
  <!-- Voice Chat Tab (Original) -->
 
859
  <audio id="audio-output"></audio>
860
 
861
  <script>
862
+ // Tab switching functionality - 맨 앞에 배치
863
+ function switchTab(tabName) {
864
+ console.log('Switching to tab:', tabName);
 
865
 
866
  // Hide all tabs
867
+ document.querySelectorAll('.tab-content').forEach(tab => {
 
 
868
  tab.style.display = 'none';
869
+ tab.classList.remove('active');
870
  });
871
 
872
+ console.log('All initialized!');
873
+
874
+ // Remove active from all buttons
875
+ document.querySelectorAll('.tab-button').forEach(btn => {
876
+ btn.classList.remove('active');
877
+ });
878
 
879
  // Show selected tab
880
  const selectedTab = document.getElementById(tabName);
881
  if (selectedTab) {
 
882
  selectedTab.style.display = 'flex';
883
+ selectedTab.classList.add('active');
884
  }
885
 
886
+ // Mark button as active
887
+ event.target.classList.add('active');
 
 
888
  }
889
 
890
+ // Global variables
891
+ let peerConnection = null;
892
+ let webrtc_id = null;
893
  let webSearchEnabled = false;
894
  let selectedLanguage = "";
895
  let systemPrompt = "You are a helpful assistant. Respond in a friendly and professional manner.";
896
  let audioLevel = 0;
897
+ let animationFrame = null;
898
+ let audioContext = null;
899
+ let analyser = null;
900
+ let audioSource = null;
901
  let dataChannel = null;
902
  let isVoiceActive = false;
903
 
904
+ // Whisper variables
905
  let micRecorder = null;
906
  let isRecording = false;
907
  let realtimeRecorder = null;
 
1070
 
1071
  async function setupWebRTC() {
1072
  const audioOutput = document.getElementById('audio-output');
1073
+ const config = typeof __RTC_CONFIGURATION__ !== 'undefined' ? __RTC_CONFIGURATION__ : {iceServers: [{urls: 'stun:stun.l.google.com:19302'}]};
1074
  peerConnection = new RTCPeerConnection(config);
1075
  const timeoutId = setTimeout(() => {
1076
  const toast = document.getElementById('error-toast');
 
1272
 
1273
  // Whisper Tab Functions
1274
 
1275
+ // Microphone recording
1276
+ async function toggleMicRecording() {
1277
+ const btn = document.getElementById('mic-record-btn');
1278
+ const status = document.getElementById('mic-status');
1279
+
1280
+ if (!isRecording) {
1281
+ try {
1282
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
1283
+ micRecorder = new MediaRecorder(stream);
1284
+ const chunks = [];
1285
+
1286
+ micRecorder.ondataavailable = (e) => chunks.push(e.data);
1287
+ micRecorder.onstop = async () => {
1288
+ const blob = new Blob(chunks, { type: 'audio/webm' });
1289
+ await processAudioBlob(blob, 'mic');
1290
+ stream.getTracks().forEach(track => track.stop());
1291
+ };
1292
+
1293
+ micRecorder.start();
1294
+ isRecording = true;
1295
+ btn.textContent = '녹음 중지';
1296
+ status.innerHTML = '<div class="recording-indicator"><div class="recording-dot"></div>녹음 중...</div>';
1297
+ } catch (err) {
1298
+ showError('마이크 접근 권한이 필요합니다.');
1299
+ }
1300
+ } else {
1301
+ micRecorder.stop();
1302
+ isRecording = false;
1303
+ btn.textContent = '녹음 시작';
1304
+ status.textContent = '처리 중...';
1305
+ }
1306
+ }
1307
+
1308
  // Process audio blob (for microphone recording)
1309
  async function processAudioBlob(blob, type) {
1310
  const formData = new FormData();
 
1533
  processor.connect(audioContext.destination);
1534
  }
1535
 
1536
+ // Simple initialization
1537
+ window.onload = function() {
1538
+ console.log('Page loaded!');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1539
 
1540
  // Web search toggle
1541
+ document.getElementById('search-toggle').onclick = function() {
1542
+ webSearchEnabled = !webSearchEnabled;
1543
+ this.classList.toggle('active', webSearchEnabled);
1544
+ console.log('Web search:', webSearchEnabled);
1545
+ };
 
 
 
 
1546
 
1547
+ // Language select
1548
+ document.getElementById('language-select').onchange = function() {
1549
+ selectedLanguage = this.value;
1550
+ console.log('Language:', selectedLanguage);
1551
+ };
 
 
 
 
1552
 
1553
  // System prompt
1554
+ document.getElementById('system-prompt').oninput = function() {
1555
+ systemPrompt = this.value || "You are a helpful assistant. Respond in a friendly and professional manner.";
1556
+ };
 
 
 
 
1557
 
1558
+ // Text input enter key
1559
+ document.getElementById('text-input').onkeypress = function(e) {
1560
+ if (e.key === 'Enter' && !e.shiftKey) {
1561
+ e.preventDefault();
1562
+ sendTextMessage();
1563
+ }
1564
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1565
 
1566
+ // Send button
1567
+ document.getElementById('send-button').onclick = sendTextMessage;
1568
+ document.getElementById('send-button').style.display = 'block';
1569
+
1570
+ // Start button
1571
+ document.getElementById('start-button').onclick = function() {
1572
+ if (!peerConnection || peerConnection.connectionState !== 'connected') {
1573
+ setupWebRTC();
1574
+ } else {
1575
+ stop();
1576
+ }
1577
+ };
 
 
1578
 
1579
+ // File upload areas
1580
  const audioUploadArea = document.getElementById('audio-upload-area');
1581
  if (audioUploadArea) {
1582
+ audioUploadArea.onclick = function() {
1583
  document.getElementById('audio-file-input').click();
1584
+ };
1585
  }
1586
 
1587
  const videoUploadArea = document.getElementById('video-upload-area');
1588
  if (videoUploadArea) {
1589
+ videoUploadArea.onclick = function() {
1590
  document.getElementById('video-file-input').click();
1591
+ };
1592
  }
1593
 
1594
  const pdfUploadArea = document.getElementById('pdf-upload-area');
1595
  if (pdfUploadArea) {
1596
+ pdfUploadArea.onclick = function() {
1597
  document.getElementById('pdf-file-input').click();
1598
+ };
1599
  }
1600
 
1601
+ // File input handlers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1602
  const audioFileInput = document.getElementById('audio-file-input');
1603
  if (audioFileInput) {
1604
+ audioFileInput.onchange = function(e) {
1605
  if (e.target.files[0]) processAudioFile(e.target.files[0]);
1606
+ };
1607
  }
1608
 
1609
  const videoFileInput = document.getElementById('video-file-input');
1610
  if (videoFileInput) {
1611
+ videoFileInput.onchange = function(e) {
1612
  if (e.target.files[0]) processVideoFile(e.target.files[0]);
1613
+ };
1614
  }
1615
 
1616
  const pdfFileInput = document.getElementById('pdf-file-input');
1617
  if (pdfFileInput) {
1618
+ pdfFileInput.onchange = function(e) {
1619
  if (e.target.files[0]) processPDFFile(e.target.files[0]);
1620
+ };
1621
  }
1622
+
1623
+ // Drag and drop handlers
1624
+ ['audio', 'video', 'pdf'].forEach(type => {
1625
+ const area = document.getElementById(`${type}-upload-area`);
1626
+ if (area) {
1627
+ area.ondragover = function(e) {
1628
+ e.preventDefault();
1629
+ area.classList.add('drag-over');
1630
+ };
1631
+
1632
+ area.ondragleave = function() {
1633
+ area.classList.remove('drag-over');
1634
+ };
1635
+
1636
+ area.ondrop = function(e) {
1637
+ e.preventDefault();
1638
+ area.classList.remove('drag-over');
1639
+ const file = e.dataTransfer.files[0];
1640
+ if (file) {
1641
+ if (type === 'audio') processAudioFile(file);
1642
+ else if (type === 'video') processVideoFile(file);
1643
+ else if (type === 'pdf') processPDFFile(file);
1644
+ }
1645
+ };
1646
+ }
1647
+ });
1648
+ };
1649
  </script>
1650
  </body>
1651