Commit
·
946a55b
1
Parent(s):
8374ff5
(wip)update html
Browse files- 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 |
});
|