From ccd74eda81254356e8cf083719c11b925f073199 Mon Sep 17 00:00:00 2001 From: "valerii@valeriis-air.(none)" Date: Mon, 1 May 2023 04:09:27 +0300 Subject: update(docker-compose.yml): Removed docker-compose.yml --- docker-compose.yml | 14 -------- gpt4free/forefront/__init__.py | 81 ++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 53 deletions(-) delete mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index e8fcb0de..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3.8' - -services: - gpt4: - build: - context: . - dockerfile: Dockerfile - image: gpt4free:latest - container_name: gpt4 - ports: - - 8501:8501 - restart: unless-stopped - read_only: true - diff --git a/gpt4free/forefront/__init__.py b/gpt4free/forefront/__init__.py index 7a4f4f28..d646de92 100644 --- a/gpt4free/forefront/__init__.py +++ b/gpt4free/forefront/__init__.py @@ -1,47 +1,59 @@ -from json import loads -from re import findall -from time import time, sleep +import re +import time from typing import Generator, Optional from uuid import uuid4 -from fake_useragent import UserAgent -from requests import post -from pymailtm import MailTm, Message -from tls_client import Session +import fake_useragent +import pymailtm +import requests from .typing import ForeFrontResponse +def speed_logging(func): + def wrapper(*args, **kwargs): + start = time.time() + res = func(*args, **kwargs) + print(time() - start) + return res + return wrapper + + class Account: + @speed_logging @staticmethod - def create(proxy: Optional[str] = None, logging: bool = False): - proxies = {'http': 'http://' + proxy, 'https': 'http://' + proxy} if proxy else False + def create_forefront_account(proxy: Optional[str] = None) -> Optional[str]: + """Create a ForeFront account. + + Args: + proxy: The proxy to use for the request. - start = time() + Returns: + The ForeFront token if successful, else None. + """ + proxies = {'http': f'http://{proxy}', 'https': f'http://{proxy}'} if proxy else None - mail_client = MailTm().get_account() + mail_client = pymailtm.MailTm().get_account() mail_address = mail_client.address - client = Session(client_identifier='chrome110') - client.proxies = proxies - client.headers = { + session = requests.Session() + session.proxies = proxies + session.headers = { 'origin': 'https://accounts.forefront.ai', - 'user-agent': UserAgent().random, + 'user-agent': fake_useragent.UserAgent().random, } - response = client.post( + response = session.post( 'https://clerk.forefront.ai/v1/client/sign_ups?_clerk_js_version=4.38.4', data={'email_address': mail_address}, ) try: trace_token = response.json()['response']['id'] - if logging: - print(trace_token) except KeyError: - return 'Failed to create account!' + return None - response = client.post( + response = session.post( f'https://clerk.forefront.ai/v1/client/sign_ups/{trace_token}/prepare_verification?_clerk_js_version=4.38.4', data={ 'strategy': 'email_link', @@ -49,38 +61,26 @@ class Account: }, ) - if logging: - print(response.text) - if 'sign_up_attempt' not in response.text: - return 'Failed to create account!' + return None while True: - sleep(1) - new_message: Message = mail_client.wait_for_message() - if logging: - print(new_message.data['id']) - - verification_url = findall(r'https:\/\/clerk\.forefront\.ai\/v1\/verify\?token=\w.+', new_message.text)[0] + time.sleep(1) + new_message = mail_client.wait_for_message() + verification_url = re.findall(r'https:\/\/clerk\.forefront\.ai\/v1\/verify\?token=\w.+', new_message.text) if verification_url: break - if logging: - print(verification_url) + response = session.get(verification_url[0]) - response = client.get(verification_url) - - response = client.get('https://clerk.forefront.ai/v1/client?_clerk_js_version=4.38.4') + response = session.get('https://clerk.forefront.ai/v1/client?_clerk_js_version=4.38.4') token = response.json()['response']['sessions'][0]['last_active_token']['jwt'] with open('accounts.txt', 'a') as f: f.write(f'{mail_address}:{token}\n') - if logging: - print(time() - start) - return token @@ -100,7 +100,7 @@ class StreamingCompletion: if not chat_id: chat_id = str(uuid4()) - proxies = { 'http': 'http://' + proxy, 'https': 'http://' + proxy } if proxy else None + proxies = { 'http': f'http://{proxy}', 'https': f'http://{proxy}' } if proxy else None headers = { 'authority': 'chat-server.tenant-forefront-default.knative.chi.coreweave.com', @@ -191,3 +191,6 @@ class Completion: raise Exception('Unable to get the response, Please try again') return final_response + + + -- cgit v1.2.3 From 12a639fb2a50a02a0475f82831b19c630b236af6 Mon Sep 17 00:00:00 2001 From: "valerii@valeriis-air.(none)" Date: Fri, 5 May 2023 00:52:53 +0300 Subject: update(quora/api): Modified a request_with_retries function. Added delay between retries (maybe it's better to wrap it in a context manager). Error logging. Function renamed. If not 200 status - raise_for_status() exception --- gpt4free/quora/api.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/gpt4free/quora/api.py b/gpt4free/quora/api.py index 897215a8..d19172ce 100644 --- a/gpt4free/quora/api.py +++ b/gpt4free/quora/api.py @@ -56,18 +56,25 @@ def generate_payload(query_name, variables): return {"query": queries[query_name], "variables": variables} -def request_with_retries(method, *args, **kwargs): - attempts = kwargs.get("attempts") or 10 +def retry_request(method, *args, **kwargs): + """Retry a request with 10 attempts by default, delay increases exponentially""" + max_attempts: int = kwargs.pop("max_attempts", 10) + delay = kwargs.pop("delay", 1) url = args[0] - for i in range(attempts): - r = method(*args, **kwargs) - if r.status_code == 200: - return r - logger.warn( - f"Server returned a status code of {r.status_code} while downloading {url}. Retrying ({i + 1}/{attempts})..." - ) - raise RuntimeError(f"Failed to download {url} too many times.") + for attempt in range(1, max_attempts + 1): + try: + response = method(*args, **kwargs) + response.raise_for_status() + return response + except Exception as error: + logger.warning( + f"Attempt {attempt}/{max_attempts} failed with error: {error}. " + f"Retrying in {delay} seconds..." + ) + time.sleep(delay) + delay *= 2 + raise RuntimeError(f"Failed to download {url} after {max_attempts} attempts.") class Client: @@ -134,7 +141,7 @@ class Client: def get_next_data(self, overwrite_vars=False): logger.info("Downloading next_data...") - r = request_with_retries(self.session.get, self.home_url) + r = retry_request(self.session.get, self.home_url) json_regex = r'' json_text = re.search(json_regex, r.text).group(1) next_data = json.loads(json_text) @@ -149,7 +156,7 @@ class Client: def get_bot(self, display_name): url = f'https://poe.com/_next/data/{self.next_data["buildId"]}/{display_name}.json' - r = request_with_retries(self.session.get, url) + r = retry_request(self.session.get, url) chat_data = r.json()["pageProps"]["payload"]["chatOfBotDisplayName"] return chat_data @@ -198,7 +205,7 @@ class Client: def get_channel_data(self, channel=None): logger.info("Downloading channel data...") - r = request_with_retries(self.session.get, self.settings_url) + r = retry_request(self.session.get, self.settings_url) data = r.json() return data["tchannelData"] @@ -222,7 +229,7 @@ class Client: } headers = {**self.gql_headers, **headers} - r = request_with_retries(self.session.post, self.gql_url, data=payload, headers=headers) + r = retry_request(self.session.post, self.gql_url, data=payload, headers=headers) data = r.json() if data["data"] is None: -- cgit v1.2.3 From cc9179eda843a2fa5b2c4e4957b583d8f0b5cc47 Mon Sep 17 00:00:00 2001 From: "valerii@valeriis-air.(none)" Date: Fri, 5 May 2023 01:13:34 +0300 Subject: add(quora/tests): Added a module with quora tests. It is covering 3 scenarios: 1. test_successful_request 2. test_exponential backoff 3. test_too_many_requests Run tests: python -m unittest gpt4free/quora/tests/test_api.py --- gpt4free/quora/tests/__init__.py | 0 gpt4free/quora/tests/test_api.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 gpt4free/quora/tests/__init__.py create mode 100644 gpt4free/quora/tests/test_api.py diff --git a/gpt4free/quora/tests/__init__.py b/gpt4free/quora/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gpt4free/quora/tests/test_api.py b/gpt4free/quora/tests/test_api.py new file mode 100644 index 00000000..2a4bb41b --- /dev/null +++ b/gpt4free/quora/tests/test_api.py @@ -0,0 +1,38 @@ +import unittest +import requests +from unittest.mock import MagicMock +from gpt4free.quora.api import retry_request + + +class TestRetryRequest(unittest.TestCase): + def test_successful_request(self): + # Mock a successful request with a 200 status code + mock_response = MagicMock() + mock_response.status_code = 200 + requests.get = MagicMock(return_value=mock_response) + + # Call the function and assert that it returns the response + response = retry_request(requests.get, "http://example.com", max_attempts=3) + self.assertEqual(response.status_code, 200) + + def test_exponential_backoff(self): + # Mock a failed request that succeeds after two retries + mock_response = MagicMock() + mock_response.status_code = 200 + requests.get = MagicMock(side_effect=[requests.exceptions.RequestException] * 2 + [mock_response]) + + # Call the function and assert that it retries with exponential backoff + with self.assertLogs() as logs: + response = retry_request(requests.get, "http://example.com", max_attempts=3, delay=1) + self.assertEqual(response.status_code, 200) + self.assertGreaterEqual(len(logs.output), 2) + self.assertIn("Retrying in 1 seconds...", logs.output[0]) + self.assertIn("Retrying in 2 seconds...", logs.output[1]) + + def test_too_many_attempts(self): + # Mock a failed request that never succeeds + requests.get = MagicMock(side_effect=requests.exceptions.RequestException) + + # Call the function and assert that it raises an exception after the maximum number of attempts + with self.assertRaises(RuntimeError): + retry_request(requests.get, "http://example.com", max_attempts=3) -- cgit v1.2.3 From 0d9ff6770488d19014c58393202228ebe8e01e74 Mon Sep 17 00:00:00 2001 From: "valerii@valeriis-air.(none)" Date: Fri, 5 May 2023 01:36:17 +0300 Subject: fix(Dockerfile): Fixed issue with unable to fetch the response. The issue was that there were no ffmpeg installed. --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 297ebbbf..ee882415 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,9 @@ WORKDIR /usr/app ENV PATH="/usr/app/venv/bin:$PATH" #RUN apt-get update && apt-get install -y git +RUN apt-get update +RUN apt-get install ffmpeg #issue 445 + RUN mkdir -p /usr/app RUN python -m venv ./venv -- cgit v1.2.3 From e4b774070d6d5f130061983e0036e85bd5971378 Mon Sep 17 00:00:00 2001 From: "valerii@valeriis-air.(none)" Date: Fri, 5 May 2023 01:53:29 +0300 Subject: fix(Dockerfile): Fixed issue with unable to fetch the response. Added -y flag. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ee882415..0ac667fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ENV PATH="/usr/app/venv/bin:$PATH" #RUN apt-get update && apt-get install -y git RUN apt-get update -RUN apt-get install ffmpeg #issue 445 +RUN apt-get install ffmpeg -y #issue 445 RUN mkdir -p /usr/app RUN python -m venv ./venv -- cgit v1.2.3