当前位置: 首页 > news >正文

实战项目中文影评情感分析系统

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>中文影评情感分析系统</title><link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;700&display=swap" rel="stylesheet"><style>:root {--primary: #23408e;--secondary: #4a7bb7;--accent: #3dc47e;--danger: #e24a4a;--neutral: #2988e5;--bg-grad: linear-gradient(120deg,#e7eaf6 40%,#b4c7e7 100%);--bg-dark: linear-gradient(120deg,#232a3b 60%,#23408e 100%);--glass-bg: rgba(255,255,255,0.90);--glass-bg-dark: rgba(30,40,60,0.96);--card-shadow: 0 7px 30px rgba(44,64,120,0.13);--border-radius: 20px;--transition: all .25s cubic-bezier(.4,2,.5,1);--nav-height: 60px;}html,body{height:100%;}body {min-height:100vh;background: var(--bg-grad);font-family:'Montserrat','Segoe UI','Microsoft YaHei',sans-serif;color:#233;transition: background 0.5s, color 0.3s;}body.dark-mode {background: var(--bg-dark);color: #dde4f2;}/* 顶部导航栏 */.nav-bar {position: fixed;top:0;left:0;right:0;height:var(--nav-height);z-index:100;background:rgba(36,64,142,0.98);box-shadow:0 2px 10px rgba(36,64,142,.10);display:flex;align-items:center;justify-content:space-between;padding:0 38px;}.nav-logo {display:flex;align-items:center;font-size:1.3rem;font-weight:700;letter-spacing:2px;color:#fff;user-select:none;}.nav-logo img {width:34px;height:34px;margin-right:12px;border-radius:8px;box-shadow:0 2px 8px rgba(44,64,120,0.09);background:#fff;}.nav-menu {display:flex;align-items:center;gap:22px;}.nav-link {color:#fff;font-size:1rem;font-weight:500;padding:7px 17px;border-radius:6px;cursor:pointer;text-decoration:none;transition:background .19s, color .19s;}.nav-link:hover, .nav-link.active {background:rgba(74,123,183,0.31);color:#fff;}.nav-right {display:flex;align-items:center;gap:16px;}.theme-toggle {cursor:pointer;font-size:1.25rem;color:#fff;border:none;background:transparent;padding:7px;border-radius:50%;transition:background .2s;}.theme-toggle:hover {background:rgba(255,255,255,0.12);}.github-btn {background:linear-gradient(90deg,#fff 70%,#4a7bb7 100%);color:#23408e;font-size:1.1rem;font-weight:600;border:none;padding:7px 16px 7px 13px;border-radius:7px;margin-left:5px;display:flex;align-items:center;box-shadow:0 2px 8px rgba(44,64,120,0.09);cursor:pointer;transition:background .2s,color .2s;}.github-btn:hover {background:linear-gradient(90deg,#4a7bb7 10%,#fff 100%);color:#fff;}.github-btn svg {margin-right:7px;}/* 主体 */.page-wrap { min-height:100vh; display:flex; flex-direction:column;}.container-main {max-width: 1280px;margin: 0 auto;flex:1;display: flex;flex-direction: row;gap:38px;padding:calc(54px + var(--nav-height)) 34px 10px 34px;}header {margin-top:var(--nav-height);background: linear-gradient(90deg,#23408e 60%,#4a7bb7 100%);color: #fff;padding:38px 0 30px 0;text-align:center;letter-spacing:1.2px;border-radius:0 0 60px 60px/0 0 30px 30px;box-shadow:0 10px 30px rgba(44,64,140,0.1);}h1 {font-size:2.8rem;margin-bottom:12px;font-weight:700;letter-spacing:2px;text-shadow:0 2px 12px rgba(44,64,140,0.06);}.subtitle {font-size:1.20rem;opacity:0.97;font-weight:500;max-width:730px;margin:0 auto;}.left-panel, .right-panel {background: var(--glass-bg);border-radius: var(--border-radius);box-shadow: var(--card-shadow);padding:42px 36px 24px 36px;min-width:340px;display: flex;flex-direction: column;justify-content: space-between;transition: background .3s,color .3s;}body.dark-mode .left-panel, body.dark-mode .right-panel {background: var(--glass-bg-dark);color: #dde4f2;}.input-area h2, .result-title {color:var(--primary);font-size:1.34rem;margin-bottom:19px;font-weight:700;border-left:5px solid var(--secondary);padding-left:10px;letter-spacing:1px;}textarea {width: 100%;height: 120px;padding: 14px 13px;border: 2px solid #b4c7e7;border-radius: 9px;font-size: 1.05rem;background:rgba(245,248,252,0.96);margin-bottom:18px;transition: border .2s, box-shadow .2s, background .2s, color .2s;color:#212c43;}body.dark-mode textarea {background:rgba(39,50,70,0.98);color:#d3e8fc;border-color: #324d93;}textarea:focus {border-color: var(--secondary);box-shadow: 0 0 0 3px rgba(74,123,183, 0.11);outline: none;}.input-row {display:flex;align-items:center;gap:12px;margin-bottom:12px;}.input-row label {font-size:1.01rem;color:#456;font-weight:500;}.input-row select {font-size:1.01rem;padding:6px 18px 6px 9px;border-radius:6px;border:1.5px solid #b4c7e7;outline:none;transition:border .2s;}.input-row select:focus {border-color:var(--secondary);}button {width:100%;background: linear-gradient(90deg, var(--secondary) 60%, var(--primary) 100%);color: #fff;font-size: 1.08rem;font-weight: 700;padding: 15px 0 13px 0;border: none;border-radius: 9px;box-shadow: 0 3px 13px rgba(44,64,120,0.08);cursor: pointer;letter-spacing:1.2px;transition: var(--transition);position:relative;overflow:hidden;}button:after {content:'';position:absolute;left:50%;top:50%;background:rgba(255,255,255,0.23);width:0;height:0;border-radius:50%;transform:translate(-50%,-50%);z-index:1;pointer-events:none;transition:.3s;}button:active:after {width:220px;height:220px;transition:0s;}button:hover:not(:disabled) {background: linear-gradient(90deg, var(--primary) 30%, var(--secondary) 100%);transform: scale(1.025);}button:disabled {background: #c1cbe0;cursor: not-allowed;box-shadow: none;}.examples-block {margin-top:36px;}.examples-block h3 {color:var(--secondary);font-size:1.08rem;margin-bottom:6px;font-weight:700;}.example-list {display: grid;grid-template-columns: repeat(2,1fr);gap: 13px 10px;margin-top:8px;}.example-card {background:rgba(255,255,255,0.95);border-radius: 11px;padding: 13px 16px 9px 16px;cursor: pointer;box-shadow: 0 1px 8px rgba(74,123,183,0.08);border-left: 6px solid var(--secondary);transition: var(--transition);min-height:48px;position:relative;font-size:1.01rem;}.example-card:hover {transform: translateY(-2px) scale(1.04);box-shadow: 0 6px 18px rgba(74,123,183, 0.16);background: #f3f4fa;}.example-card.positive { border-left-color: var(--accent);}.example-card.negative { border-left-color: var(--danger);}.example-card.neutral { border-left-color: var(--neutral);}.example-text {font-style: italic;color: #444;margin-bottom: 6px;line-height:1.5;}.example-label {position: absolute;right: 18px;bottom: 8px;font-size: 0.95rem;font-weight: 700;color:var(--secondary);}.example-card.positive .example-label { color: var(--accent);}.example-card.negative .example-label { color: var(--danger);}.example-card.neutral .example-label { color: var(--neutral);}.history-block {margin-top:38px;background:rgba(244,250,255,0.93);border-radius: 11px;padding: 15px 16px 8px 16px;box-shadow:0 2px 10px rgba(44,64,120,0.05);}.history-title {color:var(--primary);font-size:1.05rem;margin-bottom:8px;font-weight:700;}.history-list {max-height:150px;overflow:auto;padding-left:3px;}.history-item {display:flex;gap:8px;align-items:center;padding:6px 0;color:#456;cursor:pointer;font-size:.98rem;border-bottom:1px dashed #cde;}.history-item:last-child{border-bottom:none;}.history-tag {display:inline-block;min-width:46px;text-align:center;padding:3px 8px;border-radius:13px;font-size:.95rem;font-weight:600;}.history-tag.positive{background:var(--accent);color:#fff;}.history-tag.negative{background:var(--danger);color:#fff;}.history-tag.neutral{background:var(--neutral);color:#fff;}.history-item:hover {background:rgba(74,123,183,0.11);}/* 右侧 */.result-title {color:var(--primary);font-size:1.29rem;margin-bottom:19px;font-weight:700;border-left:5px solid var(--accent);padding-left:10px;letter-spacing:1px;}.result-box {padding: 26px 19px 18px 19px;border-radius: 13px;min-height: 170px;margin-bottom: 24px;background: rgba(255,255,255,0.90);box-shadow: 0 2px 14px rgba(60,80,160,0.06);display: flex;flex-direction: column;justify-content: center;transition: var(--transition);border-left: 8px solid #eee;}.result-box.positive { background: linear-gradient(120deg, #e8f5e9 66%, #d1f5e5 100%); border-left: 8px solid var(--accent);}.result-box.negative { background: linear-gradient(120deg, #ffebee 66%, #ffe0e0 100%); border-left: 8px solid var(--danger);}.result-box.neutral  { background: linear-gradient(120deg, #e3f2fd 66%, #d3e8fc 100%); border-left: 8px solid var(--neutral);}.result-placeholder {color: #a2a9b5;text-align: center;font-style: italic;font-size: 1.05rem;}.sentiment-tag {display: inline-block;padding: 8px 28px;border-radius: 30px;font-weight: 700;margin-bottom: 13px;font-size: 1.32rem;letter-spacing: 2px;box-shadow: 0 2px 12px rgba(0,0,0,0.04);background: #eee;color: var(--primary);transition: background .19s,color .19s;}.result-box.positive .sentiment-tag { background: var(--accent); color: #fff;}.result-box.negative .sentiment-tag { background: var(--danger); color: #fff;}.result-box.neutral  .sentiment-tag { background: var(--neutral); color: #fff;}.result-content {background:rgba(255,255,255,0.74);padding:10px 12px 4px 12px;border-radius:7px;margin-bottom:7px;font-size:1.07rem;}.tokens {display: flex;flex-wrap: wrap;gap:8px 7px;margin-top:12px;}.token {background: linear-gradient(90deg, var(--secondary) 70%, #8bbbe8 100%);color: #fff;padding: 6px 15px;border-radius: 16px;font-size: 14.5px;margin-bottom: 4px;transition: box-shadow .12s;box-shadow: 0 1px 7px rgba(74,123,183, 0.09);}.token:hover {box-shadow: 0 2px 14px rgba(74,123,183, 0.16);background: #285fa7;}.model-info-block {margin-top:32px;background:rgba(245,248,252,0.93);border-radius:10px;padding:14px 19px 10px 19px;font-size:.99rem;color:#346;}.model-info-block code {background:#f3f3f7;color:#23408e;padding:2px 7px;border-radius:5px;font-size:.96em;}.help-btn {background:linear-gradient(90deg,#4a7bb7 70%,#fff 100%);color:#23408e;font-size:.99rem;font-weight:600;border:none;padding:5px 18px 5px 14px;border-radius:7px;margin:8px 0 0 0;box-shadow:0 2px 8px rgba(44,64,120,0.07);cursor:pointer;transition:background .2s,color .2s;}.help-btn:hover {background:linear-gradient(90deg,#fff 10%,#4a7bb7 100%);color:#fff;}/* 帮助弹窗 */.modal-mask {display:none;position:fixed;top:0;left:0;right:0;bottom:0;z-index:200;background:rgba(40,60,90,0.34);}.modal-mask.show {display:block;}.modal-dialog {max-width:390px;margin:80px auto 0 auto;background:var(--glass-bg);border-radius:12px;box-shadow:0 7px 40px rgba(44,64,120,0.23);padding:30px 22px 22px 22px;position:relative;color:#23408e;}.modal-dialog h4 {font-size:1.21rem;font-weight:700;margin-bottom:11px;}.modal-dialog p {font-size:.99rem;line-height:1.8;}.modal-close {position:absolute;top:11px;right:16px;background:none;border:none;color:#23408e;font-size:1.5rem;font-weight:700;cursor:pointer;}.modal-dialog ul{margin-left:19px;}/* 系统说明 */.system-info {margin-top: 18px;padding: 10px 15px 2px 15px;background: rgba(244,250,255,0.92);border-radius: 9px;font-size: 1.01rem;color: #555;box-shadow: 0 2px 8px rgba(74,123,183,0.03);}.system-info ul {margin-top: 7px; margin-left: 28px;}.loading {display: none;text-align: center;padding: 14px 0;}.spinner {border: 5px solid #f3f3f3;border-top: 5px solid var(--secondary);border-radius: 50%;width: 44px;height: 44px;animation: spin 1s linear infinite;margin: 0 auto 17px;}@keyframes spin { 0% { transform: rotate(0deg);} 100% { transform: rotate(360deg);} }/* 响应式 */@media (max-width: 1200px) {.container-main{padding:calc(30px + var(--nav-height)) 6vw;}}@media (max-width: 900px) {.container-main{flex-direction:column;gap:20px;}.left-panel,.right-panel{min-width:0;margin:0;}}@media (max-width: 580px) {.nav-bar{padding:0 2vw;}.container-main{padding:7px 1vw;}.left-panel,.right-panel{padding:16px 6px;}}/* 额外左右背景填充 */body:before,body:after {content:'';position:fixed;top:0;bottom:0;width:16vw;z-index:-1;background:linear-gradient(120deg,rgba(36,64,140,0.13) 60%,rgba(74,123,183,0.08) 100%);pointer-events:none;}body:before{left:0;}body:after{right:0;}@media (max-width: 1000px) { body:before,body:after{display:none;} }::selection { background: #b9d7ef;}textarea::selection { background: #b9d7ef;}</style>
</head>
<body>
<div class="nav-bar"><div class="nav-logo"><img src="https://img.icons8.com/color/48/000000/movie-projector.png" alt="Logo"/>影评情感分析</div><div class="nav-menu"><a class="nav-link active" href="#">首页</a><a class="nav-link" href="#" id="help-link">帮助中心</a><a class="nav-link" href="https://github.com/yourrepo" target="_blank">项目仓库</a></div><div class="nav-right"><button class="theme-toggle" id="theme-toggle" title="切换主题">🌙</button><button class="github-btn" οnclick="window.open('https://github.com/yourrepo','_blank')"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M12 2C6.48 2 2 6.58 2 12.27C2 16.65 4.87 20.27 8.84 21.5C9.34 21.58 9.52 21.29 9.52 21.04C9.52 20.82 9.51 20.13 9.51 19.25C7 19.83 6.34 18.37 6.34 18.37C5.87 17.32 5.16 17.07 5.16 17.07C4.17 16.38 5.23 16.4 5.23 16.4C6.32 16.49 6.87 17.61 6.87 17.61C7.84 19.17 9.34 18.74 9.91 18.5C9.99 17.75 10.29 17.26 10.62 16.98C8.41 16.7 6.08 15.8 6.08 12.62C6.08 11.67 6.43 10.87 7.01 10.22C6.92 9.94 6.6 8.91 7.1 7.53C7.1 7.53 7.84 7.24 9.5 8.3C10.22 8.1 11 8 11.78 8C12.56 8 13.34 8.1 14.06 8.3C15.72 7.24 16.46 7.53 16.46 7.53C16.96 8.91 16.64 9.94 16.55 10.22C17.13 10.87 17.48 11.67 17.48 12.62C17.48 15.81 15.15 16.69 12.94 16.97C13.37 17.33 13.74 18.01 13.74 19.04C13.74 20.37 13.73 21.4 13.73 21.04C13.73 21.29 13.91 21.58 14.41 21.5C18.38 20.27 21.25 16.65 21.25 12.27C21.25 6.58 16.77 2 12 2Z" fill="currentColor"/></svg>Github</button></div>
</div>
<div class="page-wrap"><header><h1>中文影评情感分析系统</h1><div class="subtitle">基于LSTM与预训练词向量的高精度影评情感判别系统</div></header><div class="container-main"><div class="left-panel"><div><div class="input-area"><h2>输入影评</h2><form id="analysis-form" autocomplete="off"><div class="input-row"><label for="segment-method">分词方式:</label><select id="segment-method"><option value="jieba">jieba中文分词</option><option value="custom">自定义分词(空格分隔)</option></select></div><textarea id="review-text" placeholder="请输入分词后的电影评论内容,例如:剧情 精彩 演员 演技 出色 值得 一看"></textarea><button type="submit" id="analyze-btn">分析情感倾向</button></form></div><div class="examples-block"><h3>示例影评</h3><div class="example-list" id="example-list"></div></div><div class="history-block" id="history-block" style="display:none;"><div class="history-title">分析历史</div><div class="history-list" id="history-list"></div></div></div><div style="margin-top:auto;padding-top:28px;"><button class="help-btn" id="help-btn">帮助中心</button></div></div><div class="right-panel"><div><div class="result-title">分析结果</div><div class="loading" id="loading"><div class="spinner"></div><p>正在分析情感倾向,请稍候…</p></div><div class="result-box" id="result-box"><div class="result-placeholder" id="result-placeholder"><p>输入电影评论并点击「分析情感倾向」,系统会显示情感分析结果</p><p>结果包括:情感(正面/负面/中性)、置信度、分词结果</p></div><div class="result-content" id="result-content" style="display:none;"><div class="sentiment-tag" id="sentiment-tag">情感倾向</div><p><strong>评论内容:</strong><span id="result-text"></span></p><p><strong>置信度:</strong><span id="result-confidence"></span></p><p><strong>预测概率:</strong><span id="result-probability"></span></p><div class="tokens" id="tokens-container"></div></div></div></div><div><div class="model-info-block"><b>模型信息:</b><br><ul><li>模型类型:<code>双向LSTM</code>, 层数:<code>2</code></li><li>嵌入层:<code>预训练Word2Vec</code> (50维)</li><li>优化器:<code>Adam</code>,损失函数:<code>binary_crossentropy</code></li><li>训练集:IMDB/自建中文数据集</li><li>分词方式:<code>jieba/自定义分词</code></li></ul></div><div class="system-info"><h2 style="color:var(--secondary);font-size:1.05rem;">系统技术说明</h2><p>本系统采用:</p><ul><li>深度学习:双向LSTM神经网络</li><li>词向量:预训练中文Word2Vec (50维)</li><li>中文分词:jieba分词</li><li>后端:Python Flask</li><li>前端:HTML5+CSS3+JavaScript</li></ul><p style="font-size:.98rem;color:#789;margin-top:7px;">支持正面/负面/中性情感判别,体验高精度中文情感分析。</p></div></div></div></div><footer style="text-align:center;padding:20px 0 17px 0;background: #23408e;color: #fff;font-size:1.01rem;letter-spacing:1px;"><div>中文影评情感分析系统 &copy; 2025 | 期末项目出品 | <a href="https://github.com/yourrepo" style="color:#bce;">Github</a></div><div style="font-size:.97rem;margin-top:7px;opacity:.85;">开发团队:AI 研究实验室 | 设计指导:张三老师</div></footer>
</div>
<!-- 帮助弹窗 -->
<div class="modal-mask" id="modal-mask"><div class="modal-dialog"><button class="modal-close" id="modal-close">&times;</button><h4>帮助中心</h4><p><b>【系统简介】</b><br>本系统可自动分析中文电影评论的情感倾向(支持正面/负面/中性等),并提供分词结果和置信概率。<br><b>【使用说明】</b><br>1. 选择分词方式,输入或粘贴分词后的影评文本。<br>2. 点击“分析情感倾向”按钮,结果将在右侧显示。<br>3. 可点击左侧示例快速体验;分析历史可随时回看。<br><b>【模型说明】</b><br>LSTM深度学习网络,词向量采用预训练的Word2Vec。<br><b>【异常说明】</b><br>若遇接口异常请检查后端服务或联系开发团队。</p></div>
</div>
<script>// ======= 主题切换 =======const themeToggleBtn = document.getElementById('theme-toggle');themeToggleBtn.onclick = () => {document.body.classList.toggle('dark-mode');themeToggleBtn.textContent = document.body.classList.contains('dark-mode') ? '☀️' : '🌙';localStorage.setItem('theme', document.body.classList.contains('dark-mode') ? 'dark' : 'light');};// 恢复主题if(localStorage.getItem('theme')==='dark'){document.body.classList.add('dark-mode');themeToggleBtn.textContent = '☀️';}// ======= 帮助弹窗 =======document.getElementById('help-link').onclick = document.getElementById('help-btn').onclick = function(){document.getElementById('modal-mask').classList.add('show');};document.getElementById('modal-close').onclick = function(){document.getElementById('modal-mask').classList.remove('show');};document.getElementById('modal-mask').onclick = function(e){if(e.target===this) this.classList.remove('show');};// ======= 示例影评 =======const examples = [{ text: "这部 电影 太 棒 了 剧情 紧凑 演员 演技 在线", label: "positive" },{ text: "故事 老套 特效 一般 没有 太多 亮点", label: "neutral" },{ text: "剧情 拖沓 演员 表演 僵硬 完全 不 值得 一看", label: "negative" },{ text: "音乐 好听 画面 唯美 但 故事 略显 平淡", label: "neutral" },{ text: "太 感人 了 我 都 哭 了 强烈 推荐", label: "positive" },{ text: "浪费 时间 情节 无聊 失望", label: "negative" }];function renderExamples() {const list = document.getElementById('example-list');list.innerHTML = '';examples.forEach(ex => {const div = document.createElement('div');div.className = 'example-card ' + ex.label;div.tabIndex = 0;div.setAttribute('role', 'button');div.setAttribute('aria-label', '点击填入示例影评');div.onclick = () => loadExample(ex.text);div.onkeydown = (e) => { if (e.key === 'Enter' || e.key === ' ') { loadExample(ex.text); } };div.innerHTML = `<div class="example-text">${ex.text}</div><div class="example-label">${ex.label === "positive" ? "正面" : ex.label === "negative" ? "负面" : "中性"}</div>`;list.appendChild(div);});}renderExamples();// ======= 历史记录 =======function saveHistory(item){let history=JSON.parse(localStorage.getItem('sentiment_history')||"[]");history.unshift(item);if(history.length>20)history=history.slice(0,20);localStorage.setItem('sentiment_history',JSON.stringify(history));renderHistory();}function renderHistory(){const historyBlock=document.getElementById('history-block');const list=document.getElementById('history-list');let history=JSON.parse(localStorage.getItem('sentiment_history')||"[]");if(!history||history.length===0){historyBlock.style.display="none";return;}historyBlock.style.display="block";list.innerHTML="";history.forEach((h,i)=>{const div=document.createElement('div');div.className='history-item';div.title="点击查看分析结果";div.innerHTML=`<span class="history-tag ${h.sentiment}">${h.sentiment==='正面'?'正面':h.sentiment==='负面'?'负面':'中性'}</span><span>${h.text.length>22?h.text.slice(0,22)+'...':h.text}</span>`;div.οnclick=()=>showHistoryResult(h);list.appendChild(div);});}function showHistoryResult(h){document.getElementById('result-text').textContent = h.text;document.getElementById('result-confidence').textContent = (h.confidence|| (h.probability !== undefined ? (h.probability > 0.5 ? h.probability : 1-h.probability) : '--')).toFixed(4);document.getElementById('result-probability').textContent = h.probability !== undefined ? h.probability.toFixed(4) : '--';document.getElementById('sentiment-tag').textContent = h.sentiment;document.getElementById('result-box').className = 'result-box ' + (h.sentiment === '正面' ? 'positive' : h.sentiment === '负面' ? 'negative':'neutral');// 分词const tokensContainer = document.getElementById('tokens-container');tokensContainer.innerHTML = '';if (h.tokens && h.tokens.length > 0) {const title = document.createElement('strong');title.textContent = '分词结果:';tokensContainer.appendChild(title);h.tokens.forEach(token => {const tokenEl = document.createElement('div');tokenEl.className = 'token';tokenEl.textContent = token;tokensContainer.appendChild(tokenEl);});}document.getElementById('result-content').style.display = 'block';document.getElementById('result-placeholder').style.display = 'none';}renderHistory();// ======= 分析流程 =======const form = document.getElementById('analysis-form');const textarea = document.getElementById('review-text');form.addEventListener('submit', e => {e.preventDefault();analyzeSentiment();});function loadExample(text) {textarea.value = text;analyzeSentiment();textarea.focus();}function analyzeSentiment() {const text = textarea.value.trim();const segMethod = document.getElementById('segment-method').value;if (!text) {textarea.focus();alert('请输入要分析的影评内容');return;}document.getElementById('loading').style.display = 'block';document.getElementById('result-placeholder').style.display = 'none';document.getElementById('result-content').style.display = 'none';fetch('/predict', {method: 'POST',headers: { 'Content-Type': 'application/x-www-form-urlencoded' },body: `text=${encodeURIComponent(text)}&segment=${encodeURIComponent(segMethod)}`}).then(resp => resp.json()).then(data => {document.getElementById('loading').style.display = 'none';if (data.error) {alert('分析出错: ' + data.error);return;}document.getElementById('result-text').textContent = data.text;document.getElementById('result-confidence').textContent = (data.confidence || (data.probability !== undefined ? (data.probability > 0.5 ? data.probability : 1-data.probability) : '--')).toFixed(4);document.getElementById('result-probability').textContent = data.probability !== undefined ? data.probability.toFixed(4) : '--';const sentimentText = data.sentiment === '正面' ? '正面' : data.sentiment === '负面' ? '负面' : '中性';document.getElementById('sentiment-tag').textContent = sentimentText;const resultBox = document.getElementById('result-box');resultBox.className = 'result-box ' + (data.sentiment === '正面' ? 'positive' : data.sentiment === '负面' ? 'negative' : 'neutral');// 分词const tokensContainer = document.getElementById('tokens-container');tokensContainer.innerHTML = '';if (data.tokens && data.tokens.length > 0) {const title = document.createElement('strong');title.textContent = '分词结果:';tokensContainer.appendChild(title);data.tokens.forEach(token => {const tokenEl = document.createElement('div');tokenEl.className = 'token';tokenEl.textContent = token;tokensContainer.appendChild(tokenEl);});}document.getElementById('result-content').style.display = 'block';saveHistory({text:data.text, sentiment:data.sentiment, confidence:data.confidence, probability:data.probability, tokens:data.tokens});}).catch(error => {document.getElementById('loading').style.display = 'none';alert('分析过程中发生错误,请稍后再试');console.error(error);});}// Ctrl+Enter 快捷分析textarea.addEventListener('keydown', e => {if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {analyzeSentiment();}});
</script>
</body>
</html>需要改一些配置:
import os
import re
from collections import defaultdict
import numpy as np
from flask import Flask, request, jsonify, render_template
from flask_cors import CORS
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.sequence import pad_sequences
import jiebaapp = Flask(__name__)
CORS(app)  # 支持跨域# =========================== 全局变量 ===========================
word2idx = {}
max_len = 100
model = None# =========================== 词表加载函数 ===========================
def load_vocab():"""加载词表到word2idx,全局可用"""global word2idxword2idx = defaultdict(lambda: 0)  # OOV返回0vocab_path = os.path.join('vocab', 'word.txt')if not os.path.isfile(vocab_path):print(f"警告:缺少词表文件 {vocab_path}")returnwith open(vocab_path, 'r', encoding='utf-8') as f:for idx, line in enumerate(f):word = line.strip()word2idx[word] = idxprint(f"词表加载完成,共 {len(word2idx)} 个词。")# =========================== 模型加载函数 ===========================
def load_models():"""加载LSTM情感分析模型到全局变量model"""global modelmodel_path = os.path.join('models', 'best_model.h5')if not os.path.isfile(model_path):print(f"警告:缺少模型文件 {model_path}")returnmodel = load_model(model_path)print("模型加载完成。")# =========================== 文本预处理 ===========================
def preprocess_text(text, segment_method='jieba'):"""按指定分词方式处理文本,返回分词列表:param text: str:param segment_method: 'jieba' or 'custom':return: list"""text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s]', '', text)  # 移除特殊字符if segment_method == 'custom':# 假设用户输入使用空格分词tokens = [token for token in text.split() if token.strip()]else:tokens = [token for token in jieba.cut(text) if token.strip()]return tokens# =========================== 文本编码 ===========================
def encode_text(tokens):"""词索引映射 + padding"""seq = [word2idx.get(token, 0) for token in tokens]padded = pad_sequences([seq], maxlen=max_len, padding='post', truncating='post')return padded# =========================== 情感预测主函数 ===========================
def predict_sentiment(text, segment_method='jieba'):tokens = preprocess_text(text, segment_method)encoded_text = encode_text(tokens)prediction = model.predict(encoded_text)pred_prob = prediction[0][0]# 阈值可调,如果接近0.5可判为"中性"if pred_prob >= 0.6:sentiment = "正面"elif pred_prob <= 0.4:sentiment = "负面"else:sentiment = "中性"# 置信度定义confidence = abs(pred_prob - 0.5) * 2return {'text': text,'tokens': tokens,'sentiment': sentiment,'probability': float(pred_prob),'confidence': confidence}# =========================== 健康检查接口 ===========================
@app.route('/health')
def health():return jsonify({'status': 'ok', 'model_loaded': model is not None, 'vocab_loaded': len(word2idx) > 0})# =========================== 首页 ===========================
@app.route('/')
def index():return render_template('index.html')# =========================== 预测API ===========================
@app.route('/predict', methods=['POST'])
def predict():try:# 支持x-www-form-urlencoded和application/json两种格式if request.content_type and 'json' in request.content_type:data = request.get_json()text = data.get('text', '')segment_method = data.get('segment', 'jieba')else:text = request.form.get('text', '')segment_method = request.form.get('segment', 'jieba')if not text:return jsonify({'error': '请输入影评内容'}), 400result = predict_sentiment(text, segment_method)return jsonify(result), 200except Exception as e:import tracebackprint(traceback.format_exc())return jsonify({'error': '后端推理异常: ' + str(e)}), 500# =========================== 示例数据(供模板渲染) ===========================
@app.context_processor
def inject_examples():examples = [{"text": "这部电影太精彩了,演员表演出色,剧情紧凑,强烈推荐!", "label": "正面"},{"text": "非常失望,剧情拖沓,特效也很假,完全不值票价。", "label": "负面"},{"text": "中规中矩的电影,没有特别出彩的地方,但也不差。", "label": "中性"},{"text": "导演的叙事手法很新颖,画面精美,但结尾有些仓促。", "label": "中性"},{"text": "演员阵容强大,但剧本太弱,浪费了这么好的演员。", "label": "负面"},{"text": "从头到尾都吸引人,今年看过最好的电影之一!", "label": "正面"}]return dict(examples=examples)# =========================== 启动时加载资源 ===========================
if __name__ == '__main__':os.makedirs('vocab', exist_ok=True)os.makedirs('models', exist_ok=True)# 加载资源load_vocab()load_models()if model is None or len(word2idx) == 0:print("模型或词表加载失败,请检查!")else:print("后端服务准备就绪,可以开始接收情感分析请求。")# 运行应用app.run(host='0.0.0.0', port=5000, debug=True)

相关文章:

  • 电子电路基础2(杂乱)
  • 全球数控金属切削机床市场:现状、趋势与应对策略
  • 火语言RPA--选择元素工具使用方法
  • D3ctf-web-d3invitation单题wp
  • 从边界防护到内生安全:企业网络安全进化路线图
  • 解决Zotero翻译插件Zotero PDF Translate无法正常翻译
  • Linux命令基础(2)
  • 使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
  • 基于 openEuler 22.03 LTS SP1 构建 DPDK 22.11.8 开发环境指南
  • 一些免费的大A数据接口库
  • 华为防火墙IPSec VPN全解析:配置实战与原理详解
  • LeetCode 热题 100 74. 搜索二维矩阵
  • 惠普HP Deskjet 9600 打印机信息
  • 网页端 js 读取发票里的二维码信息(图片和PDF格式)
  • 【Veristand】Veristand环境安装教程-Linux RT / Windows
  • Flink checkpoint
  • 港股TRS交易系统开发:跨境资本的精密调度引擎
  • 海康工业相机文档大小写错误
  • 独家首发!低照度环境下YOLOv8的增强方案——从理论到TensorRT部署
  • 中科院提出多方协作注意力控制方法MCA-Ctrl,无需调优的即可使用文本和复杂的视觉条件实现高质量的图像定制。
  • 做做网站需要多少钱/广告公司排名
  • 企业营销型网站类型/软文有哪些推广渠道
  • 私人做网站有什么用/沧州网站seo
  • 企业网站代码怎么优化/seo引擎搜索网站
  • 做路牌的网站/东莞网站制作公司
  • 本地电脑做网站服务器/百度快照什么意思