chore: initial commit
This commit is contained in:
347
admin_commands.py
Normal file
347
admin_commands.py
Normal file
@@ -0,0 +1,347 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
管理员命令模块
|
||||
为integrated_bot_ai.py添加管理员后台功能
|
||||
"""
|
||||
import sqlite3
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List
|
||||
import os
|
||||
import psutil
|
||||
|
||||
ADMIN_ID = 7363537082
|
||||
|
||||
class AdminCommands:
|
||||
"""管理员命令处理类"""
|
||||
|
||||
def __init__(self, bot_instance, logger):
|
||||
self.bot = bot_instance
|
||||
self.logger = logger
|
||||
self.stats = {
|
||||
"start_time": datetime.now(),
|
||||
"messages_received": 0,
|
||||
"searches_performed": 0,
|
||||
"ai_queries": 0,
|
||||
"cache_hits": 0
|
||||
}
|
||||
|
||||
async def handle_stats(self, update, context):
|
||||
"""处理 /stats 命令 - 查看统计信息"""
|
||||
user = update.effective_user
|
||||
if user.id != ADMIN_ID:
|
||||
return
|
||||
|
||||
uptime = datetime.now() - self.stats["start_time"]
|
||||
days = uptime.days
|
||||
hours = uptime.seconds // 3600
|
||||
minutes = (uptime.seconds % 3600) // 60
|
||||
|
||||
# 获取进程信息
|
||||
process = psutil.Process(os.getpid())
|
||||
memory_mb = process.memory_info().rss / 1024 / 1024
|
||||
|
||||
# 查询日志获取用户数
|
||||
user_count = self._get_unique_users_from_logs()
|
||||
|
||||
# 查询缓存数据库
|
||||
cache_stats = self._get_cache_stats()
|
||||
|
||||
text = (
|
||||
"📊 **机器人统计信息**\\n\\n"
|
||||
f"⏱ **运行时间:** {days}天 {hours}小时 {minutes}分钟\\n"
|
||||
f"📅 **启动时间:** {self.stats['start_time'].strftime('%Y-%m-%d %H:%M:%S')}\\n\\n"
|
||||
|
||||
"👥 **用户统计:**\\n"
|
||||
f"• 总访问用户:{user_count}人\\n"
|
||||
f"• AI对话次数:{self.stats['ai_queries']}\\n"
|
||||
f"• 搜索执行次数:{self.stats['searches_performed']}\\n\\n"
|
||||
|
||||
"💾 **缓存统计:**\\n"
|
||||
f"• 缓存记录数:{cache_stats['total']}\\n"
|
||||
f"• 缓存命中率:{cache_stats['hit_rate']:.1f}%\\n\\n"
|
||||
|
||||
"💻 **系统资源:**\\n"
|
||||
f"• 内存使用:{memory_mb:.1f} MB\\n"
|
||||
f"• CPU核心数:{psutil.cpu_count()}\\n"
|
||||
)
|
||||
|
||||
await update.message.reply_text(text, parse_mode='Markdown')
|
||||
self.logger.info(f"[管理员] 查看统计信息")
|
||||
|
||||
async def handle_users(self, update, context):
|
||||
"""处理 /users 命令 - 查看用户列表"""
|
||||
user = update.effective_user
|
||||
if user.id != ADMIN_ID:
|
||||
return
|
||||
|
||||
users = self._get_users_from_logs()
|
||||
|
||||
if not users:
|
||||
await update.message.reply_text("暂无用户访问记录")
|
||||
return
|
||||
|
||||
text = f"👥 **访问用户列表** ({len(users)}人)\\n\\n"
|
||||
|
||||
for i, (user_id, count) in enumerate(users[:20], 1):
|
||||
text += f"{i}. 用户 `{user_id}` - {count}次交互\\n"
|
||||
|
||||
if len(users) > 20:
|
||||
text += f"\\n... 还有 {len(users)-20} 个用户"
|
||||
|
||||
text += f"\\n\\n💡 使用 /userinfo <用户ID> 查看详情"
|
||||
|
||||
await update.message.reply_text(text, parse_mode='Markdown')
|
||||
self.logger.info(f"[管理员] 查看用户列表")
|
||||
|
||||
async def handle_userinfo(self, update, context):
|
||||
"""处理 /userinfo 命令 - 查看指定用户信息"""
|
||||
user = update.effective_user
|
||||
if user.id != ADMIN_ID:
|
||||
return
|
||||
|
||||
if not context.args:
|
||||
await update.message.reply_text(
|
||||
"用法:/userinfo <用户ID>\\n"
|
||||
"示例:/userinfo 123456789"
|
||||
)
|
||||
return
|
||||
|
||||
try:
|
||||
target_user_id = int(context.args[0])
|
||||
info = self._get_user_info(target_user_id)
|
||||
|
||||
if not info:
|
||||
await update.message.reply_text(f"未找到用户 {target_user_id} 的记录")
|
||||
return
|
||||
|
||||
text = (
|
||||
f"👤 **用户信息** (ID: `{target_user_id}`)\\n\\n"
|
||||
f"📊 交互次数:{info['interactions']}\\n"
|
||||
f"🔍 搜索次数:{info['searches']}\\n"
|
||||
f"💬 AI对话次数:{info['ai_chats']}\\n"
|
||||
f"⏰ 首次访问:{info['first_seen']}\\n"
|
||||
f"🕐 最后活跃:{info['last_seen']}\\n"
|
||||
)
|
||||
|
||||
await update.message.reply_text(text, parse_mode='Markdown')
|
||||
|
||||
except ValueError:
|
||||
await update.message.reply_text("❌ 用户ID格式错误,请输入数字")
|
||||
except Exception as e:
|
||||
await update.message.reply_text(f"❌ 查询失败:{str(e)}")
|
||||
self.logger.error(f"[管理员] 查询用户信息失败: {e}")
|
||||
|
||||
async def handle_logs(self, update, context):
|
||||
"""处理 /logs 命令 - 查看最近日志"""
|
||||
user = update.effective_user
|
||||
if user.id != ADMIN_ID:
|
||||
return
|
||||
|
||||
lines = context.args[0] if context.args else "50"
|
||||
try:
|
||||
num_lines = int(lines)
|
||||
log_file = "./logs/integrated_bot_detailed.log"
|
||||
|
||||
if os.path.exists(log_file):
|
||||
with open(log_file, 'r') as f:
|
||||
all_lines = f.readlines()
|
||||
recent_lines = all_lines[-num_lines:]
|
||||
|
||||
log_text = ''.join(recent_lines)
|
||||
|
||||
# Telegram消息限制4096字符
|
||||
if len(log_text) > 4000:
|
||||
log_text = log_text[-4000:]
|
||||
|
||||
await update.message.reply_text(
|
||||
f"📋 **最近 {num_lines} 行日志:**\\n\\n```\\n{log_text}\\n```",
|
||||
parse_mode='Markdown'
|
||||
)
|
||||
else:
|
||||
await update.message.reply_text("❌ 日志文件不存在")
|
||||
|
||||
except Exception as e:
|
||||
await update.message.reply_text(f"❌ 读取日志失败:{str(e)}")
|
||||
|
||||
async def handle_cache(self, update, context):
|
||||
"""处理 /cache 命令 - 查看缓存详情"""
|
||||
user = update.effective_user
|
||||
if user.id != ADMIN_ID:
|
||||
return
|
||||
|
||||
stats = self._get_cache_details()
|
||||
|
||||
text = (
|
||||
"💾 **缓存详细信息**\\n\\n"
|
||||
f"📦 总记录数:{stats['total']}\\n"
|
||||
f"✅ 有效记录:{stats['valid']}\\n"
|
||||
f"❌ 过期记录:{stats['expired']}\\n"
|
||||
f"📈 命中率:{stats['hit_rate']:.1f}%\\n"
|
||||
f"💿 数据库大小:{stats['db_size_mb']:.2f} MB\\n\\n"
|
||||
"🔝 **热门搜索:**\\n"
|
||||
)
|
||||
|
||||
for item in stats['top_searches'][:10]:
|
||||
text += f"• {item['command']} {item['keyword']} ({item['count']}次)\\n"
|
||||
|
||||
await update.message.reply_text(text, parse_mode='Markdown')
|
||||
|
||||
def _get_unique_users_from_logs(self):
|
||||
"""从日志中提取唯一用户数"""
|
||||
try:
|
||||
log_file = "./logs/integrated_bot_detailed.log"
|
||||
if not os.path.exists(log_file):
|
||||
return 0
|
||||
|
||||
user_ids = set()
|
||||
with open(log_file, 'r') as f:
|
||||
for line in f:
|
||||
if '用户' in line:
|
||||
import re
|
||||
matches = re.findall(r'用户 (\\d+)', line)
|
||||
user_ids.update(matches)
|
||||
|
||||
return len(user_ids)
|
||||
except:
|
||||
return 0
|
||||
|
||||
def _get_users_from_logs(self):
|
||||
"""从日志中获取用户列表及交互次数"""
|
||||
try:
|
||||
log_file = "./logs/integrated_bot_detailed.log"
|
||||
if not os.path.exists(log_file):
|
||||
return []
|
||||
|
||||
user_counts = {}
|
||||
with open(log_file, 'r') as f:
|
||||
for line in f:
|
||||
if '用户' in line:
|
||||
import re
|
||||
matches = re.findall(r'用户 (\\d+)', line)
|
||||
for user_id in matches:
|
||||
user_counts[user_id] = user_counts.get(user_id, 0) + 1
|
||||
|
||||
return sorted(user_counts.items(), key=lambda x: x[1], reverse=True)
|
||||
except:
|
||||
return []
|
||||
|
||||
def _get_user_info(self, user_id):
|
||||
"""获取指定用户的详细信息"""
|
||||
try:
|
||||
log_file = "./logs/integrated_bot_detailed.log"
|
||||
if not os.path.exists(log_file):
|
||||
return None
|
||||
|
||||
info = {
|
||||
'interactions': 0,
|
||||
'searches': 0,
|
||||
'ai_chats': 0,
|
||||
'first_seen': None,
|
||||
'last_seen': None
|
||||
}
|
||||
|
||||
with open(log_file, 'r') as f:
|
||||
for line in f:
|
||||
if f'用户 {user_id}' in line:
|
||||
info['interactions'] += 1
|
||||
|
||||
# 提取时间戳
|
||||
import re
|
||||
time_match = re.search(r'(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})', line)
|
||||
if time_match:
|
||||
timestamp = time_match.group(1)
|
||||
if not info['first_seen']:
|
||||
info['first_seen'] = timestamp
|
||||
info['last_seen'] = timestamp
|
||||
|
||||
if '镜像' in line or '搜索' in line:
|
||||
info['searches'] += 1
|
||||
if 'AI对话' in line or 'Claude API' in line:
|
||||
info['ai_chats'] += 1
|
||||
|
||||
return info if info['interactions'] > 0 else None
|
||||
except:
|
||||
return None
|
||||
|
||||
def _get_cache_stats(self):
|
||||
"""获取缓存统计"""
|
||||
try:
|
||||
db_path = "/home/atai/bot_data/cache.db"
|
||||
if not os.path.exists(db_path):
|
||||
return {'total': 0, 'hit_rate': 0}
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 总记录数
|
||||
cursor.execute("SELECT COUNT(*) FROM search_cache")
|
||||
total = cursor.fetchone()[0]
|
||||
|
||||
# 访问统计
|
||||
cursor.execute("SELECT SUM(access_count) FROM search_cache")
|
||||
total_accesses = cursor.fetchone()[0] or 0
|
||||
|
||||
conn.close()
|
||||
|
||||
hit_rate = (total_accesses / (total_accesses + total) * 100) if total > 0 else 0
|
||||
|
||||
return {
|
||||
'total': total,
|
||||
'hit_rate': hit_rate
|
||||
}
|
||||
except:
|
||||
return {'total': 0, 'hit_rate': 0}
|
||||
|
||||
def _get_cache_details(self):
|
||||
"""获取缓存详细统计"""
|
||||
try:
|
||||
db_path = "/home/atai/bot_data/cache.db"
|
||||
if not os.path.exists(db_path):
|
||||
return {'total': 0, 'valid': 0, 'expired': 0, 'hit_rate': 0, 'db_size_mb': 0, 'top_searches': []}
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 总记录数
|
||||
cursor.execute("SELECT COUNT(*) FROM search_cache")
|
||||
total = cursor.fetchone()[0]
|
||||
|
||||
# 有效记录数
|
||||
cursor.execute("SELECT COUNT(*) FROM search_cache WHERE expires_at IS NULL OR expires_at > ?",
|
||||
(datetime.now().isoformat(),))
|
||||
valid = cursor.fetchone()[0]
|
||||
|
||||
# 访问统计
|
||||
cursor.execute("SELECT SUM(access_count) FROM search_cache")
|
||||
total_accesses = cursor.fetchone()[0] or 0
|
||||
|
||||
# 热门搜索
|
||||
cursor.execute("""
|
||||
SELECT command, keyword, access_count
|
||||
FROM search_cache
|
||||
ORDER BY access_count DESC
|
||||
LIMIT 10
|
||||
""")
|
||||
top_searches = [
|
||||
{'command': row[0], 'keyword': row[1], 'count': row[2]}
|
||||
for row in cursor.fetchall()
|
||||
]
|
||||
|
||||
conn.close()
|
||||
|
||||
# 数据库大小
|
||||
db_size_mb = os.path.getsize(db_path) / 1024 / 1024
|
||||
|
||||
hit_rate = (total_accesses / (total_accesses + total) * 100) if total > 0 else 0
|
||||
|
||||
return {
|
||||
'total': total,
|
||||
'valid': valid,
|
||||
'expired': total - valid,
|
||||
'hit_rate': hit_rate,
|
||||
'db_size_mb': db_size_mb,
|
||||
'top_searches': top_searches
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return {'total': 0, 'valid': 0, 'expired': 0, 'hit_rate': 0, 'db_size_mb': 0, 'top_searches': []}
|
||||
Reference in New Issue
Block a user