scam-detectorv2 / script.js
jerrynnms's picture
Update script.js
63da521 verified
document.addEventListener('DOMContentLoaded', () => {
// ─────────────────────────────────────────────────────────────────────────
// 1. 文字分析相關元素
const inputTextArea = document.getElementById('predict_info');
const inputButton = document.getElementById('detect_button');
const clearButton = document.getElementById('clear_button');
const normalOrScam = document.getElementById('is_scam');
const confidenceScoreSpan = document.getElementById('confidence_score');
const suspiciousPhrasesDiv = document.getElementById('suspicious_phrases');
const feedbackArea = document.getElementById('feedback_area');
const feedbackCorrectBtn = document.getElementById('feedback_correct');
const feedbackWrongBtn = document.getElementById('feedback_wrong');
const feedbackStatus = document.getElementById('feedback_status');
let lastPrediction = null;
const TEXT_API = '/predict';
const FEEDBACK_API = '/feedback';
// 文字檢測:當按「檢測!」時觸發
inputButton.addEventListener('click', async () => {
const message = inputTextArea.value.trim();
if (!message) {
alert('請輸入您想檢測的訊息內容。');
return;
}
// 顯示 loading
normalOrScam.textContent = '檢測中...';
normalOrScam.style.color = 'gray';
confidenceScoreSpan.textContent = '計算中...';
suspiciousPhrasesDiv.innerHTML = '<p>正在分析訊息,請稍候...</p>';
feedbackArea.style.display = 'none';
feedbackStatus.textContent = '';
feedbackCorrectBtn.style.display = 'inline-block';
feedbackWrongBtn.style.display = 'inline-block';
try {
const res = await fetch(TEXT_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: message })
});
if (!res.ok) throw new Error(`伺服器錯誤: ${res.status}`);
const data = await res.json();
// 更新文字分析結果
normalOrScam.textContent = data.status;
confidenceScoreSpan.textContent = data.confidence + '%';
// 可疑詞句
suspiciousPhrasesDiv.innerHTML = '';
if (Array.isArray(data.suspicious_keywords) && data.suspicious_keywords.length) {
const ul = document.createElement('ul');
data.suspicious_keywords.forEach(kw => {
const li = document.createElement('li');
li.textContent = kw;
ul.appendChild(li);
});
suspiciousPhrasesDiv.appendChild(ul);
} else {
suspiciousPhrasesDiv.innerHTML = '<p>沒有偵測到可疑詞句。</p>';
}
// 顯示回饋區
feedbackArea.style.display = 'block';
lastPrediction = { text: message, model_status: data.status };
} catch (err) {
console.error('文字檢測失敗:', err);
alert(`文字檢測失敗,請檢查後端。\n錯誤:${err.message}`);
// 還原預設文字區
normalOrScam.textContent = '待檢測';
normalOrScam.style.color = 'inherit';
confidenceScoreSpan.textContent = '待檢測';
suspiciousPhrasesDiv.innerHTML = '<p>請輸入訊息並點擊「檢測!」按鈕。</p>';
}
});
// 「清除」按鈕:清空文字、圖片結果
clearButton.addEventListener('click', () => {
inputTextArea.value = '';
// 清空文字檢測結果
normalOrScam.textContent = '待檢測';
normalOrScam.style.color = 'inherit';
confidenceScoreSpan.textContent = '待檢測';
suspiciousPhrasesDiv.innerHTML = '<p>請輸入訊息並點擊「檢測!」按鈕。</p>';
feedbackArea.style.display = 'none';
feedbackStatus.textContent = '';
// 清空圖片OCR結果
extractedTextSpan.textContent = '尚未上傳圖片';
imgIsScamSpan.textContent = '尚未上傳圖片';
imgConfidenceSpan.textContent = '尚未上傳圖片';
imgSuspiciousDiv.innerHTML = '<p>尚未上傳圖片。</p>';
imageUpload.value = '';
});
// 使用者回饋
feedbackCorrectBtn.addEventListener('click', () => submitFeedback('正確'));
feedbackWrongBtn.addEventListener('click', () => submitFeedback('錯誤'));
async function submitFeedback(user_feedback) {
if (!lastPrediction) return;
const payload = { ...lastPrediction, user_feedback };
try {
const r = await fetch(FEEDBACK_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
await r.json();
feedbackStatus.textContent = '✅ 感謝您的回饋!';
feedbackCorrectBtn.style.display = 'none';
feedbackWrongBtn.style.display = 'none';
} catch (e) {
feedbackStatus.textContent = '❌ 回饋提交失敗';
}
}
// ─────────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────────
// 2. 圖片OCR相關元素
const imageUpload = document.getElementById('image_upload');
const imageButton = document.getElementById('image_button');
const extractedTextSpan = document.getElementById('extracted_text');
const imgIsScamSpan = document.getElementById('img_is_scam');
const imgConfidenceSpan = document.getElementById('img_confidence');
const imgSuspiciousDiv = document.getElementById('img_suspicious_phrases');
const IMAGE_API = '/analyze-image';
imageButton.addEventListener('click', async () => {
// 確認 user 已經選擇檔案
if (!imageUpload.files.length) {
alert('請先選擇一個圖片檔案。');
return;
}
// 顯示 Loading
extractedTextSpan.textContent = '辨識中...';
imgIsScamSpan.textContent = '辨識中...';
imgConfidenceSpan.textContent = '辨識中...';
imgSuspiciousDiv.innerHTML = '<p>正在分析圖片,請稍候...</p>';
// 建立 FormData,append 檔案
const formData = new FormData();
formData.append('file', imageUpload.files[0]);
try {
const resp = await fetch(IMAGE_API, {
method: 'POST',
body: formData
});
if (!resp.ok) throw new Error(`伺服器錯誤: ${resp.status}`);
const data = await resp.json();
// 此 data 格式:{ extracted_text: "...", analysis_result: { status, confidence, suspicious_keywords } }
const extracted = data.extracted_text || '';
const result = data.analysis_result || {};
// 更新前端OCR結果
extractedTextSpan.textContent = extracted || '(無文字)';
imgIsScamSpan.textContent = result.status || '(無法辨識)';
imgConfidenceSpan.textContent = (result.confidence !== undefined)
? result.confidence + '%'
: '(無法辨識)';
imgSuspiciousDiv.innerHTML = '';
if (Array.isArray(result.suspicious_keywords) && result.suspicious_keywords.length) {
const ul2 = document.createElement('ul');
result.suspicious_keywords.forEach(kw => {
const li2 = document.createElement('li');
li2.textContent = kw;
ul2.appendChild(li2);
});
imgSuspiciousDiv.appendChild(ul2);
} else {
imgSuspiciousDiv.innerHTML = '<p>無可疑詞句。</p>';
}
} catch (err) {
console.error('圖片辨識失敗:', err);
extractedTextSpan.textContent = '(圖片辨識失敗)';
imgIsScamSpan.textContent = '(失敗)';
imgConfidenceSpan.textContent = '0%';
imgSuspiciousDiv.innerHTML = `<p style="color:red;">❌ ${err.message}</p>`;
}
});
// ─────────────────────────────────────────────────────────────────────────
});