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 |
});
|