Translator / frontend /index.html
daihui.zhang
add frontend demo
2a2d4ba
raw
history blame
4.47 kB
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>试试翻译</title>
<style>
body {
background-color: #f9f9fc;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
margin: 0;
padding: 2rem;
}
.translation-box {
background: #f2f2f8;
border-radius: 12px;
padding: 1.5rem;
max-width: 800px;
margin: 0 auto;
min-height: 200px;
}
.entry {
margin-bottom: 1.5rem;
}
.timestamp {
font-size: 0.75rem;
color: #999;
}
.original {
font-size: 1rem;
color: #333;
}
.translation {
font-size: 1rem;
font-weight: bold;
color: #000;
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 2rem;
}
.lang-select {
background: white;
border-radius: 9999px;
padding: 0.4rem 1rem;
border: none;
font-size: 1rem;
box-shadow: 0 0 0 1px #ddd;
}
.record-button {
background-color: #1e40af;
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 9999px;
font-size: 1rem;
cursor: pointer;
}
</style>
</head>
<body>
<div class="translation-box" id="translationBox">
<!-- 实时内容将插入这里 -->
</div>
<div class="footer">
<select class="lang-select">
<option>中文 » 英语</option>
</select>
<button class="record-button" onclick="startRecording()">🎤 录音</button>
</div>
<script>
let ws;
let mediaRecorder;
function formatTimestamp(ms) {
const sec = ms / 1000;
const min = Math.floor(sec / 60);
const s = (sec % 60).toFixed(1);
return `${String(min).padStart(2, '0')}:${s.padStart(4, '0')}`;
}
let lastSegId = null; // 用于存储上一个 seg_id
function addTranslation(result) {
const box = document.getElementById('translationBox');
// 创建一个新的 div 来显示翻译
const entry = document.createElement('div');
entry.className = 'entry';
console.log(result);
const start = formatTimestamp(result.bg);
const end = formatTimestamp(result.ed);
// 判断是否是新的一行
if (result.seg_id === lastSegId) {
// 如果 seg_id 相同,更新该行内容
const existingEntry = box.querySelector(`.entry[data-seg-id="${result.seg_id}"]`);
if (existingEntry) {
const translationDiv = existingEntry.querySelector('.translation');
translationDiv.innerHTML = result.tranContent;
}
} else {
// 如果 seg_id 不同,表示是新的行,添加新行
entry.setAttribute('data-seg-id', result.seg_id); // 设置 seg_id
entry.innerHTML = `
<div class="original">${result.context}</div>
<div class="translation">${result.tranContent}</div>
`;
box.appendChild(entry);
}
// 更新 lastSegId 以便下一次判断
lastSegId = result.seg_id;
}
async function startRecording() {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const audioContext = new AudioContext({ sampleRate: 16000 });
const source = audioContext.createMediaStreamSource(stream);
const processor = audioContext.createScriptProcessor(4096, 1, 1);
const wsUrl = "ws://localhost:9090?from=zh&to=en";
ws = new WebSocket(wsUrl);
ws.binaryType = "arraybuffer";
ws.onopen = () => {
console.log("WebSocket opened");
source.connect(processor);
processor.connect(audioContext.destination);
processor.onaudioprocess = (e) => {
const input = e.inputBuffer.getChannelData(0);
const buffer = new Int16Array(input.length);
for (let i = 0; i < input.length; i++) {
buffer[i] = Math.max(-1, Math.min(1, input[i])) * 0x7FFF;
}
ws.send(buffer);
};
};
ws.onmessage = (event) => {
try {
const msg = JSON.parse(event.data);
if (msg.result) {
addTranslation(msg.result);
}
} catch (e) {
console.error("Parse error:", e);
}
};
ws.onerror = (e) => console.error("WebSocket error:", e);
ws.onclose = () => {
console.log("WebSocket closed");
processor.disconnect();
source.disconnect();
};
}
</script>
</body>
</html>