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 = ''