925 lines
33 KiB
HTML
925 lines
33 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<script src="lang-1.6.js"></script>
|
||
<title data-i18n="title">黑盒圆桌</title>
|
||
<style>
|
||
body {
|
||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||
max-width: 1000px;
|
||
margin: 0 auto;
|
||
padding: 50px;
|
||
line-height: 1.8;
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 3.2em;
|
||
color: #1a1a1a;
|
||
margin-bottom: 40px;
|
||
text-align: center;
|
||
letter-spacing: 5px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
#question-form {
|
||
margin-bottom: 50px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
#question-input {
|
||
flex-grow: 1;
|
||
padding: 15px 20px;
|
||
font-size: 16px;
|
||
border: none;
|
||
border-radius: 25px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
margin-right: 20px;
|
||
background-color: #fff;
|
||
}
|
||
|
||
#rounds-input {
|
||
width: 70px;
|
||
padding: 15px;
|
||
font-size: 16px;
|
||
border: none;
|
||
border-radius: 25px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
text-align: center;
|
||
margin-right: 20px;
|
||
background-color: #fff;
|
||
}
|
||
|
||
#submit-button {
|
||
padding: 15px 30px;
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 25px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
transition: background-color 0.3s ease, transform 0.2s ease;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
#submit-button:hover {
|
||
background-color: #333;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
#discussion-output {
|
||
margin-top: 40px;
|
||
}
|
||
|
||
.message-container {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
background-color: white;
|
||
border-radius: 15px;
|
||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
||
margin-bottom: 25px;
|
||
padding: 25px;
|
||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||
border-left: 4px solid #1a1a1a;
|
||
}
|
||
|
||
.avatar {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 50%;
|
||
margin-right: 20px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.message-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.message-container:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 6px 12px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.message-role {
|
||
font-weight: 600;
|
||
margin-bottom: 15px;
|
||
color: #1a1a1a;
|
||
font-size: 1.1em;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
.message-text {
|
||
white-space: pre-wrap;
|
||
margin-bottom: 20px;
|
||
line-height: 1.8;
|
||
color: #333;
|
||
}
|
||
|
||
.audio-player {
|
||
width: 100%;
|
||
margin-top: 20px;
|
||
border-radius: 25px;
|
||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.human-message {
|
||
background-color: #f9f9f9;
|
||
border-left: 4px solid #1a1a1a;
|
||
}
|
||
|
||
.ai-message {
|
||
background-color: #fff;
|
||
border-left: 4px solid #666;
|
||
}
|
||
|
||
#roles-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-bottom: 40px;
|
||
justify-content: center;
|
||
}
|
||
|
||
.role-tag {
|
||
background-color: #fff;
|
||
color: #1a1a1a;
|
||
padding: 10px 20px;
|
||
font-size: 14px;
|
||
transition: all 0.2s ease;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
border-radius: 20px;
|
||
cursor: pointer;
|
||
border: 1px solid #1a1a1a;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.role-tag:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||
}
|
||
|
||
.role-tag.selected {
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
body {
|
||
padding: 30px;
|
||
}
|
||
|
||
#question-form {
|
||
flex-direction: column;
|
||
}
|
||
|
||
#question-input, #rounds-input, #submit-button {
|
||
width: 100%;
|
||
margin-right: 0;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
#roles-list {
|
||
justify-content: center;
|
||
}
|
||
|
||
.role-tag {
|
||
font-size: 12px;
|
||
padding: 8px 16px;
|
||
}
|
||
|
||
}
|
||
#session-id {
|
||
margin-top: 10px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
|
||
@media (max-width: 768px) {
|
||
#back-to-square {
|
||
top: 10px;
|
||
left: 10px;
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
}
|
||
}
|
||
|
||
.topic-message {
|
||
background-color: #000000;
|
||
border: 2px solid #ffffff;
|
||
border-radius: 15px;
|
||
padding: 25px;
|
||
margin: 20px 0;
|
||
text-align: center;
|
||
box-shadow: 0 4px 15px rgba(255, 255, 255, 0.1);
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.topic-message .message-role {
|
||
font-size: 1.2em;
|
||
color: #ffffff;
|
||
margin-bottom: 0;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1.5px;
|
||
font-weight: bold;
|
||
text-align: center;
|
||
}
|
||
|
||
#download-audio-btn {
|
||
background-color: #000000;
|
||
color: #ffffff;
|
||
border: 2px solid #ffffff;
|
||
border-radius: 15px;
|
||
padding: 25px;
|
||
margin: 20px 0;
|
||
cursor: pointer;
|
||
font-size: 1em;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1.5px;
|
||
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
text-align: center;
|
||
display: block;
|
||
}
|
||
|
||
#download-audio-btn:hover {
|
||
background-color: #333333;
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 15px rgba(255, 255, 255, 0.2);
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.topic-message,
|
||
#download-audio-btn {
|
||
padding: 20px;
|
||
font-size: 0.9em;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.container {
|
||
padding: 10px;
|
||
}
|
||
|
||
#language-select {
|
||
font-size: 14px;
|
||
padding: 8px;
|
||
}
|
||
|
||
#back-to-square {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
}
|
||
}
|
||
|
||
.topic-selector {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.topic-button {
|
||
background-color: white;
|
||
color: black;
|
||
border: 1px solid #1a1a1a;
|
||
border-radius: 25px;
|
||
padding: 10px 20px;
|
||
margin: 0 10px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
transition: background-color 0.3s ease, transform 0.2s ease;
|
||
}
|
||
|
||
.topic-button:hover {
|
||
background-color: #f0f0f0;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.topic-button.active {
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
}
|
||
|
||
/* 添加语言选择器样式 */
|
||
.container {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 20px 0;
|
||
width: 100%;
|
||
max-width: 1000px;
|
||
box-sizing: border-box;
|
||
margin: 0 auto;
|
||
}
|
||
.right-section {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
#back-to-square {
|
||
padding: 10px 20px;
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 25px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
transition: background-color 0.3s ease, transform 0.2s ease;
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
width: auto; /* Allow the width to adjust to content */
|
||
min-width: 40px; /* Set a minimum width */
|
||
}
|
||
|
||
#back-to-square:hover {
|
||
background-color: #333;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
#language-selector {
|
||
margin: 10px;
|
||
}
|
||
|
||
#language-select {
|
||
padding: 10px 20px;
|
||
font-size: 16px;
|
||
border: none;
|
||
border-radius: 25px;
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
cursor: pointer;
|
||
transition: background-color 0.3s ease;
|
||
width: auto; /* Allow the width to adjust to content */
|
||
min-width: 40px; /* Set a minimum width */
|
||
}
|
||
|
||
#language-select:hover {
|
||
background-color: #333;
|
||
}
|
||
|
||
#language-select option {
|
||
background-color: white;
|
||
color: black;
|
||
padding: 10px;
|
||
}
|
||
|
||
#language-select:focus {
|
||
outline: none;
|
||
box-shadow: 0 0 0 2px rgba(255,255,255,0.5);
|
||
}
|
||
.avatar {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 50%;
|
||
margin-right: 20px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.message-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
position: relative;
|
||
cursor: pointer;
|
||
margin-left: auto; /* 将用户信息推到右侧 */
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-weight: bold;
|
||
font-size: 20px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.user-dropdown {
|
||
display: none;
|
||
position: absolute;
|
||
top: 100%;
|
||
right: 0;
|
||
background-color: white;
|
||
border: 1px solid #ccc;
|
||
border-radius: 5px;
|
||
padding: 10px;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.user-dropdown.show {
|
||
display: block;
|
||
}
|
||
|
||
.logout-btn {
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 10px; /* Increased padding */
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
width: 100%; /* Make the button full width within its container */
|
||
min-width: 60px; /* Set a minimum width */
|
||
font-size: 13px; /* Increased font size */
|
||
transition: background-color 0.3s ease; /* Smooth transition for hover effect */
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.container {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 10px;
|
||
width: calc(100% - 30px);
|
||
}
|
||
|
||
#back-to-square {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
white-space: nowrap;
|
||
min-width: 100px;
|
||
}
|
||
|
||
.right-section {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: auto; /* 将右侧部分推到最右边 */
|
||
}
|
||
|
||
#language-select {
|
||
font-size: 14px;
|
||
padding: 8px 16px;
|
||
white-space: nowrap;
|
||
width: 100px;
|
||
min-width: 100px;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 14px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.user-dropdown {
|
||
right: 0;
|
||
left: auto;
|
||
transform: none;
|
||
}
|
||
.logout-btn {
|
||
background-color: #1a1a1a;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 8px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
width: auto; /* 调整为自动宽度 */
|
||
min-width: 60px;
|
||
font-size: 13px;
|
||
transition: background-color 0.3s ease;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="container">
|
||
<button id="back-to-square" data-i18n="backToSquare">返回广场</button>
|
||
<div class="right-section">
|
||
<div id="language-selector">
|
||
<select id="language-select">
|
||
<option value="zh">中文</option>
|
||
<option value="en">English</option>
|
||
<option value="ko">한국어</option>
|
||
</select>
|
||
</div>
|
||
<div class="user-info" id="userInfo">
|
||
<div class="user-avatar" id="userAvatar"></div>
|
||
<span id="username"></span>
|
||
<div class="user-dropdown" id="userDropdown">
|
||
<button class="logout-btn" id="logoutBtn" data-i18n="logout">登出</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<h1 data-i18n="title">黑盒圆桌</h1>
|
||
<div class="topic-selector">
|
||
<button class="topic-button active" data-topic="brainstorm" data-i18n="brainstorm">头脑风暴</button>
|
||
<button class="topic-button" data-topic="hallOfFame" data-i18n="hallOfFame">名人堂</button>
|
||
</div>
|
||
<div id="roles-list"></div>
|
||
<form id="question-form">
|
||
<input type="text" id="question-input" data-i18n="inputPlaceholder" placeholder="在此处输入问题" required>
|
||
<label for="rounds-input" data-i18n="roundsLabel">讨论轮数:</label>
|
||
<input type="number" id="rounds-input" value="1" min="1" max="10">
|
||
<button type="submit" id="submit-button" data-i18n="startDiscussion">开始讨论</button>
|
||
</form>
|
||
<div id="session-id"></div>
|
||
<div id="discussion-output"></div>
|
||
<script>
|
||
const BASE_URL = 'https://dev.obscura.work/user';
|
||
const questionForm = document.getElementById('question-form');
|
||
const questionInput = document.getElementById('question-input');
|
||
const roundsInput = document.getElementById('rounds-input');
|
||
const discussionOutput = document.getElementById('discussion-output');
|
||
const rolesList = document.getElementById('roles-list');
|
||
const sessionIdDisplay = document.getElementById('session-id');
|
||
const specialRoles = {
|
||
brainstorm: ['市场营销专家', '技术专家', '创意专家', '财务专家', '项目规划专家', '数据分析专家'],
|
||
hallOfFame: ['马化腾', '李诞', '罗翔', '许知远', '大冰', '余华', '刘震云', '雷军']
|
||
};
|
||
let currentTopic = 'brainstorm';
|
||
let selectedRoles = ['主持人'];
|
||
let isAudioReady = false;
|
||
// 删除这行: let currentLanguage = localStorage.getItem('preferredLanguage') || 'zh';
|
||
|
||
// 获取URL参数中的语言设置
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
let currentLanguage = urlParams.get('lang') || localStorage.getItem('preferredLanguage') || 'zh';
|
||
|
||
function initializeRoles() {
|
||
rolesList.innerHTML = '';
|
||
specialRoles[currentTopic].forEach(role => {
|
||
const roleTag = document.createElement('span');
|
||
roleTag.className = 'role-tag';
|
||
roleTag.textContent = translations[currentLanguage].roles[role] || role;
|
||
roleTag.setAttribute('data-role', role);
|
||
roleTag.addEventListener('click', () => toggleRole(role, roleTag));
|
||
rolesList.appendChild(roleTag);
|
||
});
|
||
}
|
||
|
||
function toggleRole(role, element) {
|
||
if (selectedRoles.includes(role)) {
|
||
selectedRoles = selectedRoles.filter(r => r !== role);
|
||
element.classList.remove('selected');
|
||
} else {
|
||
selectedRoles.push(role);
|
||
element.classList.add('selected');
|
||
}
|
||
}
|
||
|
||
function updateLanguage(lang) {
|
||
currentLanguage = lang;
|
||
localStorage.setItem('preferredLanguage', lang);
|
||
document.documentElement.lang = lang;
|
||
document.querySelectorAll('[data-i18n]').forEach(element => {
|
||
const key = element.getAttribute('data-i18n');
|
||
if (translations[lang][key]) {
|
||
if (element.tagName === 'INPUT' && element.getAttribute('placeholder')) {
|
||
element.placeholder = translations[lang][key];
|
||
} else {
|
||
element.textContent = translations[lang][key];
|
||
}
|
||
}
|
||
});
|
||
|
||
// 更新角色标签的语言
|
||
document.querySelectorAll('.role-tag').forEach(tag => {
|
||
const role = tag.getAttribute('data-role');
|
||
tag.textContent = translations[lang].roles[role] || role;
|
||
});
|
||
|
||
// 更新URL,不刷新页面
|
||
const newUrl = new URL(window.location.href);
|
||
newUrl.searchParams.set('lang', lang);
|
||
window.history.pushState({}, '', newUrl);
|
||
}
|
||
|
||
document.getElementById('language-select').addEventListener('change', function() {
|
||
updateLanguage(this.value);
|
||
initializeRoles(); // 重新初始化角色列表
|
||
});
|
||
|
||
questionForm.addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
const question = questionInput.value;
|
||
const maxRounds = roundsInput.value;
|
||
const sessionId = generateSessionId();
|
||
const selectedLanguage = document.getElementById('language-select').value; // 获取选择的语言
|
||
console.log('提交的问题:', question, '最大轮数:', maxRounds, 'Session_ID:', sessionId, '选中的角色:', selectedRoles, '选择的语言:', selectedLanguage);
|
||
discussionOutput.innerHTML = `<p>${translations[currentLanguage].discussionInProgress}</p>`;
|
||
currentSessionId = sessionId;
|
||
try {
|
||
console.log('发送请求至:', `${BASE_URL}/api/start-discussion`);
|
||
const response = await fetch(`${BASE_URL}/api/start-discussion`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
topic: question,
|
||
max_rounds: parseInt(maxRounds),
|
||
session_id: sessionId,
|
||
selected_roles: selectedRoles,
|
||
language: selectedLanguage,
|
||
current_topic: currentTopic // 添加这一行
|
||
}),
|
||
});
|
||
console.log('收到响应:', response);
|
||
|
||
const reader = response.body.getReader();
|
||
const decoder = new TextDecoder();
|
||
|
||
let isCompleted = false;
|
||
discussionOutput.innerHTML = '';
|
||
|
||
while (!isCompleted) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
|
||
const content = decoder.decode(value);
|
||
console.log('Received content:', content);
|
||
if (content.includes('[AUDIO_COMPLETED]')) {
|
||
console.log('Received AUDIO_COMPLETED message');
|
||
const downloadButton = document.createElement('button');
|
||
downloadButton.id = 'download-audio-btn';
|
||
downloadButton.textContent = translations[currentLanguage].discussionCompleted;
|
||
downloadButton.onclick = () => downloadAudio(currentSessionId);
|
||
discussionOutput.appendChild(downloadButton);
|
||
console.log('Download button added to DOM');
|
||
isCompleted = true;
|
||
|
||
try {
|
||
const jsonData = JSON.parse(content);
|
||
if (jsonData.audio_task_id) {
|
||
handleAudio(jsonData.audio_task_id, completionMessage);
|
||
}
|
||
} catch (jsonError) {
|
||
console.error('Error parsing AUDIO_COMPLETED JSON:', jsonError);
|
||
}
|
||
|
||
break;
|
||
}
|
||
const lines = content.split('\n');
|
||
for (const line of lines) {
|
||
if (line.startsWith('data: ')) {
|
||
const data = line.slice(6);
|
||
console.log('Parsed data:', data);
|
||
|
||
try {
|
||
const jsonData = JSON.parse(data);
|
||
console.log('Parsed JSON data:', jsonData);
|
||
|
||
if (jsonData.topic) {
|
||
const topicContainer = document.createElement('div');
|
||
topicContainer.className = 'message-container topic-message';
|
||
topicContainer.innerHTML = `
|
||
<div class="message-role">${jsonData.topic}</div>
|
||
`;
|
||
discussionOutput.appendChild(topicContainer);
|
||
} else if (jsonData.chunk) {
|
||
const messageContainer = document.createElement('div');
|
||
messageContainer.className = 'message-container';
|
||
|
||
const avatarImg = document.createElement('img');
|
||
avatarImg.className = 'avatar';
|
||
avatarImg.src = `${BASE_URL}/avatar/${jsonData.avatar}`; // 更新头像路径
|
||
avatarImg.alt = jsonData.post;
|
||
|
||
const messageContent = document.createElement('div');
|
||
messageContent.className = 'message-content';
|
||
messageContent.innerHTML = `
|
||
<div class="message-role">${jsonData.post}</div>
|
||
<div class="message-text">${jsonData.chunk}</div>
|
||
`;
|
||
messageContainer.appendChild(avatarImg);
|
||
messageContainer.appendChild(messageContent);
|
||
discussionOutput.appendChild(messageContainer);
|
||
console.log('New message container created with avatar');
|
||
|
||
if (jsonData.audio_task_id) {
|
||
console.log('Audio task ID detected:', jsonData.audio_task_id);
|
||
handleAudio(jsonData.audio_task_id, messageContent);
|
||
}
|
||
}
|
||
discussionOutput.scrollTop = discussionOutput.scrollHeight;
|
||
console.log('Discussion output scrolled to bottom');
|
||
} catch (jsonError) {
|
||
console.error('Error parsing JSON:', jsonError, 'Raw data:', data);
|
||
}
|
||
}
|
||
}
|
||
console.log('Discussion output content:', discussionOutput.innerHTML);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('获取操作出错:', error);
|
||
discussionOutput.innerHTML += `<p>${translations[currentLanguage].errorOccurred}</p>`;
|
||
}
|
||
});
|
||
|
||
async function downloadAudio(sessionId) {
|
||
if (!sessionId) {
|
||
alert(translations[currentLanguage].startDiscussionFirst);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const selectedLanguage = document.getElementById('language-select').value;
|
||
const response = await fetch(`${BASE_URL}/api/get-combined-audio/${sessionId}?language=${selectedLanguage}`);
|
||
|
||
if (response.ok) {
|
||
const blob = await response.blob();
|
||
const url = window.URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.style.display = 'none';
|
||
a.href = url;
|
||
a.download = `${sessionId}_combined.wav`;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
window.URL.revokeObjectURL(url);
|
||
} else if (response.status === 404) {
|
||
const data = await response.json();
|
||
if (data.detail === "Combined audio not found") {
|
||
alert(translations[currentLanguage].audioGenerating);
|
||
} else {
|
||
alert(translations[currentLanguage].audioNotExist);
|
||
}
|
||
} else {
|
||
throw new Error(translations[currentLanguage].downloadError);
|
||
}
|
||
} catch (error) {
|
||
console.error('下载音频时发生错误:', error);
|
||
alert(translations[currentLanguage].downloadError);
|
||
}
|
||
}
|
||
|
||
function generateSessionId() {
|
||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||
return v.toString(16);
|
||
});
|
||
}
|
||
|
||
async function handleAudio(taskId, messageContainer) {
|
||
console.log('Handling audio for task ID:', taskId);
|
||
let status = 'queued';
|
||
while (status === 'queued' || status === 'processing') {
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
try {
|
||
const response = await fetch(`${BASE_URL}/tts_result/${taskId}`);
|
||
const data = await response.json();
|
||
status = data.status;
|
||
console.log('Audio status:', status);
|
||
} catch (error) {
|
||
console.error('Error checking audio status:', error);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (status === 'completed') {
|
||
try {
|
||
console.log('Audio completed, fetching audio file');
|
||
const audioResponse = await fetch(`${BASE_URL}/tts_audio/${taskId}`);
|
||
const audioBlob = await audioResponse.blob();
|
||
const audioUrl = URL.createObjectURL(audioBlob);
|
||
|
||
const audioPlayer = document.createElement('audio');
|
||
audioPlayer.controls = true;
|
||
audioPlayer.src = audioUrl;
|
||
audioPlayer.className = 'audio-player';
|
||
|
||
messageContainer.appendChild(audioPlayer);
|
||
console.log('Audio player added to message container');
|
||
} catch (error) {
|
||
console.error('Error fetching or creating audio:', error);
|
||
}
|
||
} else {
|
||
console.error('Audio generation failed');
|
||
}
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
document.getElementById('language-select').value = currentLanguage;
|
||
updateLanguage(currentLanguage);
|
||
initializeRoles();
|
||
});
|
||
|
||
document.getElementById('back-to-square').addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
const lang = document.getElementById('language-select').value;
|
||
window.location.href = `https://beta.obscura.work/space.html?lang=${lang}`;
|
||
});
|
||
|
||
document.querySelectorAll('.topic-button').forEach(button => {
|
||
button.addEventListener('click', () => {
|
||
switchTopic(button.getAttribute('data-topic'));
|
||
});
|
||
});
|
||
|
||
function switchTopic(topic) {
|
||
currentTopic = topic;
|
||
document.querySelectorAll('.topic-button').forEach(button => {
|
||
button.classList.remove('active');
|
||
});
|
||
document.querySelector(`[data-topic="${topic}"]`).classList.add('active');
|
||
selectedRoles = ['主持人'];
|
||
initializeRoles();
|
||
}
|
||
|
||
|
||
// 检查登录状态的函数
|
||
async function checkLoginStatus() {
|
||
const token = localStorage.getItem('access_token');
|
||
if (!token) {
|
||
window.location.href = '/login.html';
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`${BASE_URL}/me`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error('未登录或会话已过期');
|
||
}
|
||
|
||
// 如果成功,用户已登录
|
||
console.log('用户已登录');
|
||
} catch (error) {
|
||
console.error('检查登录状态时出错:', error);
|
||
localStorage.removeItem('access_token');
|
||
window.location.href = '/login.html';
|
||
}
|
||
}
|
||
|
||
// 添加用户信息和登出功能
|
||
const userInfo = document.getElementById('userInfo');
|
||
const userDropdown = document.getElementById('userDropdown');
|
||
const logoutBtn = document.getElementById('logoutBtn');
|
||
const usernameSpan = document.getElementById('username');
|
||
const userAvatar = document.getElementById('userAvatar');
|
||
|
||
async function fetchUserInfo() {
|
||
try {
|
||
const response = await fetch(`${BASE_URL}/user-info`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
|
||
}
|
||
});
|
||
if (response.ok) {
|
||
const userData = await response.json();
|
||
usernameSpan.textContent = userData.username;
|
||
userAvatar.textContent = userData.avatar;
|
||
}
|
||
} catch (error) {
|
||
console.error('Error fetching user info:', error);
|
||
}
|
||
}
|
||
|
||
userInfo.addEventListener('click', () => {
|
||
userDropdown.classList.toggle('show');
|
||
});
|
||
|
||
logoutBtn.addEventListener('click', async () => {
|
||
try {
|
||
const response = await fetch(`${BASE_URL}/logout`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
|
||
}
|
||
});
|
||
if (response.ok) {
|
||
localStorage.removeItem('access_token');
|
||
window.location.href = '/login.html';
|
||
}
|
||
} catch (error) {
|
||
console.error('Error logging out:', error);
|
||
}
|
||
});
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// 现有的初始化代码
|
||
checkLoginStatus();
|
||
fetchUserInfo();
|
||
});
|
||
|
||
// 在页面加载时检查登录状态
|
||
document.addEventListener('DOMContentLoaded', checkLoginStatus);
|
||
</script>
|
||
</body>
|
||
</html> |