901 lines
37 KiB
HTML
901 lines
37 KiB
HTML
{% extends 'base_page.html' %}
|
|
{% block title %}
|
|
舆情预测
|
|
{% endblock %}
|
|
{% block nav %}
|
|
<nav class="iq-sidebar-menu">
|
|
<ul id="iq-sidebar-toggle" class="side-menu">
|
|
<li class="px-3 pt-3 pb-2 ">
|
|
<span class="text-uppercase small font-weight-bold">首页</span>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/home" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">首页</span>
|
|
</a>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/hotWord" class="svg-icon ">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">热词统计</span>
|
|
</a>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/tableData" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">微博舆情统计</span>
|
|
</a>
|
|
</li>
|
|
<li class="px-3 pt-3 pb-2 ">
|
|
<span class="text-uppercase small font-weight-bold">数据可视化</span>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/articleChar" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">文章分析</span>
|
|
</a>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/ipChar" class="svg-icon">
|
|
<i class="">
|
|
<svg class="icon line" width="18" id="receipt" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path d="M17,16V3L13,5,10,3,7,5,3,3V17.83A3.13,3.13,0,0,0,5.84,21,3,3,0,0,0,9,18V17a1,1,0,0,1,1-1H20a1,1,0,0,1,1,1v1a3,3,0,0,1-3,3H6" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></path>
|
|
<line x1="8" y1="10" x2="12" y2="10" style="fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></line>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">IP分析</span>
|
|
</a>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/commentChar" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path>
|
|
</svg>
|
|
</i><span class="ml-2">评论分析</span>
|
|
</a>
|
|
</li>
|
|
<li class="active sidebar-layout">
|
|
<a href="/page/yuqingChar" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">舆情分析</span>
|
|
</a>
|
|
</li>
|
|
<li class="active sidebar-layout">
|
|
<a href="/page/yuqingpredict" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
|
</svg>
|
|
</i>
|
|
<span class="ml-2">舆情预测</span>
|
|
</a>
|
|
</li>
|
|
<li class="px-3 pt-3 pb-2">
|
|
<span class="text-uppercase small font-weight-bold">词云图</span>
|
|
</li>
|
|
<li class=" sidebar-layout">
|
|
<a href="/page/articleCloud" class="svg-icon">
|
|
<i class="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" fill="none" viewbox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
|
</svg>
|
|
</i><span class="ml-2">文章内容词云图</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-md-12 mb-4 mt-1">
|
|
<div class="d-flex flex-wrap justify-content-between align-items-center">
|
|
<h4 class="font-weight-bold">话题统计页</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div class="card card-block card-stretch card-height">
|
|
<div class="card-body">
|
|
<div class="collapse" id="form-element-15">
|
|
<div class="card"><kbd class="bg-dark"><pre id="select-size" class="text-white"><code>
|
|
<div class="form-group">
|
|
<label>Small</label>
|
|
<select class="form-control form-control-sm mb-3">
|
|
<option selected="">Open this select menu</option>
|
|
<option value="1">One</option>
|
|
<option value="2">Two</option>
|
|
<option value="3">Three</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Default</label>
|
|
<select class="form-control mb-3">
|
|
<option selected="">Open this select menu</option>
|
|
<option value="1">One</option>
|
|
<option value="2">Two</option>
|
|
<option value="3">Three</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Large</label>
|
|
<select class="form-control form-control-lg">
|
|
<option selected="">Open this select menu</option>
|
|
<option value="1">One</option>
|
|
<option value="2">Two</option>
|
|
<option value="3">Three</option>
|
|
</select>
|
|
</div>
|
|
</code></pre></kbd></div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>话题选择</label>
|
|
<select onchange="hotWordChange(event)" class="form-control mb-3">
|
|
{% for i in hotWordList %}
|
|
{% if defaultHotWord == i[0] %}
|
|
<option selected value="{{ i[0] }}">{{ i[0] }}</option>
|
|
{% else %}
|
|
<option value="{{ i[0] }}">{{ i[0] }}</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>模型选择</label>
|
|
<select onchange="modelChange(event)" class="form-control mb-3">
|
|
{% if model_type == 'basic' %}
|
|
<option selected value="basic">基础模型</option>
|
|
<option value="pro">改进模型</option>
|
|
{% else %}
|
|
<option value="basic">基础模型</option>
|
|
<option selected value="pro">改进模型</option>
|
|
{% endif %}
|
|
</select>
|
|
</div>
|
|
<script>
|
|
function hotWordChange(e){
|
|
const model = document.querySelector('select[onchange="modelChange(event)"]').value;
|
|
window.location.href = 'http://127.0.0.1:5000/page/yuqingpredict?Topic=' + e.target.value + '&model=' + model;
|
|
}
|
|
function modelChange(e){
|
|
const topic = document.querySelector('select[onchange="hotWordChange(event)"]').value;
|
|
window.location.href = 'http://127.0.0.1:5000/page/yuqingpredict?Topic=' + topic + '&model=' + e.target.value;
|
|
}
|
|
</script>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="row" style="justify-content: center">
|
|
<div class="col-md-6 col-xl-6">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4 class="card-title font-size-16 mt-0">{{ defaultHotWord }}</h4>
|
|
</div>
|
|
<ul class="list-group list-group-flush">
|
|
<li class="list-group-item">话题名称:{{ defaultHotWord }}</li>
|
|
<li class="list-group-item">出现次数:{{ hotWordLen }}次</li>
|
|
<li class="list-group-item">话题情感:{{ sentences }}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h4 class="card-title font-size-16 mt-0">话题年份变化趋势</h4>
|
|
</div>
|
|
<div id="main" style="width:100%;height: 450px"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between">
|
|
<div class="header-title">
|
|
<h4 class="card-title">话题查询表格</h4>
|
|
</div>
|
|
<div class="header-action">
|
|
<i data-toggle="collapse" data-target="#datatable-1" aria-expanded="false">
|
|
<svg width="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
|
|
</svg>
|
|
</i>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="collapse" id="datatable-1">
|
|
<div class="card"><kbd class="bg-dark">
|
|
<pre id="bootstrap-datatables" class="text-white"><code>
|
|
<table id="datatable" class="table data-table table-striped table-bordered" >
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Position</th>
|
|
<th>Office</th>
|
|
<th>Age</th>
|
|
<th>Start date</th>
|
|
<th>Salary</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Tiger Nixon</td>
|
|
<td>System Architect</td>
|
|
<td>Edinburgh</td>
|
|
<td>61</td>
|
|
<td>2011/04/25</td>
|
|
<td>$320,800</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Garrett Winters</td>
|
|
<td>Accountant</td>
|
|
<td>Tokyo</td>
|
|
<td>63</td>
|
|
<td>2011/07/25</td>
|
|
<td>$170,750</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Ashton Cox</td>
|
|
<td>Junior Technical Author</td>
|
|
<td>San Francisco</td>
|
|
<td>66</td>
|
|
<td>2009/01/12</td>
|
|
<td>$86,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Cedric Kelly</td>
|
|
<td>Senior Javascript Developer</td>
|
|
<td>Edinburgh</td>
|
|
<td>22</td>
|
|
<td>2012/03/29</td>
|
|
<td>$433,060</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Airi Satou</td>
|
|
<td>Accountant</td>
|
|
<td>Tokyo</td>
|
|
<td>33</td>
|
|
<td>2008/11/28</td>
|
|
<td>$162,700</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Brielle Williamson</td>
|
|
<td>Integration Specialist</td>
|
|
<td>New York</td>
|
|
<td>61</td>
|
|
<td>2012/12/02</td>
|
|
<td>$372,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Herrod Chandler</td>
|
|
<td>Sales Assistant</td>
|
|
<td>San Francisco</td>
|
|
<td>59</td>
|
|
<td>2012/08/06</td>
|
|
<td>$137,500</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Rhona Davidson</td>
|
|
<td>Integration Specialist</td>
|
|
<td>Tokyo</td>
|
|
<td>55</td>
|
|
<td>2010/10/14</td>
|
|
<td>$327,900</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Colleen Hurst</td>
|
|
<td>Javascript Developer</td>
|
|
<td>San Francisco</td>
|
|
<td>39</td>
|
|
<td>2009/09/15</td>
|
|
<td>$205,500</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Sonya Frost</td>
|
|
<td>Software Engineer</td>
|
|
<td>Edinburgh</td>
|
|
<td>23</td>
|
|
<td>2008/12/13</td>
|
|
<td>$103,600</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Jena Gaines</td>
|
|
<td>Office Manager</td>
|
|
<td>London</td>
|
|
<td>30</td>
|
|
<td>2008/12/19</td>
|
|
<td>$90,560</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Quinn Flynn</td>
|
|
<td>Support Lead</td>
|
|
<td>Edinburgh</td>
|
|
<td>22</td>
|
|
<td>2013/03/03</td>
|
|
<td>$342,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Charde Marshall</td>
|
|
<td>Regional Director</td>
|
|
<td>San Francisco</td>
|
|
<td>36</td>
|
|
<td>2008/10/16</td>
|
|
<td>$470,600</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Haley Kennedy</td>
|
|
<td>Senior Marketing Designer</td>
|
|
<td>London</td>
|
|
<td>43</td>
|
|
<td>2012/12/18</td>
|
|
<td>$313,500</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Tatyana Fitzpatrick</td>
|
|
<td>Regional Director</td>
|
|
<td>London</td>
|
|
<td>19</td>
|
|
<td>2010/03/17</td>
|
|
<td>$385,750</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Michael Silva</td>
|
|
<td>Marketing Designer</td>
|
|
<td>London</td>
|
|
<td>66</td>
|
|
<td>2012/11/27</td>
|
|
<td>$198,500</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Paul Byrd</td>
|
|
<td>Chief Financial Officer (CFO)</td>
|
|
<td>New York</td>
|
|
<td>64</td>
|
|
<td>2010/06/09</td>
|
|
<td>$725,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Gloria Little</td>
|
|
<td>Systems Administrator</td>
|
|
<td>New York</td>
|
|
<td>59</td>
|
|
<td>2009/04/10</td>
|
|
<td>$237,500</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Bradley Greer</td>
|
|
<td>Software Engineer</td>
|
|
<td>London</td>
|
|
<td>41</td>
|
|
<td>2012/10/13</td>
|
|
<td>$132,000</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Dai Rios</td>
|
|
<td>Personnel Lead</td>
|
|
<td>Edinburgh</td>
|
|
<td>35</td>
|
|
<td>2012/09/26</td>
|
|
<td>$217,500</td>
|
|
</tr>
|
|
</table>
|
|
</code></pre></kbd></div>
|
|
</div>
|
|
<p>根据选择的话题从而查询出评论数据</p>
|
|
<div class="table-responsive">
|
|
<div id="datatable-1_wrapper" class="dataTables_wrapper dt-bootstrap4">
|
|
<div class="row"><div class="col-sm-12"><table id="datatable-1" class="table data-table table-striped table-bordered dataTable" role="grid" aria-describedby="datatable-1_info">
|
|
<thead>
|
|
<tr role="row">
|
|
<th class="sorting sorting_asc" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-sort="ascending" aria-label="Name: activate to sort column descending" style="width: 250.844px;">文章ID</th>
|
|
<th class="sorting" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-label="Position: activate to sort column ascending" style="width: 392.094px;">评论用户</th>
|
|
<th class="sorting" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-label="Office: activate to sort column ascending" style="width: 190.75px;">评论性别</th>
|
|
<th class="sorting" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-label="Age: activate to sort column ascending" style="width: 84.2656px;">评论话题</th>
|
|
<th class="sorting" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-label="Start date: activate to sort column ascending" style="width: 172.594px;">评论内容</th>
|
|
<th class="text-right sorting" tabindex="0" aria-controls="datatable-1" rowspan="1" colspan="1" aria-label="Salary: activate to sort column ascending" style="width: 158.453px;">点赞量</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for i in comments %}
|
|
<tr class="odd">
|
|
<td class="sorting_1">{{ i[0] }}</td>
|
|
<td>{{ i[5] }}</td>
|
|
<td>
|
|
{% if i[6] =='f' %}
|
|
女生
|
|
{% else %}
|
|
男生
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ i[9] }}</td>
|
|
<td>{{ i[4] }}</td>
|
|
<td class="text-right">👍{{ i[2] }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AI分析结果展示区域 -->
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between">
|
|
<div class="header-title">
|
|
<h4 class="card-title">AI深度分析</h4>
|
|
</div>
|
|
<div class="analysis-controls">
|
|
<!-- 批量处理设置 -->
|
|
<div class="d-flex align-items-center">
|
|
<div class="form-group mx-2 mb-0">
|
|
<select id="batchSize" class="form-control form-control-sm">
|
|
<option value="10">每批10条</option>
|
|
<option value="20">每批20条</option>
|
|
<option value="50" selected>每批50条</option>
|
|
<option value="100">每批100条</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mx-2 mb-0">
|
|
<select id="modelType" class="form-control form-control-sm">
|
|
<option value="gpt-3.5-turbo" selected>GPT-3.5</option>
|
|
<option value="gpt-4">GPT-4</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mx-2 mb-0">
|
|
<select id="analysisDepth" class="form-control form-control-sm">
|
|
<option value="basic">基础分析</option>
|
|
<option value="standard" selected>标准分析</option>
|
|
<option value="deep">深度分析</option>
|
|
</select>
|
|
</div>
|
|
<div class="custom-control custom-switch mx-2">
|
|
<input type="checkbox" class="custom-control-input" id="autoUpdate">
|
|
<label class="custom-control-label" for="autoUpdate">自动更新</label>
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="requestAIAnalysis()">
|
|
开始分析
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- 进度显示 -->
|
|
<div id="analysis-progress" class="mb-3" style="display: none;">
|
|
<div class="progress">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
<small class="text-muted mt-1 d-block">正在分析: <span id="progress-text">0/0</span></small>
|
|
</div>
|
|
|
|
<!-- 分析结果过滤器 -->
|
|
<div class="mb-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class="form-group mb-0 mr-2">
|
|
<input type="text" class="form-control form-control-sm" id="keywordFilter" placeholder="按关键词过滤">
|
|
</div>
|
|
<div class="form-group mb-0 mr-2">
|
|
<select class="form-control form-control-sm" id="sentimentFilter">
|
|
<option value="">全部情感</option>
|
|
<option value="积极">积极</option>
|
|
<option value="消极">消极</option>
|
|
<option value="中性">中性</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<select class="form-control form-control-sm" id="riskFilter">
|
|
<option value="">全部风险等级</option>
|
|
<option value="高">高风险</option>
|
|
<option value="中">中风险</option>
|
|
<option value="低">低风险</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="ai-analysis-results" class="analysis-container">
|
|
<!-- 分析结果将在这里动态显示 -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 更新CSS样式 -->
|
|
<style>
|
|
.analysis-container {
|
|
max-height: 600px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.analysis-card {
|
|
border: 1px solid #eee;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-bottom: 15px;
|
|
background-color: #fff;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.analysis-card:hover {
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.risk-level {
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.risk-low {
|
|
background-color: #e8f5e9;
|
|
color: #2e7d32;
|
|
}
|
|
|
|
.risk-medium {
|
|
background-color: #fff3e0;
|
|
color: #f57c00;
|
|
}
|
|
|
|
.risk-high {
|
|
background-color: #ffebee;
|
|
color: #c62828;
|
|
}
|
|
|
|
.keywords-container {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.keyword-tag {
|
|
background-color: #e3f2fd;
|
|
color: #1976d2;
|
|
padding: 4px 8px;
|
|
border-radius: 16px;
|
|
font-size: 0.9em;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.keyword-tag:hover {
|
|
background-color: #1976d2;
|
|
color: #fff;
|
|
}
|
|
|
|
.sentiment-score {
|
|
display: inline-block;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-size: 0.9em;
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.sentiment-positive {
|
|
background-color: #e8f5e9;
|
|
color: #2e7d32;
|
|
}
|
|
|
|
.sentiment-negative {
|
|
background-color: #ffebee;
|
|
color: #c62828;
|
|
}
|
|
|
|
.sentiment-neutral {
|
|
background-color: #f5f5f5;
|
|
color: #616161;
|
|
}
|
|
|
|
.progress {
|
|
height: 0.5rem;
|
|
}
|
|
|
|
.analysis-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.analysis-controls {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<!-- 更新JavaScript代码 -->
|
|
<script>
|
|
let currentAnalysis = {
|
|
inProgress: false,
|
|
totalMessages: 0,
|
|
processedMessages: 0,
|
|
autoUpdateInterval: null
|
|
};
|
|
|
|
async function requestAIAnalysis() {
|
|
if (currentAnalysis.inProgress) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
currentAnalysis.inProgress = true;
|
|
showProgress();
|
|
|
|
const batchSize = parseInt(document.getElementById('batchSize').value);
|
|
const modelType = document.getElementById('modelType').value;
|
|
const analysisDepth = document.getElementById('analysisDepth').value;
|
|
|
|
const response = await fetch('/page/api/analyze_messages', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
batch_size: batchSize,
|
|
model_type: modelType,
|
|
analysis_depth: analysisDepth
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
if (result.success) {
|
|
displayAnalysisResults(result.data);
|
|
setupAutoUpdate();
|
|
} else {
|
|
showError(result.error);
|
|
}
|
|
} catch (error) {
|
|
console.error('AI分析请求失败:', error);
|
|
showError('请求失败,请稍后重试');
|
|
} finally {
|
|
currentAnalysis.inProgress = false;
|
|
hideProgress();
|
|
}
|
|
}
|
|
|
|
function showProgress() {
|
|
const progressDiv = document.getElementById('analysis-progress');
|
|
progressDiv.style.display = 'block';
|
|
updateProgress(0, 100);
|
|
}
|
|
|
|
function hideProgress() {
|
|
const progressDiv = document.getElementById('analysis-progress');
|
|
progressDiv.style.display = 'none';
|
|
}
|
|
|
|
function updateProgress(current, total) {
|
|
const progressBar = document.querySelector('.progress-bar');
|
|
const progressText = document.getElementById('progress-text');
|
|
const percentage = (current / total) * 100;
|
|
|
|
progressBar.style.width = `${percentage}%`;
|
|
progressText.textContent = `${current}/${total}`;
|
|
}
|
|
|
|
function setupAutoUpdate() {
|
|
const autoUpdate = document.getElementById('autoUpdate').checked;
|
|
if (autoUpdate && !currentAnalysis.autoUpdateInterval) {
|
|
currentAnalysis.autoUpdateInterval = setInterval(requestAIAnalysis, 300000); // 5分钟更新一次
|
|
} else if (!autoUpdate && currentAnalysis.autoUpdateInterval) {
|
|
clearInterval(currentAnalysis.autoUpdateInterval);
|
|
currentAnalysis.autoUpdateInterval = null;
|
|
}
|
|
}
|
|
|
|
function filterResults() {
|
|
const keyword = document.getElementById('keywordFilter').value.toLowerCase();
|
|
const sentiment = document.getElementById('sentimentFilter').value;
|
|
const risk = document.getElementById('riskFilter').value;
|
|
|
|
const cards = document.querySelectorAll('.analysis-card');
|
|
cards.forEach(card => {
|
|
let show = true;
|
|
|
|
// 关键词过滤
|
|
if (keyword) {
|
|
const content = card.textContent.toLowerCase();
|
|
show = show && content.includes(keyword);
|
|
}
|
|
|
|
// 情感过滤
|
|
if (sentiment) {
|
|
const cardSentiment = card.querySelector('.sentiment-text').textContent;
|
|
show = show && cardSentiment.includes(sentiment);
|
|
}
|
|
|
|
// 风险等级过滤
|
|
if (risk) {
|
|
const cardRisk = card.querySelector('.risk-level').textContent;
|
|
show = show && cardRisk.includes(risk);
|
|
}
|
|
|
|
card.style.display = show ? 'block' : 'none';
|
|
});
|
|
}
|
|
|
|
function displayAnalysisResults(results) {
|
|
const container = document.getElementById('ai-analysis-results');
|
|
container.innerHTML = ''; // 清空现有结果
|
|
|
|
results.forEach(analysis => {
|
|
const card = document.createElement('div');
|
|
card.className = 'analysis-card';
|
|
|
|
const riskLevelClass =
|
|
analysis.risk_level === '高' ? 'risk-high' :
|
|
analysis.risk_level === '中' ? 'risk-medium' : 'risk-low';
|
|
|
|
const sentimentClass =
|
|
analysis.sentiment === '积极' ? 'sentiment-positive' :
|
|
analysis.sentiment === '消极' ? 'sentiment-negative' : 'sentiment-neutral';
|
|
|
|
card.innerHTML = `
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-2">消息ID: ${analysis.id}</h5>
|
|
<span class="risk-level ${riskLevelClass}">
|
|
风险等级: ${analysis.risk_level}
|
|
</span>
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>情感倾向:</strong>
|
|
<span class="sentiment-text">${analysis.sentiment}</span>
|
|
<span class="sentiment-score ${sentimentClass}">${analysis.sentiment_score}</span>
|
|
</div>
|
|
<div class="keywords-container">
|
|
${analysis.keywords.split(',').map(keyword =>
|
|
`<span class="keyword-tag">${keyword.trim()}</span>`
|
|
).join('')}
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>核心观点:</strong>
|
|
<p class="mb-1">${analysis.key_points}</p>
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>影响分析:</strong>
|
|
<p class="mb-1">${analysis.influence}</p>
|
|
</div>
|
|
<div class="text-muted">
|
|
分析时间: ${analysis.analysis_time}
|
|
</div>
|
|
`;
|
|
|
|
container.appendChild(card);
|
|
});
|
|
|
|
// 应用当前的过滤器
|
|
filterResults();
|
|
}
|
|
|
|
function showError(message) {
|
|
alert(message);
|
|
}
|
|
|
|
// 设置事件监听器
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// 自动更新切换
|
|
document.getElementById('autoUpdate').addEventListener('change', setupAutoUpdate);
|
|
|
|
// 过滤器变化监听
|
|
document.getElementById('keywordFilter').addEventListener('input', filterResults);
|
|
document.getElementById('sentimentFilter').addEventListener('change', filterResults);
|
|
document.getElementById('riskFilter').addEventListener('change', filterResults);
|
|
|
|
// 首次加载时请求分析
|
|
requestAIAnalysis();
|
|
});
|
|
</script>
|
|
|
|
{% endblock %}
|
|
|
|
{% block echarts %}
|
|
<script>
|
|
var yData = {{ yData | tojson }};
|
|
var xData = {{ xData | tojson }};
|
|
|
|
var chartDom = document.getElementById('main');
|
|
var myChart = echarts.init(chartDom);
|
|
var option;
|
|
|
|
var lastFiveStartIndex = yData.length - 5; // 最后五个数据点的开始索引
|
|
|
|
option = {
|
|
tooltip: {
|
|
trigger: 'axis'
|
|
},
|
|
legend: {
|
|
data: ['话题出现时间分布个数', '话题预测时间分布个数']
|
|
},
|
|
toolbox: {
|
|
show: true,
|
|
feature: {
|
|
dataView: { show: true, readOnly: false },
|
|
magicType: { show: true, type: ['line', 'bar'] },
|
|
restore: { show: true },
|
|
saveAsImage: { show: true }
|
|
}
|
|
},
|
|
calculable: true,
|
|
xAxis: [
|
|
{
|
|
type: 'category',
|
|
data: xData
|
|
}
|
|
],
|
|
yAxis: [
|
|
{
|
|
type: 'value'
|
|
}
|
|
],
|
|
dataZoom: [
|
|
{
|
|
show: true,
|
|
start: 10,
|
|
end: 60
|
|
},
|
|
{
|
|
type: 'inside',
|
|
start: 10,
|
|
end: 60
|
|
}
|
|
],
|
|
series: [
|
|
{
|
|
name: '话题预测时间分布个数',
|
|
type: 'bar',
|
|
data: yData.map((value, index) => ({
|
|
value: value,
|
|
itemStyle: {
|
|
color: index >= lastFiveStartIndex ? 'orange' : 'blue'
|
|
}
|
|
})),
|
|
markPoint: {
|
|
data: [
|
|
{ type: 'max', name: 'Max' },
|
|
{ type: 'min', name: 'Min' }
|
|
]
|
|
},
|
|
markLine: {
|
|
data: [{ type: 'average', name: 'Avg' }]
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
myChart.setOption(option);
|
|
</script>
|
|
|
|
{% endblock %} |