diff --git a/cloud.py b/cloud.py index 69c829f..b9097bf 100644 --- a/cloud.py +++ b/cloud.py @@ -6,20 +6,29 @@ import os import json from oss2.credentials import EnvironmentVariableCredentialsProvider # 云端存储的文件名称都是shixun_id.json,并且要保证都是有答案的. -# 阿里云 OSS 配置 -access_key_id = 'LTAI5t927vdUFZa9NRnWfrL3' -access_key_secret = 'FbXoJUqe545eZhWFvADvGcFwatsGAx' -bucket_name = 'tasks-jsons' -endpoint = 'oss-cn-shenzhen.aliyuncs.com' # 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行 -bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name) # 判断文件是否存在 + + +# 这些key和secret都是我自己的,如果需要使用,需要自己去阿里云申请捏(云工开物神中神) +# 就一个小40G的OSS存储,里面也没啥重要数据,就是用来存储答案的,hack了也没啥用 +access_key_id='LTAI5t927vdUFZa9NRnWfrL3' +access_key_secret='FbXoJUqe545eZhWFvADvGcFwatsGAx' +bucket_name="tasks-jsons" +endpoint="oss-cn-shenzhen.aliyuncs.com" + +bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name) def is_exist(name:str) -> bool: return bucket.object_exists(name) # 如果文件存在,则下载到本地并命名为shixun_id_answer def download(name): - bucket.get_object_to_file(name, f'{name}_answer') + # 先检查本地文件是否存在,如果存在,则不下载 + if os.path.exists(name): + return + else: + # 将云端文件下载到本地并命名为shixun_id_answer.json + bucket.get_object_to_file(name, name) # 上传函数,用于获得答案后上传到云端,此步骤在获得答案后调用 # (to do)如果用户将答案认证为正确,则将本地json中的verified参数改为True后再上传并覆盖云端文件 def upload(name): @@ -38,13 +47,10 @@ def delete(name): # 先检查文件是否存在,如果存在,则删除 if is_exist(name): bucket.delete_object(name) - if __name__ == '__main__': # 测试用 # print(is_exist('18503.json')) - # download('18503.json') + #download('18503.json') # delete('18503.json') - for obj in oss2.ObjectIterator(bucket): - print(obj.key) diff --git a/get_answer.py b/get_answer.py index 0e181ec..18dba81 100644 --- a/get_answer.py +++ b/get_answer.py @@ -8,6 +8,9 @@ from openai import AsyncOpenAI import os import json import asyncio +from cloud import download,delete + +download('apis.json') #读取当前目录下的json文件 #获得指定目录下的所有json文件的文件名 def get_json(file): @@ -26,6 +29,12 @@ json_name = get_json(file)[0] #读取json文件并转换为字典 with open(json_name,'r',encoding='utf-8') as f: data = json.load(f) +with open('apis.json','r',encoding='utf-8') as f: + apis = json.load(f) +#获得api_key +api_key = apis['openaiapi'] +#删除本地的apis.json文件 +os.remove('apis.json') #遍历字典,获得每一关的参数,构造请求,获得答案 ''' 用于构造请求的参数:describe,require,code @@ -43,7 +52,7 @@ promot = '现在,我想让你扮演一个Python程序员来解一个问题, # 初始化异步客户端 client = AsyncOpenAI( - api_key='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', + api_key=api_key, base_url='https://api.op-enai.com/v1' ) def get_answer_from_api(jsonfile:dict,client:AsyncOpenAI,promot:str) -> dict: @@ -83,9 +92,10 @@ def get_answer_from_api(jsonfile:dict,client:AsyncOpenAI,promot:str) -> dict: # 运行主函数 return asyncio.run(main(data=data)) -new_data = get_answer_from_api(jsonfile=data,client=client,promot=promot) -print(new_data) -#重写本地json文件 -with open(json_name,'w',encoding='utf-8') as f: - json.dump(new_data,f,ensure_ascii=False,indent=4) +if __name__ == '__main__': + new_data = get_answer_from_api(jsonfile=data,client=client,promot=promot) + print(new_data) + #重写本地json文件 + with open(json_name,'w',encoding='utf-8') as f: + json.dump(new_data,f,ensure_ascii=False,indent=4) diff --git a/get_params.py b/get_params.py index fe1fc54..e6d57c7 100644 --- a/get_params.py +++ b/get_params.py @@ -29,9 +29,9 @@ opt.add_experimental_option('detach', True) #opt.add_argument('--headless') chrome_driver = 'D:\ChromeDownload\chromedriver-win64\chromedriver-win64' # 发行版时改为调用userinfo.json文件中的用户名和密码 -url = 'https://www.educoder.net/tasks/27V4D95N/1191515/vmxpzae734bj?coursesId=27V4D95N' -user_name = 'hnu202311020126' -password = 'hzy123456' +# url = 'https://www.educoder.net/tasks/27V4D95N/1191515/vmxpzae734bj?coursesId=27V4D95N' +# user_name = 'hnu202311020126' +# password = 'hzy123456' platf = platform.platform() def is_practice(url:str) -> bool: obj=re.compile(r'www.educoder.net/tasks') @@ -84,9 +84,9 @@ def get_parameters(url:str,user_name:str,password:str): response = requests.get(url=id_url, headers=headers) shixun_id = dict(response.json())['challenge']['shixun_id'] #判断云端文件是否存在 - try: - exist = is_exist(f'{shixun_id}.json') - if exist: #存在,则跳转到云端下载并终止本程序 + exist = is_exist(f'{shixun_id}.json') + if exist: + try: print('云端文件已存在,正在下载') download(f'{shixun_id}.json') # 检测本地文件是否下载完成 @@ -99,9 +99,9 @@ def get_parameters(url:str,user_name:str,password:str): break except Exception as e: print(e) - except Exception as e: - print(e) - finally: #不存在,则继续执行本程序 + except Exception as e: + print(e) + else:#不存在,则继续执行本程序 print('云端文件不存在,正在爬取') #获取关卡数 #点击展开关卡页面 @@ -190,5 +190,8 @@ def get_parameters(url:str,user_name:str,password:str): else: print('这不是一个实训作业') exit() - -get_parameters(url,user_name,password) \ No newline at end of file +if __name__ == '__main__': + url = 'https://www.educoder.net/tasks/27V4D95N/1191515/vmxpzae734bj?coursesId=27V4D95N' + user_name = 'hnu202311020126' + password = 'hzy123456' + get_parameters(url,user_name,password) \ No newline at end of file diff --git a/haha.py b/haha.py new file mode 100644 index 0000000..ae8df88 --- /dev/null +++ b/haha.py @@ -0,0 +1 @@ +import printtxt \ No newline at end of file diff --git a/login_ui.py b/login_ui.py index 07c186a..1352a56 100644 --- a/login_ui.py +++ b/login_ui.py @@ -5,10 +5,11 @@ import sys from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel from PyQt5.QtCore import Qt,QTimer from PyQt5.QtGui import QPixmap, QPainter -import os import platform +from solve_path import b2_path, b2txt_path import json - +from show_welcome import show_image +platf = platform.platform() class MyApp(QWidget): def __init__(self): super().__init__() @@ -16,7 +17,9 @@ class MyApp(QWidget): def initUI(self): # 加载背景图片 - self.background = QPixmap('/Users/xuxiaolan/PycharmProjects/GPTPowered_EducoderHelper/picture/b2.png') + if 'Windows' in platf: + b2_path.replace('\b','\\b') + self.background = QPixmap(b2_path) # 创建一个垂直布局 mainLayout = QVBoxLayout() @@ -113,7 +116,7 @@ class MyApp(QWidget): pwd = self.pwdEdit.text() url = self.urlEdit.text() - if name == '' or pwd == '' or url == '' or ~url.startswith('https') or ~url.startswith('www'): + if name == '' or pwd == '' or url == '': self.showError("非法输入!") else: with open('userinfo.json', 'w') as f: @@ -130,14 +133,11 @@ class MyApp(QWidget): # 关闭窗口 - -# 判断当前操作系统(基础太渣,只能这样判断了,哈哈) -platf = platform.platform() -if platf.startswith('Windows'): - os.system('python show_welcome.py') -else: - os.system('python3 show_welcome.py') -app = QApplication(sys.argv) # 创建应用程序对象 -ex = MyApp() # 创建窗口对象 -ex.show() # 显示窗口 -sys.exit(app.exec_()) # 保证程序完整退出 \ No newline at end of file +def show_login(): + app = QApplication(sys.argv) + ex = MyApp() + ex.show() + app.exec_() +if __name__ == '__main__': + show_image() + show_login() \ No newline at end of file diff --git a/main.py b/main.py index 5958e92..2918b2a 100644 --- a/main.py +++ b/main.py @@ -1,84 +1,69 @@ -''' -主程序:整合各个模块 -1、ui文件调用相应ui模块 -2、get_params.py获取参数 -3、get_answer.py获取答案 -4、cloud.py将json文件存入云端 -''' +# ''' +# 主程序:整合各个模块 +# 1、ui文件调用相应ui模块 +# 2、get_params.py获取参数 +# 3、get_answer.py获取答案 +# 4、cloud.py将json文件存入云端 +# ''' +# # 生成图形化界面,引导用户登陆并输入实训网址 +# # 调用get_params.py获取参数,这一步同时隐含了云端获取答案的过程 +# # 如果云端答案不存在,则调用get_answer.py获取答案,并展示给用户 +# # 用户verif选项确认后,调用cloud.py将json文件存入云端 -# 生成图形化界面,引导用户登陆并输入实训网址 -# 调用get_params.py获取参数,这一步同时隐含了云端获取答案的过程 -# 如果云端答案不存在,则调用get_answer.py获取答案,并展示给用户 -# 用户verif选项确认后,调用cloud.py将json文件存入云端 +# # 导入所需模块 -# 导入所需模块 -import platform -from get_params import get_parameters -from get_answer import get_answer_from_api,promot,client -import json -import os +# from get_params import get_parameters +# from get_answer import get_answer_from_api,promot,client +# from login_ui import show_login,show_image,MyApp +# from trans_to_txt import transToTxt,readJson -# 判断当前操作系统 -platf = platform.platform() -# 调用login_ui获得用户输入的用户名、密码和实训网址 -if platf.startswith('Windows'): - os.system('python login_ui.py') -else: - os.system('python3 login_ui.py') +# import json +# import os -# 检查userinfo.json文件是否存在,存在,则程序继续 -assert os.path.exists('userinfo.json'), 'userinfo.json文件不存在,请检查' +# # 调用login_ui获得用户输入的用户名、密码和实训网址 +# show_image() +# show_login() -# 先读取userinfo.json文件,获得用户名、密码和实训网址 -with open('userinfo.json', 'r') as f: - userinfo = json.load(f) -user_name = userinfo['name'] -password = userinfo['pwd'] -url = userinfo['url'] +# # 检查userinfo.json文件是否存在,存在,则程序继续 +# assert os.path.exists('userinfo.json'), 'userinfo.json文件不存在,请检查' -# 调用get_params.py获得参数,完成后本地应该有一个json文件,里面有参数 -get_parameters(url,user_name,password) -def get_json(file): - return [i for i in os.listdir(file) if i.endswith('.json')] +# # 先读取userinfo.json文件,获得用户名、密码和实训网址 +# with open('userinfo.json', 'r') as f: +# userinfo = json.load(f) +# user_name = userinfo['name'] +# password = userinfo['pwd'] +# url = userinfo['url'] -#将file指定为当前目录 -file = os.getcwd() -json_names = get_json(file) +# # 调用get_params.py获得参数,完成后本地应该有一个json文件,里面有参数 +# get_parameters(url,user_name,password) -# 遍历查找以数字开头的json文件,即为获得到的json文件,可能是云端下载的,也可能是爬取的 -global j_name -for j in json_names: - if j[0].isdigit(): - # 将该文件名赋值给json_name - j_name = j - break +# # 获得本地所有数字开头的json文件名 +# j_name = readJson()[0] +# # 判断j_name文件中是否有answer +# with open(j_name,'r',encoding='utf-8') as f: +# json_data = json.load(f) -# 判断json_name文件中是否有answer,若有提取answer并格式化或展现 -with open(j_name,'r',encoding='utf-8') as f: - json_data = json.load(f) -def is_exist_answer(data:dict) -> bool: - for i,j in data.items(): - if 'answer' in j.keys(): - return True - return False -if is_exist_answer(json_data): - pass -else: - # 调用API获取答案 - new_data = get_answer_from_api(jsonfile=json_data,client=client,promot=promot) - # 重写本地json文件 - with open(j_name,'w',encoding='utf-8') as f: - json.dump(new_data,f,ensure_ascii=False,indent=4) +# def is_exist_answer(data:dict) -> bool: +# for i,j in data.items(): +# if 'answer' in j.keys(): +# return True +# return False -# 上面的判断执行完后,本地的json文件中已经有answer了,下面实现信息展示 -# release版本要优化UI,beta版本先用print代替 +# if is_exist_answer(json_data): +# pass +# else: +# # 调用API获取答案 +# new_data = get_answer_from_api(jsonfile=json_data,client=client,promot=promot) +# # 重写本地json文件 +# with open(j_name,'w',encoding='utf-8') as f: +# json.dump(new_data,f,ensure_ascii=False,indent=4) -# 读取json文件,获得answer -with open(j_name,'r',encoding='utf-8') as f: - data = json.load(f) -# 由于python3.6之后字典是有序的,所以可以直接遍历字典,显示关卡序号和答案 -# 要将key在data中对应的索引值+1,因为索引值是从0开始的 -for i,j in enumerate(data.items()): - print(f'第{i+1}关的答案是:{j[-1]["answer"]}') - -# 询问用户是否认证答案正确(下午新开一个模块实现) \ No newline at end of file +# # 上面的判断执行完后,本地的json文件中已经有answer了,下面实现信息展示 +# # 使用readJson函数读取当前目录下的所有json文件 +# JSONS = readJson() +# # 构建txt文件 +# # transToTxt(JSONS) +# # 展示txt文件 +print('哈哈终于要写完了') +import haha +#询问用户是否认证答案正确(下午新开一个模块实现) \ No newline at end of file diff --git a/printtxt.py b/printtxt.py index 7f9e2b6..0670f7c 100644 --- a/printtxt.py +++ b/printtxt.py @@ -1,7 +1,11 @@ import sys -from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTextEdit, QDesktopWidget, QScrollBar -from PyQt5.QtCore import QTimer +from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QTextEdit, QDesktopWidget +from PyQt5.QtCore import QTimer, Qt from PyQt5.QtGui import QFont +import platform +import os +from PyQt5.QtGui import QTextCursor +platf = platform.platform() class TypewriterEffectApp(QWidget): def __init__(self, filepaths): @@ -37,48 +41,60 @@ class TypewriterEffectApp(QWidget): def startTyping(self): self.content = "" for filepath in self.filepaths: - with open(filepath, 'r') as file: - self.content += file.read() + "\n" + "-"*50 + "\n" + with open(filepath, 'r', encoding='utf-8') as file: + file_content = file.read() + # 处理转义字符 + file_content = file_content.replace('\\t', '\t').replace('\\n', '\n') + self.content += file_content + "\n" + "-" * 50 + "\n" self.index = 0 self.timer = QTimer(self) self.timer.timeout.connect(self.displayNextCharacter) - self.timer.start(5) + self.timer.start(20) def displayNextCharacter(self): if self.index < len(self.content): char = self.content[self.index] - #如果char和下一个字符是\n,那么就要执行换行 - if char == '\n' and self.content[self.index+1] == '\n': - text_to_display = self.textEdit.toPlainText() + '\n\n' - self.index += 1 - elif char == '\\t': - # 对制表符进行处理 - text_to_display = self.textEdit.toPlainText() + '\t' - else: - # 普通字符 - text_to_display = self.textEdit.toPlainText() + char - - # 添加光标(移除啦,加了总是有神奇bug) - #text_to_display += '|' if self.cursorVisible else '' - self.textEdit.setPlainText(text_to_display) + text_to_display = self.textEdit.toPlainText() + char + + # 设置光标 + cursor = self.textEdit.textCursor() + cursor.movePosition(QTextCursor.End) + cursor.insertText(char) + + # 交替修改光标显示状态 + cursor.clearSelection() + cursor.setPosition(cursor.position() - 1) + cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor) + cursor.setCharFormat(cursor.charFormat()) + + self.textEdit.setTextCursor(cursor) + self.index += 1 self.textEdit.ensureCursorVisible() # 始终滚动到底部 else: self.timer.stop() - #self.cursorTimer.stop() # 停止光标闪烁 - - def onScrollBarValueChanged(self, value): + def onScrollBarValueChanged(self, value): # 滚动条滚动时,停止自动滚动 scroll_bar = self.textEdit.verticalScrollBar() self.userIsScrolling = value < scroll_bar.maximum() -def main(): + +def print_txt(json_path: list): # 传入json文件路径 app = QApplication(sys.argv) - filepaths = ['18503 copy.json'] # 替换为您的文件路径 + filepaths = json_path ex = TypewriterEffectApp(filepaths) ex.show() - sys.exit(app.exec_()) + app.exec_() + + +def get_all_txt_file(path): + file_list = [] + for root, dirs, files in os.walk(path): + for file in files: + if file.endswith('.txt') and file[0].isdigit(): + file_list.append(os.path.join(root, file)) + return file_list + -if __name__ == '__main__': - main() +print_txt(get_all_txt_file(os.getcwd())) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..98656b6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +lxml==4.9.3 +openai==1.3.7 +oss2==2.18.3 +pycryptodome==3.19.0 +PyQt5==5.15.10 +PyQt5_sip==12.13.0 +Requests==2.31.0 +selenium==4.16.0 diff --git a/show_welcome.py b/show_welcome.py index 2aac2f0..615af4f 100644 --- a/show_welcome.py +++ b/show_welcome.py @@ -2,7 +2,9 @@ import sys from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QDesktopWidget from PyQt5.QtGui import QPixmap from PyQt5.QtCore import QTimer, Qt - +import platform +from solve_path import b2txt_path +platf = platform.platform() class ImageWindow(QWidget): def __init__(self, image_path): super().__init__() @@ -38,9 +40,9 @@ class ImageWindow(QWidget): def show_image(): app = QApplication(sys.argv) - ex = ImageWindow('/Users/xuxiaolan/PycharmProjects/GPTPowered_EducoderHelper/picture/b2txt.png') # 图片路径 + if 'Windows' in platf: + b2txt_path.replace('\b','\\b') + ex = ImageWindow(b2txt_path) # 图片路径 ex.show() - sys.exit(app.exec_()) - + app.exec_() # 这里不需要exec_(),因为我们只是想显示图片,而不是整个应用程序 -show_image() \ No newline at end of file diff --git a/solve_path.py b/solve_path.py new file mode 100644 index 0000000..a65d30f --- /dev/null +++ b/solve_path.py @@ -0,0 +1,27 @@ +''' +本模块用于解决macOS和Windows路径格式问题 +''' +import os +# 获取当前脚本所在的目录 +current_directory = os.path.dirname(os.path.abspath(__file__)) +# 拼接完整路径 +picture_folder_path = os.path.join(current_directory, 'picture') +# 获取所有文件 +all_files = os.listdir(picture_folder_path) +# 筛选以a.png和b.png结尾的文件 +target_files = [file for file in all_files if file.endswith(('b2.png', 'b2txt.png'))] +# 获取完整路径 +file_paths = [os.path.join(picture_folder_path, file) for file in target_files] +# 打印文件路径 +b2_path = '' +b2txt_path = '' +for file_path in file_paths: + if file_path.endswith('b2.png'): + b2_path = file_path + else: + b2txt_path = file_path + +if __name__ == '__main__': + print(b2_path) + print(b2txt_path) + print(os.listdir(current_directory)) \ No newline at end of file diff --git a/tempCodeRunnerFile.py b/tempCodeRunnerFile.py new file mode 100644 index 0000000..e5c931b --- /dev/null +++ b/tempCodeRunnerFile.py @@ -0,0 +1,66 @@ +''' +# 主程序:整合各个模块 +# 1、ui文件调用相应ui模块 +# 2、get_params.py获取参数 +# 3、get_answer.py获取答案 +# 4、cloud.py将json文件存入云端 +# ''' +# # 生成图形化界面,引导用户登陆并输入实训网址 +# # 调用get_params.py获取参数,这一步同时隐含了云端获取答案的过程 +# # 如果云端答案不存在,则调用get_answer.py获取答案,并展示给用户 +# # 用户verif选项确认后,调用cloud.py将json文件存入云端 + +# # 导入所需模块 + +# from get_params import get_parameters +# from get_answer import get_answer_from_api,promot,client +# from login_ui import show_login,show_image,MyApp +# from trans_to_txt import transToTxt,readJson + +# import json +# import os + +# # 调用login_ui获得用户输入的用户名、密码和实训网址 +# show_image() +# show_login() + +# # 检查userinfo.json文件是否存在,存在,则程序继续 +# assert os.path.exists('userinfo.json'), 'userinfo.json文件不存在,请检查' + +# # 先读取userinfo.json文件,获得用户名、密码和实训网址 +# with open('userinfo.json', 'r') as f: +# userinfo = json.load(f) +# user_name = userinfo['name'] +# password = userinfo['pwd'] +# url = userinfo['url'] + +# # 调用get_params.py获得参数,完成后本地应该有一个json文件,里面有参数 +# get_parameters(url,user_name,password) + +# # 获得本地所有数字开头的json文件名 +# j_name = readJson()[0] +# # 判断j_name文件中是否有answer +# with open(j_name,'r',encoding='utf-8') as f: +# json_data = json.load(f) + +# def is_exist_answer(data:dict) -> bool: +# for i,j in data.items(): +# if 'answer' in j.keys(): +# return True +# return False + +# if is_exist_answer(json_data): +# pass +# else: +# # 调用API获取答案 +# new_data = get_answer_from_api(jsonfile=json_data,client=client,promot=promot) +# # 重写本地json文件 +# with open(j_name,'w',encoding='utf-8') as f: +# json.dump(new_data,f,ensure_ascii=False,indent=4) + +# # 上面的判断执行完后,本地的json文件中已经有answer了,下面实现信息展示 +# # 使用readJson函数读取当前目录下的所有json文件 +# JSONS = readJson() +# # 构建txt文件 +# # transToTxt(JSONS) +# # 展示txt文件 \ No newline at end of file diff --git a/trans_to_txt.py b/trans_to_txt.py new file mode 100644 index 0000000..e4d4f94 --- /dev/null +++ b/trans_to_txt.py @@ -0,0 +1,25 @@ +import os +import json +#读取当前下的所有以数字命名的json文件 +def readJson(): + files = os.listdir() + jsons = [] + for file in files: + if file.endswith('.json') and file[0].isdigit(): + jsons.append(file) + return jsons +#这就是我们的答案json文件,提取每个键盘对应的值的answer键对应的值,写入不同的txt文件 +def transToTxt(jsons:list): + for j in jsons: + with open(j,'r',encoding='utf-8') as f: + data = json.load(f) + i=1 + for key in data.keys(): + if key != 'answer': + with open(f'{i}.txt','w',encoding='utf-8') as f: + f.write(data[key]['answer']) + i+=1 + f.close() +if __name__ == '__main__': + jsons = readJson() + transToTxt(jsons) \ No newline at end of file