Popiai-skill仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

180 lines
6.2 KiB

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原声音乐画廊</title>
<style>
:root {
--bg: #0d1117; --surface: #161b22; --border: #30363d;
--text: #e6edf3; --text-secondary: #8b949e; --accent: #58a6ff;
--comedy: #3fb950; --romantic: #d2a8ff; --warm: #f0883e;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 24px; padding-bottom: 80px; }
h1 { font-size: 24px; margin-bottom: 8px; }
.subtitle { color: var(--text-secondary); margin-bottom: 32px; }
.section { margin-bottom: 40px; }
.section-title {
font-size: 18px; font-weight: 600; margin-bottom: 16px;
padding-bottom: 8px; border-bottom: 1px solid var(--border);
}
.audio-card {
background: var(--surface); border: 1px solid var(--border);
border-radius: 12px; padding: 20px; margin-bottom: 12px;
position: relative;
}
.audio-card:hover { border-color: var(--accent); }
.audio-name { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
.audio-type {
display: inline-block; font-size: 11px; padding: 2px 8px;
border-radius: 10px; margin-bottom: 12px;
}
.audio-type.character { background: rgba(210,168,255,0.2); color: var(--romantic); }
.audio-type.op { background: rgba(240,136,62,0.2); color: var(--warm); }
.audio-type.ed { background: rgba(88,166,255,0.2); color: var(--accent); }
.audio-type.bgm { background: rgba(63,185,80,0.2); color: var(--comedy); }
.audio-player {
width: 100%; margin-top: 8px;
}
audio { width: 100%; height: 40px; border-radius: 8px; }
audio::-webkit-media-controls-panel { background: var(--bg); }
.cite-btn {
position: absolute; top: 12px; right: 12px;
background: var(--border); border: none; color: var(--text-secondary);
width: 28px; height: 28px; border-radius: 6px; cursor: pointer;
font-size: 14px; display: flex; align-items: center; justify-content: center;
}
.cite-btn:hover { background: var(--accent); color: var(--bg); }
.feedback-bar {
position: fixed; bottom: 0; left: 0; right: 0;
background: var(--surface); border-top: 1px solid var(--border);
padding: 12px 24px; display: flex; gap: 12px; align-items: center; z-index: 100;
}
.feedback-bar textarea {
flex: 1; background: var(--bg); border: 1px solid var(--border);
color: var(--text); border-radius: 8px; padding: 10px 14px;
font-size: 14px; resize: none; height: 44px; line-height: 24px; font-family: inherit;
}
.feedback-bar textarea:focus { outline: none; border-color: var(--accent); }
.feedback-bar button {
background: var(--accent); color: var(--bg); border: none;
padding: 10px 20px; border-radius: 8px; font-weight: 600;
cursor: pointer; font-size: 14px; white-space: nowrap;
}
.feedback-bar button.lgtm { background: var(--comedy); }
.feedback-bar button:hover { opacity: 0.9; }
.empty-state {
text-align: center; padding: 60px 20px; color: var(--text-secondary);
}
.empty-state svg { width: 48px; height: 48px; margin-bottom: 16px; opacity: 0.3; }
</style>
</head>
<body>
<script>
const PREVIEW_DATA = null; /* __PREVIEW_DATA__ */
</script>
<div id="app"></div>
<div class="feedback-bar">
<textarea id="feedbackText" placeholder="输入修改建议… 点击 @ 引用特定曲目"></textarea>
<button class="lgtm" onclick="submitFeedback('LGTM')">LGTM</button>
<button onclick="submitFeedback()">提交建议</button>
</div>
<script>
const data = JSON.parse(PREVIEW_DATA);
function renderAudioCard(item, type, typeLabel) {
const citeRef = `@${typeLabel}/${item.name}`;
return `
<div class="audio-card">
<button class="cite-btn" title="引用" onclick="cite('${citeRef}')">@</button>
<div class="audio-name">${item.name}</div>
<span class="audio-type ${type}">${typeLabel}</span>
<div class="audio-player">
<audio controls preload="metadata" src="${item.audio_url}"></audio>
</div>
</div>
`;
}
function render() {
let html = `<h1>${data.title || '原声音乐'} — 音频画廊</h1>`;
html += `<div class="subtitle">试听所有生成的音乐,确认满意后提交</div>`;
let hasContent = false;
if (data.opening) {
hasContent = true;
html += `<div class="section"><div class="section-title">片头曲 (OP)</div>`;
html += renderAudioCard(data.opening, 'op', 'OP');
html += '</div>';
}
if (data.character_themes && data.character_themes.length) {
hasContent = true;
html += `<div class="section"><div class="section-title">角色主题曲</div>`;
data.character_themes.forEach(t => { html += renderAudioCard(t, 'character', '角色曲'); });
html += '</div>';
}
if (data.ending) {
hasContent = true;
html += `<div class="section"><div class="section-title">片尾曲 (ED)</div>`;
html += renderAudioCard(data.ending, 'ed', 'ED');
html += '</div>';
}
if (data.bgm && data.bgm.length) {
hasContent = true;
html += `<div class="section"><div class="section-title">场景配乐 (BGM)</div>`;
data.bgm.forEach(t => { html += renderAudioCard(t, 'bgm', 'BGM'); });
html += '</div>';
}
if (!hasContent) {
html += `<div class="empty-state">
<div style="font-size:48px;opacity:0.3;">🎵</div>
<p>暂无已完成的音频文件</p>
</div>`;
}
document.getElementById('app').innerHTML = html;
}
function cite(ref) {
const ta = document.getElementById('feedbackText');
ta.value += (ta.value ? ' ' : '') + ref;
ta.focus();
}
async function submitFeedback(override) {
const text = override || document.getElementById('feedbackText').value.trim();
if (!text) return;
try {
const res = await fetch('/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ feedback: text }),
});
const d = await res.json();
if (d.ok) {
document.body.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100vh;font-size:20px;color:#3fb950;">已提交,窗口即将关闭</div>';
}
} catch (e) {
alert('提交失败: ' + e.message);
}
}
render();
</script>
</body>
</html>