赞
踩
steam上有一款很火的游戏,桌面虚拟宠物,我想做一个简单的。第一个程序用来显示画面,一组图片构成的动图,参考Python代码实现桌面宠物,真IKUN才能养_哔哩哔哩_bilibili。第二个程序用模拟鼠标点击的方式,将gpt与自己的微信小号相连接,即gpt接入微信,我所使用的gpt是中转chatgpt,参考使用chatgpt实现微信自动回复_wechat-chatgpt-CSDN博客。gpt接入微信,长时间的使用wxauto库,可能会导致封号。目前的方式有两种,一种是将设备设置为手表接入微信,一种是土方法模拟鼠标点击,从安全性和简单程度来讲,我选择了后者。代码分享。
- import sys
- import os
- from functools import partial
- from PyQt5.QtGui import *
- from PyQt5.QtCore import *
- from PyQt5.QtWidgets import *
- from PyQt5 import QtGui, QtCore, QtWidgets
- from PyQt5.QtCore import QProcess
- import wxchat
- import threading
-
- event = threading.Event() # 共享的标志用于告知线程2何时结束
-
- class Qt_pet(QtWidgets.QWidget):
- def __init__(self):
- super(Qt_pet, self).__init__()
-
- self.dis_file = "img1"
- self.windowinit()
- self.icon_quit()
-
- self.pos_first = self.pos()
- self.timer = QTimer()
- self.timer.timeout.connect(self.img_update)
- self.timer.start(100)
-
-
- def img_update(self):
- if self.img_num < len(self.dir2img[self.current_dir])-1:
- self.img_num += 1
- else:
- self.img_num = 0
- self.qpixmap = QtGui.QPixmap(os.path.join(self.current_dir, self.dir2img[self.current_dir][self.img_num]))
- self.lab.setMaximumSize(self.pet_width, self.pet_height)
- self.lab.setScaledContents(True)
- # 重新设置lab的大小与图片保持一致
- self.lab.setGeometry(0, 0, self.qpixmap.width(), self.qpixmap.height())
- self.lab.setPixmap(self.qpixmap)
-
-
- # 获取放图片的路径,图片文件必须放在D:/Program Files (x86)/pet_conf/或者D:/Program Files/pet_conf/中,在里面放一个名为 imgN(比如img1,img2,img3的文件夹)的文件夹,文件夹中放具体的图片,图片的格式为N.png(比如1.png,2.png等)
- def get_conf_dir(self):
- conf_dirs = [r"你的图片地址"]
- for conf_dir in conf_dirs:
- if os.path.exists(conf_dir) and os.path.isdir(conf_dir):
- self.conf_dir = conf_dir
- for root, dirs, files in os.walk(self.conf_dir):
- if root in conf_dirs:
- for dir in dirs:
- for r, _, f in os.walk(os.path.join(root, dir)):
- if r == os.path.join(root, dir) and len(f)>0:
- try:
- f.sort(key=lambda x: int(x.split(sep='.', maxsplit=1)[0]))
- except ValueError:
- f.sort(key=lambda x: x.split(sep='.', maxsplit=1)[0])
- self.dir2img.update({r: f})
- return True
- QtWidgets.QMessageBox.warning(None, "警告", "没有找到配置文件!请查看使用说明", QtWidgets.QMessageBox.StandardButton.Ok)
- return False
-
- def windowinit(self):
- # 初始窗口设置大一点以免放入的图片显示不全
- self.pet_width = 500
- self.pet_height = 500
- # 获取桌面桌面大小决定宠物的初始位置为右上角
- desktop = QtWidgets.QApplication.desktop()
- self.x = desktop.width()-self.pet_width
- self.y = 100
- self.setGeometry(self.x, self.y, self.pet_width, self.pet_height)
- self.setWindowTitle('桌面宠物-by')
- self.img_num = 0
- # 找到配置文件,失败则退出
- self.dir2img = {}
- if not self.get_conf_dir():
- self.quit()
-
- self.lab = QtWidgets.QLabel(self)
- self.current_dir = list(self.dir2img.keys())[0]
- self.qpixmap = QtGui.QPixmap(os.path.join(self.current_dir, self.dir2img[self.current_dir][self.img_num]))
- self.lab.setPixmap(self.qpixmap)
-
- # 设置窗口为 无边框 | 保持顶部显示
- self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint| QtCore.Qt.WindowType.WindowStaysOnTopHint)
- # 设置窗口透明
- self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True)
- # 设置窗口的属性,使其不在任务栏显示
- self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint | Qt.Tool)
- self.show()
-
- # 设置系统托盘
- def icon_quit(self):
- mini_icon = QtWidgets.QSystemTrayIcon(self)
- mini_icon.setIcon(QtGui.QIcon(os.path.join(self.current_dir, self.dir2img[self.current_dir][0])))
- mini_icon.setToolTip("桌面宠物-by")
- # 1 toggle()、triggered()、clicked()区别
- # 这三个信号都是按钮点击后发射的信号,区别在于:
- # clicked()用于Button发射的信号
- # triggered()用于QAction发射的信号,原型:void triggered(bool checked = false);
- # toggle()用于ChekBox,非开即关,原型:void toggled(bool);
- quit_menu = QtWidgets.QAction('退出', self, triggered=self.quit)
- tpMenu = QtWidgets.QMenu(self)
-
- changeSubMenu = QtWidgets.QMenu(self)
- changeSubMenu.setTitle("切换")
- for dir in self.dir2img.keys():
- act = QtWidgets.QAction(os.path.basename(dir), self, triggered=partial(self.changeImg, dir))
- changeSubMenu.addAction(act)
- tpMenu.addMenu(changeSubMenu)
- tpMenu.addAction(quit_menu)
- mini_icon.setContextMenu(tpMenu)
- mini_icon.show()
-
- # 鼠标左键按下的时候获取当前位置
- def mousePressEvent(self, QMouseEvent):
- if QMouseEvent.button() == QtCore.Qt.MouseButton.LeftButton:
- self.pos_first = QMouseEvent.globalPos() - self.pos()
- QMouseEvent.accept()
- self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.OpenHandCursor))
-
- # 拖动移动
- def mouseMoveEvent(self, QMouseEvent):
- self.move(QMouseEvent.globalPos() - self.pos_first)
- # self.x, self.y = self.pos().x, self.pos().y
- QMouseEvent.accept()
-
- def quit(self):
- event.set()
- self.close()
- sys.exit()
-
- def changeImg(self, dir):
- self.current_dir = dir
-
- def mypet():
- app = QApplication(sys.argv)
- pet = Qt_pet()
- sys.exit(app.exec_())
-
- if __name__ == '__main__':
- t1 = threading.Thread(target=wxchat.resize_wechat_window)
- t2 = threading.Thread(target=mypet)
- t1.start()
- t2.start()
程序的名称是windows_pet.py,在原作者的基础上加入了多线程,因为两个程序都是无限循环的逻辑,两个线程不影响,设置了监听事件event用于同时结束两个线程,即当前线程退出,另一个线程也退出。另外补充,设置窗口的属性,使其不在任务栏显示。
- import pygetwindow as gw
- import pyautogui
- import pyperclip
- import time
- import get_API
- from windows_pet import event
-
-
- def resize_wechat_window(): # 调整窗口大小
- window_titles = gw.getAllTitles() # 获取所有打开的窗口
- wechat_window = None
- for title in window_titles: # 判断是否存在标题包含“微信”的窗口
- if "微信" in title:
- wechat_window = gw.getWindowsWithTitle(title)[0]
- break
- if wechat_window:
- wechat_window.restore() # 还原窗口
- wechat_window.activate() # 激活窗口显示在前台
- wechat_window.resizeTo(700, 500)
- autowx()
- else:
- print("微信窗口未找到")
-
-
- def autowx():
- red = r'you_red.png' # 消息来了的红图标
- name = r'you_name.png' # 接收人的图标
- while True:
- #print(event.is_set())
- if event.is_set():
- break
- else:
- location_red = pyautogui.locateCenterOnScreen(red, confidence=0.90)
- location_name = pyautogui.locateCenterOnScreen(name, confidence=0.90)
- if location_red and location_name:
- if location_red[0] - location_name[0] < 50:
- pyautogui.click(location_red)
- text = find_txt()
- else:
- time.sleep(1)
-
- def find_txt():
- pos3 = r'you_pos3.png' # 聊天窗口
- while True:
- locations_pos3 = pyautogui.locateAllOnScreen(pos3, confidence=0.98) # 所有坐标
- if locations_pos3:
- break
- else:
- print("没有收到窗口消息,1秒后重试")
- time.sleep(1)
- time.sleep(0.1)
- list_text = list(locations_pos3)
- if list_text != []:
- pos = sorted(list_text, key=lambda x:x[1], reverse=True)[0] # lambda x:x[1]元组的第二个元素从小到大排序的顺 # reverse降序
- pyautogui.doubleClick(x = pos[0] + 15 + pos[2] / 2,y = pos[1] + pos[3] / 2)
- time.sleep(0.1)
- pyautogui.hotkey('ctrl', 'c')
- time.sleep(0.1)
- text = pyperclip.paste()
- get_API.getchat(text)
-
- def givechat(text):
- pos1 = r'you_pos1.png' # 笑脸图标
- send = r'you_send.png' # 发送图标
- while True:
- location_pos1 = pyautogui.locateCenterOnScreen(pos1, confidence=0.90)
- location_send = pyautogui.locateCenterOnScreen(send, confidence=0.90)
- if location_pos1 and location_send:
- break
- else:
- print("没有收到gpt消息,1秒后重试")
- time.sleep(1)
- pyautogui.click(location_pos1[0], location_pos1[1]+30)
- pyperclip.copy(text)
- pyautogui.hotkey('ctrl', 'v')
- time.sleep(0.1)
- pyautogui.click(location_send)
-
- #if __name__ == '__main__':
- #resize_wechat_window()
程序的名称是wxchat.py,在原作者的原理上基本重写了代码,加入了首先设置微信程序的大小,后面也是使用while True轮询和pyautogui模拟鼠标点击,简化了原作者的代码只实现我要的一些基础功能。
- from openai import OpenAI
- import httpx
- import wxchat
-
- def getchat(access):
- client = OpenAI(
- base_url="https://oneapi.xty.app/v1",
- api_key="you_API",
- http_client=httpx.Client(
- base_url="https://oneapi.xty.app/v1",
- follow_redirects=True,
- ),
- )
-
- completion = client.chat.completions.create(
- model="gpt-3.5-turbo",
- temperature=0.99,
- max_tokens=2048,
- messages=[{"role": "system",
- "content": "you_初始化文本"},
- {"role": "user", "content": access}]
- )
- response = completion.choices[0].message.content
- wxchat.givechat(response)
-
程序的名称是get_API.py,使用的是中专API,官方的三月封号,至于我的桌面虚拟模拟器Vpet则使用了chatglm的API。至此我就有两个伙伴了。
未来的展望,后面有时间再瞎折腾了,大概就是,和桌面虚拟模拟器Vpet不一样,玩游戏的时候是真的在玩游戏,简单的是模拟鼠标玩一个“种田“游戏。在我写代码的时候在旁边鼓励之类的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。