综合设计——多源异构数据采集与融合应用综合实践
一.基本信息
这个项目属于哪个课程 | https://edu.cnblogs.com/campus/fzu/2024DataCollectionandFusiontechnology |
---|---|
组名、项目简介 | 组名:福小兵,项目需求:实时舆情监控系统,项目目标:为福州大学提供舆情监控与决策辅助工具,技术路线:使用 Flask 后端、Memfire(PostgreSQL)数据库和 Vue 前端技术栈,建立从数据采集到情感分析再到可视化的完整系统 |
团队成员学号 | 102202141黄昕怡,102202101马鑫,1022021045谢含,102202112刘莹,102202126陈家凯,102202106王强,102202124阿依娜孜·赛日克,102202153来在提’叶鲁别克 |
这个项目目标 | 多模态数据采集,话题总结,智慧情绪分析,智能AI舆情分析 |
其他参考文献 | [1]马茜, 谷峪, 张天成, & 于戈. (2013). 一种基于数据质量的异构多源多模态感知数据获取方法. 计算机学报, 36(10), 12. [2]司俊勇, & 付永华. (2024). 多模态数据融合的在线学习情感计算研究. 图书与情报(3), 69-80. [3]何炎祥, 孙松涛, 牛菲菲, & 李飞. (2017). 用于微博情感分析的一种情感语义增强的深度学习模型. 计算机学报, 40(4), 18. [4] 张玲, 王磊, & 李铭. (2021). 面向社交媒体情感分析的多模态数据融合方法研究. 图书情报工作, 65(8), 21-28. [5]杨宇恒.基于跨模态预测融合的多模态情感识别方法研究[D].西安理工大学,2024.DOI:10.27398/d.cnki.gxalu.2024.000099. |
Github代码链接 | https://github.com/fufubuff/fu_police |
Gitee代码链接 | <https://gitee.com/wang-qiangsy/crawl_project/tree/master/福小兵-综合实验 > |
二.整体项目
1.项目名称
福小兵:情感分析及舆情分析平台
2.项目背景
随着互联网的飞速发展和社交媒体的广泛普及,网络舆情已经成为影响高校形象和声誉的关键因素。各种社交媒体平台、论坛和新闻网站为公众提供了发表观点和分享信息的渠道,使得信息传播的速度和范围空前扩大。福州大学作为福建省重点建设的高水平大学,其在网络上的公众形象不仅关系到学校在福建省内的地位,更直接影响到其在全国乃至国际上的知名度和美誉度。于是本项目面向福州大学,聚焦其在微博、贴吧、知乎等平台的多模态网络舆情数据,以 Flask 后端、Memfire(PostgreSQL) 数据库和 Vue 前端 为主要技术栈,搭建一个从数据采集到情感分析再到可视化展示的完整系统,为学校舆情监控与管理提供支持和决策辅助。
3.项目内容
多模态数据采集
- 爬取福州大学在各大网站(如微博、贴吧、知乎等)上的评论、帖子内容和评论图片。
- 建立一个全面的舆情数据库,涵盖多平台、多媒体形式的数据。
话题总结
- 分析网络社区中关于福州大学的热点话题和关注点。
- 提取高频关键词,了解公众最关心的问题。
智慧情绪分析
- 使用多种深度学习模型,对文本和图片数据进行情感倾向分析(积极、中立、消极)。
- 监测公共对福州大学相关的情绪变化趋势,识别潜在的舆情风险。
智能AI舆情分析
- 调用大语言模型的接口(如GPT-4),提供深入的AI分析和预测,对学校的舆论概况进行智能监控。
- 生成自动化的舆情报告,辅助决策。
学校保护与归属
- 通过系统的建立,表达对福州大学的归属感和保护欲望。
- 帮助学校及时监控舆情,维护良好的公众形象。
4.项目架构
前端层(Vue,HTML+CSS+js)
- 前端一包括用户自爬取数据和报告式分析使用 Vue 搭建前端页面,包含搜索输入框、情感分析可视化、AI 总结输出等界面。
- 前端二包含爬取内容的数据库的数据展示,方式有柱形图,饼图,词云图,分页表格,还包含音乐播放器,日历。此外还有ai聊天窗口可让用户对舆情数据进行了解。
- 以上通过对接后端api,获取处理数据进行数据可视化。
后端层(Flask)
- 后端api接口包括:
数据获取:在数据库中获取相关内容。
情感分析:基于深度学习模型,对文本做多类别情感识别。
数据可视化:情感分析进行统计总结,通过各种图标,不限于柱形图词云图进行可视化。 - 整合大语言模型接口,用于对检索和情感分析结果进行二次生成与深入总结。
数据爬取
- 利用爬虫技术从微博、贴吧等平台抓取多模态内容。
- 将抓取的数据上传到云端的PostgreSQL数据库内。
5.项目展示
- 爬取内容的数据库的数据展示,方式有柱形图,饼图,词云图,分页表格,还包含音乐播放器,日历。此外还有ai聊天窗口可让用户对舆情数据进行了解。
- 用户自爬取数据和报告式分析
三.个人工作
1.爬取内容的数据库的数据展示页面前端设计
- 以图片数据的数据展示为例,展示部分代码
<header>
<h1>福卫兵is all you need</h1>
<h1>福卫兵出击</h1>
</header>
<main>
<!-- Update the HTML in templates/data.html -->
<div class="chart-container">
<canvas id="emotionChart"></canvas>
<div id="wordCloud" style="display: none;">
<p class="word">Fzuer都说了什么呢</p>
<img src="img/wordcloud.png" alt="Word Cloud" class="wordcloud">
</div>
<div class="chart-pagination">
<button id="prevChart" title="上一页">
<img src="img/back-icon.png" alt="上一页">
</button>
<button id="nextChart" title="下一页">
<img src="img/skip.png" alt="下一页">
</button>
</div>
</div>
<div class="left-sidebar">
<div class="ai-window">
<div id="chatContainer"></div>
<input type="text" id="userInput" placeholder="福兵,开启今日的巡查吧!" onkeypress="handleKeyPress(event)">
</div>
<div class="button-container">
<img src="img/fu.png" alt="Clickable Image" class="clickable-image" onclick="sendText()">
</div>
</div>
<div class="right-sidebar">
<!-- 音乐播放器 -->
<div class="player">
<!-- 歌曲封面 -->
<div class="cover">
<img src="music/back.jpg" alt="" class="music-back">
<div class="song">
<p>
纯音乐,请欣赏<br>
</p>
</div>
</div>
<!-- 歌词设置 -->
<h2>清澈的眼睛</h2>
<!-- audio标签 -->
<div class="mus">
<audio src="music/bgm.mp3" controls autoplay loop></audio>
</div>
</div>
<div class="calendar-container">
<div id="calendar"></div>
</div>
</div>
<table>
<thead>
<tr>
<th>序号</th>
<th>评论图片</th>
<th>图片文字分析</th>
<th>情感分析</th>
</tr>
</thead>
<tbody id="commentsTableBody"></tbody>
</table>
<div class="pagination">
<button id="prevPage" disabled>上一页</button>
<span id="pageInfo"></span>
<button id="nextPage">下一页</button>
<input type=" number" id="jumpToPage" min="1" placeholder="页码">
<button id="jumpPageButton">跳转</button>
</div>
</main>
- 数据展示(饼图)
new Chart(ctx, {
type: 'pie',
data: {
labels: ['愤怒', '厌恶', '恐惧', '高兴', '悲伤', '惊讶', '中性'],
datasets: [{
data: [
emotionData.angry || 0,
emotionData.disgust || 0,
emotionData.fear || 0,
emotionData.happy || 0,
emotionData.sad || 0,
emotionData.surprise || 0,
emotionData.neutral || 0
],
backgroundColor: [
'#c0392b',
'#a93226',
'#e67e22',
'#f1c40f',
'#3498db',
'#9b59b6',
'#95a5a6'
],
hoverBackgroundColor: [
'#c0392b',
'#a93226',
'#e67e22',
'#f1c40f',
'#3498db',
'#9b59b6',
'#95a5a6'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom'
}
}
}
});
// 点击图片打开新标签页
row.querySelector('img').addEventListener('click', function () {
window.open(this.src, '_blank');
});
}
2.实现后端数据库获取数据
api
def get_db_connection():
try:
conn = psycopg2.connect(
host='101.132.80.183',
port='5433',
database='dbf72a0c3d7d054ef39b98488f2995d159zz',
user='zzsthere',
password='20020925Aa'
)
return conn
except Exception as e:
print(f"数据库连接错误: {e}")
return None
elif 'merged_images' in query:
# 处理 merged_images 表数据
sentiment_data = row[3]
try:
sentiment = json.loads(sentiment_data)
except (TypeError, json.JSONDecodeError):
sentiment = sentiment_data
# 将 image_data 转换为 Base64 编码的字符串
image_data_base64 = base64.b64encode(row[4]).decode('utf-8')
comment = {
'id': row[0],
'name': row[1],
'description': row[2],
'sentiment': sentiment,
'image_data': image_data_base64
}
@app.route('/api/merged_images', methods=['GET'])
def get_merged_images():
try:
print("接收到 /api/merged_images 请求")
query = 'SELECT id, image_name, description, emotions, image_data FROM merged_images'
comments = fetch_comments(query)
if comments is None:
return jsonify({'error': '无法获取 merged_images 数据'}), 500
print(f"查询到 {len(comments)} 条 merged_images 数据")
return jsonify({'merged_images': comments})
except Exception as e:
print(f"错误: {e}")
return jsonify({'error': str(e)}), 500
接口与数据可视化
fetch('http://localhost:5000/api/merged_images')
.then(response => response.json())
.then(data => {
mergedImagesData = data.merged_images;
// 初始化情绪计数,确保每张图片都被计数
mergedImagesData.forEach(item => {
const emotionData = item.sentiment;
// 计算主导情绪
const dominantEmotion = Object.keys(emotionData).reduce((a, b) => emotionData[a] > emotionData[b] ? a : b);
if (emotionSummary.hasOwnProperty(dominantEmotion)) {
emotionSummary[dominantEmotion]++;
} else {
console.warn(`未识别的情感类别 "${dominantEmotion}" 出现在图片 ${item.image_name}`);
}
console.log(`图片 ${item.image_name} 的主导情感为: ${dominantEmotion}`);
});
renderTable(currentPage);
// 绘制情绪摘要柱状图
const ctx = document.getElementById('emotionChart').getContext('2d');
const emotionChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['愤怒', '厌恶', '恐惧', '高兴', '悲伤', '惊讶', '中性'],
datasets: [{
label: '情感计数',
data: [
emotionSummary.angry,
emotionSummary.disgust,
emotionSummary.fear,
emotionSummary.happy,
emotionSummary.sad,
emotionSummary.surprise,
emotionSummary.neutral
],
backgroundColor: [
'#c0392b',
'#a93226',
'#e67e22',
'#f1c40f',
'#3498db',
'#9b59b6',
'#95a5a6'
],
hoverBackgroundColor: [
'#c0392b',
'#a93226',
'#e67e22',
'#f1c40f',
'#3498db',
'#9b59b6',
'#95a5a6'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom'
}
},
scales: {
x: {
title: {
display: true,
text: '情感类型'
},
grid: {
display: false // 删除 x 轴背景方格线
}
},
y: {
beginAtZero: true,
title: {
display: true,
text: '数量'
},
ticks: {
stepSize: 1
},
grid: {
display: false // 删除 y 轴背景方格线
}
}
}
}
});
})
.catch(error => {
console.error('获取数据时出现问题:', error);
});
});
document.addEventListener('DOMContentLoaded', function () {
const calendar = document.getElementById('calendar');
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth();
const date = today.getDate();
let isStamped = false; // Flag to track if the stamp has been applied
function generateCalendar(year, month) {
calendar.innerHTML = '';
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
for (let i = 0; i < firstDay; i++) {
const emptyCell = document.createElement('div');
calendar.appendChild(emptyCell);
}
for (let day = 1; day <= daysInMonth; day++) {
const dayCell = document.createElement('div');
dayCell.textContent = day;
dayCell.classList.add('calendar-day');
if (day === date) {
dayCell.classList.add('today');
}
calendar.appendChild(dayCell);
}
}
generateCalendar(year, month);
const clickableImage = document.querySelector('.clickable-image');
clickableImage.addEventListener('click', function () {
if (!isStamped) { // Check if the stamp has already been applied
const todayCell = document.querySelector('.calendar-day.today');
if (todayCell) {
const stamp = document.createElement('img');
stamp.src = 'img/fu.png';
stamp.classList.add('stamp');
todayCell.appendChild(stamp);
setTimeout(() => {
todayCell.classList.add('marked');
stamp.remove();
const smallImage = document.createElement('img');
smallImage.src = 'img/fu.png'; // Path to the small image
smallImage.classList.add('small-stamp');
todayCell.appendChild(smallImage);
}, 1000); // Adjust the timeout duration as needed
isStamped = true; // Set the flag to true after stamping
}
}
});
});
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步