You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
9.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import logging
import os
import re
import jsonpickle
from django.conf import settings
from werobot import WeRoBot
from werobot.replies import ArticlesReply, Article
from werobot.session.filestorage import FileStorage
from djangoblog.utils import get_sha256
from servermanager.api.blogapi import BlogApi
from servermanager.api.commonapi import ChatGPT, CommandHandler
from .MemcacheStorage import MemcacheStorage
# 初始化微信机器人实例配置token和启用session功能
robot = WeRoBot(token=os.environ.get('DJANGO_WEROBOT_TOKEN')
or 'lylinux', enable_session=True)
# 创建Memcache存储实例用于session存储
memstorage = MemcacheStorage()
# 根据存储可用性配置机器人的session存储方式
if memstorage.is_available:
robot.config['SESSION_STORAGE'] = memstorage
else:
# 如果文件存储存在则删除旧文件使用文件存储作为session存储
if os.path.exists(os.path.join(settings.BASE_DIR, 'werobot_session')):
os.remove(os.path.join(settings.BASE_DIR, 'werobot_session'))
robot.config['SESSION_STORAGE'] = FileStorage(filename='werobot_session')
# 初始化博客API和命令处理器实例
blogapi = BlogApi()
cmd_handler = CommandHandler()
logger = logging.getLogger(__name__)
def convert_to_article_reply(articles, message):
"""
将文章列表转换为微信文章回复格式
Args:
articles: 文章对象列表
message: 微信消息对象
Returns:
ArticlesReply: 微信文章回复对象
"""
reply = ArticlesReply(message=message)
from blog.templatetags.blog_tags import truncatechars_content
for post in articles:
# 提取文章中的图片URL
imgs = re.findall(r'(?:http\:|https\:)?\/\/.*\.(?:png|jpg)', post.body)
imgurl = ''
if imgs:
imgurl = imgs[0]
# 创建单篇文章对象
article = Article(
title=post.title,
description=truncatechars_content(post.body),
img=imgurl,
url=post.get_full_url()
)
reply.add_article(article)
return reply
@robot.filter(re.compile(r"^\?.*"))
def search(message, session):
"""
处理文章搜索请求,根据关键词搜索文章并返回结果
Args:
message: 微信消息对象,包含搜索关键词
session: 用户会话对象
Returns:
ArticlesReply或str: 搜索结果或提示信息
"""
search_str = str(message.content).replace('?', '')
result = blogapi.search_articles(search_str)
if result:
# 修复将map替换为列表推导式
articles = [item.object for item in result]
reply = convert_to_article_reply(articles, message)
return reply
else:
return '没有找到相关文章。'
@robot.filter(re.compile(r'^category\s*$', re.I))
def category(message, session):
"""
获取所有文章分类目录信息
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
str: 包含所有分类名称的字符串
"""
categories = blogapi.get_category_lists()
# 修复将map替换为列表推导式
content = ','.join([category.name for category in categories])
return '所有文章分类目录:' + content
@robot.filter(re.compile(r'^recent\s*$', re.I))
def recents(message, session):
"""
获取最新发布的文章列表
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
ArticlesReply或str: 最新文章列表或提示信息
"""
articles = blogapi.get_recent_articles()
if articles:
reply = convert_to_article_reply(articles, message)
return reply
else:
return "暂时还没有文章"
@robot.filter(re.compile('^help$', re.I))
def help(message, session):
"""
返回系统帮助信息,包含所有可用命令说明
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
str: 帮助信息文本
"""
return '''欢迎关注!
默认会与图灵机器人聊天~~
你可以通过下面这些命令来获得信息
?关键字搜索文章.
如?python.
category获得文章分类目录及文章数.
category-***获得该分类目录文章
如category-python
recent获得最新文章
help获得帮助.
weather:获得天气
如weather:西安
idcard:获得身份证信息
如idcard:61048119xxxxxxxxxx
music:音乐搜索
如music:阴天快乐
PS:以上标点符号都不支持中文标点~~
'''
@robot.filter(re.compile(r'^weather\:.*$', re.I))
def weather(message, session):
"""
处理天气查询请求(待实现)
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
str: 建设中提示信息
"""
return "建设中..."
@robot.filter(re.compile(r'^idcard\:.*$', re.I))
def idcard(message, session):
"""
处理身份证信息查询请求(待实现)
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
str: 建设中提示信息
"""
return "建设中..."
@robot.handler
def echo(message, session):
"""
主消息处理函数,创建消息处理器并处理用户消息
Args:
message: 微信消息对象
session: 用户会话对象
Returns:
str或其他类型: 处理结果
"""
handler = MessageHandler(message, session)
return handler.handler()
class MessageHandler:
"""微信消息处理器类,负责处理各种用户消息和命令"""
def __init__(self, message, session):
"""
初始化消息处理器
Args:
message: 微信消息对象
session: 用户会话对象
"""
userid = message.source
self.message = message
self.session = session
self.userid = userid
try:
info = session[userid]
self.userinfo = jsonpickle.decode(info)
except Exception:
# 修复移除了未使用的变量e
userinfo = WxUserInfo()
self.userinfo = userinfo
@property
def is_admin(self):
"""
判断当前用户是否为管理员
Returns:
bool: 是否为管理员
"""
return self.userinfo.is_admin
@property
def is_password_set(self):
"""
判断管理员密码是否已设置
Returns:
bool: 密码是否已设置
"""
return self.userinfo.is_password_set
def save_session(self):
"""
保存用户会话信息到session中
"""
info = jsonpickle.encode(self.userinfo)
self.session[self.userid] = info
def handler(self):
"""
主要的消息处理逻辑,根据用户状态和输入内容进行相应处理
Returns:
str: 处理结果响应文本
"""
info = self.message.content
# 处理管理员退出命令
if self.userinfo.is_admin and info.upper() == 'EXIT':
self.userinfo = WxUserInfo()
self.save_session()
return "退出成功"
# 处理管理员登录命令
if info.upper() == 'ADMIN':
self.userinfo.is_admin = True
self.save_session()
return "输入管理员密码"
# 处理管理员密码验证
if self.userinfo.is_admin and not self.userinfo.is_password_set:
return self._handle_password_verification(info)
# 处理管理员命令执行
if self.userinfo.is_admin and self.userinfo.is_password_set:
return self._handle_admin_commands(info)
# 默认使用ChatGPT处理普通消息
return ChatGPT.chat(info)
def _handle_password_verification(self, info):
"""处理管理员密码验证逻辑"""
passwd = settings.WXADMIN
if settings.TESTING:
passwd = '123'
if passwd.upper() == get_sha256(get_sha256(info)).upper():
self.userinfo.is_password_set = True
self.save_session()
return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助"
else:
# 处理密码错误次数限制
if self.userinfo.count >= 3:
self.userinfo = WxUserInfo()
self.save_session()
return "超过验证次数"
self.userinfo.count += 1
self.save_session()
return "验证失败,请重新输入管理员密码:"
def _handle_admin_commands(self, info):
"""处理管理员命令执行逻辑"""
if self.userinfo.command != '' and info.upper() == 'Y':
return cmd_handler.run(self.userinfo.command)
else:
if info.upper() == 'HELPME':
return cmd_handler.get_help()
self.userinfo.command = info
self.save_session()
return "确认执行: " + info + " 命令?"
class WxUserInfo:
"""微信用户信息类,存储用户的状态信息"""
def __init__(self):
"""
初始化用户信息,默认为非管理员状态
"""
# 修复字段命名符合Python小写加下划线规范
self.is_admin = False
self.is_password_set = False
self.count = 0
self.command = ''