diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..cb28e27 Binary files /dev/null and b/.DS_Store differ diff --git a/ApiServer/AiServer/AiDialogue.py b/ApiServer/AiServer/AiDialogue.py new file mode 100644 index 0000000..09802e0 --- /dev/null +++ b/ApiServer/AiServer/AiDialogue.py @@ -0,0 +1,369 @@ +from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException +from tencentcloud.common.profile.client_profile import ClientProfile +from tencentcloud.hunyuan.v20230901 import hunyuan_client, models +from tencentcloud.common.profile.http_profile import HttpProfile +from sparkai.llm.llm import ChatSparkLLM, ChunkPrintHandler +from sparkai.core.messages import ChatMessage +from tencentcloud.common import credential +import ApiServer.AiServer.sparkPicApi as sPa +import FileCache.FileCacheServer as Fcs +import Config.ConfigServer as Cs +from OutPut.outPut import op +import requests +import time +import json + + +class AiDialogue: + def __init__(self): + + configData = Cs.returnConfigData() + self.systemAiRole = configData['apiServer']['aiConfig']['systemAiRule'] + self.openAiConfig = {'openAiApi': configData['apiServer']['aiConfig']['openAi']['openAiApi'], + 'openAiKey': configData['apiServer']['aiConfig']['openAi']['openAiKey']} + self.sparkAiConfig = {'sparkAiApi': configData['apiServer']['aiConfig']['sparkApi']['sparkAiApi'], + 'sparkAiAppid': configData['apiServer']['aiConfig']['sparkApi']['sparkAiAppid'], + 'sparkAiSecret': configData['apiServer']['aiConfig']['sparkApi']['sparkAiSecret'], + 'sparkAiKey': configData['apiServer']['aiConfig']['sparkApi']['sparkAiKey'], + 'sparkDomain': configData['apiServer']['aiConfig']['sparkApi']['sparkDomain']} + self.qianfanAiConfig = { + 'qfAccessKey': configData['apiServer']['aiConfig']['qianFan']['qfAccessKey'], + 'qfSecretKey': configData['apiServer']['aiConfig']['qianFan']['qfSecretKey'], + 'qfAppid': configData['apiServer']['aiConfig']['qianFan']['qfAppid'], + 'qfPicAccessKey': configData['apiServer']['aiConfig']['qianFan']['qfPicAccessKey'], + 'qfPicSecretKey': configData['apiServer']['aiConfig']['qianFan']['qfPicSecretKey'], + 'qfPicAppid': configData['apiServer']['aiConfig']['qianFan']['qfPicAppid'], + } + self.hunYuanAiConfig = { + 'hunYuanSecretId': configData['apiServer']['aiConfig']['hunYuan']['hunYuanSecretId'], + 'hunYuanSecretKey': configData['apiServer']['aiConfig']['hunYuan']['hunYuanSecretKey'] + } + self.openAiMessages = [{"role": "system", "content": f'{self.systemAiRole}'}] + self.qianFanMessages = [{"role": "system", "content": f'{self.systemAiRole}'}] + self.hunYuanMessages = [{"Role": "system", "Content": f'{self.systemAiRole}'}] + self.aiPriority = configData['apiServer']['aiConfig']['aiPriority'] + self.aiPicPriority = configData['apiServer']['aiConfig']['aiPicPriority'] + + def getOpenAi(self, content, messages): + op(f'[*]: 正在调用OpenAi对话接口... ...') + """ + Open Ai对话 + :param OpenAiConfig: OpenAi 配置字典 + :param content: 对话内容 + :param messages: 消息列表 + :return: + """ + if not self.openAiConfig.get('openAiKey'): + op(f'[-]: GPT模型未配置, 请检查相关配置!!!') + return None, [] + messages.append({"role": "user", "content": f'{content}'}) + data = { + "model": "gpt-3.5-turbo", + "messages": messages + } + headers = { + "Content-Type": "application/json", + "Authorization": f"{self.openAiConfig.get('openAiKey')}", + } + try: + resp = requests.post(url=self.openAiConfig.get('openAiApi'), headers=headers, json=data, timeout=15) + json_data = resp.json() + assistant_content = json_data['choices'][0]['message']['content'] + messages.append({"role": "assistant", "content": f"{assistant_content}"}) + if len(messages) == 21: + del messages[1] + del messages[2] + return assistant_content, messages + except Exception as e: + op(f'[-]: Gpt对话接口出现错误, 错误信息: {e}') + return None, [{"role": "system", "content": f'{self.systemAiRole}'}] + + def getSparkAi(self, content): + """ + 星火大模型Ai 对话 + :param content: 对话内容 + :return: + """ + op(f'[*]: 正在调用星火大模型对话接口... ...') + SparkAppid = self.sparkAiConfig.get('sparkAiAppid') + SparkSecret = self.sparkAiConfig.get('sparkAiSecret') + SParkApiKey = self.sparkAiConfig.get('sparkAiKey') + SParkApi = self.sparkAiConfig.get('sparkAiApi') + SParkDomain = self.sparkAiConfig.get('sparkDomain') + try: + spark = ChatSparkLLM( + spark_api_url=SParkApi, + spark_app_id=SparkAppid, + spark_api_key=SParkApiKey, + spark_api_secret=SparkSecret, + spark_llm_domain=SParkDomain, + streaming=False, + ) + messages = [ChatMessage( + role='system', + content=self.systemAiRole + ), ChatMessage( + role="user", + content=content + )] + handler = ChunkPrintHandler() + sparkObject = spark.generate([messages], callbacks=[handler]) + sparkContent = sparkObject.generations[0][0].text + return sparkContent + except Exception as e: + op(f'[-]: 星火大模型对话接口出现错误, 错误信息: {e}') + return None + + def getSparkPic(self, content): + """ + 星火大模型 图像生成 + :param content: + :return: + """ + op(f'[*]: 正在调用星火大模型图像生成接口... ...') + try: + res = sPa.main(content, self.sparkAiConfig.get('sparkAiAppid'), self.sparkAiConfig.get('sparkAiKey'), + self.sparkAiConfig.get('sparkAiSecret')) + savePath = sPa.parser_Message(res) + return savePath + except Exception as e: + op(f'[-]: 星火大模型图像生成出现错误, 错误信息: {e}') + return None + + def getQianFanAi(self, content, messages): + """ + 千帆模型 Ai对话 + :param content: 对话内容 + :param messages: 消息列表 + :return: + """ + op(f'[*]: 正在调用千帆大模型对话接口... ...') + messages.append({"role": "user", "content": content}) + if not self.qianfanAiConfig.get('qfAccessKey') or not self.qianfanAiConfig.get('qfSecretKey'): + op(f'[-]: 千帆大模型未配置, 请检查相关配置!!!') + return None, [] + + def getAccessToken(): + try: + headers = { + 'Content-Type': 'application/json' + } + query = { + 'grant_type': 'client_credentials', + 'client_id': self.qianfanAiConfig.get('qfAccessKey'), + 'client_secret': self.qianfanAiConfig.get('qfSecretKey'), + } + resp = requests.post('https://aip.baidubce.com/oauth/2.0/token', headers=headers, data=query) + access_token = resp.json()['access_token'] + return access_token + except Exception as e: + op(f'[-]: 获取千帆模型AccessToken出现错误, 错误信息: {e}') + return None + + def getAiContent(access_token, messages): + try: + url = f'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-4.0-turbo-8k?access_token={access_token}' + data = { + 'messages': messages + } + resp = requests.post(url, json=data) + result = resp.json()['result'] + messages.append({"role": "assistant", "content": result}) + return result, messages + except Exception as e: + op(f'[-]: 请求千帆模型AccessToken出现错误, 错误信息: {e}') + return None, messages + + access_token = getAccessToken() + if not access_token: + op(f'[-]: 获取千帆模型AccessToken失败, 请检查千帆配置!!!') + return None, messages + + aiContent = getAiContent(access_token, messages) + if len(messages) == 21: + del messages[1] + del messages[2] + return aiContent, messages + + def getQianFanPic(self, content): + """ + 千帆模型生成图片 + :param content: + :return: + """ + op(f'[*]: 正在调用千帆模型图片生成接口... ...') + + def getAccessToken(): + try: + headers = { + 'Content-Type': 'application/json' + } + query = { + 'grant_type': 'client_credentials', + 'client_id': self.qianfanAiConfig.get('qfPicAccessKey'), + 'client_secret': self.qianfanAiConfig.get('qfPicSecretKey'), + } + resp = requests.post('https://aip.baidubce.com/oauth/2.0/token', headers=headers, data=query) + access_token = resp.json()['access_token'] + return access_token + except Exception as e: + op(f'[-]: 获取千帆模型AccessToken出现错误, 错误信息: {e}') + return None + + def getTaskId(content, accessToken): + try: + url = f'https://aip.baidubce.com/rpc/2.0/ernievilg/v1/txt2imgv2?access_token={accessToken}' + data = { + "prompt": content, + "width": 1024, + "height": 1024, + "image_num": 1, + } + resp = requests.post(url, json=data) + json_data = resp.json() + task_id = json_data['data']['task_id'] + return task_id + except Exception as e: + op(f'[-]: 千帆模型Ai图像生成出现错误, 错误信息: {e}') + return None + + def getPicUrl(task_id, accessToken): + try: + url = f'https://aip.baidubce.com/rpc/2.0/ernievilg/v1/getImgv2?access_token={accessToken}' + data = { + 'task_id': task_id + } + resp = requests.post(url, json=data) + json_data = resp.json() + print(json_data) + if json_data['data']['task_status'] == 'SUCCESS': + sub_task_result_list = json_data['data']['sub_task_result_list'] + final_image_list = sub_task_result_list[0]['final_image_list'] + img_url = final_image_list[0]['img_url'] + return img_url + except Exception as e: + op(f'[-]: 千帆模型Ai图像生成出现错误, 错误信息: {e}') + + def downloadImg(imgUrl): + try: + save_path = Fcs.returnAiPicFolder() + '/' + str(int(time.time() * 1000)) + '.jpg' + resp = requests.get(url=imgUrl) + imgContent = resp.content + with open(save_path, mode='wb') as f: + f.write(imgContent) + return save_path + except Exception as e: + op(f'[-]: 千帆模型Ai图像下载出现错误, 错误信息: {e}') + return None + + accessToken = getAccessToken() + if accessToken: + task_id = getTaskId(content, accessToken) + if task_id: + time.sleep(20) + imgUrl = getPicUrl(task_id, accessToken) + if imgUrl: + savePath = downloadImg(imgUrl) + return savePath + return None + + def getHunYuanAi(self, content, messages): + """ + 腾讯混元模型 Ai对话接口 + :param content: + :param messages: + :return: + """ + try: + op(f'[*]: 正在调用混元模型对话接口... ...') + cred = credential.Credential(self.hunYuanAiConfig.get('hunYuanSecretId'), + self.hunYuanAiConfig.get('hunYuanSecretKey')) + httpProfile = HttpProfile() + httpProfile.endpoint = "hunyuan.tencentcloudapi.com" + clientProfile = ClientProfile() + clientProfile.httpProfile = httpProfile + client = hunyuan_client.HunyuanClient(cred, "ap-beijing", clientProfile) + req = models.ChatCompletionsRequest() + messages.append({'Role': 'user', 'Content': content}) + params = { + "Model": "hunyuan-pro", + "Messages": messages, + } + req.from_json_string(json.dumps(params)) + Choices = str(client.ChatCompletions(req).Choices[0]) + jsonData = json.loads(Choices) + Message = jsonData['Message'] + messages.append({'Role': Message['Role'], 'Content': Message['Content']}) + content = Message['Content'] + if len(messages) == 21: + del messages[1] + del messages[2] + if content: + return content, messages + return None, [] + except TencentCloudSDKException as e: + op(f'[-]: 腾讯混元Ai对话接口出现错误, 错误信息: {e}') + return None, messages + + def getAi(self, content): + """ + 处理优先级 + :param content: + :return: + """ + result = '' + for i in range(1, 5): + aiModule = self.aiPriority.get(i) + if aiModule == 'hunYuan': + result, self.hunYuanMessages = self.getHunYuanAi(content, self.hunYuanMessages) + if aiModule == 'sparkAi': + result = self.getSparkAi(content) + if aiModule == 'openAi': + result, self.openAiMessages = self.getOpenAi(content, self.openAiMessages) + if aiModule == 'qianFan': + result, self.qianFanMessages = self.getQianFanAi(content, self.qianFanMessages) + if not result: + continue + else: + break + return result + + def getPicAi(self, content): + """ + 处理优先级 + :param content: + :return: + """ + picPath = '' + for i in range(1, 3): + aiPicModule = self.aiPicPriority.get(i) + if aiPicModule == 'sparkAi': + picPath = self.getSparkPic(content) + if aiPicModule == 'qianFan': + picPath = self.getQianFanPic(content) + if not picPath: + continue + else: + break + return picPath + + +if __name__ == '__main__': + messages = [] + Ad = AiDialogue() + print(Ad.getPicAi('画一只布尔猫')) + # while 1: + # print(Ad.getAi(input('>> '))) + # Ad.getAi(1) + # while 1: + # content, messages = Ad.getHunYuanAi(input(), messages) + # print(content) + # Ad.getHunYuanAi('1', []) + # print(Ad.getQianFanPic('画一只赛博小狗')) + # print(Ad.getSparkPic('画一只赛博小狗')) + + # print(Ad.getQianFanAi('你是谁', [])) + # print(Ad.getOpenAi()) + # print(Ad.getSparkAi('你是谁')) + # while 1: + # print(Ad.getAi(input('>> '))) diff --git a/ApiServer/AiServer/__pycache__/AiDialogue.cpython-38.pyc b/ApiServer/AiServer/__pycache__/AiDialogue.cpython-38.pyc new file mode 100644 index 0000000..856dc7a Binary files /dev/null and b/ApiServer/AiServer/__pycache__/AiDialogue.cpython-38.pyc differ diff --git a/ApiServer/AiServer/__pycache__/sparkPicApi.cpython-38.pyc b/ApiServer/AiServer/__pycache__/sparkPicApi.cpython-38.pyc new file mode 100644 index 0000000..5d812ab Binary files /dev/null and b/ApiServer/AiServer/__pycache__/sparkPicApi.cpython-38.pyc differ diff --git a/ApiServer/AiServer/sparkPicApi.py b/ApiServer/AiServer/sparkPicApi.py new file mode 100644 index 0000000..f50dc69 --- /dev/null +++ b/ApiServer/AiServer/sparkPicApi.py @@ -0,0 +1,154 @@ +# encoding: UTF-8 +from wsgiref.handlers import format_date_time +import FileCache.FileCacheServer as Fcs +from urllib.parse import urlencode +from datetime import datetime +from OutPut.outPut import op +from time import mktime +from io import BytesIO +from PIL import Image +import requests +import hashlib +import base64 +import json +import hmac + + +class AssembleHeaderException(Exception): + def __init__(self, msg): + self.message = msg + + +class Url: + def __init__(this, host, path, schema): + this.host = host + this.path = path + this.schema = schema + pass + + +# calculate sha256 and encode to base64 +def sha256base64(data): + sha256 = hashlib.sha256() + sha256.update(data) + digest = base64.b64encode(sha256.digest()).decode(encoding='utf-8') + return digest + + +def parse_url(requset_url): + stidx = requset_url.index("://") + host = requset_url[stidx + 3:] + schema = requset_url[:stidx + 3] + edidx = host.index("/") + if edidx <= 0: + raise AssembleHeaderException("invalid request url:" + requset_url) + path = host[edidx:] + host = host[:edidx] + u = Url(host, path, schema) + return u + + +# 生成鉴权url +def assemble_ws_auth_url(requset_url, method="GET", api_key="", api_secret=""): + u = parse_url(requset_url) + host = u.host + path = u.path + now = datetime.now() + date = format_date_time(mktime(now.timetuple())) + # print(date) + # date = "Thu, 12 Dec 2019 01:57:27 GMT" + signature_origin = "host: {}\ndate: {}\n{} {} HTTP/1.1".format(host, date, method, path) + # print(signature_origin) + signature_sha = hmac.new(api_secret.encode('utf-8'), signature_origin.encode('utf-8'), + digestmod=hashlib.sha256).digest() + signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8') + authorization_origin = "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"" % ( + api_key, "hmac-sha256", "host date request-line", signature_sha) + authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') + # print(authorization_origin) + values = { + "host": host, + "date": date, + "authorization": authorization + } + + return requset_url + "?" + urlencode(values) + + +# 生成请求body体 +def getBody(appid, text): + body = { + "header": { + "app_id": appid, + "uid": "123456789" + }, + "parameter": { + "chat": { + "domain": "general", + "temperature": 0.5, + "max_tokens": 4096, + "width": 1024, + "height": 1024 + } + }, + "payload": { + "message": { + "text": [ + { + "role": "user", + "content": text + } + ] + } + } + } + return body + + +# 发起请求并返回结果 +def main(text, appid, apikey, apisecret): + host = 'http://spark-api.cn-huabei-1.xf-yun.com/v2.1/tti' + url = assemble_ws_auth_url(host, method='POST', api_key=apikey, api_secret=apisecret) + content = getBody(appid, text) + response = requests.post(url, json=content, headers={'content-type': "application/json"}).text + return response + + +# 将base64 的图片数据存在本地 +def base64_to_image(base64_data, save_path): + # 解码base64数据 + img_data = base64.b64decode(base64_data) + + # 将解码后的数据转换为图片 + img = Image.open(BytesIO(img_data)) + + # 保存图片到本地 + img.save(save_path) + + +# 解析并保存到指定位置 +def parser_Message(message): + data = json.loads(message) + code = data['header']['code'] + if code != 0: + op(f'[-]: 星火Ai生成图片出现错误, 错误信息: {code}, {data}') + else: + text = data["payload"]["choices"]["text"] + imageContent = text[0] + imageBase = imageContent["content"] + imageName = data['header']['sid'] + savePath = Fcs.returnAiPicFolder() + '/' + imageName + '.png' + base64_to_image(imageBase, savePath) + return savePath + + +if __name__ == '__main__': + # 运行前请配置以下鉴权三要素,获取途径:https://console.xfyun.cn/services/tti + APPID = 'XXXXXXXX' + APISecret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + APIKEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + desc = '''生成一张图:远处有着高山,山上覆盖着冰雪,近处有着一片湛蓝的湖泊''' + res = main(desc, appid=APPID, apikey=APIKEY, apisecret=APISecret) + # print(res) + # 保存到指定位置 + imgPath = parser_Message(res) diff --git a/ApiServer/ApiMainServer.py b/ApiServer/ApiMainServer.py new file mode 100644 index 0000000..b86cac0 --- /dev/null +++ b/ApiServer/ApiMainServer.py @@ -0,0 +1,115 @@ +from ApiServer.AiServer.AiDialogue import AiDialogue +import ApiServer.pluginServer as Ps + + +class ApiMainServer: + def __init__(self): + """ + 将所有插件服务全部注册在__init__.py文件中 + 此文件做所有插件总体调用 + """ + # Ai对象实例化 + self.Ad = AiDialogue() + + def getAiWen(self, ip): + """ + 埃文IP查询调用接口 + :param ip: + :return: + """ + return Ps.Pa.getAiWenIpv4(ip) + + def getThreatBook(self, ip): + """ + 微步IP查询调用接口 + :param ip: + :return: + """ + return Ps.Pa.getThreatBook(ip) + + def getCmd5(self, ciphertext): + """ + MD5查询调用接口 + :param ciphertext: + :return: + """ + return Ps.Pa.getCmd5(ciphertext) + + def getMorningNews(self, ): + """ + 新闻早报调用接口 + :return: + """ + return Ps.Na.getMorningNews() + + def getEveningNews(self, ): + """ + 新闻晚报调用接口 + :return: + """ + return Ps.Na.getEveningNews() + + def getGirlPic(self, ): + """ + 美女图片调用接口 + :return: + """ + return Ps.Ha.getPic() + + def getGirlVideo(self, ): + """ + 美女视频调用接口 + :return: + """ + return Ps.Ha.getVideo() + + def getFish(self, ): + """ + 摸鱼日历调用接口 + :return: + """ + return Ps.Ha.getFish() + + def getKfc(self, ): + """ + 疯狂星期四调用接口 + :return: + """ + return Ps.Ha.getKfc() + + def getDog(self, ): + """ + 舔狗日记调用接口 + :return: + """ + return Ps.Ha.getDog() + + def getAi(self, content): + """ + Ai对话调用接口 + :param content: + :return: + """ + return self.Ad.getAi(content) + + def getAiPic(self, content): + """ + Ai图像生成调用接口 + :return: + """ + return self.Ad.getPicAi(content) + + def getEmoticon(self, avatarPathList, memeKey=None): + """ + 表情包生成接口 + :param avatarPathList: + :param content: + :return: + """ + return Ps.Ha.getEmoticon(avatarPathList, memeKey) + + +if __name__ == '__main__': + Ams = ApiMainServer() + # print(Ams.getAiWen('1.14.145.103')) + # print(Ams.getAi('你好')) diff --git a/ApiServer/__pycache__/ApiMainServer.cpython-38.pyc b/ApiServer/__pycache__/ApiMainServer.cpython-38.pyc new file mode 100644 index 0000000..fc66393 Binary files /dev/null and b/ApiServer/__pycache__/ApiMainServer.cpython-38.pyc differ diff --git a/ApiServer/pluginServer/HappyApi.py b/ApiServer/pluginServer/HappyApi.py new file mode 100644 index 0000000..cc12246 --- /dev/null +++ b/ApiServer/pluginServer/HappyApi.py @@ -0,0 +1,169 @@ +from meme_generator import get_meme, get_meme_keys +import FileCache.FileCacheServer as Fcs +import Config.ConfigServer as Cs +from OutPut.outPut import op +import requests +import asyncio +import random +import time +import os + + +class HappyApi: + def __init__(self): + """ + 不要直接调用此类 + 娱乐功能Api文件 + """ + # 读取配置文件 + configData = Cs.returnConfigData() + self.txKey = configData['apiServer']['apiConfig']['txKey'] + self.picUrlList = configData['apiServer']['picApi'] + self.videoUrlList = configData['apiServer']['videosApi'] + self.dogApi = configData['apiServer']['dogApi'] + self.fishApi = configData['apiServer']['fishApi'] + self.kfcApi = configData['apiServer']['kfcApi'] + + def downloadFile(self, url, savePath): + """ + 通用下载文件函数 + :param url: + :param savePath: + :return: + """ + try: + content = requests.get(url, timeout=30, verify=True).content + with open(savePath, mode='wb') as f: + f.write(content) + return savePath + except Exception as e: + op(f'[-]: 通用下载文件函数出现错误, 错误信息: {e}') + return None + + def getPic(self, ): + """ + 美女图片下载 + :return: + """ + op(f'[*]: 正在调用美女图片Api接口... ...') + picUrl = random.choice(self.picUrlList) + savePath = Fcs.returnPicCacheFolder() + '/' + str(int(time.time() * 1000)) + '.jpg' + picPath = self.downloadFile(picUrl, savePath) + if not picPath: + for picUrl in self.picUrlList: + picPath = self.downloadFile(picUrl, savePath) + if picPath: + break + continue + return picPath + + def getVideo(self, ): + """ + 美女视频下载 + :return: + """ + op(f'[*]: 正在调用美女视频Api接口... ...') + videoUrl = random.choice(self.videoUrlList) + savePath = Fcs.returnVideoCacheFolder() + '/' + str(int(time.time() * 1000)) + '.mp4' + videoPath = self.downloadFile(videoUrl, savePath) + if not videoPath: + for videoUrl in self.videoUrlList: + videoPath = self.downloadFile(videoUrl, savePath) + if videoPath: + break + continue + return videoPath + + def getFish(self, ): + """ + 摸鱼日历下载 + :return: + """ + op(f'[*]: 正在调用摸鱼日历Api接口... ...') + savePath = Fcs.returnPicCacheFolder() + '/' + str(int(time.time() * 1000)) + '.jpg' + fishPath = self.downloadFile(url=self.fishApi, savePath=savePath) + if not fishPath: + for i in range(2): + fishPath = self.downloadFile(self.fishApi, savePath) + if fishPath: + break + continue + return fishPath + + def getKfc(self, ): + """ + 疯狂星期四 + :return: + """ + op(f'[*]: 正在调用KFC疯狂星期四Api接口... ... ') + try: + jsonData = requests.get(url=self.kfcApi, timeout=30).json() + result = jsonData.get('text') + if result: + return result + return None + except Exception as e: + op(f'[-]: KFC疯狂星期四Api接口出现错误, 错误信息: {e}') + return None + + def getDog(self, ): + """ + 舔狗日记Api接口 + :return: + """ + op(f'[*]: 正在调用舔狗日记Api接口... ... ') + try: + jsonData = requests.get(url=self.dogApi.format(self.txKey), timeout=30).json() + result = jsonData.get('result') + if result: + content = result.get('content') + if content: + return content + return None + except Exception as e: + op(f'[-]: 舔狗日记Api接口出现错误, 错误信息: {e}') + return None + + def getEmoticon(self, avatarPathList, memeKey=None): + """ + 表情包Api接口 + :param memeKey: 消息内容 + :param avatarPathList: 头像列表 + :return: + """ + op(f'[*]: 正在调用表情包Api接口... ...') + if not avatarPathList: + op(f'[-]: 表情包Api接口出现错误, 错误信息: avatarPathList不能为空') + return + if not avatarPathList: + raise 'avatarPathList None' + if not memeKey: + memeKey = random.choices(get_meme_keys())[0] + + savePath = Fcs.returnPicCacheFolder() + '/' + str(int(time.time() * 1000)) + '.gif' + try: + async def makeEmo(): + meme = get_meme(memeKey) + result = await meme(images=avatarPathList, texts=[], args={"circle": False}) + with open(savePath, "wb") as f: + f.write(result.getvalue()) + + loop = asyncio.new_event_loop() + loop.run_until_complete(makeEmo()) + # 图片大小判断 如果大于1mb 就以图片形式发送 + file_size_bytes = os.path.getsize(savePath) + size_limit_bytes = 1024 * 1024 + sizeBool = file_size_bytes <= size_limit_bytes + return savePath, sizeBool + except Exception as e: + op(f'[-]: 表情包Api接口出现错误, 错误信息: {e}') + return None, None + + + + +if __name__ == '__main__': + Ha = HappyApi() + # print(Ha.getDog()) + # print(Ha.getKfc()) + Ha.getEmoticon('C:/Users/Administrator/Desktop/NGCBot V2.1/avatar.jpg') diff --git a/ApiServer/pluginServer/NewsApi.py b/ApiServer/pluginServer/NewsApi.py new file mode 100644 index 0000000..391c754 --- /dev/null +++ b/ApiServer/pluginServer/NewsApi.py @@ -0,0 +1,144 @@ +from urllib.parse import urljoin +import Config.ConfigServer as Cs +from OutPut.outPut import op +from lxml import etree +import feedparser +import datetime +import requests +import urllib3 +import time + + +class NewsApi: + def __init__(self): + """ + 不要直接调用此文件 + 新闻Api接口 + """ + # 忽略HTTPS告警 + urllib3.disable_warnings() + # 读取配置文件 + configData = Cs.returnConfigData() + # 读取系统版权设置 + self.systemCopyright = configData['systemConfig']['systemCopyright'] + + def getMorningNews(self, ): + """ + 早报获取 + :return: + """ + op(f'[*]: 正在获取FreeBuf早报... ...') + yesterday = (datetime.date.today() + datetime.timedelta(-1)) + morningTime = yesterday.strftime("%a, %d %b %Y", ) + morningNews = "#FreeBuf早报\n" + try: + rs1 = feedparser.parse('https://www.freebuf.com/feed') + print(rs1) + for ent in rs1['entries']: + if morningTime in ent['published']: + title = ent['title'] + link = ent['link'] + morningNews += '\n' + title + '\n' + link + '\n' + if 'http' not in morningNews: + morningNews += '\n今日暂无文章' + except Exception as e: + morningNews = "\n今日暂无文章" + morningNews += morningNews + op("[-]: 获取FreeBuf早报出错,错误信息: {}".format(e)) + morningNews += f"\n{self.systemCopyright + '整理分享,更多内容请戳 #' + self.systemCopyright if self.systemCopyright else ''}\n{time.strftime('%Y-%m-%d %X')}" + return morningNews + + def getEveningNews(self, ): + """ + 晚报获取 + :return: + """ + op(f'[*]: 正在调用晚报接口... ...') + def getXzNews(): + """ + 获取先知文章 + :return: + """ + yesterday = (datetime.date.today() + datetime.timedelta(-1)) + yesterdayTime = str(yesterday.strftime('%Y-%m-%d')) + eveningNews = "#先知社区" + try: + rs1 = feedparser.parse('https://xz.aliyun.com/feed') + for ent in rs1['entries']: + if yesterdayTime in ent['published']: + title = ent['title'] + link = ent['link'] + eveningNews += '\n' + title + '\n' + link + '\n' + if 'http' not in eveningNews: + eveningNews += '\n今日暂无文章\n\n' + else: + eveningNews += '\n' + except Exception as e: + eveningNews += "\n今日暂无文章\n" + op("[-]: 获取先知社区文章出错,错误信息: {}".format(e)) + return eveningNews + + def getQaxNews(eveningNews): + """ + 获取奇安信攻防社区文章 + :return: + """ + eveningNews += '#奇安信攻防社区' + try: + yesterday = (datetime.date.today() + datetime.timedelta(-1)) + yesterdayTime = str(yesterday.strftime('%Y-%m-%d')) + resp = requests.get(url='https://forum.butian.net/community?page=1', verify=True) + tree = etree.HTML(resp.text) + sections = tree.xpath('//div[@class="stream-list blog-stream"]/section') + for section in sections: + title = section.xpath('./div/h2/a/text()')[0].strip() + href = section.xpath('./div/h2/a/@href')[0] + dateTime = section.xpath('./div/ul/li[4]/text()')[0].strip('发布于 ').strip() + if yesterdayTime in dateTime: + eveningNews += f'\n{title}\n{href}' + if 'http' not in eveningNews: + eveningNews += '\n今日暂无文章\n' + else: + eveningNews += '\n' + except Exception as e: + eveningNews += "\n今日暂无文章\n" + op("[-]: 获取奇安信攻防社区文章出错,错误信息: {}".format(e)) + return eveningNews + + def getAnQuanKe(eveningNews): + yesterday = (datetime.date.today() + datetime.timedelta(-1)) + yesterdayTime = str(yesterday.strftime('%Y-%m-%d')) + eveningNews += "\n#安全客" + try: + resp = requests.get('https://www.anquanke.com/news', timeout=5, verify=True) + tree = etree.HTML(resp.text) + divs = tree.xpath('//div[@id="post-list"]/div') + for div in divs: + title = div.xpath('./div/div[2]/div/div[@class="title"]/a/text()')[0].strip().replace(' ', '') + href = urljoin('https://www.anquanke.com/news', + div.xpath('./div/div[2]/div/div[@class="title"]/a/@href')[0]) + dateTime = div.xpath('./div/div[2]/div/div[@class="info"]/div[1]/span[@class="date"]/span/text()')[ + 1] + if yesterdayTime in dateTime: + eveningNews += f'\n{title}\n{href}' + if 'http' not in eveningNews: + eveningNews += '\n今日暂无文章\n' + else: + eveningNews += '\n' + except Exception as e: + eveningNews += "\n今日暂无文章\n" + op("[-]: 获取安全客文章出错,错误信息: {}".format(e)) + return eveningNews + + eveningNews = '' + eveningNews += getXzNews() + eveningNews += getQaxNews('') + eveningNews += getAnQuanKe('') + eveningNews += f"\n{self.systemCopyright + '整理分享,更多内容请戳 #' + self.systemCopyright if self.systemCopyright else ''}\n{time.strftime('%Y-%m-%d %X')}" + return eveningNews + + +if __name__ == '__main__': + Na = NewsApi() + print(Na.getMorningNews()) + # print(Na.getEveningNews()) diff --git a/ApiServer/pluginServer/PointApi.py b/ApiServer/pluginServer/PointApi.py new file mode 100644 index 0000000..11bca71 --- /dev/null +++ b/ApiServer/pluginServer/PointApi.py @@ -0,0 +1,189 @@ +import FileCache.FileCacheServer as Fcs +import Config.ConfigServer as Cs +from OutPut.outPut import op +import requests +import time + + +class PointApi: + def __init__(self): + """ + 不要直接调用此类 + 积分功能Api文件 + """ + configData = Cs.returnConfigData() + # 高德配置 + self.gaoDeApi = configData['apiServer']['gaoDeApi'] + self.gaoDeKey = configData['apiServer']['apiConfig']['gaoDeKey'] + # 埃文配置 + self.aiWenApi = configData['apiServer']['aiWenApi'] + self.aiWenKey = configData['apiServer']['apiConfig']['aiWenKey'] + # 微步配置 + self.threatBookApi = configData['apiServer']['threatBookApi'] + self.threatBookKey = configData['apiServer']['apiConfig']['threatBookKey'] + # Cmd5配置 + self.cmd5Api = configData['apiServer']['cmd5Api'] + self.cmd5Email = configData['apiServer']['apiConfig']['cmd5Email'] + self.cmd5Key = configData['apiServer']['apiConfig']['cmd5Key'] + + def getGaoDeMap(self, lat, lng): + op(f'[*]: 正在调用高德地图Api接口... ...') + params = { + 'location': f'{lat},{lng}', + 'zoom': 13, + 'size': '1024*1024', + 'markers': f'mid,,A:{lat},{lng}', + 'key': self.gaoDeKey + } + try: + file_name = Fcs.returnGaoDeCacheFolder() + '/' + str(int(time.time() * 1000)) + '.png' + resp = requests.get(url=self.gaoDeApi, params=params) + with open(file_name, mode='wb') as f: + f.write(resp.content) + return file_name + except Exception as e: + op(f'[-]: 高德地图Api接口查询错误, 错误信息: {e}') + return None + + def getAiWenIpv4(self, ip): + dictData = {'maps': [], 'message': ''} + """ + 埃文科技IPV4地址查询 + :param ip: + :return: + """ + ips = str(ip).split('.') + op(f'[*]: 正在调用埃文IPV4查询接口... ...') + if ips[0] in ['127', '192', '0', '224', '240', '255'] or \ + ip in ['1.1.1.1', '2.2.2.2', '3.3.3.3', '4.4.4.4', '5.5.5.5', '6.6.6.6', '7.7.7.7', + '8.8.8.8', '9.9.9.9', '10.10.10.10'] or \ + '.'.join(ips[0:2]) in ['169.254', '100.64', '198.51', '198.18', '172.16'] or \ + '.'.join(ips[0:3]) in ['203.0.113'] or \ + ips[-1] in ['255', '254']: + return None + + parameters = { + 'key': self.aiWenKey, + 'ip': ip, + 'lang': '', + 'coordsys': 'WGS84', + 'area': 'multi', + } + try: + resp = requests.get(url=self.aiWenApi, params=parameters, timeout=10) + json_data = resp.json() + if json_data['code'] != 'Success': + return None + continent = json_data['data']['continent'] + country = json_data['data']['country'] + accuracy = json_data['data']['accuracy'] + isp = json_data['data']['isp'] + multiAreas = json_data['data']['multiAreas'] + dictData['message'] = f'==========\n地区: {continent}\n国家: {country}\n精确度: {accuracy}\n运营商: {isp}\n' + for areas in multiAreas: + picPath = self.getGaoDeMap(areas.get('lng'), areas.get('lat')) + dictData['maps'].append(picPath) + dictData[ + 'message'] += f'纬度: {areas.get("lat")}\n经度: {areas.get("lng")}\n省份: {areas.get("prov")}\n市区: {areas.get("city")}\n县: {areas.get("district")}\n详细地址: {areas.get("address")}\n==========\n' + return dictData + except Exception as e: + op(f'[-]: 埃文IPV4查询接口错误, 错误信息: {e}') + return None + + def getThreatBook(self, ip): + """ + 微步威胁Ip查询 + :param ip: IP地址 + :return: + """ + ips = str(ip).split('.') + op(f'[*]: 正在调用微步IP查询API接口... ...') + if ips[0] in ['127', '192', '0', '224', '240', '255'] or \ + ip in ['1.1.1.1', '2.2.2.2', '3.3.3.3', '4.4.4.4', '5.5.5.5', '6.6.6.6', '7.7.7.7', + '8.8.8.8', '9.9.9.9', '10.10.10.10'] or \ + '.'.join(ips[0:2]) in ['169.254', '100.64', '198.51', '198.18', '172.16'] or \ + '.'.join(ips[0:3]) in ['203.0.113'] or \ + ips[-1] in ['255', '254']: + return None + params = { + "apikey": self.threatBookKey, + "resource": ip, + 'lang': 'zh' + } + try: + msg = '==========\n' + msg += f'查询IP: {ip}\n' + resp = requests.get( + self.threatBookApi, + params=params, + timeout=10, + verify=True, + ) + jsonData = resp.json()['data'][f'{ip}'] + if resp.status_code == 200 and resp.json()["response_code"] == 0: + # 获取标签 + tags_classes = jsonData['tags_classes'] + for tag_class in tags_classes: + tags = tag_class.get('tags') + msg += '标签: ' + ','.join(tags) + '\n' + msg += '标签类别: ' + tag_class.get('tags_type') + '\n' + # 获取威胁类型 + judgments = jsonData['judgments'] + msg += '威胁类别: ' + ','.join(judgments) + '\n' + '----------\n' + # 获取微步在线情报 + threatBook_labs = jsonData['intelligences']['threatbook_lab'] + for threatBook_lab in threatBook_labs: + msg += threatBook_lab.get('source') + '\n' + msg += '可信度: ' + str(threatBook_lab.get('confidence')) + '\n' + msg += '是否有效: ' + msg += 'YES\n' if not threatBook_lab.get('expired') else 'NO\n' + intel_tags = threatBook_lab.get('intel_tags') + if intel_tags: + msg += '威胁标签: ' + ','.join(threatBook_lab.get('intel_tags')[0].get('tags')) + '\n' + msg += '标签类别: ' + threatBook_lab.get('intel_tags')[0].get('tags_type') + '\n' + msg += '威胁类型: ' + ','.join(threatBook_lab.get('intel_types')) + '\n' + msg += '发现时间: ' + threatBook_lab.get('find_time') + '\n' + msg += '更新时间: ' + threatBook_lab.get('update_time') + '\n' + msg += '----------\n' + # 获取运营商 + msg += '服务商: ' + jsonData.get('basic').get('carrier') + '\n' + # 获取地址 + msg += '所在国家: ' + jsonData.get('basic').get('location').get('country') + '\n' + msg += '所在省份: ' + jsonData.get('basic').get('location').get('province') + '\n' + msg += '所在市区: ' + jsonData.get('basic').get('location').get('city') + '\n' + # 获取最后更新时间 + msg += '最后更新时间: ' + jsonData.get('update_time') + '\n' + msg += '==========' + return msg + else: + op(f"[-]: 微步威胁IP查询失败, 返回信息:{resp.json()['verbose_msg']}") + return None + except Exception as e: + op(f"[-]: 微步威胁IP查询出现错误, 错误信息:{e}") + return None + + def getCmd5(self, ciphertext): + """ + MD5解密接口 + :param ciphertext: 密文 + :return: + """ + op(f'[*]: 正在调用cMd5解密接口... ...') + md5Url = self.cmd5Api.format(self.cmd5Email, self.cmd5Key, ciphertext) + try: + content = requests.get(url=md5Url).text + print(content) + if 'CMD5-ERROR' in content: + return None + else: + return content + except Exception as e: + op(f'[-]: 调用CMD5解密接口出现错误, 错误信息: {e}') + return None + + +if __name__ == '__main__': + Pa = PointApi() + print(Pa.getAiWenIpv4('117.167.255.42')) + # print(Pa.getThreatBook('117.167.255.42')) + print(Pa.getCmd5('827ccb0eea8a706c4c34a16891f84e7b')) \ No newline at end of file diff --git a/ApiServer/pluginServer/__init__.py b/ApiServer/pluginServer/__init__.py new file mode 100644 index 0000000..272dfbc --- /dev/null +++ b/ApiServer/pluginServer/__init__.py @@ -0,0 +1,11 @@ +from ApiServer.pluginServer.HappyApi import HappyApi +from ApiServer.pluginServer.NewsApi import NewsApi +from ApiServer.pluginServer.PointApi import PointApi + + +# 实例化接口 (注册接口) +Ha = HappyApi() +Na = NewsApi() +Pa = PointApi() + + diff --git a/ApiServer/pluginServer/__pycache__/HappyApi.cpython-38.pyc b/ApiServer/pluginServer/__pycache__/HappyApi.cpython-38.pyc new file mode 100644 index 0000000..891fed9 Binary files /dev/null and b/ApiServer/pluginServer/__pycache__/HappyApi.cpython-38.pyc differ diff --git a/ApiServer/pluginServer/__pycache__/NewsApi.cpython-38.pyc b/ApiServer/pluginServer/__pycache__/NewsApi.cpython-38.pyc new file mode 100644 index 0000000..302153f Binary files /dev/null and b/ApiServer/pluginServer/__pycache__/NewsApi.cpython-38.pyc differ diff --git a/ApiServer/pluginServer/__pycache__/PointApi.cpython-38.pyc b/ApiServer/pluginServer/__pycache__/PointApi.cpython-38.pyc new file mode 100644 index 0000000..1ad713f Binary files /dev/null and b/ApiServer/pluginServer/__pycache__/PointApi.cpython-38.pyc differ diff --git a/ApiServer/pluginServer/__pycache__/__init__.cpython-38.pyc b/ApiServer/pluginServer/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..b557fdd Binary files /dev/null and b/ApiServer/pluginServer/__pycache__/__init__.cpython-38.pyc differ diff --git a/BotServer/BotFunction/AdminFunction.py b/BotServer/BotFunction/AdminFunction.py new file mode 100644 index 0000000..a0e092b --- /dev/null +++ b/BotServer/BotFunction/AdminFunction.py @@ -0,0 +1,110 @@ +from BotServer.BotFunction.InterfaceFunction import * +from BotServer.BotFunction.JudgeFuncion import * +from DbServer.DbMainServer import DbMainServer +import Config.ConfigServer as Cs + + +class AdminFunction: + def __init__(self, wcf): + self.wcf = wcf + self.Dms = DbMainServer() + configData = Cs.returnConfigData() + self.addBlackRoomKeyWords = configData['adminFunctionWord']['addBlackRoomWord'] + self.delBlackRoomKeyWords = configData['adminFunctionWord']['delBlackRoomWord'] + self.addWhiteRoomKeyWords = configData['adminFunctionWord']['addWhiteRoomWord'] + self.delWhiteRoomKeyWords = configData['adminFunctionWord']['delWhiteRoomWord'] + self.addPushRoomKeyWords = configData['adminFunctionWord']['addPushRoomWord'] + self.delPushRoomKeyWords = configData['adminFunctionWord']['delPushRoomWord'] + self.addBlackGhKeyWords = configData['adminFunctionWord']['addBlackGhWord'] + self.delBlackGhKeyWords = configData['adminFunctionWord']['delBlackGhWord'] + self.delUserKeyWords = configData['adminFunctionWord']['delUserWord'] + self.addPointKeyWords = configData['pointConfig']['addPointWord'] + self.delPointKeyWords = configData['pointConfig']['delPointWord'] + + def mainHandle(self, message): + content = message.content.strip() + sender = message.sender + roomId = message.roomid + msgType = message.type + roomName = getIdName(self.wcf, roomId) + senderName = self.wcf.get_alias_in_chatroom(sender, roomId) + atUserLists, noAtMsg = getAtData(self.wcf, message) + if msgType == 1: + # 增加积分 + if judgeSplitAllEqualWord(noAtMsg, self.addPointKeyWords): + if atUserLists: + point = noAtMsg.split(' ')[-1] + for atUser in atUserLists: + if self.Dms.addPoint(atUser, roomId, point): + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(atUser, roomId)}\n 基于你的表现, 管理员施舍了你 {point} 分', + receiver=roomId, aters=atUser) + else: + self.wcf.send_text( + f'@{senderName}\n {self.wcf.get_alias_in_chatroom(atUser, roomId)} 用户积分添加失败, 请查看日志', + receiver=roomId, aters=sender) + # 扣除积分 + elif judgeSplitAllEqualWord(noAtMsg, self.delPointKeyWords): + if atUserLists: + point = noAtMsg.split(' ')[-1] + for atUser in atUserLists: + if self.Dms.reducePoint(atUser, roomId, point): + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(atUser, roomId)}\n 基于你的表现, 管理员扣除了你 {point} 分', + receiver=roomId, aters=atUser) + else: + self.wcf.send_text( + f'@{senderName}\n {self.wcf.get_alias_in_chatroom(atUser, roomId)} 用户积分扣除失败, 请查看日志', + receiver=roomId, aters=atUser) + # 添加白名单群聊 + elif judgeEqualListWord(content, self.addWhiteRoomKeyWords): + if self.Dms.addWhiteRoom(roomId, roomName): + self.wcf.send_text(f'@{senderName} 添加白名单群聊成功 !!!', receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName} 此群已在白名单中', receiver=roomId, aters=sender) + # 移出白名单群聊 + elif judgeEqualListWord(content, self.delWhiteRoomKeyWords): + if self.Dms.delWhiteRoom(roomId): + self.wcf.send_text(f'@{senderName} 移出白名单群聊成功 !!!', receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName} 此群已移出白名单 !!!', receiver=roomId, aters=sender) + # 添加黑名单群聊 + elif judgeEqualListWord(content, self.addBlackRoomKeyWords): + if self.Dms.addBlackRoom(roomId, roomName): + self.wcf.send_text(f'@{senderName} 此群已拉黑 !!!', receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName} 此群已在黑名单中 !!!', receiver=roomId, aters=sender) + # 移出黑名单群聊 + elif judgeEqualListWord(content, self.delBlackRoomKeyWords): + if self.Dms.delBlackRoom(roomId): + self.wcf.send_text(f'@{senderName} 移出黑名单成功 !!!', receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName} 此群已移出黑名单 !!!', receiver=roomId, aters=sender) + # 添加推送群聊 + elif judgeEqualListWord(content, self.addPushRoomKeyWords): + if self.Dms.addPushRoom(roomId, roomName): + self.wcf.send_text(f'@{senderName} 开启推送服务成功 !!!', receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName} 此群已开启推送服务 !!!', receiver=roomId, aters=sender) + # 移出推送群聊 + elif judgeEqualListWord(content, self.delPushRoomKeyWords): + if self.Dms.delPushRoom(roomId): + self.wcf.send_text(f'@{senderName} 此群已关闭推送服务 !!!', receiver=roomId, aters=sender) + # 踢人 + elif judgeEqualListWord(noAtMsg, self.delUserKeyWords): + for atWxId in atUserLists: + if self.wcf.del_chatroom_members(roomId, atWxId): + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(atWxId, roomId)} 基于你的表现, 给你移出群聊的奖励', + receiver=roomId) + else: + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)} [{self.wcf.get_alias_in_chatroom(atWxId, roomId)}] 移出群聊失败', + receiver=roomId, aters=sender) + # # 添加黑名单公众号 阉割 + # elif judgeEqualListWord(content, self.addBlackGhKeyWords): + # pass + # # 移出黑名单公众号 + # elif judgeEqualListWord(content, self.delBlackGhKeyWords): + # pass + diff --git a/BotServer/BotFunction/AdministratorFunction.py b/BotServer/BotFunction/AdministratorFunction.py new file mode 100644 index 0000000..1fcbc4c --- /dev/null +++ b/BotServer/BotFunction/AdministratorFunction.py @@ -0,0 +1,45 @@ +from BotServer.BotFunction.InterfaceFunction import * +from BotServer.BotFunction.JudgeFuncion import * +from DbServer.DbMainServer import DbMainServer +import Config.ConfigServer as Cs + + +class AdministratorFunction: + def __init__(self, wcf): + self.wcf = wcf + self.Dms = DbMainServer() + configData = Cs.returnConfigData() + self.addAdminKeyWords = configData['adminFunctionWord']['addAdminWord'] + self.delAdminKeyWords = configData['adminFunctionWord']['delAdminWord'] + + def mainHandle(self, message): + sender = message.sender + roomId = message.roomid + msgType = message.type + atUserLists, noAtMsg = getAtData(self.wcf, message) + if msgType == 1: + # 添加管理员 + if judgeEqualListWord(noAtMsg, self.addAdminKeyWords): + if atUserLists: + for atUser in atUserLists: + if self.Dms.addAdmin(atUser, roomId): + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)}\n管理员 [{self.wcf.get_alias_in_chatroom(atUser, roomId)}] 添加成功', + receiver=roomId, aters=sender) + else: + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)}\n群成员 [{self.wcf.get_alias_in_chatroom(atUser, roomId)}] 已是管理员', + receiver=roomId, aters=sender) + # 删除管理员 + elif judgeEqualListWord(noAtMsg, self.delAdminKeyWords): + if atUserLists: + for atUser in atUserLists: + if self.Dms.delAdmin(atUser, roomId): + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)}\n管理员 [{self.wcf.get_alias_in_chatroom(atUser, roomId)}] 删除成功', + receiver=roomId, aters=sender) + else: + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)}\n群成员 [{self.wcf.get_alias_in_chatroom(atUser, roomId)}] 已不是管理员', + receiver=roomId, aters=sender) + diff --git a/BotServer/BotFunction/HappyFunction.py b/BotServer/BotFunction/HappyFunction.py new file mode 100644 index 0000000..5f792a1 --- /dev/null +++ b/BotServer/BotFunction/HappyFunction.py @@ -0,0 +1,166 @@ +from BotServer.BotFunction.InterfaceFunction import * +from ApiServer.ApiMainServer import ApiMainServer +from BotServer.BotFunction.JudgeFuncion import * +import Config.ConfigServer as Cs + + +class HappyFunction: + def __init__(self, wcf): + self.wcf = wcf + self.Ams = ApiMainServer() + configData = Cs.returnConfigData() + self.picKeyWords = configData['functionKeyWord']['picWord'] + self.videoKeyWords = configData['functionKeyWord']['videoWord'] + self.fishKeyWords = configData['functionKeyWord']['fishWord'] + self.kfcKeyWords = configData['functionKeyWord']['kfcWord'] + self.dogKeyWords = configData['functionKeyWord']['dogWord'] + self.morningPageKeyWords = configData['functionKeyWord']['morningPageWord'] + self.eveningPageKeyWords = configData['functionKeyWord']['eveningPageWord'] + self.helpKeyWords = configData['functionKeyWord']['helpMenu'] + self.emoHelpKeyWords = configData['emoConfig']['emoHelp'] + self.emoKeyWords = configData['emoConfig']['emoKeyWord'] + self.emoOneKeyWordsData = configData['emoConfig']['onePicEmo'] + self.emoTwoKeyWordsData = configData['emoConfig']['twoPicEwo'] + self.emoRandomKeyWords = configData['emoConfig']['emoRandomKeyWord'] + + def mainHandle(self, message): + content = message.content.strip() + sender = message.sender + roomId = message.roomid + msgType = message.type + atUserLists, noAtMsg = getAtData(self.wcf, message) + senderName = self.wcf.get_alias_in_chatroom(sender, roomId) + avatarPathList = [] + if msgType == 1: + # 美女图片 + if judgeEqualListWord(content, self.picKeyWords): + picPath = self.Ams.getGirlPic() + if not picPath: + self.wcf.send_text( + f'@{senderName} 美女图片接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_image(picPath, receiver=roomId) + # 美女视频 + elif judgeEqualListWord(content, self.videoKeyWords): + videoPath = self.Ams.getGirlVideo() + if not videoPath: + self.wcf.send_text( + f'@{senderName} 美女视频接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_file(videoPath, receiver=roomId) + + # 摸鱼日历 + elif judgeEqualListWord(content, self.fishKeyWords): + fishPath = self.Ams.getFish() + if not fishPath: + self.wcf.send_text( + f'@{senderName} 摸鱼日历接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_file(fishPath, receiver=roomId) + + # 疯狂星期四 + elif judgeEqualListWord(content, self.kfcKeyWords): + kfcText = self.Ams.getKfc() + if not kfcText: + self.wcf.send_text( + f'@{senderName} KFC疯狂星期四接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName} {kfcText}', + receiver=roomId, aters=sender) + + # 舔狗日记 + elif judgeEqualListWord(content, self.dogKeyWords): + dogText = self.Ams.getDog() + if not dogText: + self.wcf.send_text( + f'@{senderName} 舔狗日记接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName} {dogText}', + receiver=roomId, aters=sender) + # 早报 + elif judgeEqualListWord(content, self.morningPageKeyWords): + morningPage = self.Ams.getMorningNews() + if not morningPage: + self.wcf.send_text( + f'@{senderName} 早报接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_text(morningPage, receiver=roomId) + # 晚报 + elif judgeEqualListWord(content, self.eveningPageKeyWords): + eveningPage = self.Ams.getEveningNews() + if not eveningPage: + self.wcf.send_text( + f'@{senderName} 晚报接口出现错误, 请联系超管查看控制台输出日志 ~~~', + receiver=roomId, aters=sender) + return + self.wcf.send_text(eveningPage, receiver=roomId) + # 随机表情 + elif judgeEqualListWord(content, self.emoRandomKeyWords): + avatarPathList.append(getUserPicUrl(self.wcf, sender)) + emoPath, sizeBool = self.Ams.getEmoticon(avatarPathList) + if not emoPath: + return + if sizeBool: + self.wcf.send_emotion(path=emoPath, receiver=roomId) + else: + self.wcf.send_image(path=emoPath, receiver=roomId) + # 表情包功能 不@制作表情 + elif not atUserLists and judgeSplitAllEqualWord(content, self.emoKeyWords): + avatarPathList.append(getUserPicUrl(self.wcf, sender)) + emoMeme = self.emoOneKeyWordsData.get(content.split(' ')[-1]) + emoPath, sizeBool = self.Ams.getEmoticon(avatarPathList, emoMeme) + if not emoPath: + return + if sizeBool: + self.wcf.send_emotion(path=emoPath, receiver=roomId) + else: + self.wcf.send_image(path=emoPath, receiver=roomId) + # 表情包功能 @制作对方表情 + elif atUserLists and judgeSplitAllEqualWord(noAtMsg, self.emoKeyWords): + for atUser in atUserLists: + avatarPathList.append(getUserPicUrl(self.wcf, atUser)) + break + emoMeme = self.emoOneKeyWordsData.get(noAtMsg.split(' ')[-1]) + emoPath, sizeBool = self.Ams.getEmoticon(avatarPathList, emoMeme) + if not emoPath: + return + if sizeBool: + self.wcf.send_emotion(path=emoPath, receiver=roomId) + else: + self.wcf.send_image(path=emoPath, receiver=roomId) + # 表情包功能 @对方制作双人表情 + elif atUserLists and judgeEqualListWord(noAtMsg, self.emoTwoKeyWordsData.keys()): + avatarPathList.append(getUserPicUrl(self.wcf, sender)) + avatarPathList.append(getUserPicUrl(self.wcf, atUserLists[0])) + emoMeme = self.emoTwoKeyWordsData.get(noAtMsg.split(' ')[-1]) + emoPath, sizeBool = self.Ams.getEmoticon(avatarPathList, emoMeme) + if not emoPath: + return + if sizeBool: + self.wcf.send_emotion(path=emoPath, receiver=roomId) + else: + self.wcf.send_image(path=emoPath, receiver=roomId) + # 表情菜单 + elif judgeEqualListWord(content, self.emoHelpKeyWords): + msg = '【单人表情】使用方法: \n表情 表情选项\n@某人 表情选项\n单人表情选项如下: \n' + for oneEmoKey in self.emoOneKeyWordsData.keys(): + msg += oneEmoKey + '\n' + msg += '【双人表情】使用方法: \n表情选项@某人 \n双人表情选项如下\n' + for twoEmoKey in self.emoTwoKeyWordsData.keys(): + msg += twoEmoKey + '\n' + self.wcf.send_text(f'@{senderName}\n{msg}', receiver=roomId, aters=sender) + # 帮助菜单 + elif judgeEqualListWord(content, self.helpKeyWords): + helpMsg = '[爱心]=== NGCBot菜单 ===[爱心]\n' + helpMsg += '【一、积分功能】\n1.1、Ai画图(@机器人 画一张xxxx)\n1.2、Ai对话(@机器人即可)\n1.3、IP溯源(溯源 ip)\n1.4、IP威胁查询(ip查询 ip)\n1.5、CMD5查询(cmd5查询 xxx)\n1.6、签到(签到)\n1.7、积分查询(积分查询)\n\n' + helpMsg += '【二、娱乐功能】\n2.1、美女图片(图片)\n2.2、美女视频(视频)\n2.3、摸鱼日历(摸鱼日历)\n2.4、舔狗日记(舔我)\n2.5、早报(早报)\n2.6、晚报(晚报)\n2.6、表情列表(表情列表)\n2.7、随机表情(随机表情, 有几率报错)\n' + helpMsg += '[爱心]=== NGCBot菜单 ===[爱心]\n' + self.wcf.send_text(f'@{senderName}\n{helpMsg}', receiver=roomId, aters=sender) diff --git a/BotServer/BotFunction/InterfaceFunction.py b/BotServer/BotFunction/InterfaceFunction.py new file mode 100644 index 0000000..ff58bf4 --- /dev/null +++ b/BotServer/BotFunction/InterfaceFunction.py @@ -0,0 +1,76 @@ +import FileCache.FileCacheServer as Fcs +import xml.etree.ElementTree as ET +import Config.ConfigServer as Cs +from OutPut.outPut import op +import requests +import time +import os + + +def getAtData(wcf, msg): + """ + 处理@信息 + :param msg: + :param wcf: + :return: + """ + noAtMsg = msg.content + try: + root_xml = ET.fromstring(msg.xml) + atUserListsElement = root_xml.find('.//atuserlist') + atUserLists = atUserListsElement.text.replace(' ', '').strip().strip(',').split( + ',') if atUserListsElement is not None else None + if not atUserLists: + return '', '' + atNames = [] + for atUser in atUserLists: + atUserName = wcf.get_alias_in_chatroom(atUser, msg.roomid) + atNames.append(atUserName) + for atName in atNames: + noAtMsg = noAtMsg.replace('@' + atName, '') + except Exception as e: + op(f'[~]: 处理@消息出现小问题, 仅方便开发调试, 不用管此报错: {e}') + return '', '' + return atUserLists, noAtMsg.strip() + + +def getIdName(wcf, Id): + """ + 获取好友或者群聊昵称 + :return: + """ + Name = '' + friendLists = wcf.get_contacts() + for friend in friendLists: + if friend.get('wxid') == Id: + Name = friend.get('name') + break + continue + return Name + + +def getUserPicUrl(wcf, sender): + """ + 获取好友头像下载地址 + :param sender: + :param wcf: + :return: + """ + imgName = str(sender) + '.jpg' + save_path = Fcs.returnAvatarFolder() + '/' + imgName + + if imgName in os.listdir(Fcs.returnAvatarFolder()): + return save_path + + headImgData = wcf.query_sql("MicroMsg.db", f"SELECT * FROM ContactHeadImgUrl WHERE usrName = '{sender}';") + try: + if headImgData: + if headImgData[0]: + bigHeadImgUrl = headImgData[0]['bigHeadImgUrl'] + content = requests.get(url=bigHeadImgUrl, timeout=30).content + with open(save_path, mode='wb') as f: + f.write(content) + return save_path + except Exception as e: + op(f'[-]: 获取好友头像下载地址出现错误, 错误信息: {e}') + return None diff --git a/BotServer/BotFunction/JudgeFuncion.py b/BotServer/BotFunction/JudgeFuncion.py new file mode 100644 index 0000000..00cdddb --- /dev/null +++ b/BotServer/BotFunction/JudgeFuncion.py @@ -0,0 +1,169 @@ +from DbServer.DbMainServer import DbMainServer + +Dms = DbMainServer() + + +def judgeOneEqualListWord(recvWord, systemListWord): + """ + 判断接收消息前面几个字是否跟 触发关键词列表中的相匹配 + :param recvWord: + :param systemListWord: + :return: + """ + for systemWord in systemListWord: + if recvWord.startswith(systemWord): + return True + return False + + +def judgeEqualWord(recvWord, systemWord): + """ + 判断接收消息和触发关键字完全相同则返回True + 接收消息 == 触发关键字 + :param recvWord: 接收消息 + :param systemWord: 触发关键字 + :return: + """ + if recvWord.strip() == systemWord.strip(): + return True + return False + + +def judgeEqualListWord(recvWord, systemListWord): + """ + 判断接收消息在触发关键字列表中则返回True + 接收消息 in ['触发关键字列表'] + :param recvWord: 接收消息 + :param systemListWord: 触发关键字列表 + :return: + """ + for listWord in systemListWord: + if listWord.strip() == recvWord.strip(): + return True + return False + + +def judgeInWord(recvWord, systemWord): + """ + 判断接收消息在触发关键字中则返回True + 接收消息 in 触发关键字 + :param recvWord: + :param systemWord: + :return: + """ + if systemWord in recvWord: + return True + return False + + +def judgeInListWord(recvWord, systemListWord): + """ + 判断触发关键词列表中每一个关键字在接收消息中则返回True + :param recvWord: + :param systemListWord: + :return: + """ + for listWord in systemListWord: + if listWord in recvWord: + return True + return False + + +def judgeSplitAllEqualWord(recvWord, systemListWord): + """ + 接收消息以空格切割,判断第一个元素是否在触发关键字列表中则返回True + :param recvWord: + :param systemListWord: + :return: + """ + if ' ' in recvWord: + recvWord = recvWord.split(' ')[0] + for listWord in systemListWord: + if recvWord == listWord: + return True + return False + return False + + +def judgePointFunction(senderPoint, functionPoint): + """ + 判断用户积分是否大于功能积分 + :param senderPoint: + :param functionPoint: + :return: + """ + if int(senderPoint) >= int(functionPoint): + return True + return False + + +def judgeWhiteRoom(roomId): + """ + 判断群聊是否属于白名单 + :param roomId: + :return: + """ + whiteRoomData = Dms.showWhiteRoom() + for whiteRoomId, whiteRoomName in whiteRoomData.items(): + if roomId == whiteRoomId: + return True + return False + + +def judgeBlackRoom(roomId): + """ + 判断群聊是否处于黑名单 + :param roomId: + :return: + """ + blackRoomData = Dms.showBlackRoom() + for blackRoomId, blackRoomName in blackRoomData.items(): + if roomId == blackRoomId: + return True + return False + + +def judgePushRoom(roomId): + """ + 判断群聊是否属于推送群聊 + :param roomId: + :return: + """ + pushRoomData = Dms.showPushRoom() + for pushRoomId, pushRoomName in pushRoomData.items(): + if roomId == pushRoomId: + return True + return False + + +def judgeBlackGh(ghId): + """ + 判断公众号是否属于黑名单公众号 + :param ghId: + :return: + """ + blackGhData = Dms.showBlackGh() + for blackGhId, blackGhName in blackGhData.items(): + if ghId == blackGhId: + return True + return False + + +def judgeAdmin(wxId, roomId): + """ + 判断用户是否是管理员 + :return: + """ + return Dms.searchAdmin(wxId, roomId) + + +def judgeAtMe(selfId, content, atUserList): + """ + 判断有人@我, @所有人不算 + :param selfId: + :param atUserList: + :return: + """ + if selfId in atUserList and '所有人' not in content: + return True + return False diff --git a/BotServer/BotFunction/PointFunction.py b/BotServer/BotFunction/PointFunction.py new file mode 100644 index 0000000..45de8d0 --- /dev/null +++ b/BotServer/BotFunction/PointFunction.py @@ -0,0 +1,120 @@ +from BotServer.BotFunction.InterfaceFunction import * +from ApiServer.ApiMainServer import ApiMainServer +from BotServer.BotFunction.JudgeFuncion import * +from DbServer.DbMainServer import DbMainServer +import Config.ConfigServer as Cs + + +class PointFunction: + def __init__(self, wcf): + """ + Ai画图 + :param wcf: + """ + self.wcf = wcf + self.Ams = ApiMainServer() + self.Dms = DbMainServer() + configData = Cs.returnConfigData() + self.aiWenKeyWords = configData['functionKeyWord']['aiWenWord'] + self.threatBookWords = configData['functionKeyWord']['threatBookWord'] + self.md5KeyWords = configData['functionKeyWord']['md5Words'] + self.signKeyWord = configData['pointConfig']['sign']['word'] + self.aiPicKeyWords = configData['functionKeyWord']['aiPic'] + self.searchPointKeyWord = configData['pointConfig']['queryPointWord'] + + def mainHandle(self, message): + content = message.content.strip() + sender = message.sender + roomId = message.roomid + msgType = message.type + senderName = self.wcf.get_alias_in_chatroom(sender, roomId) + atUserLists, noAtMsg = getAtData(self.wcf, message) + if msgType == 1: + # 埃文IPV4地址查询 + if judgeSplitAllEqualWord(content, self.aiWenKeyWords): + ip = content.split(' ')[-1] + aiWenData = self.Ams.getAiWen(ip) + if not aiWenData: + self.wcf.send_text( + f'@{senderName} 埃文IP地址查询接口出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) + return + mapsPaths = aiWenData['maps'] + for mapsPath in mapsPaths: + self.wcf.send_image(mapsPath, receiver=roomId) + aiWenMessage = aiWenData['message'] + self.wcf.send_text(f'@{senderName} 查询结果如下\n{aiWenMessage}', + receiver=roomId, aters=sender) + + # 微步IPV4查询 + elif judgeSplitAllEqualWord(content, self.threatBookWords): + ip = content.split(' ')[-1] + threatMsg = self.Ams.getThreatBook(ip) + if not threatMsg: + self.wcf.send_text( + f'@{senderName} 微步IPV4地址查询接口出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) + return + self.wcf.send_text(f'@{senderName}\n{threatMsg}', receiver=roomId, + aters=sender) + + # CMD5查询 + elif judgeSplitAllEqualWord(content, self.md5KeyWords): + ciphertext = content.split(' ')[-1] + plaintext = self.Ams.getCmd5(ciphertext) + if not plaintext: + self.wcf.send_text( + f'@{senderName} MD5解密接口出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName}\n密文: {ciphertext}\n明文: {plaintext}', + receiver=roomId, + aters=sender) + # 签到口令提示 + elif judgeEqualWord(content, '签到'): + self.wcf.send_text( + f'@{senderName} 签到失败\n签到口令已改为:{self.signKeyWord}', + receiver=roomId, aters=sender) + # 签到 + elif judgeEqualWord(content, self.signKeyWord): + if not self.Dms.sign(wxId=sender, roomId=roomId): + self.wcf.send_text( + f'@{senderName} 签到失败, 当日已签到!!!\n当前剩余积分: {self.Dms.searchPoint(sender, roomId)}', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName} 签到成功, 当前剩余积分: {self.Dms.searchPoint(sender, roomId)}', + receiver=roomId, aters=sender) + # 查询积分 + elif judgeEqualListWord(content, self.searchPointKeyWord): + userPoint = self.Dms.searchPoint(sender, roomId) + if not userPoint: + self.wcf.send_text( + f'@{senderName} 积分查询出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName} 当前剩余积分: {self.Dms.searchPoint(sender, roomId)}', + receiver=roomId, aters=sender) + # Ai对话 + elif judgeAtMe(self.wcf.self_wxid, content, atUserLists) and not judgeOneEqualListWord(noAtMsg, + self.aiPicKeyWords): + aiMsg = self.Ams.getAi(noAtMsg) + if aiMsg: + self.wcf.send_text(f'@{senderName} {aiMsg}', + receiver=roomId, aters=sender) + return + self.wcf.send_text( + f'@{senderName} Ai对话接口出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) + # Ai画图 + elif judgeAtMe(self.wcf.self_wxid, content, atUserLists) and judgeOneEqualListWord(noAtMsg, + self.aiPicKeyWords): + aiPicPath = self.Ams.getAiPic(noAtMsg) + if aiPicPath: + self.wcf.send_image(path=aiPicPath, receiver=roomId) + return + self.wcf.send_text( + f'@{senderName} Ai画图接口出现错误, 请联系超管查看控制台输出日志', + receiver=roomId, aters=sender) diff --git a/BotServer/BotFunction/__pycache__/AdminFunction.cpython-38.pyc b/BotServer/BotFunction/__pycache__/AdminFunction.cpython-38.pyc new file mode 100644 index 0000000..a28acaa Binary files /dev/null and b/BotServer/BotFunction/__pycache__/AdminFunction.cpython-38.pyc differ diff --git a/BotServer/BotFunction/__pycache__/AdministratorFunction.cpython-38.pyc b/BotServer/BotFunction/__pycache__/AdministratorFunction.cpython-38.pyc new file mode 100644 index 0000000..c6a01ce Binary files /dev/null and b/BotServer/BotFunction/__pycache__/AdministratorFunction.cpython-38.pyc differ diff --git a/BotServer/BotFunction/__pycache__/HappyFunction.cpython-38.pyc b/BotServer/BotFunction/__pycache__/HappyFunction.cpython-38.pyc new file mode 100644 index 0000000..0548e61 Binary files /dev/null and b/BotServer/BotFunction/__pycache__/HappyFunction.cpython-38.pyc differ diff --git a/BotServer/BotFunction/__pycache__/InterfaceFunction.cpython-38.pyc b/BotServer/BotFunction/__pycache__/InterfaceFunction.cpython-38.pyc new file mode 100644 index 0000000..20d2193 Binary files /dev/null and b/BotServer/BotFunction/__pycache__/InterfaceFunction.cpython-38.pyc differ diff --git a/BotServer/BotFunction/__pycache__/JudgeFuncion.cpython-38.pyc b/BotServer/BotFunction/__pycache__/JudgeFuncion.cpython-38.pyc new file mode 100644 index 0000000..a8a262c Binary files /dev/null and b/BotServer/BotFunction/__pycache__/JudgeFuncion.cpython-38.pyc differ diff --git a/BotServer/BotFunction/__pycache__/PointFunction.cpython-38.pyc b/BotServer/BotFunction/__pycache__/PointFunction.cpython-38.pyc new file mode 100644 index 0000000..886455b Binary files /dev/null and b/BotServer/BotFunction/__pycache__/PointFunction.cpython-38.pyc differ diff --git a/BotServer/MainServer.py b/BotServer/MainServer.py new file mode 100644 index 0000000..bfdd493 --- /dev/null +++ b/BotServer/MainServer.py @@ -0,0 +1,74 @@ +from BotServer.MsgHandleServer.FriendMsgHandle import FriendMsgHandle +from BotServer.MsgHandleServer.RoomMsgHandle import RoomMsgHandle +from PushServer.PushMainServer import PushMainServer +from DbServer.DbInitServer import DbInitServer +import FileCache.FileCacheServer as Fcs +from threading import Thread +from OutPut.outPut import op +from cprint import cprint +from queue import Empty +from wcferry import Wcf + + +class MainServer: + def __init__(self): + self.wcf = Wcf() + self.Dis = DbInitServer() + # 开启全局接收 + self.wcf.enable_receiving_msg() + self.Rmh = RoomMsgHandle(self.wcf) + self.Fmh = FriendMsgHandle(self.wcf) + self.Pms = PushMainServer(self.wcf) + # 初始化服务以及配置 + Thread(target=self.initConfig, name='初始化服务以及配置').start() + + def isLogin(self, ): + """ + 判断是否登录 + :return: + """ + ret = self.wcf.is_login() + if ret: + userInfo = self.wcf.get_user_info() + # 用户信息打印 + cprint.info(f""" + \t========== NGCBot V2.1 ========== + \t微信名:{userInfo.get('name')} + \t微信ID:{userInfo.get('wxid')} + \t手机号:{userInfo.get('mobile')} + \t========== NGCBot V2.1 ========== + """.replace(' ', '')) + + def processMsg(self, ): + # 判断是否登录 + self.isLogin() + while self.wcf.is_receiving_msg(): + try: + msg = self.wcf.get_msg() + # 调试专用 + op(f'[*]: 接收到消息: {msg}') + # op(f'[*]: 接收到消息\n[*]: 群聊ID: {msg.roomid}\n[*]: 发送人ID: {msg.sender}\n[*]: 发送内容: {msg.content}\n--------------------') + # 群聊消息处理 + if '@chatroom' in msg.roomid: + Thread(target=self.Rmh.mainHandle, args=(msg,)).start() + # 好友消息处理 + elif '@chatroom' not in msg.roomid and 'gh_' not in msg.sender: + Thread(target=self.Fmh.mainHandle, args=(msg,)).start() + else: + pass + except Empty: + continue + + def initConfig(self, ): + """ + 初始化数据库 缓存文件夹 开启定时推送服务 + :return: + """ + self.Dis.initDb() + Fcs.initCacheFolder() + Thread(target=self.Pms.run, name='定时推送服务').start() + + +if __name__ == '__main__': + Ms = MainServer() + Ms.processMsg() diff --git a/BotServer/MsgHandleServer/FriendMsgHandle.py b/BotServer/MsgHandleServer/FriendMsgHandle.py new file mode 100644 index 0000000..24e7666 --- /dev/null +++ b/BotServer/MsgHandleServer/FriendMsgHandle.py @@ -0,0 +1,291 @@ +from BotServer.BotFunction.InterfaceFunction import * +from ApiServer.AiServer.AiDialogue import AiDialogue +from BotServer.BotFunction.JudgeFuncion import * +from DbServer.DbMainServer import DbMainServer +import xml.etree.ElementTree as ET +import Config.ConfigServer as Cs +from OutPut.outPut import op +from threading import Thread + + +class FriendMsgHandle: + def __init__(self, wcf): + """ + 关键词拉群 yes + 好友消息转发给超管 yes + 好友Ai消息 yes + 自定义关键词回复 yes + 管理员公众号消息转发给推送群聊 yes + 查看白名单群聊 yes + 查看黑名单群聊 yes + 查看推送群聊 yes + 查看黑名单公众号 yes + 好友红包消息处理 yes + 好友转账接收 yes 微信版本过低无法使用 + :param wcf: + """ + self.wcf = wcf + self.Ad = AiDialogue() + self.Dms = DbMainServer() + configData = Cs.returnConfigData() + # 超级管理员列表 + self.Administrators = configData['Administrators'] + # 给好友发消息关键词 + self.sendMsgKeyWords = configData['adminFunctionWord']['sendMsgWord'] + # Ai锁 + self.aiLock = configData['systemConfig']['aiLock'] + # 转账接收锁 + self.acceptMoneyLock = configData['systemConfig']['acceptMoneyLock'] + # 自动同意好友锁 + self.acceptFriendLock = configData['systemConfig']['acceptFriendLock'] + # 进群关键词字典 + self.roomKeyWords = configData['roomKeyWord'] + # 自定义回复关键词字典 + self.customKeyWords = configData['customKeyWord'] + # 查看白名单群聊关键词 + self.showWhiteRoomKeyWords = configData['adminFunctionWord']['showWhiteRoomWord'] + # 查看黑名单群聊关键词 + self.showBlackRoomKeyWords = configData['adminFunctionWord']['showBlackRoomWord'] + # 查看推送群聊关键词 + self.showPushRoomKeyWords = configData['adminFunctionWord']['showPushRoomWord'] + # 查看黑名单公众号关键词 + self.showBlackGhKeyWords = configData['adminFunctionWord']['showBlackGhWord'] + # 添加好友后自动回复消息 + self.acceptFriendMsg = configData['customMsg']['acceptFriendMsg'] + + def mainHandle(self, msg): + content = msg.content.strip() + sender = msg.sender + msgType = msg.type + + if msgType == 1: + # 关键词进群 + if judgeEqualListWord(content, self.roomKeyWords.keys()): + self.keyWordJoinRoom(sender, content) + # Thread(target=self.keyWordJoinRoom, args=(sender, content)).start() + # 自定义关键词回复功能 + elif judgeEqualListWord(content, self.customKeyWords.keys()): + self.customKeyWordMsg(sender, content) + # Thread(target=self.customKeyWordMsg, args=(sender, content)).start() + # 查看白名单群聊 + elif judgeEqualListWord(content, self.showWhiteRoomKeyWords) and sender in self.Administrators: + self.showWhiteRoom(sender, ) + # Thread(target=self.showWhiteRoom, args=(sender,)).start() + # 查看黑名单群聊 + elif judgeEqualListWord(content, self.showBlackRoomKeyWords) and sender in self.Administrators: + self.showBlackRoom(sender, ) + # Thread(target=self.showBlackRoom, args=(sender,)).start() + # 查看推送群聊 + elif judgeEqualListWord(content, self.showPushRoomKeyWords) and sender in self.Administrators: + self.showPushRoom(sender, ) + # Thread(target=self.showPushRoom, args=(sender,)).start() + # 查看黑名单公众号 + elif judgeEqualListWord(content, self.showBlackGhKeyWords) and sender in self.Administrators: + self.showBlackGh(sender, ) + # Thread(target=self.showBlackGh, args=(sender,)).start() + # Ai对话 Ai锁功能 对超管没用 + elif self.aiLock or sender in self.Administrators: + Thread(target=self.getAiMsg, args=(content, sender)).start() + # 超级管理员发消息转发给好友 + if judgeSplitAllEqualWord(content, self.sendMsgKeyWords): + Thread(target=self.sendFriendMsg, args=(content,)).start() + # 好友消息转发给超级管理员 超级管理员不触发 + if sender not in self.Administrators: + Thread(target=self.forwardMsgToAdministrators, args=(sender, content)).start() + # 转发公众号消息到推送群聊 超管有效 + if msg.type == 49: + if msg.sender in self.Administrators and 'gh_' in msg.content: + Thread(target=self.forwardGhMsg, args=(msg.id,)).start() + # 暂时没用 等Hook作者更新 老版本微信有用 + elif '转账' in msg.content and self.acceptMoneyLock: + Thread(target=self.acceptMoney, args=(msg,)).start() + # 红包消息处理 转发红包消息给主人 + if msgType == 10000 and '请在手机上查看' in msg.content: + Thread(target=self.forwardRedPacketMsg, args=(sender,)).start() + # 好友自动同意处理 暂时没用 老版本微信有用 + if msgType == 37 and self.acceptFriendLock: + Thread(target=self.acceptFriend, args=(msg,)).start() + + def acceptFriend(self, msg): + """ + 同意好友申请处理 + :return: + """ + root_xml = ET.fromstring(msg.content.strip()) + wxId = root_xml.attrib["fromusername"] + op(f'[*]: 接收到新的好友申请, 微信id为: {wxId}') + v3 = root_xml.attrib["encryptusername"] + v4 = root_xml.attrib["ticket"] + scene = int(root_xml.attrib["scene"]) + ret = self.wcf.accept_new_friend(v3=v3, v4=v4, scene=scene) + acceptSendMsg = self.acceptFriendMsg.replace('\\n', '\n') + self.wcf.send_text(acceptSendMsg, receiver=wxId) + if ret: + op(f'[+]: 好友 {self.wcf.get_info_by_wxid(wxId).get("name")} 已自动通过 !') + else: + op(f'[-]: 好友通过失败!!!') + + def acceptMoney(self, msg): + """ + 处理转账消息, 只处理好友转账 + :param msg: + :return: + """ + root_xml = ET.fromstring(msg.content.strip()) + title_element = root_xml.find(".//title") + title = title_element.text if title_element is not None else None + if '微信转账' == title and msg.sender != self.wcf.self_wxid: + transCationId = root_xml.find('.//transcationid').text + transFerid = root_xml.find('.//transferid').text + if not self.wcf.receive_transfer(wxid=msg.sender, transactionid=transCationId, + transferid=transFerid): + op(f'[-]: 接收好友转账失败, 可能是版本不支持') + + def forwardRedPacketMsg(self, sender): + """ + 转发红包消息给主人 + :return: + """ + for administrator in self.Administrators: + self.wcf.send_text(f'[爱心]接收到好友: {getIdName(self.wcf, sender)} 的红包, 请在手机上接收', + receiver=administrator) + self.wcf.send_text(f'[爱心]已接收到您的红包, 感谢支持', receiver=sender) + + def showBlackGh(self, sender): + """ + 查看黑名单公众号 + :param sender: + :return: + """ + blackGhData = self.Dms.showBlackGh() + sendMsg = '===== 推送群聊列表 =====\n' + for roomId, roomName in blackGhData.items(): + sendMsg += f'公众号ID: {roomId}\n公众号昵称: {roomName}\n---------------\n' + if not blackGhData: + sendMsg = '暂无公众号添加至黑名单' + self.wcf.send_text(sendMsg, receiver=sender) + + def showPushRoom(self, sender): + """ + 查看推送群聊 + :param sender: + :return: + """ + pushRoomData = self.Dms.showPushRoom() + sendMsg = '===== 推送群聊列表 =====\n' + for roomId, roomName in pushRoomData.items(): + sendMsg += f'群聊ID: {roomId}\n群聊昵称: {roomName}\n---------------\n' + if not pushRoomData: + sendMsg = '暂无群聊开启推送服务' + self.wcf.send_text(sendMsg, receiver=sender) + + def showBlackRoom(self, sender): + """ + 查看黑名单群聊 超管有效 + :return: + """ + blackRoomData = self.Dms.showBlackRoom() + sendMsg = '===== 黑名单群聊列表 =====\n' + for roomId, roomName in blackRoomData.items(): + sendMsg += f'群聊ID: {roomId}\n群聊昵称: {roomName}\n---------------\n' + if not blackRoomData: + sendMsg = '暂无群聊添加至黑名单' + self.wcf.send_text(sendMsg, receiver=sender) + + def showWhiteRoom(self, sender): + """ + 查看白名单群聊 超管有效 + :return: + """ + whiteRoomData = self.Dms.showWhiteRoom() + sendMsg = '===== 白名单群聊列表 =====\n' + for roomId, roomName in whiteRoomData.items(): + sendMsg += f'群聊ID: {roomId}\n群聊昵称: {roomName}\n---------------\n' + if not whiteRoomData: + sendMsg = '暂无群聊添加至白名单' + self.wcf.send_text(sendMsg, receiver=sender) + + def forwardGhMsg(self, msgId): + """ + 转发公众号消息到推送群来哦 超管有效 + :param msgId: + :return: + """ + pushRoomDicts = self.Dms.showPushRoom() + for pushRoomId in pushRoomDicts.keys(): + self.wcf.forward_msg(msgId, receiver=pushRoomId) + + def customKeyWordMsg(self, sender, content): + """ + 自定义关键词消息回复 + :param sender: + :param content: + :return: + """ + for keyWord in self.customKeyWords.keys(): + if judgeEqualWord(content, keyWord): + replyMsgLists = self.customKeyWords.get(keyWord) + for replyMsg in replyMsgLists: + self.wcf.send_text(replyMsg, receiver=sender) + + def keyWordJoinRoom(self, sender, content): + """ + 关键词进群 + :param sender: + :param content: + :return: + """ + for keyWord in self.roomKeyWords.keys(): + if judgeEqualWord(content, keyWord): + roomLists = self.roomKeyWords.get(keyWord) + for roomId in roomLists: + roomMember = self.wcf.get_chatroom_members(roomId) + if len(roomMember) == 500: + continue + if sender in roomMember.keys(): + self.wcf.send_text(f'你小子已经进群了, 还想干吗[旺柴]', receiver=sender) + break + if self.wcf.invite_chatroom_members(roomId, sender): + op(f'[+]: 已将 {sender} 拉入群聊【{roomId}】') + break + else: + op(f'[-]: {sender} 拉入群聊【{roomId}】失败 !!!') + + def sendFriendMsg(self, content): + """ + 给好友发消息 只对超管生效 + :param content: + :return: + """ + wxId = content.split(' ')[1] + sendMsg = f'==== [爱心]来自超管的消息[爱心] ====\n\n{content.split(" ")[-1]}\n\n====== [爱心]NGCBot[爱心] ======' + self.wcf.send_text(sendMsg, receiver=wxId) + + def getAiMsg(self, content, sender): + """ + 好友Ai对话 + :param content: + :param sender: + :return: + """ + aiMsg = self.Ad.getAi(content) + if aiMsg: + self.wcf.send_text(aiMsg, receiver=sender) + return + self.wcf.send_text(f'Ai对话接口出现错误, 请稍后再试 ~~~', receiver=sender) + + def forwardMsgToAdministrators(self, wxId, content): + """ + 好友消息转发给超级管理员 + :param wxId: + :param content: + :return: + """ + forwardMsg = f"= [爱心]收到来自好友的消息[爱心] =\n好友ID: {wxId}\n好友昵称: {getIdName(self.wcf, wxId)}\n好友消息: {content}\n====== [爱心]NGCBot[爱心] ======" + for administrator in self.Administrators: + self.wcf.send_text(forwardMsg, receiver=administrator) + + +if __name__ == '__main__': + Fmh = FriendMsgHandle(1) + Fmh.showWhiteRoom() diff --git a/BotServer/MsgHandleServer/GhMsgHandle.py b/BotServer/MsgHandleServer/GhMsgHandle.py new file mode 100644 index 0000000..44da1be --- /dev/null +++ b/BotServer/MsgHandleServer/GhMsgHandle.py @@ -0,0 +1,7 @@ + +class GhMsgHandle: + def __init__(self): + """ + 公众号消息处理 + """ + pass \ No newline at end of file diff --git a/BotServer/MsgHandleServer/RoomMsgHandle.py b/BotServer/MsgHandleServer/RoomMsgHandle.py new file mode 100644 index 0000000..3080491 --- /dev/null +++ b/BotServer/MsgHandleServer/RoomMsgHandle.py @@ -0,0 +1,213 @@ +from BotServer.BotFunction.AdministratorFunction import AdministratorFunction +from BotServer.BotFunction.AdminFunction import AdminFunction +from BotServer.BotFunction.HappyFunction import HappyFunction +from BotServer.BotFunction.PointFunction import PointFunction +from BotServer.BotFunction.InterfaceFunction import * +from ApiServer.AiServer.AiDialogue import AiDialogue +from BotServer.BotFunction.JudgeFuncion import * +from DbServer.DbMainServer import DbMainServer +import Config.ConfigServer as Cs +from threading import Thread +import re + + +class RoomMsgHandle: + def __init__(self, wcf): + """ + 超级管理员功能 所有功能+管理员操作 + 管理员功能 积分功能+娱乐功能 + 白名单群聊功能 积分功能免费 + 黑名单群聊功能 所有功能无法使用 管理员以及超管除外 + 普通群聊功能 所有功能正常使用 + :param wcf: + """ + self.wcf = wcf + self.Ad = AiDialogue() + self.Dms = DbMainServer() + self.Hf = HappyFunction(self.wcf) + self.Pf = PointFunction(self.wcf) + self.Af = AdminFunction(self.wcf) + self.Asf = AdministratorFunction(self.wcf) + configData = Cs.returnConfigData() + self.Administrators = configData['Administrators'] + self.aiWenKeyWords = configData['functionKeyWord']['aiWenWord'] + self.aiWenPoint = configData['pointConfig']['functionPoint']['awIp'] + self.threatBookWords = configData['functionKeyWord']['threatBookWord'] + self.threatBookPoint = configData['pointConfig']['functionPoint']['wbIp'] + self.md5KeyWords = configData['functionKeyWord']['md5Words'] + self.md5Point = configData['pointConfig']['functionPoint']['md5'] + self.signKeyWord = configData['pointConfig']['sign']['word'] + self.searchPointKeyWord = configData['pointConfig']['queryPointWord'] + self.aiMsgPoint = configData['pointConfig']['functionPoint']['aiPoint'] + self.aiPicKeyWords = configData['functionKeyWord']['aiPic'] + self.aiPicPoint = configData['pointConfig']['functionPoint']['aiPicPoint'] + self.joinRoomMsg = configData['customMsg']['joinRoomMsg'] + self.joinRoomCardData = configData['customMsg']['JoinRoomCard'] + + def mainHandle(self, msg): + roomId = msg.roomid + sender = msg.sender + # 白名单群聊功能 + if judgeWhiteRoom(roomId): + # 超管功能以及管理功能 + self.AdminFunction(msg) + # 积分功能 + Thread(target=self.Pf.mainHandle, args=(msg,)).start() + # 娱乐功能 + Thread(target=self.Hf.mainHandle, args=(msg,)).start() + # 黑名单群聊功能 + elif judgeBlackRoom(roomId): + # 超管功能以及管理功能 + self.AdminFunction(msg) + # 超管和管理才能使用娱乐和积分功能 + if sender in self.Administrators or judgeAdmin(sender, roomId): + Thread(target=self.Asf.mainHandle, args=(msg,)).start() + Thread(target=self.Af.mainHandle, args=(msg,)).start() + # 推送群聊功能 + elif judgePushRoom(roomId): + # 超管功能以及管理功能 + self.AdminFunction(msg) + # 入群欢迎 + Thread(target=self.JoinRoomWelcome, args=(msg,)).start() + # 娱乐功能 和 积分功能 + Thread(target=self.HappyFunction, args=(msg,)).start() + + # 普通群聊功能 + else: + # 超管功能以及管理功能 + self.AdminFunction(msg) + # 娱乐功能 和 积分功能 + Thread(target=self.HappyFunction, args=(msg,)).start() + + def JoinRoomWelcome(self, msg): + """ + 进群欢迎 + :param msg: + :return: + """ + try: + ret = 1 + content = msg.content.strip() + wx_names = None + if '二维码' in content: + wx_names = re.search(r'"(?P.*?)"通过扫描', content) + elif '邀请' in content: + wx_names = re.search(r'邀请"(?P.*?)"加入了', content) + if wx_names: + wx_names = wx_names.group('wx_names') + if '、' in wx_names: + wx_names = wx_names.split('、') + else: + wx_names = [wx_names] + for wx_name in wx_names: + for roomIds, data in self.joinRoomCardData.items(): + roomIdLists = roomIds.split(',') + for roomId in roomIdLists: + if msg.roomid == roomId: + name = data.get('name') + account = data.get('account') + title = data.get('title').format(wx_name) + digest = data.get('digest') + url = data.get('url') + thumbUrl = data.get('thumbUrl') + ret = self.wcf.send_rich_text(name, account, title, digest, url, thumbUrl, roomId) + + if not ret: + joinRoomMsg = f'@{wx_name} ' + self.joinRoomMsg.replace("\\n", "\n") + self.wcf.send_text(msg=joinRoomMsg, receiver=msg.roomid) + except Exception as e: + pass + + def HappyFunction(self, msg): + """ + 娱乐功能 + :param msg: + :return: + """ + # 娱乐功能 + Thread(target=self.Hf.mainHandle, args=(msg,)).start() + # 超管和普通管理不需要积分调用积分功能 + if msg.sender in self.Administrators or judgeAdmin(msg.sender, msg.roomid): + # 积分功能 + Thread(target=self.Pf.mainHandle, args=(msg,)).start() + else: + # 普通用户需要积分调用此功能 + Thread(target=self.PointFunction, args=(msg.sender, msg.roomid, msg.content.strip(), msg)).start() + + def AdminFunction(self, msg): + """ + 超级管理员以及管理员功能 + :param msg: + :return: + """ + # 超级管理员功能 + if msg.sender in self.Administrators: + self.Asf.mainHandle(msg) + # 管理员功能 超管也可以调用 + if judgeAdmin(msg.sender, msg.roomid) or msg.sender in self.Administrators: + self.Af.mainHandle(msg) + + def PointFunction(self, sender, roomId, content, msg): + """ + 积分功能 需要积分充足使用, + 开发者必看: 如果加上积分功能 在后续的一系列调用链都要加上 + :param roomId: + :param sender: + :param content: + :param msg: + :return: + """ + atUserLists, noAtMsg = getAtData(self.wcf, msg) + senderPoint = self.Dms.searchPoint(sender, roomId) + lock = 0 + pointLock = 0 + # 埃文IPV4地址查询 + if judgeSplitAllEqualWord(content, self.aiWenKeyWords): + pointLock = 1 + if judgePointFunction(senderPoint, self.aiWenPoint): + self.Dms.reducePoint(sender, roomId, self.aiWenPoint) + lock = 1 + # 微步IPV4查询 + elif judgeSplitAllEqualWord(content, self.threatBookWords): + pointLock = 1 + if judgePointFunction(senderPoint, self.threatBookPoint): + self.Dms.reducePoint(sender, roomId, self.threatBookPoint) + lock = 1 + # CMD5查询 + elif judgeSplitAllEqualWord(content, self.md5KeyWords): + pointLock = 1 + if judgePointFunction(senderPoint, self.md5Point): + self.Dms.reducePoint(sender, roomId, self.md5Point) + lock = 1 + # Ai对话 + elif judgeAtMe(self.wcf.self_wxid, content, atUserLists) and not judgeOneEqualListWord(noAtMsg, + self.aiPicKeyWords): + pointLock = 1 + if judgePointFunction(senderPoint, self.aiMsgPoint): + self.Dms.reducePoint(sender, roomId, self.aiMsgPoint) + lock = 1 + # Ai画图 + elif judgeAtMe(self.wcf.self_wxid, content, atUserLists) and judgeOneEqualListWord(noAtMsg, self.aiPicKeyWords): + pointLock = 1 + if judgePointFunction(senderPoint, self.aiPicPoint): + self.Dms.reducePoint(sender, roomId, self.aiPicPoint) + lock = 1 + # 签到 + elif judgeEqualWord(content, self.signKeyWord): + pointLock = 1 + lock = 1 + # 签到口令提示 + elif judgeEqualWord(content, '签到'): + pointLock = 1 + lock = 1 + # 查询积分 + elif judgeEqualListWord(content, self.searchPointKeyWord): + pointLock = 1 + lock = 1 + if lock: + Thread(target=self.Pf.mainHandle, args=(msg,)).start() + else: + if pointLock: + self.wcf.send_text( + f'@{self.wcf.get_alias_in_chatroom(sender, roomId)} 积分不足, 请签到或祈求管理员施舍 ~~~', + receiver=roomId, aters=sender) diff --git a/BotServer/MsgHandleServer/__pycache__/FriendMsgHandle.cpython-38.pyc b/BotServer/MsgHandleServer/__pycache__/FriendMsgHandle.cpython-38.pyc new file mode 100644 index 0000000..e4f1802 Binary files /dev/null and b/BotServer/MsgHandleServer/__pycache__/FriendMsgHandle.cpython-38.pyc differ diff --git a/BotServer/MsgHandleServer/__pycache__/RoomMsgHandle.cpython-38.pyc b/BotServer/MsgHandleServer/__pycache__/RoomMsgHandle.cpython-38.pyc new file mode 100644 index 0000000..5110044 Binary files /dev/null and b/BotServer/MsgHandleServer/__pycache__/RoomMsgHandle.cpython-38.pyc differ diff --git a/BotServer/__pycache__/MainServer.cpython-38.pyc b/BotServer/__pycache__/MainServer.cpython-38.pyc new file mode 100644 index 0000000..8dc4b5d Binary files /dev/null and b/BotServer/__pycache__/MainServer.cpython-38.pyc differ diff --git a/Config/.DS_Store b/Config/.DS_Store new file mode 100644 index 0000000..5dce13b Binary files /dev/null and b/Config/.DS_Store differ diff --git a/Config/Config.yaml b/Config/Config.yaml new file mode 100644 index 0000000..2ea8126 --- /dev/null +++ b/Config/Config.yaml @@ -0,0 +1,561 @@ +## 超级管理员配置 +Administrators: + - 'wxid_7bizfilssbwi22' + +## 系统配置 +systemConfig: + # 版权信息 + systemCopyright: 'NGC660安全实验室' + # 好友Ai开关 + # 1开/0关 + aiLock: 0 + # 自动接收转账 + acceptMoneyLock: 1 + # 自动同意好友开关 + acceptFriendLock: 1 + +## 定时发送配置 +pushConfig: + # 早报推送时间 + morningPageTime: '08:30' + # 晚报发送时间设置 + eveningPageTime: '17:00' + # 下班推送时间设置 + offWorkTime: '18:00' + # 摸鱼日记推送时间设置 + fishTime: '10:00' + # KFC文案发送时间设置 每周四发送 + kfcTime: '11:50' + # 定时功能回复配置 + keyWord: + # 下班消息 换行用\n 支持微信表情 + offWorkMsg: '下班时间到!我要下班 我要下班 我要下班 下下下!\n到点即刻下班,给老板省去水电,给自己来套保健,给老板来句操蛋,出自: #NGC660安全实验室\n速速下班!!![旺柴]' + +## 进群关键词配置 +roomKeyWord: + 进群: + - '47442567074@chatroom' + - '47362882837@chatroom' + Bot交流群: + - '47442567074@chatroom' + - '47362882837@chatroom' + 开发者: + - '46017987363@chatroom' + +## 自定义关键词回复 +customKeyWord: + # 设置关键词 + '关键词1': + - '回复内容1' + - '回复内容2' + '关键词2': + - '回复内容1' + - '回复内容2' + +## 自定义各种消息 \n换行 +customMsg: + # 加好友后回复 + acceptFriendMsg: '你好, 我是久安信息技术有限公司旗下NGC660安全实验室开发的微信机器人, 你可以叫我NGCBot! 私聊我即可进行智能对话哦[爱心]~~~ ~~~' + # 进群欢迎词配置 换行用\n 支持微信表情 默认使用文本 卡片自己配置 + joinRoomMsg: '欢迎新进群的小可爱\n群主正在床上等你哦[爱心]~~~ ~~~' + # 进群欢迎词 卡片配置 + JoinRoomCard: + # 不同的Room需要不同配置 多个room加 , 即可 + '43064515504@chatroom,47442567074@chatroom,47362882837@chatroom,46017987363@chatroom': + # 左下角显示的名字 一般是公众号名称 + name: 'NGC660安全实验室' + # 填公众号ID 可以显示对应的头像 + account: 'gh_5fc2f516b008' + # 卡片消息标题 最多两行 + title: '欢迎 ❤{}❤ 一起搞机' + # 摘要 最多三行 + digest: '【NGCBot V2.1】新版本来袭!全新功能!全新架构!自动化私域管理必备!' + # 点击后跳转的URL + url: 'http://mp.weixin.qq.com/s?__biz=MzkyODMxODUwNQ==&mid=2247493526&idx=1&sn=d0f7675929a314941ad3845769bafdcb&chksm=c21832d0f56fbbc6c4451105df94e39283228e9f6bb69eae00888c4869f5b91e3703bd302e92&mpshare=1&scene=1&srcid=0716KB1OiULdPNzLUXmMVVlV&sharer_shareinfo=dd05c6b9c14d98dc6b745cbf673dabec&sharer_shareinfo_first=24b3af78c3e815a698c81c03a49a0244#rd' + # 缩略图的链接 到控制台输出拿 + thumbUrl: 'https://mmbiz.qpic.cn/mmbiz_jpg/QABjQccnicQpAnrqNicQd9iaTIQg3TZia6nr3OaAJQS8bOMrdtFct30axbiaO3OTnULGjHpE0RQD0NmT76FWa5daiaZA/300?wxtype=jpeg&wxfrom=401' +# 'roomId': +# # 左下角显示的名字 一般是公众号名称 +# name: 'NGC660安全实验室' +# # 填公众号ID 可以显示对应的头像 +# account: '' +# # 卡片消息标题 最多两行 +# title: '' +# # 摘要 最多三行 +# digest: '' +# # 点击后跳转的URL +# url: '' +# # 缩略图的链接 到控制台输出拿 +# thumbUrl: '' + + +## 管理功能关键词配置 +adminFunctionWord: + # 新增管理员关键词 + addAdminWord: + - '添加管理员' + - '添加管理' + - '新增管理员' + # 删除管理员关键词 + delAdminWord: + - '删除管理员' + - '删除管理' + - '移除管理员' + # 新增黑名单群聊关键词 + addBlackRoomWord: + - '拉黑群聊' + - '拉黑' + - '添加黑名单' + # 移出黑名单群聊关键词 + delBlackRoomWord: + - '解除拉黑' + - '移出黑名单' + # 查看白名单群聊关键词 + showWhiteRoomWord: + - '查看群聊' + - '查看白名单群聊' + # 查看黑名单群聊关键词 + showBlackRoomWord: + - '查看黑名单群聊' + - '查看拉黑群聊' + # 查看推送群聊关键词 + showPushRoomWord: + - '查看推送群聊' + - '查看广告群' + # 新增白名单群聊关键词 + addWhiteRoomWord: + - '拉白' + - '加白' + - '添加白名单' + # 移出白名单群聊关键词 + delWhiteRoomWord: + - '移出白名单' + - '移除白名单' + - '去白' + # 新增推送群聊关键词 + addPushRoomWord: + - '开启推送服务' + - '开启推送' + # 移除推送群聊关键词 + delPushRoomWord: + - '关闭推送服务' + - '关闭推送' + # 添加黑名单公众号 + addBlackGhWord: + - '黑号' + - '拉黑' + # 移除黑名单公众号 + delBlackGhWord: + - '移除拉黑' + - '移除' + - '移出' + # 查看黑名单公众号 + showBlackGhWord: + - '查看拉黑公众号' + - '拉黑公众号' + - '拉黑公号' + # 踢人关键词 + delUserWord: + - '滚蛋' + - '滚' + - '踢出' + - '踢' + - '滚出去' + - '移出' + # 给好友发消息关键词 + sendMsgWord: + - '发' + - '发送' + + +## 积分功能配置 +pointConfig: + # 签到功能 + sign: + # 签到口令 + word: '签到: 久安信息技术有限公司承接各类安全服务' + # 签到积分 + point: '10' + # 功能积分配置 + functionPoint: + # Md5积分配置 + md5: '10' + # 微步IP查询积分配置 + wbIp: '10000' + # 埃文IP地址查询配置 + awIp: '10000' + # Ai对话积分配置 + aiPoint: '10' + # Ai画图配置 + aiPicPoint: '10' + # 增加积分关键词 + addPointWord: + - '加' + - '+' + - '加积分' + - '增' + # 减少积分关键词 + delPointWord: + - '减' + - '-' + - '扣除' + - '扣' + # 积分查询关键词 + queryPointWord: + - '积分查询' + - '查询积分' + +## 其它功能关键词配置 +functionKeyWord: + # 触发美女图片关键词 + picWord: + - '图片' + - '美女图片' + - '妹子' + - '色图' + - '色色' + # 触发美女视频关键词 + videoWord: + - '视频' + - '美女视频' + - '成人视频' + - '18禁' + # 触发摸鱼日记关键词 + fishWord: + - '摸鱼日记' + - '摸鱼日历' + # 触发疯狂星期四文案关键词 + kfcWord: + - 'Kfc' + - '疯狂星期四' + - '星期四' + - '今天星期四' + - 'KFC' + - 'kfc' + - 'v我50' + - '明天星期四' + # 触发舔狗日记关键词 + dogWord: + - '舔狗日记' + - '舔我' + # 触发微步IP查询关键词 + threatBookWord: + - 'ip查询' + - 'IP查询' + - '查询ip' + - '查询IP' + - '微步查询' + # 触发埃文IP地址查询关键词 + aiWenWord: + - 'ip定位' + - '溯源' + - '定位' + # 触发早报关键词 + morningPageWord: + - '早报' + - '早间咨询' + # 触发晚报关键词 + eveningPageWord: + - '晚报' + - '晚间咨询' + # MD5解密关键词 + md5Words: + - 'md5解密' + - 'MD5解密' + - 'md5查询' + - 'Md5查询' + - 'MD5查询' + # 帮助菜单 + helpMenu: + - '帮助' + - 'help' + - 'Help' + - 'HELP' + - '帮助菜单' + - '菜单' + # Ai画图关键词 + aiPic: + - '画' + - '画一个' + +## API接口服务配置 +apiServer: + apiConfig: + # cmd5Email + cmd5Email: '' + # cmd5 Key + cmd5Key: '' + # 微步Key + threatBookKey: '' + # 埃文Key + aiWenKey: '' + # 高德 Key + gaoDeKey: '' + # 天行Key + txKey: '' + aiConfig: + # Ai优先级 + # 修改序号即可修改优先对话模型 + aiPriority: + 1: 'hunYuan' + 2: 'sparkAi' + 3: 'openAi' + 4: 'qianFan' + # 画图Ai优先级 + aiPicPriority: + 1: 'sparkAi' + 2: 'qianFan' + # Ai角色配置 + systemAiRule: '你叫NGCBot, 你的主人是云山, 你隶属于久安信息技术有限公司旗下NGC660安全实验室, 是一名网络安全专家' + # 星火大模型 4.0 Ultra模型 + 图像生成模型 + sparkApi: + # 模型Url + sparkAiApi: 'wss://spark-api.xf-yun.com/v4.0/chat' + # 模型Secret + sparkAiSecret: '' + # 模型版本 + sparkDomain: '4.0Ultra' + # 模型Key + sparkAiKey: '' + # 模型Appid + sparkAiAppid: '' + # OpenAi 3.5模型 + openAi: + # Open_Ai接口 + openAiApi: 'https://api.xiaoai.plus/v1/chat/completions' + # OpenAi Key Bearer留着 + openAiKey: 'Bearer sk-' + # 千帆大模型 ERNIE-4.0-Turbo-8K模型 + qianFan: + # 应用中的Api Key + qfAccessKey: '' + # 应用中的Secret Key + qfSecretKey: '' + # 应用中的应用ID + qfAppid: '' + # 千帆Ai作画Api 两个key是不一样的 不能通用 + # https://console.bce.baidu.com/ai/#/ai/intelligentwriting/app/detail~appId=5507940 + # 应用中的Api Key + qfPicAccessKey: '' + # 应用中的Secret Key + qfPicSecretKey: '' + # 应用中的应用ID + qfPicAppid: '' + # 腾讯混元大模型, 有免费额度 + hunYuan: + # 腾讯云SecretId + hunYuanSecretId: '' + # 腾讯云SecretKey + hunYuanSecretKey: '' + + # 微步查询API + threatBookApi: 'https://api.threatbook.cn/v3/ip/query' + # 高德地图API + gaoDeApi: 'https://restapi.amap.com/v3/staticmap' + # 埃文IP地址查询API + aiWenApi: 'https://api.ipplus360.com/ip/geo/v1/street/biz/' + + # 舔狗日记API + dogApi: 'https://apis.tianapi.com/tiangou/index?key={}' + # 摸鱼日记API + fishApi: 'https://api.vvhan.com/api/moyu' + # 疯狂星期四文案Api + kfcApi: 'https://api.pearktrue.cn/api/kfc' + # Cmd5解密Api配置 + cmd5Api: 'http://www.cmd5.com/api.ashx?email={}&key={}&hash={}' + # 图片API配置 + picApi: + - 'https://api.btstu.cn/sjbz/api.php?lx=dongman&format=images&method=mobile&lx=meizi' + - 'http://3650000.xyz/api/' + - 'https://cdn.seovx.com/?mom=302' + - 'https://tuapi.eees.cc/api.php?category=meinv&px=m&type=302' + # 视频API配置 + videosApi: + - 'http://api.yujn.cn/api/heisis.php' + - 'http://api.yujn.cn/api/xjj.php' + - 'http://api.yujn.cn/api/zzxjj.php' + - 'https://api.yujn.cn/api/manzhan.php' + - 'http://api.yujn.cn/api/rewu.php?type=video' + - 'http://api.ovoe.top/API/hbss.php' + - 'http://abc.gykj.asia/API/hbss.php' + - 'https://api.qtkj.love/api/hbss.php' + - 'http://api.yujn.cn/api/hanfu.php?type=video' + - 'http://abc.gykj.asia/API/gzhf.php' + - 'http://www.yujn.cn/api/heisis.php' + - 'http://api.yujn.cn/api/manyao.php?type=video' + - 'https://api.shenke.love/api/mnsp.php?msg=my&type=video' + - 'http://api.yujn.cn/api/COS.php?type=video' + - 'http://abc.gykj.asia/API/ntCOS.php' + - 'http://api.yujn.cn/api/jksp.php?type=video' + +# 表情包关键词配置,跟官网的相匹配,同时删减一些默认表情 +# https://github.com/MeetWq/meme-generator/wiki/%E8%A1%A8%E6%83%85%E5%88%97%E8%A1%A8 +emoConfig: + emoHelp: + - '表情帮助' + - '表情菜单' + - '表情列表' + emoKeyWord: + - '表情' + - '表情包' + emoRandomKeyWord: + - '随机表情' + onePicEmo: + '跟我去二次元': 'acg_entrance' + '添乱': 'add_chaos' + '上瘾': 'addiction' + '一样': 'alike' + '永远喜欢': 'always_like' + '诱拐': 'anti_kidnap' + '阿尼亚喜欢': 'anya_suki' + '鼓掌': 'applaud' + '打工人': 'back_to_work' + '拍头': 'beat_head' + '啃': 'bite' + '高血压': 'blood_pressure' + '手稿': 'bocchi_draft' + '奶茶': 'bubble_tea' + '草神': 'caoshen_bite' + '画': 'capoo_draw' + '撕': 'rip' + '咖波撕': 'capoo_rip' + '蹭': 'capoo_rub' + '撞': 'capoo_strike' + '字符画': 'charpic' + '追': 'chase_train' + '国旗': 'china_flag' + '小丑': 'clown' + '迷惑': 'confuse' + '兑奖': 'coupon' + '捂脸': 'cover_face' + '爬': 'crawl' + '亲亲': 'decent_kiss' + '典': 'dianzhongdian' + '恐龙': 'dinosaur' + '涣散': 'distracted' + '离婚协议': 'divorce' + '狗都不玩': 'dog_dislike' + '痴': 'dog_of_vtb' + '不要靠近': 'dont_go_near' + '别碰': 'dont_touch' + '吃': 'eat' + '要上吗': 'fight_with_sunuo' + '满脑子': 'fill_head' + '闪瞎': 'flash_blind' + '关注': 'follow' + '拿': 'frieren_take' + '哈哈镜': 'funny_mirror' + '垃圾桶': 'garbage' + '启动': 'genshin_start' + '鬼畜': 'guichu' + '手枪': 'gun' + '锤': 'hammer' + '打穿': 'hit_screen' + '抱紧': 'hold_tight' + '抱大腿': 'hug_leg' + '胡桃啃': 'hutao_bite' + '不文明': 'incivilization' + '采访': 'interview' + '急急国王': 'jiji_king' + '啾啾': 'jiujiu' + '跳': 'jump' + '万花筒': 'kaleidoscope' + '指': 'karyl_point' + '远离': 'keep_away' + '踢球': 'kick_ball' + '卡比锤': 'kirby_hammer' + '可莉吃': 'klee_eat' + '敲': 'knock' + '偷学': 'learn' + '横跳': 'left_right_jump' + '让我进去': 'let_me_in' + '无穷小': 'lim_x_0' + '听音乐': 'listen_music' + '小天使': 'little_angel' + '加载中': 'loading' + '看扁': 'look_flat' + '看图标': 'look_this_icon' + '循环': 'loop' + '寻狗启示': 'lost_dog' + '永远爱你': 'love_you' + '交个朋友': 'make_friend' + '结婚申请': 'marriage' + '上香': 'mourning' + '我朋友说': 'my_friend' + '我老婆': 'my_wife' + '需要': 'need' + '无响应': 'no_response' + '请假条': 'note_for_leave' + 'out': 'out' + '加班': 'overtime' + '这像画吗': 'paint' + '小画家': 'painter' + '拍': 'pat' + '完美': 'perfect' + '摸': 'petpet' + '捏': 'pinch' + '顶': 'play' + '玩游戏': 'play_game' + '一起玩': 'play_together' + '出警': 'police' + '警察': 'police1' + '搞': 'pound' + '打印': 'printing' + '舔': 'prpr' + '打拳': 'punch' + '举': 'raise_image' + '看书': 'read_book' + '怒撕': 'rip_angrily' + '诈尸': 'rise_dead' + '滚': 'roll' + '三维旋转': 'rotate_3d' + '快逃': 'run_away' + '安全感': 'safe_sense' + '挠头': 'scratch_head' + '刮刮乐': 'scratchcard' + '震惊': 'shock' + '坐的住': 'sit_still`' + '砸': 'smash' + '踩': 'step_on' + '炖': 'stew' + '科目三': 'subject3' + '吸': 'suck' + '精神支柱': 'support' + '回旋转': 'swirl_turn' + '嘲讽': 'taunt' + '唐可可举牌': 'tankuku_raisesign' + '讲课': 'teach' + '拿捏': 'tease' + '望远镜': 'telescope' + '想什么': 'think_what' + '这是鸡': 'this_chicken' + '丢': 'throw' + '抛': 'throw_gif' + '捶': 'thump' + '锤爆': 'thump_wildly' + '紧贴': 'tightly' + '一起': 'together' + '嘲笑': 'tom_tease' + '上坟': 'tomb_yeah' + '恍惚': 'trance' + '转': 'turn' + '搓': 'twist' + '震动': 'vibrate' + '墙纸': 'wallpaper' + '胡桃平板': 'walnut_pad' + '胡桃放大': 'walnut_zoom' + '洗衣机': 'washer' + '波纹': 'wave' + '我想上的': 'what_I_want_to_do' + '最想要的东西': 'what_he_wants' + '为什么@我': 'why_at_me' + '为什么要有手': 'why_have_hands' + '风车转': 'windmill_turn' + '木鱼': 'wooden_fish' + '膜拜': 'worship' + '致电': 'you_should_call' + twoPicEwo: + '揍': 'beat_up' + '击剑': 'fencing' + '亲': 'kiss' + '贴贴': 'rub' \ No newline at end of file diff --git a/Config/ConfigServer.py b/Config/ConfigServer.py new file mode 100644 index 0000000..63eeedd --- /dev/null +++ b/Config/ConfigServer.py @@ -0,0 +1,40 @@ +import yaml +import os + + +def returnConfigPath(): + """ + 返回配置文件夹路径 + :return: + """ + current_path = os.path.dirname(__file__) + current_list_path = current_path.split('\\')[0:-1] + configPath = '/'.join(current_list_path) + '/Config/' + return configPath + + +def returnConfigData(): + """ + 返回配置文件数据(YAML格式) + :return: + """ + current_path = returnConfigPath() + configData = yaml.load(open(current_path + '/Config.yaml', mode='r', encoding='UTF-8'), yaml.Loader) + return configData + + +def returnUserDbPath(): + return returnConfigPath() + 'User.db' + + +def returnRoomDbPath(): + return returnConfigPath() + 'Room.db' + + +def returnGhDbPath(): + return returnConfigPath() + 'Gh.db' + +def returnPointDbPath(): + return returnConfigPath() + 'Point.db' + + diff --git a/Config/__pycache__/ConfigServer.cpython-38.pyc b/Config/__pycache__/ConfigServer.cpython-38.pyc new file mode 100644 index 0000000..7e5d776 Binary files /dev/null and b/Config/__pycache__/ConfigServer.cpython-38.pyc differ diff --git a/DbServer/DbDomServer.py b/DbServer/DbDomServer.py new file mode 100644 index 0000000..396bb0e --- /dev/null +++ b/DbServer/DbDomServer.py @@ -0,0 +1,12 @@ +import sqlite3 + + +def openDb(dbPath, ): + conn = sqlite3.connect(database=dbPath, ) + cursor = conn.cursor() + return conn, cursor + + +def closeDb(conn, cursor): + cursor.close() + conn.close() \ No newline at end of file diff --git a/DbServer/DbGhServer.py b/DbServer/DbGhServer.py new file mode 100644 index 0000000..5c42e25 --- /dev/null +++ b/DbServer/DbGhServer.py @@ -0,0 +1,138 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbGhServer: + def __init__(self): + pass + + def addWhiteGh(self, ghId, ghName): + """ + 添加白名单公众号 + :param ghName: + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('INSERT INTO whiteGh VALUES (?, ?)', (ghId, ghName)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 添加白名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delWhiteGh(self, ghId): + """ + 删除白名单公众号 + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('SELECT ghId FROM whiteGh WHERE ghId=?', (ghId,)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除白名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchWhiteGh(self, ghId): + """ + 查询白名单公众号 + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('SELECT ghId FROM whiteGh WHERE ghId=?', (ghId,)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result + else: + return '' + except Exception as e: + op(f'[-]: 查询白名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return '' + + def addBlackGh(self, ghId, ghName): + """ + 添加黑名单公众号 + :param ghName: + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('INSERT INTO blackGh VALUES (?, ?)', (ghId, ghName)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 添加黑名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delBlackGh(self, ghId): + """ + 删除黑名单公众号 + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('SELECT ghId FROM blackGh WHERE ghId=?', (ghId,)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除黑名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchBlackGh(self, ghId): + """ + 查询黑名单公众号 + :param ghId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnGhDbPath()) + try: + cursor.execute('SELECT ghId FROM blackGh WHERE ghId=?', (ghId,)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result + else: + return '' + except Exception as e: + op(f'[-]: 查询黑名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return '' + + def showBlackGh(self, ): + """ + 查看所有黑名单公众号 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + dataDict = dict() + try: + cursor.execute('SELECT ghId, ghName FROM blackGh') + result = cursor.fetchall() + Dds.closeDb(conn, cursor) + if result: + for res in result: + dataDict[res[0]] = res[1] + return dataDict + except Exception as e: + op(f'[-]: 查看黑名单公众号出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return dataDict diff --git a/DbServer/DbInitServer.py b/DbServer/DbInitServer.py new file mode 100644 index 0000000..88c4fd4 --- /dev/null +++ b/DbServer/DbInitServer.py @@ -0,0 +1,59 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbInitServer: + def __init__(self): + self.userDb = Cs.returnUserDbPath() + self.pointDb = Cs.returnPointDbPath() + self.roomDb = Cs.returnRoomDbPath() + self.ghDb = Cs.returnGhDbPath() + + def createTable(self, cursor, table_name, columns): + """ + :param table_name: 要创建的表名 + :param columns: 要创建的字段名 要符合SQL语法 + :return: + """ + try: + cursor.execute( + f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})" + ) + return True + except Exception as e: + op(f'[-]: 创建数据表出现错误, 错误信息: {e}') + return False + + def initDb(self, ): + # 初始化用户数据库 用户表 管理员表 + userConn, userCursor = Dds.openDb(self.userDb) + self.createTable(userCursor, 'User', 'wxId varchar(255), wxName varchar(255)') + self.createTable(userCursor, 'Admin', 'wxId varchar(255), roomId varchar(255)') + Dds.closeDb(userConn, userCursor) + + # 初始化积分数据库 积分数据表 签到表 + pointConn, pointCursor = Dds.openDb(self.pointDb) + self.createTable(pointCursor, 'Point', 'wxId varchar(255), roomId varchar(255), poInt int(32)') + self.createTable(pointCursor, 'Sign', 'wxId varchar(255), roomId varchar(255)') + Dds.closeDb(pointConn, pointCursor) + + # 初始化群聊数据库 黑名单群聊数据表 白名单群聊数据表 推送群聊数据表 所有群聊数据表 + roomConn, roomCursor = Dds.openDb(self.roomDb) + self.createTable(roomCursor, 'whiteRoom', 'roomId varchar(255), roomName varchar(255)') + self.createTable(roomCursor, 'blackRoom', 'roomId varchar(255), roomName varchar(255)') + self.createTable(roomCursor, 'pushRoom', 'roomId varchar(255), roomName varchar(255)') + self.createTable(roomCursor, 'Room', 'roomId varchar(255), roomName varchar(255)') + Dds.closeDb(roomConn, roomCursor) + + # 初始化公众号数据库 白名单公众号 黑名单公众号 + ghConn, ghCursor = Dds.openDb(self.ghDb) + self.createTable(ghCursor, 'whiteGh', 'ghId varchar(255), ghName varchar(255)') + self.createTable(ghCursor, 'blackGh', 'ghId varchar(255), ghName varchar(255)') + Dds.closeDb(ghConn, ghCursor) + op(f'[+]: 数据库初始化成功!!!') + + +if __name__ == '__main__': + Dis = DbInitServer() + Dis.initDb() diff --git a/DbServer/DbMainServer.py b/DbServer/DbMainServer.py new file mode 100644 index 0000000..8e68b3c --- /dev/null +++ b/DbServer/DbMainServer.py @@ -0,0 +1,333 @@ +from DbServer.DbPointServer import DbPointServer +from DbServer.DbUserServer import DbUserServer +from DbServer.DbRoomServer import DbRoomServer +from DbServer.DbSignServer import DbSignServer +from DbServer.DbInitServer import DbInitServer +from DbServer.DbGhServer import DbGhServer +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbMainServer: + def __init__(self): + self.Dps = DbPointServer() + self.Dus = DbUserServer() + self.Drs = DbRoomServer() + self.Dss = DbSignServer() + self.Dis = DbInitServer() + self.Dgs = DbGhServer() + self.configData = Cs.returnConfigData() + + def initUser(self, wxId, roomId, ): + """ + 初始化数据库用户 + :param wxId: + :param roomId: + :return: + """ + # 初始化积分数据库用户 + try: + if not self.Dps.searchPointUser(wxId=wxId, roomId=roomId): + self.Dps.initUserPoint(wxId=wxId, roomId=roomId) + except Exception as e: + op(f'[-]: 初始化积分数据库用户出现错误, 错误信息: {e}') + + def addPoint(self, wxId, roomId, point): + """ + 增加用户积分 + :param wxId: + :param roomId: + :param point: + :return: + """ + try: + self.initUser(wxId=wxId, roomId=roomId) + if self.Dps.addPoint(wxId=wxId, roomId=roomId, point=point): + return True + return False + except Exception as e: + op(f'[-]: 增加用户积分出现错误, 错误信息: {e}') + + def reducePoint(self, wxId, roomId, point): + """ + 扣除用户积分 + :param wxId: + :param roomId: + :param point: + :return: + """ + try: + self.initUser(wxId=wxId, roomId=roomId) + if self.Dps.reducePoint(wxId=wxId, roomId=roomId, point=point): + return True + return False + except Exception as e: + op(f'[-]: 扣除用户积分出现错误, 错误信息: {e}') + + def searchPoint(self, wxId, roomId): + """ + 查询用户积分 + :param wxId: + :param roomId: + :return: + """ + try: + self.initUser(wxId=wxId, roomId=roomId) + userPoint = self.Dps.searchUserPoint(wxId=wxId, roomId=roomId) + return userPoint + except Exception as e: + op(f'[-]: 查询用户积分出现错误, 错误信息: {e}') + return False + + def sign(self, wxId, roomId): + """ + 签到 + :param wxId: + :param roomId: + :return: + """ + try: + self.initUser(wxId, roomId) + signPoint = self.configData['pointConfig']['sign']['point'] + if not self.Dss.searchSignUser(wxId=wxId, roomId=roomId): + if self.Dss.addSignUser(wxId=wxId, roomId=roomId): + self.addPoint(wxId=wxId, roomId=roomId, point=signPoint) + return True + return False + except Exception as e: + op(f'[-]: 签到功能出现错误, 错误信息: {e}') + return False + + def clearSign(self, ): + """ + 清除签到表 + :return: + """ + try: + if self.Dss.clearSign(): + return True + return False + except Exception as e: + op(f'[-]: 清除签到表出现错误, 错误信息: {e}') + return False + + def addAdmin(self, wxId, roomId): + """ + 添加管理员 + :param wxId: + :param roomId: + :return: + """ + try: + if not self.Dus.searchAdmin(wxId, roomId): + return self.Dus.addAdmin(wxId, roomId) + op(f'[-]: 添加管理员出现错误, 错误信息: 当前管理员已存在') + return False + except Exception as e: + op(f'[-]: 添加管理员出现错误, 错误信息: {e}') + return False + + def delAdmin(self, wxId, roomId): + """ + 删除管理员 + :param wxId: + :param roomId: + :return: + """ + try: + return self.Dus.delAdmin(wxId, roomId) + except Exception as e: + op(f'[-]: 删除管理员出现错误, 错误信息: {e}') + return False + + def searchAdmin(self, wxId, roomId): + """ + 搜索管理员 + :param wxId: + :param roomId: + :return: + """ + try: + return self.Dus.searchAdmin(wxId, roomId) + except Exception as e: + op(f'[-]: 搜索管理员出现错误, 错误信息: {e}') + return False + + def addWhiteRoom(self, roomId, roomName): + """ + 添加白名单群聊 + :param roomName: + :param roomId: + :return: + """ + try: + if not self.Drs.searchWhiteRoom(roomId=roomId): + if self.Drs.addWhiteRoom(roomId, roomName): + return True + return False + except Exception as e: + op(f'[-]: 添加白名单群聊出现错误, 错误信息: {e}') + return False + + def delWhiteRoom(self, roomId): + """ + 移出白名单群聊 + :param roomId: + :return: + """ + try: + return self.Drs.delWhiteRoom(roomId=roomId) + except Exception as e: + op(f'[-]: 移出白名单群聊出现错误, 错误信息: {e}') + return False + + def showWhiteRoom(self, ): + """ + 查看所有白名单群聊 + :return: + """ + try: + return self.Drs.showWhiteRoom() + except Exception as e: + op(f'[-]: 查看所有白名单群聊出现错误, 错误信息: {e}') + return dict() + + def searchWhiteRoom(self, roomId): + """ + 搜索白名单群聊 + :return: + """ + try: + return self.Drs.searchWhiteRoom(roomId) + except Exception as e: + op(f'[-]: 搜索白名单群聊出现错误, 错误信息: {e}') + return False + + def addBlackRoom(self, roomId, roomName): + """ + 添加黑名单群聊 + :param roomName: + :param roomId: + :return: + """ + try: + if not self.Drs.searchBlackRoom(roomId=roomId): + if self.Drs.addBlackRoom(roomId, roomName): + return True + return False + except Exception as e: + op(f'[-]: 添加黑名单群聊出现错误, 错误信息: {e}') + return False + + def delBlackRoom(self, roomId): + """ + 移出黑名单群聊 + :param roomId: + :return: + """ + try: + return self.Drs.delBlackRoom(roomId=roomId) + except Exception as e: + op(f'[-]: 移出黑名单群聊出现错误, 错误信息: {e}') + return False + + def showBlackRoom(self, ): + """ + 查看所有黑名单群聊 + :return: + """ + try: + return self.Drs.showBlackRoom() + except Exception as e: + op(f'[-]: 查看所有黑名单群聊出现错误, 错误信息: {e}') + return dict() + + def searchBlackRoom(self, roomId): + """ + 搜索黑名单群聊 + :return: + """ + try: + return self.Drs.searchBlackRoom(roomId) + except Exception as e: + op(f'[-]: 搜索黑名单群聊出现错误, 错误信息: {e}') + return False + + def addPushRoom(self, roomId, roomName): + """ + 添加推送群聊 + :param roomName: + :param roomId: + :return: + """ + try: + if not self.Drs.searchPushRoom(roomId=roomId): + if self.Drs.addPushRoom(roomId, roomName): + return True + return False + except Exception as e: + op(f'[-]: 添加推送群聊出现错误, 错误信息: {e}') + return False + + def delPushRoom(self, roomId): + """ + 移出推送群聊 + :param roomId: + :return: + """ + try: + return self.Drs.delPushRoom(roomId=roomId) + except Exception as e: + op(f'[-]: 移出推送群聊出现错误, 错误信息: {e}') + return False + + def showPushRoom(self, ): + """ + 查看所有推送群聊 + :return: + """ + try: + return self.Drs.showPushRoom() + except Exception as e: + op(f'[-]: 查看所有推送群聊出现错误, 错误信息: {e}') + return dict() + + def addBlackGh(self, ghId, ghName): + """ + 添加黑名单公众号 + :return: + """ + try: + return self.Dgs.addBlackGh(ghId=ghId, ghName=ghName) + except Exception as e: + op(f'[-]: 添加黑名单公众号出现错误, 错误信息: {e}') + return False + + def delBlackGh(self, ghId): + """ + 删除黑名单公众号 + :param ghId: + :return: + """ + try: + return self.Dgs.delBlackGh(ghId, ) + except Exception as e: + op(f'[-]: 移出黑名单公众号出现错误, 错误信息: {e}') + return False + + def showBlackGh(self, ): + """ + 查看黑名单群聊 + :return: + """ + try: + return self.Dgs.showBlackGh() + except Exception as e: + op(f'[-]: 查看黑名单公众号出现错误, 错误信息: {e}') + return dict() + + +if __name__ == '__main__': + Ds = DbMainServer() + # print(Ds.clearSign()) + print(Ds.searchPoint('sender', 'roomid')) \ No newline at end of file diff --git a/DbServer/DbPointServer.py b/DbServer/DbPointServer.py new file mode 100644 index 0000000..27f1fcf --- /dev/null +++ b/DbServer/DbPointServer.py @@ -0,0 +1,106 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbPointServer: + def __init__(self): + pass + + def addPoint(self, wxId, roomId, point): + """ + 增加积分 + :param wxId: 微信ID + :param roomId 群聊ID + :param point: 积分 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute(f'UPDATE Point SET point=point+{int(point)} WHERE wxId=? AND roomId=?', (wxId, roomId)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 查询积分出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def reducePoint(self, wxId, roomId, point): + """ + 扣除积分 + :param wxId: 微信ID + :param roomId 群聊ID + :param point:积分 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute(f'UPDATE Point SET point=point-{int(point)} WHERE wxId=? AND roomId=?', (wxId, roomId)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 扣除积分出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchPointUser(self, wxId, roomId): + """ + 查询用户是否在积分数据库 + :param wxId: + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('SELECT wxId FROM Point WHERE wxId=? AND roomId=?', (wxId, roomId)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result[0] + else: + return False + except Exception as e: + op(f'[-]: 查询积分出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchUserPoint(self, wxId, roomId): + """ + 查询积分 + :param wxId: 微信ID + :param roomId 群聊ID + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('SELECT poInt FROM Point WHERE wxId=? AND roomId=?', (wxId, roomId)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result[0] + else: + return False + except Exception as e: + op(f'[-]: 查询积分出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def initUserPoint(self, wxId, roomId): + """ + 初始化积分数据库用户 + :param wxId: + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('INSERT INTO Point VALUES (?, ?, ?)', (wxId, roomId, 0)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 初始化积分数据库用户出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False diff --git a/DbServer/DbRoomServer.py b/DbServer/DbRoomServer.py new file mode 100644 index 0000000..69b5733 --- /dev/null +++ b/DbServer/DbRoomServer.py @@ -0,0 +1,232 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbRoomServer: + def __init__(self): + pass + + def addWhiteRoom(self, roomId, roomName): + """ + 新增白名单群聊 + :param roomName: + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('INSERT INTO whiteRoom VALUES (?, ?)', (roomId, roomName)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 新增白名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delWhiteRoom(self, roomId): + """ + 删除白名单群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('DELETE FROM whiteRoom WHERE roomId=?', (roomId,)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除白名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchWhiteRoom(self, roomId): + """ + 查询白名单群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('SELECT roomName FROM whiteRoom WHERE roomId=?', (roomId,)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return True + return False + except Exception as e: + op(f'[-]: 查询白名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def showWhiteRoom(self, ): + """ + 查看所有白名单群聊 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + dataDict = dict() + try: + cursor.execute('SELECT roomId, roomName FROM whiteRoom') + result = cursor.fetchall() + Dds.closeDb(conn, cursor) + if result: + for res in result: + dataDict[res[0]] = res[1] + return dataDict + except Exception as e: + op(f'[-]: 查看所有白名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return dataDict + + def addBlackRoom(self, roomId, roomName): + """ + 新增黑名单群聊 + :param roomName: + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('INSERT INTO blackRoom VALUES (?, ?)', (roomId, roomName)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 新增黑名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delBlackRoom(self, roomId): + """ + 删除黑名单群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('DELETE FROM blackRoom WHERE roomId=?', (roomId,)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除黑名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchBlackRoom(self, roomId): + """ + 查询黑名单群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('SELECT roomName FROM blackRoom WHERE roomId=?', (roomId,)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result + else: + return False + except Exception as e: + op(f'[-]: 查询黑名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def showBlackRoom(self, ): + """ + 查看所有黑名单群聊 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + dataDict = dict() + try: + cursor.execute('SELECT roomId, roomName FROM blackRoom') + result = cursor.fetchall() + Dds.closeDb(conn, cursor) + if result: + for res in result: + dataDict[res[0]] = res[1] + return dataDict + except Exception as e: + op(f'[-]: 查看所有黑名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return dataDict + + def addPushRoom(self, roomId, roomName): + """ + 新增推送群聊 + :param roomName: + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('INSERT INTO pushRoom VALUES (?, ?)', (roomId, roomName)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 新增推送群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delPushRoom(self, roomId): + """ + 删除推送群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('DELETE FROM pushRoom WHERE roomId=?', (roomId,)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除推送群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchPushRoom(self, roomId): + """ + 查询推送群聊 + :param roomId: + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + try: + cursor.execute('SELECT roomName FROM pushRoom WHERE roomId=?', (roomId,)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return result + else: + return False + except Exception as e: + op(f'[-]: 查询推送群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def showPushRoom(self, ): + """ + 查看所有推送群聊 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnRoomDbPath()) + dataDict = dict() + try: + cursor.execute('SELECT roomId, roomName FROM pushRoom') + result = cursor.fetchall() + Dds.closeDb(conn, cursor) + if result: + for res in result: + dataDict[res[0]] = res[1] + return dataDict + except Exception as e: + op(f'[-]: 查看所有黑名单群聊出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return dataDict diff --git a/DbServer/DbSignServer.py b/DbServer/DbSignServer.py new file mode 100644 index 0000000..de042ce --- /dev/null +++ b/DbServer/DbSignServer.py @@ -0,0 +1,63 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbSignServer: + def __init__(self): + """ + 签到的增删 + """ + + def searchSignUser(self, wxId, roomId): + """ + 查找签到人 + :param wxId: 微信ID + :param roomId 群聊ID + :return: True False + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('SELECT wxId FROM Sign WHERE wxId=? AND roomId=?', (wxId, roomId)) + result = cursor.fetchone() + if result: + return True + else: + return False + except Exception as e: + op(f'[-]: 查找签到人出现错误, 错误信息: {e}') + return False + + def addSignUser(self, wxId, roomId): + """ + 新增签到人 + :param wxId: 微信ID + :param roomId 群聊ID + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('INSERT INTO Sign VALUES (?, ?)', (wxId, roomId)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + Dds.closeDb(conn, cursor) + op(f'[-]: 新增签到人出现错误, 错误信息: {e}') + return False + + def clearSign(self, ): + """ + 清除签到表 + :return: + """ + conn, cursor = Dds.openDb(Cs.returnPointDbPath()) + try: + cursor.execute('DELETE FROM Sign') + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + Dds.closeDb(conn, cursor) + op(f'[-]: 清除签到表出现错误, 错误信息: {e}') + return False diff --git a/DbServer/DbUserServer.py b/DbServer/DbUserServer.py new file mode 100644 index 0000000..28ccbdf --- /dev/null +++ b/DbServer/DbUserServer.py @@ -0,0 +1,65 @@ +import DbServer.DbDomServer as Dds +import Config.ConfigServer as Cs +from OutPut.outPut import op + + +class DbUserServer: + def __init__(self): + pass + + def addAdmin(self, wxId, roomId): + """ + 增加管理员 + :param wxId: 微信ID + :param roomId: 群聊ID + :return: + """ + conn, cursor = Dds.openDb(Cs.returnUserDbPath()) + try: + cursor.execute('INSERT INTO Admin VALUES (?, ?)', (wxId, roomId)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 增加管理员出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def delAdmin(self, wxId, roomId): + """ + 删除管理员 + :param wxId: 微信ID + :param roomId: 群聊ID + :return: + """ + conn, cursor = Dds.openDb(Cs.returnUserDbPath()) + try: + cursor.execute('DELETE FROM Admin WHERE wxId=? AND roomId=?', (wxId, roomId)) + conn.commit() + Dds.closeDb(conn, cursor) + return True + except Exception as e: + op(f'[-]: 删除管理员出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False + + def searchAdmin(self, wxId, roomId): + """ + 查询管理员 + :param wxId: 微信ID + :param roomId: 群聊ID + :return: + """ + conn, cursor = Dds.openDb(Cs.returnUserDbPath()) + try: + cursor.execute('SELECT wxId FROM Admin WHERE wxId=? AND roomId=?', (wxId, roomId)) + result = cursor.fetchone() + Dds.closeDb(conn, cursor) + if result: + return True + else: + return False + except Exception as e: + op(f'[-]: 查询管理员出现错误, 错误信息: {e}') + Dds.closeDb(conn, cursor) + return False diff --git a/DbServer/__pycache__/DbDomServer.cpython-38.pyc b/DbServer/__pycache__/DbDomServer.cpython-38.pyc new file mode 100644 index 0000000..48db6e9 Binary files /dev/null and b/DbServer/__pycache__/DbDomServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbGhServer.cpython-38.pyc b/DbServer/__pycache__/DbGhServer.cpython-38.pyc new file mode 100644 index 0000000..9452051 Binary files /dev/null and b/DbServer/__pycache__/DbGhServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbInitServer.cpython-38.pyc b/DbServer/__pycache__/DbInitServer.cpython-38.pyc new file mode 100644 index 0000000..77aa17f Binary files /dev/null and b/DbServer/__pycache__/DbInitServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbMainServer.cpython-38.pyc b/DbServer/__pycache__/DbMainServer.cpython-38.pyc new file mode 100644 index 0000000..6496a63 Binary files /dev/null and b/DbServer/__pycache__/DbMainServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbPointServer.cpython-38.pyc b/DbServer/__pycache__/DbPointServer.cpython-38.pyc new file mode 100644 index 0000000..0364f4d Binary files /dev/null and b/DbServer/__pycache__/DbPointServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbRoomServer.cpython-38.pyc b/DbServer/__pycache__/DbRoomServer.cpython-38.pyc new file mode 100644 index 0000000..bb6a75b Binary files /dev/null and b/DbServer/__pycache__/DbRoomServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbSignServer.cpython-38.pyc b/DbServer/__pycache__/DbSignServer.cpython-38.pyc new file mode 100644 index 0000000..c77c892 Binary files /dev/null and b/DbServer/__pycache__/DbSignServer.cpython-38.pyc differ diff --git a/DbServer/__pycache__/DbUserServer.cpython-38.pyc b/DbServer/__pycache__/DbUserServer.cpython-38.pyc new file mode 100644 index 0000000..78c7f0a Binary files /dev/null and b/DbServer/__pycache__/DbUserServer.cpython-38.pyc differ diff --git a/FileCache/FileCacheServer.py b/FileCache/FileCacheServer.py new file mode 100644 index 0000000..c9d2e18 --- /dev/null +++ b/FileCache/FileCacheServer.py @@ -0,0 +1,108 @@ +from OutPut.outPut import op +import os + + +def returnCachePath(): + """ + 返回缓存文件夹路径 + :return: + """ + current_path = os.path.dirname(__file__) + current_list_path = current_path.split('\\')[0:-1] + fileCachePath = '/'.join(current_list_path) + '/FileCache' + return fileCachePath + + +def returnPicCacheFolder(): + """ + 返回图片缓存文件夹 + :return: + """ + return returnCachePath() + '/picCacheFolder' + + +def returnVideoCacheFolder(): + """ + 返回视频缓存文件夹 + :return: + """ + return returnCachePath() + '/videoCacheFolder' + + +def returnFishCacheFolder(): + """ + 返回摸鱼日历缓存文件夹 + :return: + """ + return returnCachePath() + '/FishCacheFolder' + + +def returnGaoDeCacheFolder(): + """ + 返回高德地图缓存文件夹 + :return: + """ + return returnCachePath() + '/gaodeCacheFolder' + + +def returnAiPicFolder(): + """ + 返回Ai生成图像缓存文件夹 + :return: + """ + return returnCachePath() + '/aiPicCacheFolder' + + +def returnAvatarFolder(): + """ + 返回微信头像缓存文件夹 + :return: + """ + return returnCachePath() + '/weChatAvatarFolder' + + +def clearCacheFolder(): + """ + 清空缓存文件夹所有文件 + :return: + """ + if os.path.exists(returnAiPicFolder()): + file_lists = [] + file_lists += [returnPicCacheFolder() + '/' + file for file in os.listdir(returnPicCacheFolder())] + file_lists += [returnVideoCacheFolder() + '/' + file for file in os.listdir(returnVideoCacheFolder())] + file_lists += [returnFishCacheFolder() + '/' + file for file in os.listdir(returnFishCacheFolder())] + file_lists += [returnGaoDeCacheFolder() + '/' + file for file in os.listdir(returnGaoDeCacheFolder())] + file_lists += [returnAiPicFolder() + '/' + file for file in os.listdir(returnAiPicFolder())] + file_lists += [returnAvatarFolder() + '/' + file for file in os.listdir(returnAvatarFolder())] + for rm_file in file_lists: + os.remove(rm_file) + return True + else: + initCacheFolder() + clearCacheFolder() + + +def initCacheFolder(): + """ + 初始化缓存文件夹 + :return: + """ + if not os.path.exists(returnPicCacheFolder()): + os.mkdir(returnPicCacheFolder()) + if not os.path.exists(returnVideoCacheFolder()): + os.mkdir(returnVideoCacheFolder()) + if not os.path.exists(returnFishCacheFolder()): + os.mkdir(returnFishCacheFolder()) + if not os.path.exists(returnGaoDeCacheFolder()): + os.mkdir(returnGaoDeCacheFolder()) + if not os.path.exists(returnAiPicFolder()): + os.mkdir(returnAiPicFolder()) + if not os.path.exists(returnAvatarFolder()): + os.mkdir(returnAvatarFolder()) + op(f'[+]: 初始化缓存文件夹成功!!!') + + +if __name__ == '__main__': + # initCacheFolder() + # print(returnCachePath()) + clearCacheFolder() diff --git a/FileCache/__pycache__/FileCacheServer.cpython-38.pyc b/FileCache/__pycache__/FileCacheServer.cpython-38.pyc new file mode 100644 index 0000000..cbafbca Binary files /dev/null and b/FileCache/__pycache__/FileCacheServer.cpython-38.pyc differ diff --git "a/NGCBot.assets/\345\205\254\344\274\227\345\217\267.jpg" "b/NGCBot.assets/\345\205\254\344\274\227\345\217\267.jpg" new file mode 100644 index 0000000..eb225e6 Binary files /dev/null and "b/NGCBot.assets/\345\205\254\344\274\227\345\217\267.jpg" differ diff --git "a/NGCBot.assets/\345\205\263\346\263\250.gif" "b/NGCBot.assets/\345\205\263\346\263\250.gif" new file mode 100644 index 0000000..20111ef Binary files /dev/null and "b/NGCBot.assets/\345\205\263\346\263\250.gif" differ diff --git "a/NGCBot.assets/\350\265\236\350\265\217\347\240\201.jpg" "b/NGCBot.assets/\350\265\236\350\265\217\347\240\201.jpg" new file mode 100644 index 0000000..aefdadb Binary files /dev/null and "b/NGCBot.assets/\350\265\236\350\265\217\347\240\201.jpg" differ diff --git a/OutPut/__pycache__/outPut.cpython-38.pyc b/OutPut/__pycache__/outPut.cpython-38.pyc new file mode 100644 index 0000000..abcc1de Binary files /dev/null and b/OutPut/__pycache__/outPut.cpython-38.pyc differ diff --git a/OutPut/outPut.py b/OutPut/outPut.py new file mode 100644 index 0000000..2d07b4c --- /dev/null +++ b/OutPut/outPut.py @@ -0,0 +1,21 @@ +from cprint import cprint +import time + + +def op(msg: str): + """ + 消息输出函数 + :param msg: + :return: + """ + now_time = time.strftime("%Y-%m-%d %X") + if '[*]' in msg: + cprint.info(f'[{now_time}]: {msg}') + elif '[+]' in msg: + cprint.ok(f'[{now_time}]: {msg}') + elif '[-]' in msg: + cprint.err(f'[{now_time}]: {msg}') + elif '[~]' in msg: + cprint.warn(f'[{now_time}]: {msg}') + else: + cprint(f'[{now_time}]: {msg}') diff --git a/PushServer/PushMainServer.py b/PushServer/PushMainServer.py new file mode 100644 index 0000000..148b74c --- /dev/null +++ b/PushServer/PushMainServer.py @@ -0,0 +1,115 @@ +from ApiServer.ApiMainServer import ApiMainServer +from DbServer.DbMainServer import DbMainServer +import FileCache.FileCacheServer as Fcs +import Config.ConfigServer as Cs +from OutPut.outPut import * +import schedule + + +class PushMainServer: + def __init__(self, wcf): + self.wcf = wcf + self.Ams = ApiMainServer() + self.Dms = DbMainServer() + configData = Cs.returnConfigData() + self.morningPageTime = configData['pushConfig']['morningPageTime'] + self.eveningPageTime = configData['pushConfig']['eveningPageTime'] + self.offWorkTime = configData['pushConfig']['offWorkTime'] + self.offWorkMsg = configData['pushConfig']['keyWord']['offWorkMsg'] + self.fishTime = configData['pushConfig']['fishTime'] + self.kfcTime = configData['pushConfig']['kfcTime'] + + def pushMorningPage(self, ): + """ + 定时早报推送 + :return: + """ + op('[*]: 定时早报推送中... ...') + morningMsg = self.Ams.getMorningNews() + room_dicts = self.Dms.showPushRoom() + for roomId in room_dicts.keys(): + self.wcf.send_text(msg=morningMsg, receiver=roomId) + op('[+]: 定时早报推送成功!!!') + + def pushEveningPage(self, ): + """ + 定时晚报推送 + :return: + """ + op('[*]: 定时晚报推送中... ...') + eveningMsg = self.Ams.getEveningNews() + room_dicts = self.Dms.showPushRoom() + for roomId in room_dicts.keys(): + self.wcf.send_text(msg=eveningMsg, receiver=roomId) + op('[+]: 定时晚报推送成功!!!') + + def pushOffWork(self, ): + """ + 定时下班推送 + :return: + """ + op('[*]: 定时下班消息推送中... ...') + offWorkMsg = self.offWorkMsg.replace('\\n', '\n') + room_dicts = self.Dms.showPushRoom() + for room_id in room_dicts.keys(): + self.wcf.send_text(msg=offWorkMsg, receiver=room_id) + op('[+]: 定时下班消息推送成功!!!') + + # 摸鱼日记推送 + def pushFish(self): + """ + 定时摸鱼日记推送 + :return: + """ + op(f'[*]: 定时摸鱼日记推送中... ...') + room_dicts = self.Dms.showPushRoom() + fishPath = self.Ams.getFish() + for room_id in room_dicts.keys(): + self.wcf.send_image(path=fishPath, receiver=room_id) + op('[+]: 定时摸鱼日记推送成功!!!') + + # 每周四KFC推送 + def pushKfc(self, ): + """ + 每周四KFC推送 + :return: + """ + op(f'[*]: 定时KFC文案推送中... ...') + kfcMsg = self.Ams.getKfc() + room_dicts = self.Dms.showPushRoom() + for room_id in room_dicts.keys(): + self.wcf.send_text(msg=kfcMsg, receiver=room_id) + op(f'[+]: 定时KFC文案发送成功!!!') + + # 定时签到表清空 + def clearSign(self, ): + """ + 定时签到表清空 + :return: + """ + op(f'[*]: 定时签到表清空中... ...') + self.Dms.clearSign() + op(f'[+]: 定时签到表清空成功!!!') + + # 定时缓存文件清空 + def clearCacheFile(self, ): + """ + 定时缓存文件清空 + :return: + """ + op(f'[*]: 定时缓存文件清空中... ...') + Fcs.clearCacheFolder() + op(f'[+]: 定时缓存文件清空成功!!!') + + def run(self, ): + schedule.every().day.at(self.morningPageTime).do(self.pushMorningPage) + schedule.every().day.at(self.fishTime).do(self.pushFish) + schedule.every().thursday.at(self.kfcTime).do(self.pushKfc) + schedule.every().day.at(self.eveningPageTime).do(self.pushEveningPage) + schedule.every().day.at(self.offWorkTime).do(self.pushOffWork) + schedule.every().day.at('00:00').do(self.clearSign) + schedule.every().day.at('03:00').do(self.clearCacheFile) + op(f'[+]: 已开启定时推送服务!!!') + while True: + schedule.run_pending() + diff --git a/PushServer/__pycache__/PushMainServer.cpython-38.pyc b/PushServer/__pycache__/PushMainServer.cpython-38.pyc new file mode 100644 index 0000000..6264f2f Binary files /dev/null and b/PushServer/__pycache__/PushMainServer.cpython-38.pyc differ diff --git a/README.assets/.DS_Store b/README.assets/.DS_Store new file mode 100644 index 0000000..4653a30 Binary files /dev/null and b/README.assets/.DS_Store differ diff --git a/README.assets/113191704454837_.pic.jpg b/README.assets/113191704454837_.pic.jpg new file mode 100644 index 0000000..0d16832 Binary files /dev/null and b/README.assets/113191704454837_.pic.jpg differ diff --git a/README.assets/Logo2.png b/README.assets/Logo2.png new file mode 100644 index 0000000..4af10e6 Binary files /dev/null and b/README.assets/Logo2.png differ diff --git a/README.assets/image-20240102112921682.png b/README.assets/image-20240102112921682.png new file mode 100644 index 0000000..1cc5e14 Binary files /dev/null and b/README.assets/image-20240102112921682.png differ diff --git a/README.assets/image-20240102113236687.png b/README.assets/image-20240102113236687.png new file mode 100644 index 0000000..f8e121f Binary files /dev/null and b/README.assets/image-20240102113236687.png differ diff --git a/README.assets/image-20240102113314858.png b/README.assets/image-20240102113314858.png new file mode 100644 index 0000000..e1cbf3d Binary files /dev/null and b/README.assets/image-20240102113314858.png differ diff --git a/README.assets/image-20240102113357436.png b/README.assets/image-20240102113357436.png new file mode 100644 index 0000000..c018fc2 Binary files /dev/null and b/README.assets/image-20240102113357436.png differ diff --git a/README.assets/image-20240715144749465.png b/README.assets/image-20240715144749465.png new file mode 100644 index 0000000..7e1611a Binary files /dev/null and b/README.assets/image-20240715144749465.png differ diff --git a/README.assets/image-20240715145000906.png b/README.assets/image-20240715145000906.png new file mode 100644 index 0000000..905e531 Binary files /dev/null and b/README.assets/image-20240715145000906.png differ diff --git a/README.assets/image-20240715145009776.png b/README.assets/image-20240715145009776.png new file mode 100644 index 0000000..6487ff0 Binary files /dev/null and b/README.assets/image-20240715145009776.png differ diff --git a/README.assets/image-20240715145124032.png b/README.assets/image-20240715145124032.png new file mode 100644 index 0000000..2b1b3cf Binary files /dev/null and b/README.assets/image-20240715145124032.png differ diff --git a/README.assets/image-20240715145204093.png b/README.assets/image-20240715145204093.png new file mode 100644 index 0000000..1ae0834 Binary files /dev/null and b/README.assets/image-20240715145204093.png differ diff --git a/README.assets/image-20240715145533212.png b/README.assets/image-20240715145533212.png new file mode 100644 index 0000000..4b184a4 Binary files /dev/null and b/README.assets/image-20240715145533212.png differ diff --git a/README.assets/image-20240715145608102.png b/README.assets/image-20240715145608102.png new file mode 100644 index 0000000..2095e16 Binary files /dev/null and b/README.assets/image-20240715145608102.png differ diff --git a/README.assets/image-20240715145709019.png b/README.assets/image-20240715145709019.png new file mode 100644 index 0000000..98cebb2 Binary files /dev/null and b/README.assets/image-20240715145709019.png differ diff --git a/README.assets/image-20240715145756341.png b/README.assets/image-20240715145756341.png new file mode 100644 index 0000000..4c721f3 Binary files /dev/null and b/README.assets/image-20240715145756341.png differ diff --git a/README.assets/image-20240715145901701.png b/README.assets/image-20240715145901701.png new file mode 100644 index 0000000..fcc41ee Binary files /dev/null and b/README.assets/image-20240715145901701.png differ diff --git a/README.assets/image-20240715150054361.png b/README.assets/image-20240715150054361.png new file mode 100644 index 0000000..60f19f6 Binary files /dev/null and b/README.assets/image-20240715150054361.png differ diff --git a/README.assets/image-20240715150144599.png b/README.assets/image-20240715150144599.png new file mode 100644 index 0000000..b887b61 Binary files /dev/null and b/README.assets/image-20240715150144599.png differ diff --git a/README.assets/image-20240715153931025.png b/README.assets/image-20240715153931025.png new file mode 100644 index 0000000..9277baf Binary files /dev/null and b/README.assets/image-20240715153931025.png differ diff --git a/README.assets/image-20240715153945343.png b/README.assets/image-20240715153945343.png new file mode 100644 index 0000000..5014c93 Binary files /dev/null and b/README.assets/image-20240715153945343.png differ diff --git a/README.assets/image-20240715154106005.png b/README.assets/image-20240715154106005.png new file mode 100644 index 0000000..dc0db55 Binary files /dev/null and b/README.assets/image-20240715154106005.png differ diff --git a/README.assets/image-20240715154133286.png b/README.assets/image-20240715154133286.png new file mode 100644 index 0000000..ddf9cd1 Binary files /dev/null and b/README.assets/image-20240715154133286.png differ diff --git a/README.assets/image-20240715155141914.png b/README.assets/image-20240715155141914.png new file mode 100644 index 0000000..f691f0a Binary files /dev/null and b/README.assets/image-20240715155141914.png differ diff --git a/README.assets/image-20240715155157245.png b/README.assets/image-20240715155157245.png new file mode 100644 index 0000000..b433492 Binary files /dev/null and b/README.assets/image-20240715155157245.png differ diff --git a/README.assets/image-20240715155301010.png b/README.assets/image-20240715155301010.png new file mode 100644 index 0000000..b87ada4 Binary files /dev/null and b/README.assets/image-20240715155301010.png differ diff --git a/README.assets/image-20240715155333575.png b/README.assets/image-20240715155333575.png new file mode 100644 index 0000000..8c2d006 Binary files /dev/null and b/README.assets/image-20240715155333575.png differ diff --git a/README.assets/image-20240715155405381.png b/README.assets/image-20240715155405381.png new file mode 100644 index 0000000..66403e2 Binary files /dev/null and b/README.assets/image-20240715155405381.png differ diff --git a/README.assets/image-20240715155443022.png b/README.assets/image-20240715155443022.png new file mode 100644 index 0000000..2f1e2bf Binary files /dev/null and b/README.assets/image-20240715155443022.png differ diff --git a/README.assets/image-20240715155524345.png b/README.assets/image-20240715155524345.png new file mode 100644 index 0000000..547c094 Binary files /dev/null and b/README.assets/image-20240715155524345.png differ diff --git a/README.assets/image-20240715155615209.png b/README.assets/image-20240715155615209.png new file mode 100644 index 0000000..aab6387 Binary files /dev/null and b/README.assets/image-20240715155615209.png differ diff --git a/README.assets/image-20240715155628761.png b/README.assets/image-20240715155628761.png new file mode 100644 index 0000000..5730e4b Binary files /dev/null and b/README.assets/image-20240715155628761.png differ diff --git a/README.assets/image-20240715155936375.png b/README.assets/image-20240715155936375.png new file mode 100644 index 0000000..b18e9b6 Binary files /dev/null and b/README.assets/image-20240715155936375.png differ diff --git a/README.assets/image-20240715155947811.png b/README.assets/image-20240715155947811.png new file mode 100644 index 0000000..fa8134f Binary files /dev/null and b/README.assets/image-20240715155947811.png differ diff --git a/README.assets/image-20240715160123777.png b/README.assets/image-20240715160123777.png new file mode 100644 index 0000000..33c420a Binary files /dev/null and b/README.assets/image-20240715160123777.png differ diff --git a/README.assets/image-20240715160153512.png b/README.assets/image-20240715160153512.png new file mode 100644 index 0000000..fd28cd4 Binary files /dev/null and b/README.assets/image-20240715160153512.png differ diff --git a/README.assets/image-20240804181102746.png b/README.assets/image-20240804181102746.png new file mode 100644 index 0000000..d8bd14e Binary files /dev/null and b/README.assets/image-20240804181102746.png differ diff --git a/README.assets/image-20240804181111049.png b/README.assets/image-20240804181111049.png new file mode 100644 index 0000000..c2dfc67 Binary files /dev/null and b/README.assets/image-20240804181111049.png differ diff --git a/README.assets/image-20240804181150704.png b/README.assets/image-20240804181150704.png new file mode 100644 index 0000000..a97fd07 Binary files /dev/null and b/README.assets/image-20240804181150704.png differ diff --git a/README.assets/image-20240804181225162.png b/README.assets/image-20240804181225162.png new file mode 100644 index 0000000..6b6f2c6 Binary files /dev/null and b/README.assets/image-20240804181225162.png differ diff --git a/README.assets/image-20240804181554258.png b/README.assets/image-20240804181554258.png new file mode 100644 index 0000000..1391c5d Binary files /dev/null and b/README.assets/image-20240804181554258.png differ diff --git "a/README.assets/\345\205\263\346\263\250-4177997.gif" "b/README.assets/\345\205\263\346\263\250-4177997.gif" new file mode 100644 index 0000000..20111ef Binary files /dev/null and "b/README.assets/\345\205\263\346\263\250-4177997.gif" differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..d86a564 --- /dev/null +++ b/README.md @@ -0,0 +1,465 @@ +

+NGCBot V2.1 +

+ + +![Logo2](./README.assets/Logo2.png) + +

+一个基于✨HOOK机制的微信机器人,支持🌱安全新闻定时推送【FreeBuf,先知,安全客,奇安信攻防社区】,👯Kfc文案,⚡备案查询,⚡手机号归属地查询,⚡WHOIS信息查询,🎉星座查询,⚡天气查询,🌱摸鱼日历,⚡微步威胁情报查询, +🐛美女视频,⚡美女图片,👯帮助菜单。📫 支持积分功能,⚡支持自动拉人,🌱自动群发,👯Ai回复,⚡Ai画图,😄自定义程度丰富,小白也可轻松上手! +

+
+ + + + + + + GitHub Star + GitHub forks + + GitHub release (latest by date including pre-releases) +
+ + + + +## 💌一、项目概述 + +**本Bot是一款基于Hook机制的微信机器人,经过一年的更新迭代,目前功能更加面向大众,此项目会不定期维护,当然如果你有代码能力,也可以自己维护。目前支持功能(请看使用帮助),最新支持功能:Ai(Gpt,星火,千帆),关键词拉人进群,自动群发,入群欢迎。如果你有更好的想法,请进群交流。转载此项目请勿标记原创,否则后果自负!!使用此项目人员请勿做违法犯罪行为,否则后果自负!!** + +**出现微信版本过低不能登陆如何解决?点击此处:https://mp.weixin.qq.com/s/g9AjM3A04sAylP-Q-17fAg** + +**💞特别感谢CKCSec安全研究院的赞助支持以及各大群友的支持, 你们的支持就是我的动力😎 ** + +#### 注意⚠️注意⚠️:此项目完全开源,如果你是给钱了才用上本项目的,请注意,你就是那个傻逼 + +#### 作者:云山/eXM + +#### 项目版本:NGCBot V2.1 + +#### 官方公众号:NGC660安全实验室 + +#### 如果你觉得此项目不错,可以给个Star或给个赞赏 关注一下公众号 + +
+ Image 1 + Image 2 +
+ + + +## 二、项目结构 + +```css +│ main.py # 入口文件 +│ README.md # Readme文件 +│ requirements.txt # 环境依赖包 +├─ApiServer # 接口服务文件夹 +│ │ ApiMainServer.py # 所有接口主服务模块 +│ ├─AiServer # Ai接口服务文件夹 +│ │ │ AiDialogue.py # Ai接口调用主服务 +│ │ │ sparkPicApi.py # 星火图像生成接口模块 +│ ├─pluginServer # 插件接口服务文件夹 +│ │ │ HappyApi.py # 娱乐功能接口模块 +│ │ │ NewsApi.py # 新闻接口模块 +│ │ │ PointApi.py # 积分接口模块 +│ │ │ __init__.py # 功能接口初始化模块 +├─BotServer # Bot服务文件夹 +│ │ MainServer.py # Bot启动主服务模块 +│ ├─BotFunction # Bot所有功能文件夹 +│ │ │ AdminFunction.py # 管理员功能模块 +│ │ │ AdministratorFunction.py # 超管功能模块 +│ │ │ HappyFunction.py # 娱乐功能模块 +│ │ │ InterfaceFunction.py # 消息处理接口 +│ │ │ JudgeFuncion.py # 关键词判断模块 +│ │ │ PointFunction.py # 积分功能模块 +│ ├─MsgHandleServer # 消息处理文件夹 +│ │ │ FriendMsgHandle.py # 好友消息处理模块 +│ │ │ GhMsgHandle.py # 公众号消息处理模块 +│ │ │ RoomMsgHandle.py # 群聊消息处理模块 +├─Config # 配置文件服务文件夹 +│ │ Config.yaml # 配置文件 +│ │ ConfigServer.py # 配置文件服务模块 +│ │ Gh.db # 公众号数据库 +│ │ Point.db # 积分数据库 +│ │ Room.db # 群聊数据库 +│ │ User.db # 用户数据库 +├─DbServer # 数据库服务文件夹 +│ │ DbDomServer.py # 数据库操作模块 +│ │ DbGhServer.py # 公众号数据库模块(暂未使用) +│ │ DbInitServer.py # 数据库初始化模块 +│ │ DbMainServer.py # 数据库主服务模块 +│ │ DbPointServer.py # 积分操作模块 +│ │ DbRoomServer.py # 群聊数据库操作模块 +│ │ DbSignServer.py # 签到服务模块 +│ │ DbUserServer.py # 用户数据库操作模块 +├─FileCache # 缓存文件服务文件夹 +│ │ FileCacheServer.py # 文件服务模块 +│ ├─aiPicCacheFolder # Ai生图缓存文件夹 +│ ├─FishCacheFolder # 摸鱼日记缓存文件夹 +│ ├─gaodeCacheFolder # 高德地图缓存文件夹 +│ ├─picCacheFolder # 美女图片缓存文件夹 +│ ├─videoCacheFolder # 美女视频缓存文件夹 +├─logs # wcf日志文件夹 +│ wcf.txt # wcf日志 +├─NGCBot.assets # README静态资源文件 +├─OutPut # 日志输出模块文件夹 +│ │ outPut.py # 日志输出模块 +├─PushServer # 定时推送服务文件夹 +│ │ PushMainServer.py # 定时推送服务 +└─README.assets # README静态资源文件 +``` + +## 三、快速启动 + +**注意:此Bot只能在Windowns系统上运行!!!无法在Linux上运行安装** + +首先请克隆代码到本地,使用命令如下 + +```git +git clone git@github.com:ngc660sec/NGCBot.git +``` + +也可以直接Download + +![image-20240102112921682](./README.assets/image-20240102112921682.png) + +下载我提供的微信版本,注意不能更新微信⚠️ + +![image-20240715144749465](./README.assets/image-20240715144749465.png) + +使用`pip`安装项目包 + +```bash +pip install -r .\requirements.txt +``` + +若安装缓慢,则自行换源 + +安装完毕后,启动`main.py`文件 + +![image-20240102113236687](./README.assets/image-20240102113236687.png) + +若出现此问题,请使用任务管理器关闭微信重启运行此文件 + +![image-20240102113314858](./README.assets/image-20240102113314858.png) + +进入微信之后,会自动初始化必备文件 + +![image-20240102113357436](./README.assets/image-20240102113357436.png) + +到此,恭喜🎉,项目启动成功!使用帮助请看使用帮助章节! + +## 四、使用帮助 + +### 4.1、第一次使用看这里🤌 + +在运行成功后,你需要设置你的权限为超级管理员,当然你也可以设置多个超级管理员,拿到你的`wxid`即可。 + +给机器人发一条消息 + +![image-20240715145009776](./README.assets/image-20240715145009776.png) + +![image-20240715145000906](./README.assets/image-20240715145000906.png) + +拿到此`wxid`,放到配置文件当中即可 + +![image-20240715145124032](./README.assets/image-20240715145124032.png) + +若添加多个超级管理员,请按格式添加! + +【使用表情包功能请完成上述操作后执行以下命令】 + +``` +meme download +``` + +![image-20240804181554258](./README.assets/image-20240804181554258.png) + +第一次安装,请等待进度条走完,即可使用,如遇报错,请往下看娱乐功能介绍 + +### 4.2、功能介绍 + +#### 4.2.1、超级管理员功能 + +1. 添加管理员 +2. 删除管理员 +3. 关键词进群(配置文件中设置) +4. 关键词回复(配置文件中设置) +5. 加好友后自动回复(配置文件中设置) +6. 进群欢迎(配置文件中设置) +7. 自动转发公众号消息到推送群聊 +8. 自动同意好友(不需要配置) +9. 查看白名单群聊 +10. 查看黑名单群聊 +11. 查看推送群聊 + +**1、添加管理** + +``` +添加管理@你要添加的人 +``` + +![image-20240715145204093](./README.assets/image-20240715145204093.png) + +或者添加多个管理 + +![image-20240715145533212](./README.assets/image-20240715145533212.png) + +**2、删除管理** + +``` +删除管理@你要删除的人 +``` + +![image-20240715145608102](./README.assets/image-20240715145608102.png) + +**3、关键词进群** + +需要先拿到`roomid`,再在配置文件中设置即可 + +在你要拉进去的群里面发条消息 + +![image-20240715145709019](./README.assets/image-20240715145709019.png) + +放到配置文件里面 + +![image-20240715145756341](./README.assets/image-20240715145756341.png) + +可设置多个群聊,当某个群聊人数满了之后自动邀请下一个群聊。给机器人发送进群关键词即可触发 + +**4、关键词回复** + +在配置文件中设置即可 + +![image-20240715145901701](./README.assets/image-20240715145901701.png) + +关键词可设置多个,回复内容只限文本。只有好友可以触发 + +![image-20240715150054361](./README.assets/image-20240715150054361.png) + +**5、加好友后自动回复** +添加好友后自动回复一条消息,在配置文件中设置 + +![image-20240715150144599](./README.assets/image-20240715150144599.png) + +![image-20240715153945343](./README.assets/image-20240715153945343.png) + +**6、进群欢迎** +当有人加入群聊后,自动回复一条消息,在配置文件中设置 只在推送群聊中有效 + +![image-20240715154106005](./README.assets/image-20240715154106005.png) + +![image-20240715153931025](./README.assets/image-20240715153931025.png) + +可单独设置卡片消息,上面的效果是单独设置的卡片消息 + +![image-20240715154133286](./README.assets/image-20240715154133286.png) + +**7、自动转发消息** + +首先你需要添加几个推送群聊,才能使用此功能。添加完推送群聊后,可以愉快使用,如下! + +给机器人发送公众号消息 + +![image-20240715155141914](./README.assets/image-20240715155141914.png) + +机器人会自动推送消息到推送群聊 + +![image-20240715155157245](./README.assets/image-20240715155157245.png) + +#### 4.2.2、管理员功能 + +**注意:管理员功能超级管理员也能用!!管理员以及超级管理员使用积分功能不消耗积分!!** + +1. 开启推送服务 +2. 开启白名单 +3. 添加黑名单 +4. 添加积分、删除积分 +5. 踢人 +6. 除超管之外的任何功能 + +这里不对开启或者关闭做任何介绍,使用方法也很简单,在群内发送你在配置文件里面设置的关键词即可,比如: + +![image-20240715155301010](./README.assets/image-20240715155301010.png) + +发送开启推送即可在此群开启推送服务,关键词可以设置多个,代表这两个关键词都可以触发这个功能 + +![image-20240715155333575](./README.assets/image-20240715155333575.png) + +踢人功能使用也很简单,需要@罢了,可以@多个人 + +![image-20240715155405381](./README.assets/image-20240715155405381.png) + +**添加积分:需要@用户,可@多个用户,注意空格。使用如下【@群友1加空格[积分]】** + +![image-20240715155443022](./README.assets/image-20240715155443022.png) + +其它功能不做介绍。介绍一下黑名单群聊,白名单群聊,普通群聊,推送群聊的功能划分 + +**黑名单群聊:所有功能无法使用** + +**白名单群聊:积分功能无限制** + +**普通群聊:可正常使用积分功能,娱乐功能** + +**推送群聊:定时推送安全新闻,等等其它推送服务**(具体查看配置文件) + +#### 4.2.3、娱乐功能 + +1. 美女图片 +2. 美女视频 +3. KFC文案 +4. 舔狗日记 +5. 早报 +6. 晚报 +7. Help功能菜单 +8. 表情包功能 + +演示几个用法,基本都是这样用的,查询类功能注意空格⚠️ + +**图片功能** + +如果发现不显示图片,此类问题一般是接口不稳定,或者网络不稳定,重新发送即可 + +![image-20240715155524345](./README.assets/image-20240715155524345.png) + +**视频** + +![image-20240715155615209](./README.assets/image-20240715155615209.png) + +**舔狗日记** + +![image-20240715155628761](./README.assets/image-20240715155628761.png) + +**表情包功能,参考示例使用** + +**注意须知:表情包功能【随机表情】有一定几率发送失败,报错属于正常情况。** + +**只有 **`wcferry==39.0.12.0` **才可以使用表情包功能,其它版本无法使用** + +如果表情包过大,则会直接发送图片原图 + +![image-20240804181102746](./README.assets/image-20240804181102746.png) + +![image-20240804181111049](./README.assets/image-20240804181111049.png) + + + +![image-20240804181150704](./README.assets/image-20240804181150704.png) + +![image-20240804181225162](./README.assets/image-20240804181225162.png) + +#### 4.2.4、积分功能(管理或超管不需要积分) + +1. 签到(签到获得的积分可在配置文件中设置) +2. Md5查询 +3. 微步IP查询 +4. 端口查询 +5. 积分查询 +6. Ai对话 +7. Ai画图 + +一样的,演示几个功能 + +![image-20240715155936375](./README.assets/image-20240715155936375.png) + +**积分查询** + +![image-20240715155947811](./README.assets/image-20240715155947811.png) + +**AI对话** + +![image-20240715160123777](./README.assets/image-20240715160123777.png) + +**Ai画图** + +![image-20240715160153512](./README.assets/image-20240715160153512.png) + +**更多功能请查看配置文件** + +## 五、微信版本选择 + +兼容老版本微信,也就是用`NGCBotV2.0 龙年贺岁版`此版本的兄弟,但是不要更新软件包 + +**如果3.9.2.23版本的微信用不了怎么办?** + +选择更新软件包,或查看`提示微信版本过低`的解决方法 + +## 5.1、如何更新 + +``` +pip install --upgrade wcferry +``` + +### 5.2、wcferry==39.0.12.0 用什么版本的微信? + +[WeChatSetup-3.9.2.23.exe](https://github.com/ngc660sec/NGCBot/releases/download/V2.0-龙年贺岁版/WeChatSetup-3.9.2.23.exe) + +### 5.3、wcferry==39.2.4.0 用什么版本的微信 + +[WeChatSetup-3.9.10.27.exe](https://github.com/lich0821/WeChatFerry/releases/download/v39.2.4/WeChatSetup-3.9.10.27.exe) + +此版本目前(2024.07.15)存在一些问题 + +- 自动接收转账无法使用 + +## 六、一些常见的问题 + +**有问题!看配置文件!看配置文件!看配置文件!有些人配置文件不配置,在这问为什么用不了?那我问问你你不拿碗不拿筷子怎么吃饭?** + +其它问题,若是Bug请提供给群主即可,配置文件空着的都要自行配置,这里并不提供! + +**若需要定制开发,请进群联系群主**!!!! + +### 6.1、Bug提交处 + +关注微信公众号,后台留言,或者添加机器人回复`Bot交流群`拉你进群! + +**公众号:** + +![关注](./README.assets/%E5%85%B3%E6%B3%A8-4177997.gif) + +**机器人微信:** + +![113191704454837_.pic](./README.assets/113191704454837_.pic.jpg) + +### 6.2、开发者交流群 + +请添加机器人好友回复 `开发者` 进开发者交流群 + + + +## 七、更新日志 + +```css +- 【2022.12.8】 推送Bot 1.0版本,为初始版本 +- 【2022.12.17】推送Bot 1.2版本,新增部分接口,重写部分代码,新增积分功能 +- 【2023.1.1】 推送Bot 1.3版本,重写部分代码,优化代码逻辑,优化积分功能,优化定时推送功能 +- 【2023.3.6】 推送Bot 1.4版本,总体代码优化,优化定时推送,优化积分功能,新增消息转发,维护API服务调用 +- 【2023.3.29】 推送Bot 1.4.1版本,增加多线程处理消息,重写AI接口。可能会出现消息串群,@错人的问题,等后续优化更新 +- 【2023.3.31】 推送Bot 18诞辰版,修复1.4.1版本,消息乱串问题,支持AI上下文检索,优化消息处理代码,实现功能分区分块处理,由于挂了代理之后,当调用ai对话接口时,会出现ERROR报错,这种问题是正常的,能弄到国外服务器就别用国内的 +- 【2023.5.4】 推送Bot v18.1诞辰版,修复AI上下文消息过多无法回复的问题,修复天气查询小BUG +- 【2023.9.10】 推送Bot v1.5版本,优化AI回复,积分功能,代码逻辑,新增MD5解密功能 +- 【2024.01.2】 推送Bot V2.0龙年贺岁版,框架重写!逻辑重构!更快!更稳!更多功能! +- 【2024.07.15】推送Bot V2.1版本 框架再次重写,逻辑再次重构,更快!更稳!删减一些不必要功能,新增Ai画图功能 +``` + + + +## 八、鸣谢: + +https://github.com/lich0821/WeChatFerry + +感谢查克大佬提供的微信Python库!!!大家可以使用此框架进行开发! + +## 九、支持 + +感谢以下团队的大力支持 + +- NGC660安全实验室 +- CKCSec安全研究院 +- 渊龙Sec安全团队 + diff --git a/logs/wcf.txt b/logs/wcf.txt new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py new file mode 100644 index 0000000..06986c9 --- /dev/null +++ b/main.py @@ -0,0 +1,21 @@ +from BotServer.MainServer import MainServer +from cprint import cprint + +Bot_Logo = """ +███▄▄▄▄ ▄██████▄ ▄████████ ▀█████████▄ ▄██████▄ ███ +███▀▀▀██▄ ███ ███ ███ ███ ███ ███ ███ ███ ▀█████████▄ +███ ███ ███ █▀ ███ █▀ ███ ███ ███ ███ ▀███▀▀██ +███ ███ ▄███ ███ ▄███▄▄▄██▀ ███ ███ ███ ▀ +███ ███ ▀▀███ ████▄ ███ ▀▀███▀▀▀██▄ ███ ███ ███ +███ ███ ███ ███ ███ █▄ ███ ██▄ ███ ███ ███ +███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ + ▀█ █▀ ████████▀ ████████▀ ▄█████████▀ ▀██████▀ ▄████▀ + Version: V2.1 + Author: 久安信息有限公司旗下-NGC660安全实验室(eXM/云山) + +""" + +if __name__ == '__main__': + cprint.info(Bot_Logo.strip()) + Ms = MainServer() + Ms.processMsg() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d208f1c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +tencentcloud_sdk_python_common==3.0.1186 +tencentcloud_sdk_python_hunyuan==3.0.1186 +meme_generator==0.0.19.1 +spark-ai-python==0.4.1 +feedparser==6.0.11 +cprint==1.2.2 +lxml==5.2.2 +Pillow==10.4.0 +PyYAML==6.0.1 +Requests==2.32.3 +schedule==1.2.2 +urllib3==2.2.2