From 51797985ae985d24039ee3ce1b893e25a1a14251 Mon Sep 17 00:00:00 2001 From: keenborder786 <21110290@lums.edu.pk> Date: Mon, 10 Jun 2024 20:51:04 +0500 Subject: [PATCH 1/5] [feat]: Claude Login Method Added --- src/free_llms/models.py | 62 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/free_llms/models.py b/src/free_llms/models.py index 0005c17..b90067f 100644 --- a/src/free_llms/models.py +++ b/src/free_llms/models.py @@ -95,7 +95,7 @@ def check_start_driver(cls, data: Dict) -> Dict: if "--window-size" in started_config: raise ValueError("You cannot change the window size in your provided driver config") options = configure_options(data["driver_config"] + DRIVERS_DEFAULT_CONFIG) - data["driver"] = uc.Chrome(options=options, headless=True) + data["driver"] = uc.Chrome(options=options, headless=False) return data @property @@ -227,7 +227,7 @@ def send_prompt(self, query: str) -> AIMessage: except TimeoutException: current_url = self.driver.current_url self.driver.quit() - self.driver = uc.Chrome(options=configure_options(self.driver_config + DRIVERS_DEFAULT_CONFIG), headless=True) + self.driver = uc.Chrome(options=configure_options(self.driver_config + DRIVERS_DEFAULT_CONFIG), headless=False) self.run_manager.on_text(text="Captacha Detected on ChatGPT. Starting Annoymous Session", verbose=self.verbose) self.driver.get(current_url) @@ -382,3 +382,61 @@ def send_prompt(self, query: str) -> AIMessage: self.run_manager.on_text(text=f"Mistral responded with {len(raw_message)} characters", verbose=self.verbose) self.messages.append((HumanMessage(content=query), AIMessage(content=raw_message))) return AIMessage(content=raw_message) + +class ClaudeChrome(LLMChrome): + + + @property + def _model_url(self) -> str: + return "https://claude.ai/login" + + @property + def _elements_identifier(self) -> Dict[str, str]: + return { + "Email": '//*[@id="email"]', + "Login_Button": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", + "Login_Code": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/div[3]/input", + "Login_Code_Confirmation":"/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", + "Starting_Prompt_Text_Area":"/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset", + "Prompt_Text_Area_Output":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[1]/div[{current}]/div/div/div[1]/div/div/p", + "Prompt_Text_Area":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset", + "Initial_Prompt_Text_Area_Submit":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button", + "Prompt_Text_Area_Submit":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button" + } + def login(self, retries_attempt: int) -> bool: + self.driver.get(self._model_url) + for i in range(retries_attempt): + self.run_manager.on_text(text=f"Making login attempt no. {i+1} on Claude", verbose=self.verbose) + try: + login_button = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Button"])) + ) + login_button.click() + email_input = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Email"])) + ) + email_input.clear() + email_input.send_keys(self.email) + time.sleep(3) + login_button.click() + login_code = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code"])) + ) + input_code = input(f'Please open your email {self.email} and type in verification code:') + login_code.send_keys(input_code) + login_code.submit() + self.run_manager.on_text(text=f"Login succeed on attempt no. {i+1}", verbose=self.verbose) + except TimeoutException: + continue + return True + def send_prompt(self, query: str) -> AIMessage: + pass + + + + + + + + + From 49f0d5c5ac1ad6c2a0d9230c5384f84a542ec700 Mon Sep 17 00:00:00 2001 From: keenborder786 <21110290@lums.edu.pk> Date: Tue, 11 Jun 2024 14:06:47 +0500 Subject: [PATCH 2/5] [wip]: Claude Model --- src/free_llms/models.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/free_llms/models.py b/src/free_llms/models.py index b90067f..05198e2 100644 --- a/src/free_llms/models.py +++ b/src/free_llms/models.py @@ -227,7 +227,7 @@ def send_prompt(self, query: str) -> AIMessage: except TimeoutException: current_url = self.driver.current_url self.driver.quit() - self.driver = uc.Chrome(options=configure_options(self.driver_config + DRIVERS_DEFAULT_CONFIG), headless=False) + self.driver = uc.Chrome(options=configure_options(self.driver_config + DRIVERS_DEFAULT_CONFIG), headless=True) self.run_manager.on_text(text="Captacha Detected on ChatGPT. Starting Annoymous Session", verbose=self.verbose) self.driver.get(current_url) @@ -397,40 +397,49 @@ def _elements_identifier(self) -> Dict[str, str]: "Login_Button": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", "Login_Code": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/div[3]/input", "Login_Code_Confirmation":"/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", - "Starting_Prompt_Text_Area":"/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset", - "Prompt_Text_Area_Output":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[1]/div[{current}]/div/div/div[1]/div/div/p", - "Prompt_Text_Area":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset", - "Initial_Prompt_Text_Area_Submit":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button", - "Prompt_Text_Area_Submit":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button" - } + "Start_Chat_Button":"/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset/div/div[2]/div[2]/button", + "Prompt_Text_Area":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[1]/div/div/div/div/p" + } def login(self, retries_attempt: int) -> bool: self.driver.get(self._model_url) for i in range(retries_attempt): self.run_manager.on_text(text=f"Making login attempt no. {i+1} on Claude", verbose=self.verbose) try: - login_button = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Button"])) - ) - login_button.click() email_input = WebDriverWait(self.driver, self.waiting_time).until( EC.presence_of_element_located((By.XPATH, self._elements_identifier["Email"])) ) email_input.clear() email_input.send_keys(self.email) - time.sleep(3) + login_button = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Button"])) + ) login_button.click() login_code = WebDriverWait(self.driver, self.waiting_time).until( EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code"])) ) input_code = input(f'Please open your email {self.email} and type in verification code:') login_code.send_keys(input_code) - login_code.submit() + login_code_confirmation = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code_Confirmation"])) + ) + login_code_confirmation.click() self.run_manager.on_text(text=f"Login succeed on attempt no. {i+1}", verbose=self.verbose) + return True except TimeoutException: continue - return True + return False def send_prompt(self, query: str) -> AIMessage: - pass + + start_chat_button = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Start_Chat_Button"])) + ) + start_chat_button.click() + prompt_text_area = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Prompt_Text_Area"])) + ) + self.driver.execute_script(f"arguments[0].innerText = '{query}'", prompt_text_area) + + time.sleep(100) From 14d34c822dfe5557f42b39c2393e468800930d63 Mon Sep 17 00:00:00 2001 From: keenborder786 <21110290@lums.edu.pk> Date: Tue, 11 Jun 2024 15:21:26 +0500 Subject: [PATCH 3/5] [feat]: Claude Model Integrated --- src/free_llms/models.py | 82 ++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/free_llms/models.py b/src/free_llms/models.py index 05198e2..786f901 100644 --- a/src/free_llms/models.py +++ b/src/free_llms/models.py @@ -383,69 +383,83 @@ def send_prompt(self, query: str) -> AIMessage: self.messages.append((HumanMessage(content=query), AIMessage(content=raw_message))) return AIMessage(content=raw_message) + class ClaudeChrome(LLMChrome): - + message_box_jump: int = 2 + """For the Cluade Chrome, the starting message box is at 2""" @property def _model_url(self) -> str: return "https://claude.ai/login" - + @property def _elements_identifier(self) -> Dict[str, str]: return { "Email": '//*[@id="email"]', "Login_Button": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", "Login_Code": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/div[3]/input", - "Login_Code_Confirmation":"/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", - "Start_Chat_Button":"/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset/div/div[2]/div[2]/button", - "Prompt_Text_Area":"/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[1]/div/div/div/div/p" - } + "Login_Code_Confirmation": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", + "Start_Chat_Button": "/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset/div/div[2]/div[2]/button", + "Prompt_Text_Area": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[1]/div/div/div/div/p", # noqa: E501 + "Prompt_Text_Area_Submit": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button", # noqa: E501 + "Prompt_Text_Area_Output": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[1]/div[{current}]/div/div/div[1]/div/div", + } + def login(self, retries_attempt: int) -> bool: self.driver.get(self._model_url) for i in range(retries_attempt): self.run_manager.on_text(text=f"Making login attempt no. {i+1} on Claude", verbose=self.verbose) try: email_input = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Email"])) - ) + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Email"])) + ) email_input.clear() email_input.send_keys(self.email) login_button = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Button"])) - ) + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Button"])) + ) login_button.click() - login_code = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code"])) - ) - input_code = input(f'Please open your email {self.email} and type in verification code:') + login_code = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code"])) + ) + input_code = input(f"Please open your email {self.email} and type in verification code:") login_code.send_keys(input_code) - login_code_confirmation = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code_Confirmation"])) - ) + login_code_confirmation = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Login_Code_Confirmation"])) + ) login_code_confirmation.click() self.run_manager.on_text(text=f"Login succeed on attempt no. {i+1}", verbose=self.verbose) return True except TimeoutException: continue return False + def send_prompt(self, query: str) -> AIMessage: - - start_chat_button = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Start_Chat_Button"])) - ) - start_chat_button.click() + try: + start_chat_button = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Start_Chat_Button"])) + ) + start_chat_button.click() + except TimeoutException: + pass prompt_text_area = WebDriverWait(self.driver, self.waiting_time).until( - EC.presence_of_element_located((By.XPATH, self._elements_identifier["Prompt_Text_Area"])) - ) + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Prompt_Text_Area"])) + ) self.driver.execute_script(f"arguments[0].innerText = '{query}'", prompt_text_area) - time.sleep(100) - - - - - - - - - + prompt_text_area_submit = WebDriverWait(self.driver, self.waiting_time).until( + EC.presence_of_element_located((By.XPATH, self._elements_identifier["Prompt_Text_Area_Submit"])) + ) + prompt_text_area_submit.click() + time.sleep(self.waiting_time) + current_n, prev_n = 0, -1 + while current_n != prev_n: + prev_n = current_n + streaming = self.driver.find_element(By.XPATH, self._elements_identifier["Prompt_Text_Area_Output"].format(current=self.message_box_jump)) + raw_message = streaming.get_attribute("innerHTML") + self.run_manager.on_text(text="Claude is responding", verbose=self.verbose) + current_n = len(raw_message) if raw_message is not None else 0 + self.message_box_jump += 2 + self.run_manager.on_text(text=f"Claude responded with {len(raw_message)} characters", verbose=self.verbose) + self.messages.append((HumanMessage(content=query), AIMessage(content=raw_message))) + return AIMessage(content=raw_message) From db616fd417c257d7eb4f4f6626b011a240595daa Mon Sep 17 00:00:00 2001 From: keenborder786 <21110290@lums.edu.pk> Date: Tue, 11 Jun 2024 15:29:31 +0500 Subject: [PATCH 4/5] [docs]: Improved docs --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df86155..15da4ce 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ pip install free_llms | ChatGPT | ✅ | | Preplexity ai | ✅ | | Mistral | ✅ | -| Groq | Work in Progress | +| Claude | ✅ | @@ -79,6 +79,24 @@ with MistralChrome(driver_config=driver_config, print(session.messages) ``` + +## Claude + +```python +from free_llms.models import ClaudeChrome +driver_config = [] # pass in selnium driver config except for the following ["--disable-gpu", f"--window-size=1920,1080"] +with ClaudeChrome(driver_config=driver_config, + email = 'mohammad.mohtashim78@gmail.com', + password = '', # password not needed for ClaudeChrome + ) as session: # A single session started with ClaudeChrome + # once you login, you will get a code at your email which you need to type in + session.send_prompt('What is silicon valley?') + session.send_prompt('How many seasons it had?') + print(session.messages) + +``` + + ## Note: - Free_LLMs only uses a `Patched Chrome Driver` as it's main driver. The driver can be found [here](https://github.com/ultrafunkamsterdam/undetected-chromedriver/tree/master) \ No newline at end of file From b0e4066dcaf1b00adf00d14d4947340cb9ae7c76 Mon Sep 17 00:00:00 2001 From: keenborder786 <21110290@lums.edu.pk> Date: Tue, 11 Jun 2024 15:29:53 +0500 Subject: [PATCH 5/5] [tests]: Test added for Claude --- src/free_llms/models.py | 4 ++-- tests/unit_tests/test_models.py | 28 ++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/free_llms/models.py b/src/free_llms/models.py index 786f901..c0ddb96 100644 --- a/src/free_llms/models.py +++ b/src/free_llms/models.py @@ -95,7 +95,7 @@ def check_start_driver(cls, data: Dict) -> Dict: if "--window-size" in started_config: raise ValueError("You cannot change the window size in your provided driver config") options = configure_options(data["driver_config"] + DRIVERS_DEFAULT_CONFIG) - data["driver"] = uc.Chrome(options=options, headless=False) + data["driver"] = uc.Chrome(options=options, headless=True) return data @property @@ -386,7 +386,7 @@ def send_prompt(self, query: str) -> AIMessage: class ClaudeChrome(LLMChrome): message_box_jump: int = 2 - """For the Cluade Chrome, the starting message box is at 2""" + """For the Claude Chrome, the starting message box is at 2""" @property def _model_url(self) -> str: diff --git a/tests/unit_tests/test_models.py b/tests/unit_tests/test_models.py index 329dd34..dc62a2b 100644 --- a/tests/unit_tests/test_models.py +++ b/tests/unit_tests/test_models.py @@ -1,6 +1,6 @@ import pytest -from free_llms.models import PreplexityChrome,GPTChrome,MistralChrome,AIMessage +from free_llms.models import PreplexityChrome,GPTChrome,MistralChrome,ClaudeChrome,AIMessage @@ -69,4 +69,28 @@ def test_mistral_chrome(): "Prompt_Text_Area_Submit": "/html/body/div[1]/div[2]/div[2]/div/div[2]/div/div[1]/div/button", "Prompt_Text_Area_Output": "/html/body/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[{current}]/div[2]/div[1]", } - assert MistralChrome(driver_config=[], email = 'wrong_email', password = 'wrong_password')._model_url == 'https://chat.mistral.ai/chat' \ No newline at end of file + assert MistralChrome(driver_config=[], email = 'wrong_email', password = 'wrong_password')._model_url == 'https://chat.mistral.ai/chat' + + +def test_claude_chrome(): + with pytest.raises(ValueError, match="Cannot Login given the credentials"): + with ClaudeChrome(driver_config=[], + email = 'wrong_email', + password = 'wrong_password', + retries_attempt=1 + ) as session: # A single session started with ChartGPT + pass + assert ClaudeChrome( + driver_config=[], + email = 'wrong_email', + password = 'wrong_password')._elements_identifier == { + "Email": '//*[@id="email"]', + "Login_Button": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", + "Login_Code": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/div[3]/input", + "Login_Code_Confirmation": "/html/body/div[2]/div/main/div[1]/div/div[1]/form/button", + "Start_Chat_Button": "/html/body/div[2]/div/main/div[1]/div[2]/div[1]/div/div/fieldset/div/div[2]/div[2]/button", + "Prompt_Text_Area": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[1]/div/div/div/div/p", # noqa: E501 + "Prompt_Text_Area_Submit": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[2]/div/div/div/div/fieldset/div[2]/div[1]/div[2]/div[2]/div/button", # noqa: E501 + "Prompt_Text_Area_Output": "/html/body/div[2]/div/div[2]/div/div[2]/div[2]/div[1]/div[{current}]/div/div/div[1]/div/div", + } + assert ClaudeChrome(driver_config=[], email = 'wrong_email', password = 'wrong_password')._model_url == 'https://claude.ai/login' \ No newline at end of file