kemuriririn commited on
Commit
946a55b
·
1 Parent(s): 8374ff5

(wip)update html

Browse files
Files changed (1) hide show
  1. templates/arena.html +79 -62
templates/arena.html CHANGED
@@ -992,6 +992,23 @@
992
  <script src="{{ url_for('static', filename='js/waveplayer.js') }}"></script>
993
  <script>
994
  document.addEventListener('DOMContentLoaded', function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
995
  const synthForm = document.querySelector('.input-container');
996
  const synthBtn = document.querySelector('.synth-btn');
997
  const mobileSynthBtn = document.querySelector('.mobile-synth-btn');
@@ -1489,12 +1506,12 @@
1489
  const podcastNextRoundBtn = podcastPlayerContainer.querySelector('.next-round-btn');
1490
  const chosenModelNameElement = podcastVoteResults.querySelector('.chosen-model-name');
1491
  const rejectedModelNameElement = podcastVoteResults.querySelector('.rejected-model-name');
1492
-
1493
  let podcastWavePlayers = { a: null, b: null };
1494
  let bothPodcastSamplesPlayed = false;
1495
  let currentPodcastSessionId = null;
1496
  let podcastModelNames = { a: 'Model A', b: 'Model B' };
1497
-
1498
  // Sample random scripts for the podcast
1499
  const randomScripts = [
1500
  [
@@ -1582,40 +1599,40 @@
1582
  { speaker: 2, text: "I think we'll see more integrated systems where bikes, scooters, and public transit work seamlessly together." }
1583
  ]
1584
  ];
1585
-
1586
  // Initialize with 2 empty lines
1587
  function initializePodcastLines() {
1588
  podcastLinesContainer.innerHTML = '';
1589
  addPodcastLine(1);
1590
  addPodcastLine(2);
1591
  }
1592
-
1593
  // Add a new podcast line
1594
  function addPodcastLine(speakerNum = null) {
1595
  const lineCount = podcastLinesContainer.querySelectorAll('.podcast-line').length;
1596
-
1597
  // If speaker number isn't specified, alternate between 1 and 2
1598
  if (speakerNum === null) {
1599
  speakerNum = (lineCount % 2) + 1;
1600
  }
1601
-
1602
  const lineElement = document.createElement('div');
1603
  lineElement.className = 'podcast-line';
1604
-
1605
  lineElement.innerHTML = `
1606
  <div class="speaker-label speaker-${speakerNum}">Speaker ${speakerNum}</div>
1607
  <input type="text" class="line-input" placeholder="Enter dialog...">
1608
  <button type="button" class="remove-line-btn" tabindex="-1">
1609
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
1610
  stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1611
  <line x1="18" y1="6" x2="6" y2="18"></line>
1612
  <line x1="6" y1="6" x2="18" y2="18"></line>
1613
  </svg>
1614
  </button>
1615
  `;
1616
-
1617
  podcastLinesContainer.appendChild(lineElement);
1618
-
1619
  // Add event listener to remove button
1620
  const removeBtn = lineElement.querySelector('.remove-line-btn');
1621
  removeBtn.addEventListener('click', function() {
@@ -1626,7 +1643,7 @@
1626
  openToast("At least 2 lines are required", "warning");
1627
  }
1628
  });
1629
-
1630
  // Add event listener for keyboard navigation in the input field
1631
  const inputField = lineElement.querySelector('.line-input');
1632
  inputField.addEventListener('keydown', function(e) {
@@ -1634,7 +1651,7 @@
1634
  if (e.key === 'Enter' && (e.altKey || e.ctrlKey)) {
1635
  e.preventDefault();
1636
  addPodcastLine();
1637
-
1638
  // Focus the new line's input field
1639
  setTimeout(() => {
1640
  const inputs = podcastLinesContainer.querySelectorAll('.line-input');
@@ -1642,25 +1659,25 @@
1642
  }, 10);
1643
  }
1644
  });
1645
-
1646
  return lineElement;
1647
  }
1648
-
1649
  // Load a random script
1650
  function loadRandomScript() {
1651
  // Clear existing lines
1652
  podcastLinesContainer.innerHTML = '';
1653
-
1654
  // Select a random script
1655
  const randomScript = randomScripts[Math.floor(Math.random() * randomScripts.length)];
1656
-
1657
  // Add each line from the script
1658
  randomScript.forEach(line => {
1659
  const lineElement = addPodcastLine(line.speaker);
1660
  lineElement.querySelector('.line-input').value = line.text;
1661
  });
1662
  }
1663
-
1664
  // Generate podcast (mock functionality)
1665
  function generatePodcast() {
1666
  // Get all lines
@@ -1668,25 +1685,25 @@
1668
  podcastLinesContainer.querySelectorAll('.podcast-line').forEach(line => {
1669
  const speaker_id = line.querySelector('.speaker-label').textContent.includes('1') ? 0 : 1;
1670
  const text = line.querySelector('.line-input').value.trim();
1671
-
1672
  if (text) {
1673
  lines.push({ speaker_id, text });
1674
  }
1675
  });
1676
-
1677
  // Validate that we have at least 2 lines with content
1678
  if (lines.length < 2) {
1679
  openToast("Please enter at least 2 lines of dialog", "warning");
1680
  return;
1681
  }
1682
-
1683
  // Reset vote buttons and hide results
1684
  podcastVoteButtons.forEach(btn => {
1685
  btn.disabled = true;
1686
  btn.classList.remove('selected');
1687
  btn.querySelector('.vote-loader').style.display = 'none';
1688
  });
1689
-
1690
  // Clear model name displays
1691
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1692
  modelNameDisplays.forEach(display => {
@@ -1695,14 +1712,14 @@
1695
 
1696
  podcastVoteResults.style.display = 'none';
1697
  podcastNextRoundContainer.style.display = 'none';
1698
-
1699
  // Reset the flag for both samples played
1700
  bothPodcastSamplesPlayed = false;
1701
-
1702
  // Show loading animation
1703
  podcastLoadingContainer.style.display = 'flex';
1704
  podcastPlayerContainer.style.display = 'none';
1705
-
1706
  // Call API to generate podcast
1707
  fetch('/api/conversational/generate', {
1708
  method: 'POST',
@@ -1721,13 +1738,13 @@
1721
  })
1722
  .then(data => {
1723
  currentPodcastSessionId = data.session_id;
1724
-
1725
  // Hide loading
1726
  podcastLoadingContainer.style.display = 'none';
1727
-
1728
  // Show player
1729
  podcastPlayerContainer.style.display = 'block';
1730
-
1731
  // Initialize WavePlayers if not already done
1732
  if (!podcastWavePlayers.a) {
1733
  podcastWavePlayers.a = new WavePlayer(podcastWavePlayerA, {
@@ -1740,11 +1757,11 @@
1740
  backend: 'MediaElement',
1741
  mediaControls: false // Hide native audio controls
1742
  });
1743
-
1744
  // Load audio in waveplayers
1745
  podcastWavePlayers.a.loadAudio(data.audio_a);
1746
  podcastWavePlayers.b.loadAudio(data.audio_b);
1747
-
1748
  // Force hide loading indicators after 5 seconds as a fallback
1749
  setTimeout(() => {
1750
  if (podcastWavePlayers.a && podcastWavePlayers.a.hideLoading) {
@@ -1760,14 +1777,14 @@
1760
  try {
1761
  podcastWavePlayers.a.wavesurfer.empty();
1762
  podcastWavePlayers.b.wavesurfer.empty();
1763
-
1764
  // Make sure loading indicators are reset
1765
  podcastWavePlayers.a.hideLoading();
1766
  podcastWavePlayers.b.hideLoading();
1767
-
1768
  podcastWavePlayers.a.loadAudio(data.audio_a);
1769
  podcastWavePlayers.b.loadAudio(data.audio_b);
1770
-
1771
  // Force hide loading indicators after 5 seconds as a fallback
1772
  setTimeout(() => {
1773
  if (podcastWavePlayers.a && podcastWavePlayers.a.hideLoading) {
@@ -1780,7 +1797,7 @@
1780
  }, 5000);
1781
  } catch (err) {
1782
  console.error('Error resetting podcast waveplayers:', err);
1783
-
1784
  // Recreate the players if there was an error
1785
  podcastWavePlayers.a = new WavePlayer(podcastWavePlayerA, {
1786
  backend: 'MediaElement',
@@ -1790,7 +1807,7 @@
1790
  backend: 'MediaElement',
1791
  mediaControls: false
1792
  });
1793
-
1794
  podcastWavePlayers.a.loadAudio(data.audio_a);
1795
  podcastWavePlayers.b.loadAudio(data.audio_b);
1796
 
@@ -1806,17 +1823,17 @@
1806
  }, 5000);
1807
  }
1808
  }
1809
-
1810
  // Setup automatic sequential playback
1811
  podcastWavePlayers.a.wavesurfer.once('ready', function() {
1812
  podcastWavePlayers.a.play();
1813
-
1814
  // When audio A ends, play audio B
1815
  podcastWavePlayers.a.wavesurfer.once('finish', function() {
1816
  // Wait a short moment before playing B
1817
  setTimeout(() => {
1818
  podcastWavePlayers.b.play();
1819
-
1820
  // When audio B ends, enable voting
1821
  podcastWavePlayers.b.wavesurfer.once('finish', function() {
1822
  bothPodcastSamplesPlayed = true;
@@ -1834,7 +1851,7 @@
1834
  console.error('Error:', error);
1835
  });
1836
  }
1837
-
1838
  // Handle vote for a podcast model
1839
  function handlePodcastVote(model) {
1840
  // Disable both vote buttons
@@ -1844,7 +1861,7 @@
1844
  btn.querySelector('.vote-loader').style.display = 'flex';
1845
  }
1846
  });
1847
-
1848
  // Send vote to server
1849
  fetch('/api/conversational/vote', {
1850
  method: 'POST',
@@ -1868,30 +1885,30 @@
1868
  // Hide loaders
1869
  podcastVoteButtons.forEach(btn => {
1870
  btn.querySelector('.vote-loader').style.display = 'none';
1871
-
1872
  // Highlight the selected button
1873
  if (btn.dataset.model === model) {
1874
  btn.classList.add('selected');
1875
  }
1876
  });
1877
-
1878
  // Store model names from vote response
1879
  podcastModelNames.a = data.names.a;
1880
  podcastModelNames.b = data.names.b;
1881
-
1882
  // Show model names after voting
1883
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1884
  modelNameDisplays[0].textContent = data.names.a ? `(${data.names.a})` : '';
1885
  modelNameDisplays[1].textContent = data.names.b ? `(${data.names.b})` : '';
1886
-
1887
  // Show vote results
1888
  chosenModelNameElement.textContent = data.chosen_model.name;
1889
  rejectedModelNameElement.textContent = data.rejected_model.name;
1890
  podcastVoteResults.style.display = 'block';
1891
-
1892
  // Show next round button
1893
  podcastNextRoundContainer.style.display = 'block';
1894
-
1895
  // Show success toast
1896
  openToast("Vote recorded successfully!", "success");
1897
  })
@@ -1901,55 +1918,55 @@
1901
  btn.disabled = false;
1902
  btn.querySelector('.vote-loader').style.display = 'none';
1903
  });
1904
-
1905
  openToast(error.message, "error");
1906
  console.error('Error:', error);
1907
  });
1908
  }
1909
-
1910
  // Reset podcast UI to initial state
1911
  function resetPodcastState() {
1912
  // Hide players, results, and next round button
1913
  podcastPlayerContainer.style.display = 'none';
1914
  podcastVoteResults.style.display = 'none';
1915
  podcastNextRoundContainer.style.display = 'none';
1916
-
1917
  // Reset vote buttons
1918
  podcastVoteButtons.forEach(btn => {
1919
  btn.disabled = true;
1920
  btn.classList.remove('selected');
1921
  btn.querySelector('.vote-loader').style.display = 'none';
1922
  });
1923
-
1924
  // Clear model name displays
1925
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1926
  modelNameDisplays.forEach(display => {
1927
  display.textContent = '';
1928
  });
1929
-
1930
  // Stop any playing audio
1931
  if (podcastWavePlayers.a) podcastWavePlayers.a.stop();
1932
  if (podcastWavePlayers.b) podcastWavePlayers.b.stop();
1933
-
1934
  // Reset session
1935
  currentPodcastSessionId = null;
1936
-
1937
  // Reset the flag for both samples played
1938
  bothPodcastSamplesPlayed = false;
1939
  }
1940
-
1941
  // Add keyboard shortcut listeners for podcast voting
1942
  document.addEventListener('keydown', function(e) {
1943
  // Check if we're in the podcast tab and it's active
1944
  const podcastTab = document.getElementById('conversational-tab');
1945
  if (!podcastTab.classList.contains('active')) return;
1946
-
1947
  // Only process if input fields are not focused
1948
- if (document.activeElement.tagName === 'INPUT' ||
1949
  document.activeElement.tagName === 'TEXTAREA') {
1950
  return;
1951
  }
1952
-
1953
  if (e.key.toLowerCase() === 'a') {
1954
  if (bothPodcastSamplesPlayed && !podcastVoteButtons[0].disabled) {
1955
  handlePodcastVote('a');
@@ -1984,20 +2001,20 @@
1984
  }
1985
  }
1986
  });
1987
-
1988
  // Event listeners
1989
  addLineBtn.addEventListener('click', function() {
1990
  addPodcastLine();
1991
  });
1992
-
1993
  randomScriptBtn.addEventListener('click', function() {
1994
  loadRandomScript();
1995
  });
1996
-
1997
  podcastSynthBtn.addEventListener('click', function() {
1998
  generatePodcast();
1999
  });
2000
-
2001
  // Add event listeners to vote buttons
2002
  podcastVoteButtons.forEach(btn => {
2003
  btn.addEventListener('click', function() {
@@ -2009,10 +2026,10 @@
2009
  }
2010
  });
2011
  });
2012
-
2013
  // Add event listener for next round button
2014
  podcastNextRoundBtn.addEventListener('click', resetPodcastState);
2015
-
2016
  // Initialize with 2 empty lines
2017
  initializePodcastLines();
2018
  });
 
992
  <script src="{{ url_for('static', filename='js/waveplayer.js') }}"></script>
993
  <script>
994
  document.addEventListener('DOMContentLoaded', function() {
995
+ // 参考音色试听功能
996
+ const voiceFileInput = document.getElementById('voice-file');
997
+ const voicePreview = document.getElementById('voice-preview');
998
+ if (voiceFileInput && voicePreview) {
999
+ voiceFileInput.addEventListener('change', function() {
1000
+ const file = this.files[0];
1001
+ if (file) {
1002
+ const url = URL.createObjectURL(file);
1003
+ voicePreview.src = url;
1004
+ voicePreview.style.display = 'inline-block';
1005
+ voicePreview.load();
1006
+ } else {
1007
+ voicePreview.src = '';
1008
+ voicePreview.style.display = 'none';
1009
+ }
1010
+ });
1011
+ }
1012
  const synthForm = document.querySelector('.input-container');
1013
  const synthBtn = document.querySelector('.synth-btn');
1014
  const mobileSynthBtn = document.querySelector('.mobile-synth-btn');
 
1506
  const podcastNextRoundBtn = podcastPlayerContainer.querySelector('.next-round-btn');
1507
  const chosenModelNameElement = podcastVoteResults.querySelector('.chosen-model-name');
1508
  const rejectedModelNameElement = podcastVoteResults.querySelector('.rejected-model-name');
1509
+
1510
  let podcastWavePlayers = { a: null, b: null };
1511
  let bothPodcastSamplesPlayed = false;
1512
  let currentPodcastSessionId = null;
1513
  let podcastModelNames = { a: 'Model A', b: 'Model B' };
1514
+
1515
  // Sample random scripts for the podcast
1516
  const randomScripts = [
1517
  [
 
1599
  { speaker: 2, text: "I think we'll see more integrated systems where bikes, scooters, and public transit work seamlessly together." }
1600
  ]
1601
  ];
1602
+
1603
  // Initialize with 2 empty lines
1604
  function initializePodcastLines() {
1605
  podcastLinesContainer.innerHTML = '';
1606
  addPodcastLine(1);
1607
  addPodcastLine(2);
1608
  }
1609
+
1610
  // Add a new podcast line
1611
  function addPodcastLine(speakerNum = null) {
1612
  const lineCount = podcastLinesContainer.querySelectorAll('.podcast-line').length;
1613
+
1614
  // If speaker number isn't specified, alternate between 1 and 2
1615
  if (speakerNum === null) {
1616
  speakerNum = (lineCount % 2) + 1;
1617
  }
1618
+
1619
  const lineElement = document.createElement('div');
1620
  lineElement.className = 'podcast-line';
1621
+
1622
  lineElement.innerHTML = `
1623
  <div class="speaker-label speaker-${speakerNum}">Speaker ${speakerNum}</div>
1624
  <input type="text" class="line-input" placeholder="Enter dialog...">
1625
  <button type="button" class="remove-line-btn" tabindex="-1">
1626
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
1627
  stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1628
  <line x1="18" y1="6" x2="6" y2="18"></line>
1629
  <line x1="6" y1="6" x2="18" y2="18"></line>
1630
  </svg>
1631
  </button>
1632
  `;
1633
+
1634
  podcastLinesContainer.appendChild(lineElement);
1635
+
1636
  // Add event listener to remove button
1637
  const removeBtn = lineElement.querySelector('.remove-line-btn');
1638
  removeBtn.addEventListener('click', function() {
 
1643
  openToast("At least 2 lines are required", "warning");
1644
  }
1645
  });
1646
+
1647
  // Add event listener for keyboard navigation in the input field
1648
  const inputField = lineElement.querySelector('.line-input');
1649
  inputField.addEventListener('keydown', function(e) {
 
1651
  if (e.key === 'Enter' && (e.altKey || e.ctrlKey)) {
1652
  e.preventDefault();
1653
  addPodcastLine();
1654
+
1655
  // Focus the new line's input field
1656
  setTimeout(() => {
1657
  const inputs = podcastLinesContainer.querySelectorAll('.line-input');
 
1659
  }, 10);
1660
  }
1661
  });
1662
+
1663
  return lineElement;
1664
  }
1665
+
1666
  // Load a random script
1667
  function loadRandomScript() {
1668
  // Clear existing lines
1669
  podcastLinesContainer.innerHTML = '';
1670
+
1671
  // Select a random script
1672
  const randomScript = randomScripts[Math.floor(Math.random() * randomScripts.length)];
1673
+
1674
  // Add each line from the script
1675
  randomScript.forEach(line => {
1676
  const lineElement = addPodcastLine(line.speaker);
1677
  lineElement.querySelector('.line-input').value = line.text;
1678
  });
1679
  }
1680
+
1681
  // Generate podcast (mock functionality)
1682
  function generatePodcast() {
1683
  // Get all lines
 
1685
  podcastLinesContainer.querySelectorAll('.podcast-line').forEach(line => {
1686
  const speaker_id = line.querySelector('.speaker-label').textContent.includes('1') ? 0 : 1;
1687
  const text = line.querySelector('.line-input').value.trim();
1688
+
1689
  if (text) {
1690
  lines.push({ speaker_id, text });
1691
  }
1692
  });
1693
+
1694
  // Validate that we have at least 2 lines with content
1695
  if (lines.length < 2) {
1696
  openToast("Please enter at least 2 lines of dialog", "warning");
1697
  return;
1698
  }
1699
+
1700
  // Reset vote buttons and hide results
1701
  podcastVoteButtons.forEach(btn => {
1702
  btn.disabled = true;
1703
  btn.classList.remove('selected');
1704
  btn.querySelector('.vote-loader').style.display = 'none';
1705
  });
1706
+
1707
  // Clear model name displays
1708
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1709
  modelNameDisplays.forEach(display => {
 
1712
 
1713
  podcastVoteResults.style.display = 'none';
1714
  podcastNextRoundContainer.style.display = 'none';
1715
+
1716
  // Reset the flag for both samples played
1717
  bothPodcastSamplesPlayed = false;
1718
+
1719
  // Show loading animation
1720
  podcastLoadingContainer.style.display = 'flex';
1721
  podcastPlayerContainer.style.display = 'none';
1722
+
1723
  // Call API to generate podcast
1724
  fetch('/api/conversational/generate', {
1725
  method: 'POST',
 
1738
  })
1739
  .then(data => {
1740
  currentPodcastSessionId = data.session_id;
1741
+
1742
  // Hide loading
1743
  podcastLoadingContainer.style.display = 'none';
1744
+
1745
  // Show player
1746
  podcastPlayerContainer.style.display = 'block';
1747
+
1748
  // Initialize WavePlayers if not already done
1749
  if (!podcastWavePlayers.a) {
1750
  podcastWavePlayers.a = new WavePlayer(podcastWavePlayerA, {
 
1757
  backend: 'MediaElement',
1758
  mediaControls: false // Hide native audio controls
1759
  });
1760
+
1761
  // Load audio in waveplayers
1762
  podcastWavePlayers.a.loadAudio(data.audio_a);
1763
  podcastWavePlayers.b.loadAudio(data.audio_b);
1764
+
1765
  // Force hide loading indicators after 5 seconds as a fallback
1766
  setTimeout(() => {
1767
  if (podcastWavePlayers.a && podcastWavePlayers.a.hideLoading) {
 
1777
  try {
1778
  podcastWavePlayers.a.wavesurfer.empty();
1779
  podcastWavePlayers.b.wavesurfer.empty();
1780
+
1781
  // Make sure loading indicators are reset
1782
  podcastWavePlayers.a.hideLoading();
1783
  podcastWavePlayers.b.hideLoading();
1784
+
1785
  podcastWavePlayers.a.loadAudio(data.audio_a);
1786
  podcastWavePlayers.b.loadAudio(data.audio_b);
1787
+
1788
  // Force hide loading indicators after 5 seconds as a fallback
1789
  setTimeout(() => {
1790
  if (podcastWavePlayers.a && podcastWavePlayers.a.hideLoading) {
 
1797
  }, 5000);
1798
  } catch (err) {
1799
  console.error('Error resetting podcast waveplayers:', err);
1800
+
1801
  // Recreate the players if there was an error
1802
  podcastWavePlayers.a = new WavePlayer(podcastWavePlayerA, {
1803
  backend: 'MediaElement',
 
1807
  backend: 'MediaElement',
1808
  mediaControls: false
1809
  });
1810
+
1811
  podcastWavePlayers.a.loadAudio(data.audio_a);
1812
  podcastWavePlayers.b.loadAudio(data.audio_b);
1813
 
 
1823
  }, 5000);
1824
  }
1825
  }
1826
+
1827
  // Setup automatic sequential playback
1828
  podcastWavePlayers.a.wavesurfer.once('ready', function() {
1829
  podcastWavePlayers.a.play();
1830
+
1831
  // When audio A ends, play audio B
1832
  podcastWavePlayers.a.wavesurfer.once('finish', function() {
1833
  // Wait a short moment before playing B
1834
  setTimeout(() => {
1835
  podcastWavePlayers.b.play();
1836
+
1837
  // When audio B ends, enable voting
1838
  podcastWavePlayers.b.wavesurfer.once('finish', function() {
1839
  bothPodcastSamplesPlayed = true;
 
1851
  console.error('Error:', error);
1852
  });
1853
  }
1854
+
1855
  // Handle vote for a podcast model
1856
  function handlePodcastVote(model) {
1857
  // Disable both vote buttons
 
1861
  btn.querySelector('.vote-loader').style.display = 'flex';
1862
  }
1863
  });
1864
+
1865
  // Send vote to server
1866
  fetch('/api/conversational/vote', {
1867
  method: 'POST',
 
1885
  // Hide loaders
1886
  podcastVoteButtons.forEach(btn => {
1887
  btn.querySelector('.vote-loader').style.display = 'none';
1888
+
1889
  // Highlight the selected button
1890
  if (btn.dataset.model === model) {
1891
  btn.classList.add('selected');
1892
  }
1893
  });
1894
+
1895
  // Store model names from vote response
1896
  podcastModelNames.a = data.names.a;
1897
  podcastModelNames.b = data.names.b;
1898
+
1899
  // Show model names after voting
1900
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1901
  modelNameDisplays[0].textContent = data.names.a ? `(${data.names.a})` : '';
1902
  modelNameDisplays[1].textContent = data.names.b ? `(${data.names.b})` : '';
1903
+
1904
  // Show vote results
1905
  chosenModelNameElement.textContent = data.chosen_model.name;
1906
  rejectedModelNameElement.textContent = data.rejected_model.name;
1907
  podcastVoteResults.style.display = 'block';
1908
+
1909
  // Show next round button
1910
  podcastNextRoundContainer.style.display = 'block';
1911
+
1912
  // Show success toast
1913
  openToast("Vote recorded successfully!", "success");
1914
  })
 
1918
  btn.disabled = false;
1919
  btn.querySelector('.vote-loader').style.display = 'none';
1920
  });
1921
+
1922
  openToast(error.message, "error");
1923
  console.error('Error:', error);
1924
  });
1925
  }
1926
+
1927
  // Reset podcast UI to initial state
1928
  function resetPodcastState() {
1929
  // Hide players, results, and next round button
1930
  podcastPlayerContainer.style.display = 'none';
1931
  podcastVoteResults.style.display = 'none';
1932
  podcastNextRoundContainer.style.display = 'none';
1933
+
1934
  // Reset vote buttons
1935
  podcastVoteButtons.forEach(btn => {
1936
  btn.disabled = true;
1937
  btn.classList.remove('selected');
1938
  btn.querySelector('.vote-loader').style.display = 'none';
1939
  });
1940
+
1941
  // Clear model name displays
1942
  const modelNameDisplays = podcastPlayerContainer.querySelectorAll('.model-name-display');
1943
  modelNameDisplays.forEach(display => {
1944
  display.textContent = '';
1945
  });
1946
+
1947
  // Stop any playing audio
1948
  if (podcastWavePlayers.a) podcastWavePlayers.a.stop();
1949
  if (podcastWavePlayers.b) podcastWavePlayers.b.stop();
1950
+
1951
  // Reset session
1952
  currentPodcastSessionId = null;
1953
+
1954
  // Reset the flag for both samples played
1955
  bothPodcastSamplesPlayed = false;
1956
  }
1957
+
1958
  // Add keyboard shortcut listeners for podcast voting
1959
  document.addEventListener('keydown', function(e) {
1960
  // Check if we're in the podcast tab and it's active
1961
  const podcastTab = document.getElementById('conversational-tab');
1962
  if (!podcastTab.classList.contains('active')) return;
1963
+
1964
  // Only process if input fields are not focused
1965
+ if (document.activeElement.tagName === 'INPUT' ||
1966
  document.activeElement.tagName === 'TEXTAREA') {
1967
  return;
1968
  }
1969
+
1970
  if (e.key.toLowerCase() === 'a') {
1971
  if (bothPodcastSamplesPlayed && !podcastVoteButtons[0].disabled) {
1972
  handlePodcastVote('a');
 
2001
  }
2002
  }
2003
  });
2004
+
2005
  // Event listeners
2006
  addLineBtn.addEventListener('click', function() {
2007
  addPodcastLine();
2008
  });
2009
+
2010
  randomScriptBtn.addEventListener('click', function() {
2011
  loadRandomScript();
2012
  });
2013
+
2014
  podcastSynthBtn.addEventListener('click', function() {
2015
  generatePodcast();
2016
  });
2017
+
2018
  // Add event listeners to vote buttons
2019
  podcastVoteButtons.forEach(btn => {
2020
  btn.addEventListener('click', function() {
 
2026
  }
2027
  });
2028
  });
2029
+
2030
  // Add event listener for next round button
2031
  podcastNextRoundBtn.addEventListener('click', resetPodcastState);
2032
+
2033
  // Initialize with 2 empty lines
2034
  initializePodcastLines();
2035
  });