From 951a1332a7dc1878feb11b60677faff4bb7b391b Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Wed, 20 Sep 2023 23:06:52 +0200 Subject: Fix create_event_loop function Add PerplexityAi Provider --- g4f/Provider/PerplexityAi.py | 87 +++++++++++++++++++++++++++++++++++++++++++ g4f/Provider/__init__.py | 2 + g4f/Provider/base_provider.py | 21 ++++++----- 3 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 g4f/Provider/PerplexityAi.py diff --git a/g4f/Provider/PerplexityAi.py b/g4f/Provider/PerplexityAi.py new file mode 100644 index 00000000..269cdafd --- /dev/null +++ b/g4f/Provider/PerplexityAi.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import json +import time +import base64 +from curl_cffi.requests import AsyncSession + +from .base_provider import AsyncProvider, format_prompt + + +class PerplexityAi(AsyncProvider): + url = "https://www.perplexity.ai" + working = True + supports_gpt_35_turbo = True + _sources = [] + + @classmethod + async def create_async( + cls, + model: str, + messages: list[dict[str, str]], + proxy: str = None, + **kwargs + ) -> str: + url = cls.url + "/socket.io/?EIO=4&transport=polling" + async with AsyncSession(proxies={"https": proxy}, impersonate="chrome107") as session: + url_session = "https://www.perplexity.ai/api/auth/session" + response = await session.get(url_session) + + response = await session.get(url, params={"t": timestamp()}) + response.raise_for_status() + sid = json.loads(response.text[1:])["sid"] + + data = '40{"jwt":"anonymous-ask-user"}' + response = await session.post(url, params={"t": timestamp(), "sid": sid}, data=data) + response.raise_for_status() + + data = "424" + json.dumps([ + "perplexity_ask", + format_prompt(messages), + { + "version":"2.1", + "source":"default", + "language":"en", + "timezone": time.tzname[0], + "search_focus":"internet", + "mode":"concise" + } + ]) + response = await session.post(url, params={"t": timestamp(), "sid": sid}, data=data) + response.raise_for_status() + + while True: + response = await session.get(url, params={"t": timestamp(), "sid": sid}) + response.raise_for_status() + for line in response.text.splitlines(): + if line.startswith("434"): + result = json.loads(json.loads(line[3:])[0]["text"]) + + cls._sources = [{ + "name": source["name"], + "url": source["url"], + "snippet": source["snippet"] + } for source in result["web_results"]] + + return result["answer"] + + @classmethod + def get_sources(cls): + return cls._sources + + + @classmethod + @property + def params(cls): + params = [ + ("model", "str"), + ("messages", "list[dict[str, str]]"), + ("stream", "bool"), + ("proxy", "str"), + ] + param = ", ".join([": ".join(p) for p in params]) + return f"g4f.provider.{cls.__name__} supports: ({param})" + + +def timestamp() -> str: + return base64.urlsafe_b64encode(int(time.time()-1407782612).to_bytes(4, 'big')).decode() \ No newline at end of file diff --git a/g4f/Provider/__init__.py b/g4f/Provider/__init__.py index c36782b4..0ca22533 100644 --- a/g4f/Provider/__init__.py +++ b/g4f/Provider/__init__.py @@ -24,6 +24,7 @@ from .Lockchat import Lockchat from .Opchatgpts import Opchatgpts from .OpenaiChat import OpenaiChat from .OpenAssistant import OpenAssistant +from .PerplexityAi import PerplexityAi from .Raycast import Raycast from .Theb import Theb from .Vercel import Vercel @@ -67,6 +68,7 @@ __all__ = [ 'Raycast', 'OpenaiChat', 'OpenAssistant', + 'PerplexityAi', 'Theb', 'Vercel', 'Vitalentum', diff --git a/g4f/Provider/base_provider.py b/g4f/Provider/base_provider.py index 003f86ba..0cceb220 100644 --- a/g4f/Provider/base_provider.py +++ b/g4f/Provider/base_provider.py @@ -6,7 +6,7 @@ from abc import ABC, abstractmethod import browser_cookie3 -from ..typing import Any, AsyncGenerator, CreateResult, Union +from ..typing import Any, AsyncGenerator, CreateResult class BaseProvider(ABC): @@ -22,7 +22,9 @@ class BaseProvider(ABC): def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, **kwargs: Any) -> CreateResult: + stream: bool, + **kwargs + ) -> CreateResult: raise NotImplementedError() @@ -118,16 +120,15 @@ class AsyncGeneratorProvider(AsyncProvider): raise NotImplementedError() +# Don't create a new event loop in a running async loop. +# Force use selector event loop on windows and linux use it anyway. def create_event_loop() -> SelectorEventLoop: - # Don't create a new loop in a running loop try: - if asyncio.get_running_loop() is not None: - raise RuntimeError( - 'Use "create_async" instead of "create" function in a async loop.') - except: - pass - # Force use selector event loop on windows and linux use it anyway - return SelectorEventLoop() + asyncio.get_running_loop() + except RuntimeError: + return SelectorEventLoop() + raise RuntimeError( + 'Use "create_async" instead of "create" function in a async loop.') _cookies = {} -- cgit v1.2.3