对消息进行格式化
This commit is contained in:
@@ -4,20 +4,19 @@ import sys
|
|||||||
import threading
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import time
|
import time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
from db.message_storage import MessageStorageDB
|
from db.message_storage import MessageStorageDB
|
||||||
from db.stats_db import StatsDBOperator
|
from db.stats_db import StatsDBOperator
|
||||||
from utils.wechat.contact_manager import ContactManager
|
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory
|
||||||
|
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||||
|
# 导入消息格式化工具
|
||||||
|
from utils.message_formatter import format_quote_message
|
||||||
|
# 导入toml用于配置文件
|
||||||
|
import toml
|
||||||
|
|
||||||
# 添加项目根目录到系统路径,确保可以导入项目模块
|
# 添加项目根目录到系统路径,确保可以导入项目模块
|
||||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, send_from_directory
|
|
||||||
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
|
||||||
|
|
||||||
# 导入toml用于配置文件
|
|
||||||
import toml
|
|
||||||
|
|
||||||
|
|
||||||
class DashboardServer:
|
class DashboardServer:
|
||||||
"""统计看板服务器"""
|
"""统计看板服务器"""
|
||||||
@@ -152,12 +151,12 @@ class DashboardServer:
|
|||||||
def errors():
|
def errors():
|
||||||
return render_template('errors.html')
|
return render_template('errors.html')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/messages')
|
@app.route('/messages')
|
||||||
@login_required
|
@login_required
|
||||||
def message_list_page():
|
def message_list_page():
|
||||||
"""消息列表页面"""
|
"""消息列表页面"""
|
||||||
return render_template('message_list.html')
|
return render_template('message_list.html')
|
||||||
|
|
||||||
# 在_create_app方法中添加新的路由
|
# 在_create_app方法中添加新的路由
|
||||||
@app.route('/robot_management')
|
@app.route('/robot_management')
|
||||||
@login_required
|
@login_required
|
||||||
@@ -170,31 +169,31 @@ class DashboardServer:
|
|||||||
try:
|
try:
|
||||||
# 获取所有群组列表
|
# 获取所有群组列表
|
||||||
groups = GroupBotManager.get_group_list()
|
groups = GroupBotManager.get_group_list()
|
||||||
|
|
||||||
# 如果方法返回None或发生异常,使用本地缓存
|
# 如果方法返回None或发生异常,使用本地缓存
|
||||||
if groups is None and hasattr(GroupBotManager, "local_cache"):
|
if groups is None and hasattr(GroupBotManager, "local_cache"):
|
||||||
groups = GroupBotManager.local_cache.get("group_list", set())
|
groups = GroupBotManager.local_cache.get("group_list", set())
|
||||||
|
|
||||||
# 如果仍然为None,则初始化为空集合
|
# 如果仍然为None,则初始化为空集合
|
||||||
if groups is None:
|
if groups is None:
|
||||||
groups = set()
|
groups = set()
|
||||||
|
|
||||||
self.logger.info(f"获取到 {len(groups)} 个群组")
|
self.logger.info(f"获取到 {len(groups)} 个群组")
|
||||||
group_data = []
|
group_data = []
|
||||||
|
|
||||||
for group_id in groups:
|
for group_id in groups:
|
||||||
try:
|
try:
|
||||||
# 获取群名称,如果失败则使用默认值
|
# 获取群名称,如果失败则使用默认值
|
||||||
group_name = self.contact_manager.get_nickname(group_id)
|
group_name = self.contact_manager.get_nickname(group_id)
|
||||||
if not group_name:
|
if not group_name:
|
||||||
group_name = f"未知群组({group_id})"
|
group_name = f"未知群组({group_id})"
|
||||||
|
|
||||||
# 获取机器人状态,如果失败则使用默认值
|
# 获取机器人状态,如果失败则使用默认值
|
||||||
try:
|
try:
|
||||||
robot_status = GroupBotManager.get_group_permission(group_id, Feature.ROBOT)
|
robot_status = GroupBotManager.get_group_permission(group_id, Feature.ROBOT)
|
||||||
except:
|
except:
|
||||||
robot_status = PermissionStatus.UNKNOWN
|
robot_status = PermissionStatus.UNKNOWN
|
||||||
|
|
||||||
group_data.append({
|
group_data.append({
|
||||||
"group_id": group_id,
|
"group_id": group_id,
|
||||||
"group_name": group_name,
|
"group_name": group_name,
|
||||||
@@ -208,7 +207,7 @@ class DashboardServer:
|
|||||||
"group_name": "获取失败",
|
"group_name": "获取失败",
|
||||||
"robot_status": "unknown"
|
"robot_status": "unknown"
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({"success": True, "data": group_data})
|
return jsonify({"success": True, "data": group_data})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"获取群组列表失败: {e}")
|
self.logger.error(f"获取群组列表失败: {e}")
|
||||||
@@ -220,7 +219,7 @@ class DashboardServer:
|
|||||||
try:
|
try:
|
||||||
permissions = GroupBotManager.list_group_permissions(group_id)
|
permissions = GroupBotManager.list_group_permissions(group_id)
|
||||||
permission_data = []
|
permission_data = []
|
||||||
|
|
||||||
for feature, status in permissions.items():
|
for feature, status in permissions.items():
|
||||||
permission_data.append({
|
permission_data.append({
|
||||||
"feature_id": feature.value,
|
"feature_id": feature.value,
|
||||||
@@ -228,7 +227,7 @@ class DashboardServer:
|
|||||||
"feature_description": feature.description,
|
"feature_description": feature.description,
|
||||||
"status": status.value
|
"status": status.value
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({"success": True, "data": permission_data})
|
return jsonify({"success": True, "data": permission_data})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"获取群组权限失败: {e}")
|
self.logger.error(f"获取群组权限失败: {e}")
|
||||||
@@ -241,11 +240,11 @@ class DashboardServer:
|
|||||||
data = request.json
|
data = request.json
|
||||||
feature_id = data.get('feature_id')
|
feature_id = data.get('feature_id')
|
||||||
status = data.get('status')
|
status = data.get('status')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
feature = Feature(int(feature_id))
|
feature = Feature(int(feature_id))
|
||||||
new_status = PermissionStatus(status)
|
new_status = PermissionStatus(status)
|
||||||
|
|
||||||
# 特殊处理ROBOT功能
|
# 特殊处理ROBOT功能
|
||||||
if feature == Feature.ROBOT:
|
if feature == Feature.ROBOT:
|
||||||
r = self.db_manager.get_redis_connection()
|
r = self.db_manager.get_redis_connection()
|
||||||
@@ -255,7 +254,7 @@ class DashboardServer:
|
|||||||
else:
|
else:
|
||||||
GroupBotManager.local_cache["group_list"].remove(group_id)
|
GroupBotManager.local_cache["group_list"].remove(group_id)
|
||||||
r.srem("group:list", group_id)
|
r.srem("group:list", group_id)
|
||||||
|
|
||||||
GroupBotManager.set_group_permission(group_id, feature, new_status)
|
GroupBotManager.set_group_permission(group_id, feature, new_status)
|
||||||
return jsonify({"success": True})
|
return jsonify({"success": True})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -269,15 +268,15 @@ class DashboardServer:
|
|||||||
data = request.json
|
data = request.json
|
||||||
operation = data.get('operation')
|
operation = data.get('operation')
|
||||||
group_ids = data.get('group_ids', [])
|
group_ids = data.get('group_ids', [])
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if operation == 'remove_groups':
|
if operation == 'remove_groups':
|
||||||
for group_id in group_ids:
|
for group_id in group_ids:
|
||||||
result = GroupBotManager.remove_group(group_id)
|
result = GroupBotManager.remove_group(group_id)
|
||||||
results[group_id] = result
|
results[group_id] = result
|
||||||
|
|
||||||
return jsonify({"success": True, "results": results})
|
return jsonify({"success": True, "results": results})
|
||||||
else:
|
else:
|
||||||
return jsonify({"success": False, "error": "不支持的操作类型"}), 400
|
return jsonify({"success": False, "error": "不支持的操作类型"}), 400
|
||||||
@@ -486,7 +485,6 @@ class DashboardServer:
|
|||||||
self.logger.error(f"添加群组失败: {e}")
|
self.logger.error(f"添加群组失败: {e}")
|
||||||
return jsonify({"success": False, "error": str(e)}), 500
|
return jsonify({"success": False, "error": str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/messages', methods=['GET'])
|
@app.route('/api/messages', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def get_messages():
|
def get_messages():
|
||||||
@@ -499,7 +497,7 @@ class DashboardServer:
|
|||||||
search_text = request.args.get('search_text')
|
search_text = request.args.get('search_text')
|
||||||
page = int(request.args.get('page', 1))
|
page = int(request.args.get('page', 1))
|
||||||
page_size = int(request.args.get('page_size', 20))
|
page_size = int(request.args.get('page_size', 20))
|
||||||
|
|
||||||
# 调用数据库方法获取消息
|
# 调用数据库方法获取消息
|
||||||
result = self.message_storage.get_messages_by_filter(
|
result = self.message_storage.get_messages_by_filter(
|
||||||
group_id=group_id,
|
group_id=group_id,
|
||||||
@@ -509,15 +507,31 @@ class DashboardServer:
|
|||||||
page=page,
|
page=page,
|
||||||
page_size=page_size
|
page_size=page_size
|
||||||
)
|
)
|
||||||
|
|
||||||
# 处理消息数据,添加群组名称和发送者昵称
|
# 处理消息数据,添加群组名称和发送者昵称,并格式化引用消息
|
||||||
for msg in result['messages']:
|
for msg in result['messages']:
|
||||||
# 获取群组名称
|
# 获取群组名称
|
||||||
msg['group_name'] = self.contact_manager.get_nickname(msg['group_id']) or msg['group_id']
|
msg['group_name'] = self.contact_manager.get_nickname(msg['group_id']) or msg['group_id']
|
||||||
|
|
||||||
# 获取发送者昵称
|
# 获取发送者昵称
|
||||||
msg['sender_name'] = self.contact_manager.get_nickname(msg['sender']) or msg['sender']
|
msg['sender_name'] = self.contact_manager.get_nickname(msg['sender']) or msg['sender']
|
||||||
|
|
||||||
|
# 处理消息内容,格式化引用消息
|
||||||
|
if msg['message_type'] == 49 and msg['content']: # 应用消息类型
|
||||||
|
try:
|
||||||
|
# 检查是否为引用消息
|
||||||
|
if '<refermsg>' in msg['content']:
|
||||||
|
# 使用格式化工具处理引用消息
|
||||||
|
msg['content'] = format_quote_message(msg['content'])
|
||||||
|
else:
|
||||||
|
# 其他类型的应用消息,解析 XML 提取标题
|
||||||
|
root = ET.fromstring(msg['content'])
|
||||||
|
title_elem = root.find('.//title')
|
||||||
|
if title_elem is not None:
|
||||||
|
msg['content'] = title_elem.text
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"解析消息类型49出错: {e}")
|
||||||
|
|
||||||
return jsonify(result)
|
return jsonify(result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"获取消息列表失败: {e}")
|
self.logger.error(f"获取消息列表失败: {e}")
|
||||||
@@ -536,7 +550,7 @@ class DashboardServer:
|
|||||||
'group_id': group_id,
|
'group_id': group_id,
|
||||||
'group_name': self.contact_manager.get_nickname(group_id) or group_id
|
'group_name': self.contact_manager.get_nickname(group_id) or group_id
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({'groups': groups})
|
return jsonify({'groups': groups})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"获取群组列表失败: {e}")
|
self.logger.error(f"获取群组列表失败: {e}")
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ from wcferry import WxMsg
|
|||||||
|
|
||||||
from db.connection import DBConnectionManager
|
from db.connection import DBConnectionManager
|
||||||
from db.message_storage import MessageStorageDB
|
from db.message_storage import MessageStorageDB
|
||||||
|
# 导入消息格式化工具
|
||||||
|
from utils.message_formatter import format_quote_message
|
||||||
|
|
||||||
# 配置日志
|
# 配置日志
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -209,18 +211,22 @@ class MessageStorage:
|
|||||||
hours_ago = int(
|
hours_ago = int(
|
||||||
(current_time - datetime.strptime(last_summary_time, '%Y-%m-%d %H:%M:%S')).total_seconds() / 3600) + 1
|
(current_time - datetime.strptime(last_summary_time, '%Y-%m-%d %H:%M:%S')).total_seconds() / 3600) + 1
|
||||||
messages = self.message_db.get_recent_messages(group_id, hours_ago=hours_ago)
|
messages = self.message_db.get_recent_messages(group_id, hours_ago=hours_ago)
|
||||||
|
|
||||||
# 构建最终的结果字符串
|
# 构建最终的结果字符串
|
||||||
result = []
|
result = []
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
timestamp, sender, content, message_type = msg['timestamp'], msg['sender'], msg['content'], msg[
|
timestamp, sender, content, message_type = msg['timestamp'], msg['sender'], msg['content'], msg['message_type']
|
||||||
'message_type']
|
|
||||||
try:
|
try:
|
||||||
if message_type == 49: # 注意这里是整数类型
|
if message_type == 49: # 应用消息类型
|
||||||
# 解析 XML 字符串
|
# 检查是否为引用消息
|
||||||
root = ET.fromstring(content)
|
if '<refermsg>' in content:
|
||||||
# 提取 title 内容
|
# 使用格式化工具处理引用消息
|
||||||
content = root.find('.//title').text
|
content = format_quote_message(content)
|
||||||
|
else:
|
||||||
|
# 其他类型的应用消息,解析 XML 提取标题
|
||||||
|
root = ET.fromstring(content)
|
||||||
|
title_elem = root.find('.//title')
|
||||||
|
if title_elem is not None:
|
||||||
|
content = title_elem.text
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"解析消息类型49出错: {e}")
|
logger.error(f"解析消息类型49出错: {e}")
|
||||||
|
|
||||||
|
|||||||
38
utils/message_formatter.py
Normal file
38
utils/message_formatter.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import html
|
||||||
|
|
||||||
|
|
||||||
|
def format_quote_message(xml_content):
|
||||||
|
"""
|
||||||
|
格式化引用消息
|
||||||
|
|
||||||
|
Args:
|
||||||
|
xml_content: XML格式的消息内容
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
格式化后的消息文本
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 解析XML
|
||||||
|
root = ET.fromstring(xml_content)
|
||||||
|
|
||||||
|
# 获取主消息内容
|
||||||
|
title_elem = root.find('.//title')
|
||||||
|
main_content = title_elem.text if title_elem is not None else ""
|
||||||
|
|
||||||
|
# 获取引用消息信息
|
||||||
|
refer_msg = root.find('.//refermsg')
|
||||||
|
if refer_msg is not None:
|
||||||
|
display_name = refer_msg.find('displayname').text if refer_msg.find('displayname') is not None else "未知用户"
|
||||||
|
quoted_content = refer_msg.find('content').text if refer_msg.find('content') is not None else ""
|
||||||
|
|
||||||
|
# 解码HTML实体
|
||||||
|
quoted_content = html.unescape(quoted_content)
|
||||||
|
|
||||||
|
# 构建格式化的引用消息
|
||||||
|
formatted_message = f"┌─────────────────────────────────\n│ 引用 {display_name}:{quoted_content}\n└─────────────────────────────────\n{main_content}"
|
||||||
|
return formatted_message
|
||||||
|
|
||||||
|
return main_content
|
||||||
|
except Exception as e:
|
||||||
|
return f"解析引用消息失败: {str(e)}"
|
||||||
Reference in New Issue
Block a user