import re import requests from uuid import uuid4 import json from typing import Any, AsyncGenerator, Dict, Generator import os from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() class v2: def __init__( self, timeout: int = 100, proxies: dict = {}, ): self.session = requests.Session() self.chat_endpoint = os.getenv("v2") self.stream_chunk_size = 64 self.timeout = timeout self.last_response = {} self.headers = { "accept": "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": "en-US,en;q=0.9,en-IN;q=0.8", "content-type": "application/json", } self.session.headers.update(self.headers) self.session.proxies = proxies def ask( self, prompt: str, stream: bool = False, raw: bool = False, ) -> Generator[Dict[str, Any], None, None]: conversation_prompt = prompt self.session.headers.update(self.headers) payload = { "query": conversation_prompt, "search_uuid": uuid4().hex, "lang": "", "agent_lang": "en", "search_options": { "langcode": "en-US" }, "search_video": True, "contexts_from": "google" } response = self.session.post( self.chat_endpoint, json=payload, stream=True, timeout=self.timeout ) if not response.ok: raise Exception( f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}" ) streaming_text = "" for line in response.iter_lines(decode_unicode=True): if line.startswith('data:'): try: data = json.loads(line[5:].strip()) if data['type'] == 'answer' and 'text' in data['data']: new_text = data['data']['text'] if len(new_text) > len(streaming_text): delta = new_text[len(streaming_text):] streaming_text = new_text resp = dict(text=delta) self.last_response.update(dict(text=streaming_text)) yield line if raw else resp except json.JSONDecodeError: pass def chat( self, prompt: str, stream: bool = False, ) -> Generator[str, None, None]: buffer = "" for response in self.ask(prompt, True): text = self.get_message(response) buffer += text lines = buffer.split('\n') for line in lines[:-1]: yield self.format_text(line) + '\n\n' buffer = lines[-1] if buffer: yield self.format_text(buffer) + '\n\n' yield "[DONE]" def get_message(self, response: dict) -> str: assert isinstance(response, dict), "Response should be of dict data-type only" if "text" in response: text = re.sub(r'\[\[\d+\]\]', '', response["text"]) return text else: return "" def format_text(self, text: str) -> str: # Convert *text* to text for italic text = re.sub(r'\*(.*?)\*', r'\1', text) return text