diff --git a/chatgpt_code_interface/__pycache__/driver.cpython-39.pyc b/chatgpt_code_interface/__pycache__/driver.cpython-39.pyc new file mode 100644 index 0000000..30b0ef0 Binary files /dev/null and b/chatgpt_code_interface/__pycache__/driver.cpython-39.pyc differ diff --git a/chatgpt_code_interface/__pycache__/exec_python_code.cpython-39.pyc b/chatgpt_code_interface/__pycache__/exec_python_code.cpython-39.pyc new file mode 100644 index 0000000..b5a8cc1 Binary files /dev/null and b/chatgpt_code_interface/__pycache__/exec_python_code.cpython-39.pyc differ diff --git a/chatgpt_code_interface/__pycache__/exec_term_code.cpython-39.pyc b/chatgpt_code_interface/__pycache__/exec_term_code.cpython-39.pyc new file mode 100644 index 0000000..e347893 Binary files /dev/null and b/chatgpt_code_interface/__pycache__/exec_term_code.cpython-39.pyc differ diff --git a/chatgpt_code_interface/__pycache__/formating_tools.cpython-39.pyc b/chatgpt_code_interface/__pycache__/formating_tools.cpython-39.pyc new file mode 100644 index 0000000..859db5b Binary files /dev/null and b/chatgpt_code_interface/__pycache__/formating_tools.cpython-39.pyc differ diff --git a/chatgpt_code_interface/driver.py b/chatgpt_code_interface/driver.py new file mode 100644 index 0000000..a355598 --- /dev/null +++ b/chatgpt_code_interface/driver.py @@ -0,0 +1,135 @@ +from selenium.webdriver.common.keys import Keys + +from undetected_chromedriver import Chrome +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +import bs4 +import re +import time + +from exec_python_code import create_namespace, run_code +from exec_term_code import run_shell_command +from formating_tools import isolate_code_bloc + +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +def better_send_keys(element, text): + lines = text.split("\n") + for i, line in enumerate(lines): + element.send_keys(line) + if i != len(lines)-1: + element.send_keys(Keys.SHIFT + Keys.ENTER) + +class GPTDriver: + def __init__(self, headless=False, data_dir="selenium1"): + time.sleep(1) + chrome_options = Options() + + if headless : + chrome_options.add_argument("--headless") + + + chrome_options.add_argument(f"user-data-dir={data_dir}") + + self.driver = Chrome(options=chrome_options, use_subprocess=True) + #full screen + self.driver.maximize_window() + + def wait_answer(self): + """Wait until the answer is ready""" + xpath = """//*[@id="__next"]/div[2]/div[2]/main/div[2]/form/div/div[1]/button/div""" + while True: + try: + element = self.driver.find_element(By.XPATH, xpath) + #if element contain "stop generating" then continue + if "stop generating" in element.text.lower(): + time.sleep(0.1) + continue + return element + except: + time.sleep(0.1) + continue + + def create_user_data_dir(self, data_dir="selenium1"): + """Create a user data dir for selenium""" + chrome_options = Options() + chrome_options.add_argument(f"user-data-dir={data_dir}") + chrome_options.add_argument("--disable-images") + self.driver = Chrome(options=chrome_options) + self.driver.set_window_size(600, 1000) + self.driver.get("https://chat.openai.com/chat") + time.sleep(60) + self.driver.quit() + + def connect(self): + self.driver.get("https://chat.openai.com/chat") + + def get_chat(self): + """Get the chat history""" + soup = bs4.BeautifulSoup(self.driver.page_source, "html.parser") + chat = soup.find("div", class_=re.compile("flex flex-col items-center text-sm")) + return chat + + def get_last_chat(self): + """Get the last chat message""" + soup = bs4.BeautifulSoup(self.driver.page_source, "html.parser") + #last chat is the last div with class = " group w-full text-gray-800 dark:text-gray-100 border-b border-black/10 dark:border-gray-900/50 bg-gray-50 dark:bg-[#444654]" + chat = soup.find_all("div", class_="""group w-full text-gray-800 dark:text-gray-100 border-b border-black/10 dark:border-gray-900/50 bg-gray-50 dark:bg-[#444654]""")[-1] + return chat + + def send_message(self, txt): + textarea = self.driver.find_element(By.XPATH, '//*[@id="__next"]/div[2]/div[2]/main/div[2]/form/div/div[2]/textarea') + better_send_keys(textarea, txt) + time.sleep(1) + button_send = self.driver.find_element(By.XPATH, '//*[@id="__next"]/div[2]/div[2]/main/div[2]/form/div/div[2]/button') + button_send.click() + + def add_run_button(self): + #html of a big red button with border-radius of 10%, green background and white text pady by 10px up and padx by 10px left + button_html = '' + xpath = """//*[@id="__next"]/div[2]/div[2]/main/div[2]/div/span""" + + # Find the element using the given XPath + element = None + while not element: + try: + element = self.driver.find_element(By.XPATH, xpath) + except: + time.sleep(0.1) + + # Inject the button after the element found using the XPath + self.driver.execute_script(f"arguments[0].insertAdjacentHTML('afterend', '{button_html}');", element) + + # Add the click event listener for the button + self.driver.execute_script(""" + document.getElementById('continueButton').addEventListener('click', function() { + window.loopControl1 = 'continue'; + }); + """) + + def add_send_result_button(self): + #html of a big red button with border-radius of 10%, green background and white text pady by 10px up and padx by 10px left + button_html = '' + xpath = """//*[@id="__next"]/div[2]/div[2]/main/div[2]/div/span""" + + # Find the element using the given XPath + element = None + while not element: + try: + element = self.driver.find_element(By.XPATH, xpath) + except: + time.sleep(0.1) + + # Inject the button after the element found using the XPath + self.driver.execute_script(f"arguments[0].insertAdjacentHTML('afterend', '{button_html}');", element) + + # Add the click event listener for the button + self.driver.execute_script(""" + document.getElementById('sendResultButton').addEventListener('click', function() { + window.loopControl2 = 'send_result'; + }); + """) + + def close(self): + self.driver.close() diff --git a/chatgpt_code_interface/exec_python_code.py b/chatgpt_code_interface/exec_python_code.py new file mode 100644 index 0000000..90ecc31 --- /dev/null +++ b/chatgpt_code_interface/exec_python_code.py @@ -0,0 +1,54 @@ +import sys +import importlib.util +import io +import contextlib +import traceback + +def create_namespace(): + module_name = "__main__" + module_spec = importlib.util.spec_from_loader(module_name, loader=None) + module = importlib.util.module_from_spec(module_spec) + sys.modules[module_name] = module + return module.__dict__ + +def run_code(code_str, namespace): + # redirect stdout to a buffer to capture output + buffer = io.StringIO() + with contextlib.redirect_stdout(buffer): + try: + # compile the code + code = compile(code_str, "", "exec") + + # execute the code in the given namespace + exec(code, namespace) + except Exception as e: + # print any errors to the buffer + print(f"Error: {e}", file=buffer) + traceback.print_exc(file=buffer) + + # return the captured output or error message as a string + result = buffer.getvalue().strip() + if result: + return result + else: + return "---\nProcess finished with no output\n---" + + + +def test(): + code_str1 = '''import numpy as np\nimport matplotlib.pyplot as plt''' + code_str2 = '''x = np.linspace(0, 10, 100)\ny = np.sin(x)\nplt.plot(x, y)\nplt.show()''' + + + namespace = create_namespace() + result1 = run_code(code_str1, namespace) + result2 = run_code(code_str2, namespace) + +def test2(): + code_str1 = '''import os''' + + result = run_code(code_str1, create_namespace()) + print(result) + +if __name__ == '__main__': + test() \ No newline at end of file diff --git a/chatgpt_code_interface/exec_term_code.py b/chatgpt_code_interface/exec_term_code.py new file mode 100644 index 0000000..d4c5cc7 --- /dev/null +++ b/chatgpt_code_interface/exec_term_code.py @@ -0,0 +1,65 @@ +import os +import subprocess +import time + +class Shell: + def __init__(self): + self.cwd = os.getcwd() + self.env = os.environ.copy() + if os.name == 'nt': + self.env['PATH'] += os.pathsep + os.getcwd() + + def run_command(self, command_string, input=None): + exit_code, stdout, stderr = 1, 'error', 'error' + if input is not None: + input = input.encode('utf-8') + + commands = command_string.split('\n') + results = [] + for command in commands: + command = command.strip() + args = command.split(" ") + + if args[0] == 'cd': + if len(args) > 1: + path = os.path.join(self.cwd, args[1]) + if os.path.exists(path) and os.path.isdir(path): + self.cwd = os.path.abspath(path) + exit_code, stdout, stderr = 0, '', '' + else: + exit_code, stdout, stderr = 1, '', f"cd: {path}: No such file or directory" + + elif os.name == 'nt': + result = subprocess.run(command, cwd=self.cwd, env=self.env, input=input, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=False) + exit_code, stdout, stderr = result.returncode, result.stdout.decode('utf-8', errors='ignore'), result.stderr.decode('utf-8', errors='ignore') + else: + result = subprocess.run(args, cwd=self.cwd, env=self.env, input=input, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=False) + exit_code, stdout, stderr = result.returncode, result.stdout.decode('utf-8',errors='ignore'), result.stderr.decode('utf-8', errors='ignore') + + results.append((command, exit_code, stdout, stderr)) + + + + str_results = "" + for result in results: + command,exit_code, stdout, stderr = result + str_results += f"result for command: {command} :\n exit_code: {exit_code}\n stdout: {stdout}\n stderr: {stderr}\n---------\n" + + return str_results + +shell = Shell() + +def run_shell_command(command_string, input=None): + return shell.run_command(command_string, input) + +def test(): + a = run_shell_command("cd ..\n\ndir") + print(type(a)) + print(a) + +if __name__ == '__main__': + test() + + + + diff --git a/chatgpt_code_interface/formating_tools.py b/chatgpt_code_interface/formating_tools.py new file mode 100644 index 0000000..ffe39ad --- /dev/null +++ b/chatgpt_code_interface/formating_tools.py @@ -0,0 +1,24 @@ +import bs4 +from collections import namedtuple + + +CodeBloc = namedtuple('CodeBloc', ['language', 'code']) + +def remove_trailing_newline(s): + if s.endswith('\n'): + return s[:-1] + return s +def isolate_code_bloc(soup): + pre_tab = soup.find_all("pre") + code_bloc = [] + for code in pre_tab: + #print(code.text) + motif = "Copy code" + finding = code.text.find(motif) + code_content = code.text[finding+len(motif):] + language = code.text[:finding] + code_bloc.append(CodeBloc(language.strip(), remove_trailing_newline(code_content))) + + print(code_bloc) + return code_bloc + diff --git a/chatgpt_code_interface/main.py b/chatgpt_code_interface/main.py new file mode 100644 index 0000000..3a39e1f --- /dev/null +++ b/chatgpt_code_interface/main.py @@ -0,0 +1,97 @@ +from driver import GPTDriver +from exec_python_code import create_namespace, run_code +from exec_term_code import run_shell_command +from formating_tools import isolate_code_bloc +import time + + +gpt_driver = GPTDriver() +import time + +def connect_to_gpt_driver(): + gpt_driver.connect() + gpt_driver.add_run_button() + time.sleep(3) + +def execute_codes(codes): + answer = "" + for code in codes: + if 'python' in code.language.lower(): + ans = run_code(code.code, create_namespace()) + else: + ans = run_shell_command(code.code) + answer += ans + "\n" + return answer + +def wait_continue_button_click(): + loop_control = gpt_driver.driver.execute_script("return window.loopControl1;") + while loop_control != 'continue': + time.sleep(0.5) + loop_control = gpt_driver.driver.execute_script("return window.loopControl1;") + gpt_driver.driver.execute_script("window.loopControl1 = 'stop';") + +def wait_send_results_click(): + loop_control = gpt_driver.driver.execute_script("return window.loopControl2;") + while loop_control != 'send_result': + time.sleep(0.5) + loop_control = gpt_driver.driver.execute_script("return window.loopControl2;") + gpt_driver.driver.execute_script("window.loopControl2 = 'stop';") + + +def main(launch_first_prompt=False, first_prompt=None): + """Main function""" + + """ + ----------------- + first prompt and execution + ----------------- + """ + connect_to_gpt_driver() + + first_prompt = """ I now give you access to a windows computer with python on it. + You just have to write code in code blocs and a I will automatically execut it and send you the output. + Don't ask the computer to change your code our anything else, it will not understand. + So form now on, I will ONLY send you the output of your last python bloc commands you wrote, you can't use os module\n + don't ask me anything else, and YOU will ONLY give me some code to execute. + Now gather as much information as possible about the limitations of GPT4 and how to overcome them + You can only use python to gather online information. bs4 and other usefull libs are already installed YOU DON'T NEED TO INSTALL THINGS\n + Sum up the infos in a few lines and get them in a file. Continue gathering information + And when you have enough information, write a little article on 'How to get the full potential of GPT4' + Your responses should always START with a small reasoning message, then a small todolist with check or X, then the message 'I must gather information online about GPT4 using python, I send code to do that, I HAVE TO ALWAYS VERIFY it worked fine (use print for debugging), then I'll sum up what I learnt in a file \ + I have to do those things myself without help and I can't ask for any handmade code modification. I can't use an API' """ + + """ + ----------------- + main loop + ----------------- + """ + + if launch_first_prompt: + answer = first_prompt + else: + answer = "" + + for j in range(100): + print(f"ITERATION {j}") + + + gpt_driver.send_message(answer) + gpt_driver.wait_answer() + + wait_continue_button_click() + + answer = gpt_driver.get_last_chat() + codes = isolate_code_bloc(answer) + + answer = execute_codes(codes) + + + time.sleep(1) + + if (j + 5) % 24 == 0: + # Wait 3 hours. GPT-4 is limited to 25 requests per 3 hours + time.sleep(60 * 60 * 3) + +if __name__ == "__main__": + main() + diff --git a/chatgpt_code_interface/requirements.txt b/chatgpt_code_interface/requirements.txt new file mode 100644 index 0000000..4d1819d --- /dev/null +++ b/chatgpt_code_interface/requirements.txt @@ -0,0 +1,6 @@ +selenium==4.8.3 +urllib3==1.26.6 +matplotlib==3.5.3 +undetected-chromedriver==3.4.6 +beautifulsoup4==4.12.0 +