Spaces:
Running
Running
| import requests | |
| import json | |
| from typing import * | |
| from webscout.AIutel import Optimizers | |
| from webscout.AIutel import Conversation | |
| from webscout.AIutel import AwesomePrompts | |
| from webscout.AIbase import Provider | |
| from webscout import exceptions | |
| class TypeGPT(Provider): | |
| """ | |
| A class to interact with the TypeGPT.net API. Improved to match webscout standards. | |
| """ | |
| url = "https://chat.typegpt.net" | |
| working = True | |
| supports_message_history = True | |
| models = [ | |
| # OpenAI Models | |
| "gpt-3.5-turbo", | |
| "gpt-3.5-turbo-202201", | |
| "gpt-4o", | |
| "gpt-4o-2024-05-13", | |
| "o1-preview", | |
| # Claude Models | |
| "claude", | |
| "claude-3-5-sonnet", | |
| "claude-sonnet-3.5", | |
| "claude-3-5-sonnet-20240620", | |
| # Meta/LLaMA Models | |
| "@cf/meta/llama-2-7b-chat-fp16", | |
| "@cf/meta/llama-2-7b-chat-int8", | |
| "@cf/meta/llama-3-8b-instruct", | |
| "@cf/meta/llama-3.1-8b-instruct", | |
| "@cf/meta-llama/llama-2-7b-chat-hf-lora", | |
| "llama-3.1-405b", | |
| "llama-3.1-70b", | |
| "llama-3.1-8b", | |
| "meta-llama/Llama-2-7b-chat-hf", | |
| "meta-llama/Llama-3.1-70B-Instruct", | |
| "meta-llama/Llama-3.1-8B-Instruct", | |
| "meta-llama/Llama-3.2-11B-Vision-Instruct", | |
| "meta-llama/Llama-3.2-1B-Instruct", | |
| "meta-llama/Llama-3.2-3B-Instruct", | |
| "meta-llama/Llama-3.2-90B-Vision-Instruct", | |
| "meta-llama/Llama-Guard-3-8B", | |
| "meta-llama/Meta-Llama-3-70B-Instruct", | |
| "meta-llama/Meta-Llama-3-8B-Instruct", | |
| "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", | |
| "meta-llama/Meta-Llama-3.1-8B-Instruct", | |
| "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", | |
| # Mistral Models | |
| "mistral", | |
| "mistral-large", | |
| "@cf/mistral/mistral-7b-instruct-v0.1", | |
| "@cf/mistral/mistral-7b-instruct-v0.2-lora", | |
| "@hf/mistralai/mistral-7b-instruct-v0.2", | |
| "mistralai/Mistral-7B-Instruct-v0.2", | |
| "mistralai/Mistral-7B-Instruct-v0.3", | |
| "mistralai/Mixtral-8x22B-Instruct-v0.1", | |
| "mistralai/Mixtral-8x7B-Instruct-v0.1", | |
| # Qwen Models | |
| "@cf/qwen/qwen1.5-0.5b-chat", | |
| "@cf/qwen/qwen1.5-1.8b-chat", | |
| "@cf/qwen/qwen1.5-7b-chat-awq", | |
| "@cf/qwen/qwen1.5-14b-chat-awq", | |
| "Qwen/Qwen2.5-3B-Instruct", | |
| "Qwen/Qwen2.5-72B-Instruct", | |
| "Qwen/Qwen2.5-Coder-32B-Instruct", | |
| # Google/Gemini Models | |
| "@cf/google/gemma-2b-it-lora", | |
| "@cf/google/gemma-7b-it-lora", | |
| "@hf/google/gemma-7b-it", | |
| "google/gemma-1.1-2b-it", | |
| "google/gemma-1.1-7b-it", | |
| "gemini-pro", | |
| "gemini-1.5-pro", | |
| "gemini-1.5-pro-latest", | |
| "gemini-1.5-flash", | |
| # Cohere Models | |
| "c4ai-aya-23-35b", | |
| "c4ai-aya-23-8b", | |
| "command", | |
| "command-light", | |
| "command-light-nightly", | |
| "command-nightly", | |
| "command-r", | |
| "command-r-08-2024", | |
| "command-r-plus", | |
| "command-r-plus-08-2024", | |
| "rerank-english-v2.0", | |
| "rerank-english-v3.0", | |
| "rerank-multilingual-v2.0", | |
| "rerank-multilingual-v3.0", | |
| # Microsoft Models | |
| "@cf/microsoft/phi-2", | |
| "microsoft/DialoGPT-medium", | |
| "microsoft/Phi-3-medium-4k-instruct", | |
| "microsoft/Phi-3-mini-4k-instruct", | |
| "microsoft/Phi-3.5-mini-instruct", | |
| "microsoft/WizardLM-2-8x22B", | |
| # Yi Models | |
| "01-ai/Yi-1.5-34B-Chat", | |
| "01-ai/Yi-34B-Chat", | |
| # Specialized Models and Tools | |
| "@cf/deepseek-ai/deepseek-math-7b-base", | |
| "@cf/deepseek-ai/deepseek-math-7b-instruct", | |
| "@cf/defog/sqlcoder-7b-2", | |
| "@cf/openchat/openchat-3.5-0106", | |
| "@cf/thebloke/discolm-german-7b-v1-awq", | |
| "@cf/tiiuae/falcon-7b-instruct", | |
| "@cf/tinyllama/tinyllama-1.1b-chat-v1.0", | |
| "@hf/nexusflow/starling-lm-7b-beta", | |
| "@hf/nousresearch/hermes-2-pro-mistral-7b", | |
| "@hf/thebloke/deepseek-coder-6.7b-base-awq", | |
| "@hf/thebloke/deepseek-coder-6.7b-instruct-awq", | |
| "@hf/thebloke/llama-2-13b-chat-awq", | |
| "@hf/thebloke/llamaguard-7b-awq", | |
| "@hf/thebloke/neural-chat-7b-v3-1-awq", | |
| "@hf/thebloke/openhermes-2.5-mistral-7b-awq", | |
| "@hf/thebloke/zephyr-7b-beta-awq", | |
| "AndroidDeveloper", | |
| "AngularJSAgent", | |
| "AzureAgent", | |
| "BitbucketAgent", | |
| "DigitalOceanAgent", | |
| "DockerAgent", | |
| "ElectronAgent", | |
| "ErlangAgent", | |
| "FastAPIAgent", | |
| "FirebaseAgent", | |
| "FlaskAgent", | |
| "FlutterAgent", | |
| "GitAgent", | |
| "GitlabAgent", | |
| "GoAgent", | |
| "GodotAgent", | |
| "GoogleCloudAgent", | |
| "HTMLAgent", | |
| "HerokuAgent", | |
| "ImageGeneration", | |
| "JavaAgent", | |
| "JavaScriptAgent", | |
| "MongoDBAgent", | |
| "Next.jsAgent", | |
| "PyTorchAgent", | |
| "PythonAgent", | |
| "ReactAgent", | |
| "RepoMap", | |
| "SwiftDeveloper", | |
| "XcodeAgent", | |
| "YoutubeAgent", | |
| "blackboxai", | |
| "blackboxai-pro", | |
| "builderAgent", | |
| "dify", | |
| "flux", | |
| "openchat/openchat-3.6-8b", | |
| "rtist", | |
| "searchgpt", | |
| "sur", | |
| "sur-mistral", | |
| "unity" | |
| ] | |
| def __init__( | |
| self, | |
| is_conversation: bool = True, | |
| max_tokens: int = 4000, # Set a reasonable default | |
| timeout: int = 30, | |
| intro: str = None, | |
| filepath: str = None, | |
| update_file: bool = True, | |
| proxies: dict = {}, | |
| history_offset: int = 10250, | |
| act: str = None, | |
| model: str = "claude-3-5-sonnet-20240620", | |
| system_prompt: str = "You are a helpful assistant.", | |
| temperature: float = 0.5, | |
| presence_penalty: int = 0, | |
| frequency_penalty: int = 0, | |
| top_p: float = 1, | |
| ): | |
| """Initializes the TypeGPT API client.""" | |
| if model not in self.models: | |
| raise ValueError(f"Invalid model: {model}. Choose from: {', '.join(self.models)}") | |
| self.session = requests.Session() | |
| self.is_conversation = is_conversation | |
| self.max_tokens_to_sample = max_tokens | |
| self.api_endpoint = "https://chat.typegpt.net/api/openai/v1/chat/completions" | |
| self.timeout = timeout | |
| self.last_response = {} | |
| self.last_response_status_code = None # Added line for status code | |
| self.model = model | |
| self.system_prompt = system_prompt | |
| self.temperature = temperature | |
| self.presence_penalty = presence_penalty | |
| self.frequency_penalty = frequency_penalty | |
| self.top_p = top_p | |
| self.headers = { | |
| "authority": "chat.typegpt.net", | |
| "accept": "application/json, text/event-stream", | |
| "accept-language": "en-US,en;q=0.9", | |
| "content-type": "application/json", | |
| "origin": "https://chat.typegpt.net", | |
| "referer": "https://chat.typegpt.net/", | |
| "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" | |
| } | |
| self.__available_optimizers = ( | |
| method | |
| for method in dir(Optimizers) | |
| if callable(getattr(Optimizers, method)) and not method.startswith("__") | |
| ) | |
| Conversation.intro = ( | |
| AwesomePrompts().get_act( | |
| act, raise_not_found=True, default=None, case_insensitive=True | |
| ) | |
| if act | |
| else intro or Conversation.intro | |
| ) | |
| self.conversation = Conversation( | |
| is_conversation, self.max_tokens_to_sample, filepath, update_file | |
| ) | |
| self.conversation.history_offset = history_offset | |
| self.session.proxies = proxies | |
| def ask( | |
| self, | |
| prompt: str, | |
| stream: bool = False, | |
| raw: bool = False, | |
| optimizer: str = None, | |
| conversationally: bool = False, | |
| ) -> Dict[str, Any] | Generator: | |
| """Sends a prompt to the TypeGPT.net API and returns the response.""" | |
| conversation_prompt = self.conversation.gen_complete_prompt(prompt) | |
| if optimizer: | |
| if optimizer in self.__available_optimizers: | |
| conversation_prompt = getattr(Optimizers, optimizer)( | |
| conversation_prompt if conversationally else prompt | |
| ) | |
| else: | |
| raise exceptions.FailedToGenerateResponseError( | |
| f"Optimizer is not one of {self.__available_optimizers}" | |
| ) | |
| payload = { | |
| "messages": [ | |
| {"role": "system", "content": self.system_prompt}, | |
| {"role": "user", "content": conversation_prompt} | |
| ], | |
| "stream": stream, | |
| "model": self.model, | |
| "temperature": self.temperature, | |
| "presence_penalty": self.presence_penalty, | |
| "frequency_penalty": self.frequency_penalty, | |
| "top_p": self.top_p, | |
| "max_tokens": self.max_tokens_to_sample, | |
| } | |
| def for_stream(): | |
| response = self.session.post( | |
| self.api_endpoint, headers=self.headers, json=payload, stream=True, timeout=self.timeout | |
| ) | |
| self.last_response_status_code = response.status_code # Capture status code | |
| if not response.ok: | |
| raise exceptions.FailedToGenerateResponseError( | |
| f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}" | |
| ) | |
| message_load = "" | |
| for line in response.iter_lines(): | |
| if line: | |
| line = line.decode("utf-8") | |
| if line.startswith("data: "): | |
| line = line[6:] # Remove "data: " prefix | |
| # Skip [DONE] message | |
| if line.strip() == "[DONE]": | |
| break | |
| try: | |
| data = json.loads(line) | |
| # Extract and yield only new content | |
| if 'choices' in data and len(data['choices']) > 0: | |
| delta = data['choices'][0].get('delta', {}) | |
| if 'content' in delta: | |
| new_content = delta['content'] | |
| message_load += new_content | |
| # Yield only the new content | |
| yield dict(text=new_content) if not raw else new_content | |
| self.last_response = dict(text=message_load) | |
| except json.JSONDecodeError: | |
| continue | |
| self.conversation.update_chat_history(prompt, self.get_message(self.last_response)) | |
| def for_non_stream(): | |
| response = self.session.post(self.api_endpoint, headers=self.headers, json=payload) | |
| self.last_response_status_code = response.status_code # Capture status code | |
| if not response.ok: | |
| raise exceptions.FailedToGenerateResponseError( | |
| f"Request failed - {response.status_code}: {response.text}" | |
| ) | |
| self.last_response = response.json() | |
| self.conversation.update_chat_history(prompt, self.get_message(self.last_response)) | |
| return self.last_response | |
| return for_stream() if stream else for_non_stream() | |
| def chat( | |
| self, | |
| prompt: str, | |
| stream: bool = False, | |
| optimizer: str = None, | |
| conversationally: bool = False, | |
| ) -> str | Generator[str, None, None]: | |
| """Generate response `str` or stream.""" | |
| if stream: | |
| gen = self.ask( | |
| prompt, stream=True, optimizer=optimizer, conversationally=conversationally | |
| ) | |
| for chunk in gen: | |
| yield self.get_message(chunk) # Extract text from streamed chunks | |
| else: | |
| return self.get_message(self.ask(prompt, stream=False, optimizer=optimizer, conversationally=conversationally)) | |
| def get_message(self, response: Dict[str, Any]) -> str: | |
| """Retrieves message from response.""" | |
| if isinstance(response, str): # Handle raw responses | |
| return response | |
| elif isinstance(response, dict): | |
| assert isinstance(response, dict), "Response should be of dict data-type only" | |
| return response.get("text", "") # Extract text from dictionary response | |
| else: | |
| raise TypeError("Invalid response type. Expected str or dict.") | |
| if __name__ == "__main__": | |
| from rich import print | |
| from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn, SpinnerColumn | |
| from rich.console import Console | |
| from rich.table import Table | |
| import concurrent.futures | |
| def make_api_call(thread_number, results): | |
| ai = TypeGPT() | |
| try: | |
| ai.ask("Test message", stream=False) | |
| status_code = ai.last_response_status_code | |
| results[thread_number] = status_code | |
| except Exception as e: | |
| results[thread_number] = str(e) | |
| results = {} | |
| total_requests = 100 | |
| console = Console() | |
| print("[bold magenta]Starting API Load Test with 100 simultaneous requests...[/bold magenta]\n") | |
| with Progress( | |
| SpinnerColumn(), | |
| "[progress.description]{task.description}", | |
| BarColumn(bar_width=None), | |
| "[progress.percentage]{task.percentage:>3.0f}%", | |
| TimeRemainingColumn(), | |
| console=console, | |
| ) as progress: | |
| task = progress.add_task("[cyan]Sending API Requests...", total=total_requests) | |
| with concurrent.futures.ThreadPoolExecutor(max_workers=total_requests) as executor: | |
| futures = { | |
| executor.submit(make_api_call, i, results): i for i in range(total_requests) | |
| } | |
| for future in concurrent.futures.as_completed(futures): | |
| progress.update(task, advance=1) | |
| progress.stop() | |
| # Process and display the results | |
| successful_calls = sum(1 for status in results.values() if status == 200) | |
| failed_calls = total_requests - successful_calls | |
| print("\n[bold magenta]API Load Test Results:[/bold magenta]\n") | |
| print(f"[bold green]Successful calls: {successful_calls}") | |
| print(f"[bold red]Failed calls: {failed_calls}\n") | |
| # Create a table to display detailed results | |
| table = Table(show_header=True, header_style="bold blue") | |
| table.add_column("Thread Number", justify="right", style="dim") | |
| table.add_column("Status", style="bold") | |
| for thread_number, status in results.items(): | |
| if status == 200: | |
| table.add_row(f"{thread_number}", f"[green]Success[/green]") | |
| else: | |
| table.add_row(f"{thread_number}", f"[red]Failed ({status})[/red]") | |
| print(table) |