HsuHH's picture
Upload index.html
f20b964 verified
Raw
History Blame Contribute Delete
3.82 kB
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>AI 情緒分析 - ONNX Web</title>
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js"></script>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; line-height: 1.6; }
textarea { width: 100%; padding: 10px; margin-bottom: 10px; border-radius: 8px; border: 1px solid #ccc; }
button { padding: 10px 20px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 5px; }
#result { margin-top: 20px; padding: 15px; border-radius: 8px; background: #f8f9fa; font-weight: bold; }
</style>
</head>
<body>
<h2>🎭 電影評論情緒分析 (邊緣運算)</h2>
<p>輸入一段英文短句進行測試:</p>
<textarea id="inputText" rows="3">This Movie is incredibly helpful and well-organized!</textarea>
<button id="runBtn">開始分析</button>
<div id="result">正在初始化模型...</div>
<script>
let session;
let wordIndex;
const MAX_LEN = 48;
// 1. 初始化模型與資源
async function init() {
try {
// 載入 ONNX 模型
session = await ort.InferenceSession.create('./best_lstm.onnx');
// 載入詞彙表
wordIndex = await fetch('./word_index.json').then(r => r.json());
document.getElementById('result').innerText = "✅ 模型載入成功,可以開始分析。";
} catch (e) {
document.getElementById('result').innerText = "❌ 錯誤: " + e.message;
}
}
// 2. 文字預處理 (Tokenization & Padding)
function preprocess(text) {
// 清理文字:轉小寫、移除標點
const tokens = text.toLowerCase().replace(/[^\w\s]/g, '').trim().split(/\s+/);
// 轉為 ID (若不在詞表則使用 <UNK> id: 1)
let sequence = tokens.map(t => wordIndex[t] || 1);
// 補齊或裁切長度至 48
if (sequence.length > MAX_LEN) {
sequence = sequence.slice(0, MAX_LEN);
} else {
while (sequence.length < MAX_LEN) sequence.push(0);
}
// 注意:模型輸入層定義為 float32
return new Float32Array(sequence);
}
// 3. 執行推論
async function runInference() {
const text = document.getElementById('inputText').value;
if (!text.trim()) return;
document.getElementById('result').innerText = "分析中...";
const inputData = preprocess(text);
const tensor = new ort.Tensor('float32', inputData, [1, MAX_LEN]);
// 注意:'input_layer' 與 'output_0' 必須與模型轉換時的名稱一致
const feeds = { input_layer: tensor };
const results = await session.run(feeds);
const output = results.output_0.data;
// 取得機率最高的類別
const predIdx = output.indexOf(Math.max(...output));
const labels = ["👿 極度負面", "🙁 負面", "😐 中性", "🙂 正面", "🌟 極度正面"];
const colors = ["#d9534f", "#f0ad4e", "#6c757d", "#5bc0de", "#5cb85c"];
const resDiv = document.getElementById('result');
resDiv.innerText = `結果:${labels[predIdx]}`;
resDiv.style.color = "white";
resDiv.style.backgroundColor = colors[predIdx];
}
document.getElementById('runBtn').onclick = runInference;
init();
</script>
</body>
</html>