diff options
Diffstat (limited to 'g4f/Provider/needs_auth')
-rw-r--r-- | g4f/Provider/needs_auth/Gemini.py | 5 | ||||
-rw-r--r-- | g4f/Provider/needs_auth/GithubCopilot.py | 93 | ||||
-rw-r--r-- | g4f/Provider/needs_auth/OpenaiChat.py | 26 | ||||
-rw-r--r-- | g4f/Provider/needs_auth/__init__.py | 1 |
4 files changed, 111 insertions, 14 deletions
diff --git a/g4f/Provider/needs_auth/Gemini.py b/g4f/Provider/needs_auth/Gemini.py index 1e89ab05..89f6f802 100644 --- a/g4f/Provider/needs_auth/Gemini.py +++ b/g4f/Provider/needs_auth/Gemini.py @@ -206,6 +206,8 @@ class Gemini(AsyncGeneratorProvider): @classmethod async def synthesize(cls, params: dict, proxy: str = None) -> AsyncIterator[bytes]: + if "text" not in params: + raise ValueError("Missing parameter text") async with ClientSession( cookies=cls._cookies, headers=REQUEST_HEADERS, @@ -213,9 +215,6 @@ class Gemini(AsyncGeneratorProvider): ) as session: if not cls._snlm0e: await cls.fetch_snlm0e(session, cls._cookies) if cls._cookies else None - if not cls._snlm0e: - async for chunk in cls.nodriver_login(proxy): - debug.log(chunk) inner_data = json.dumps([None, params["text"], "de-DE", None, 2]) async with session.post( "https://gemini.google.com/_/BardChatUi/data/batchexecute", diff --git a/g4f/Provider/needs_auth/GithubCopilot.py b/g4f/Provider/needs_auth/GithubCopilot.py new file mode 100644 index 00000000..0c12dfd0 --- /dev/null +++ b/g4f/Provider/needs_auth/GithubCopilot.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import json + +from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin, BaseConversation +from ...typing import AsyncResult, Messages, Cookies +from ...requests.raise_for_status import raise_for_status +from ...requests import StreamSession +from ...providers.helper import format_prompt +from ...cookies import get_cookies + +class Conversation(BaseConversation): + conversation_id: str + + def __init__(self, conversation_id: str): + self.conversation_id = conversation_id + +class GithubCopilot(AsyncGeneratorProvider, ProviderModelMixin): + url = "https://copilot.microsoft.com" + working = True + needs_auth = True + supports_stream = True + default_model = "gpt-4o" + models = [default_model, "o1-mini", "o1-preview", "claude-3.5-sonnet"] + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + stream: bool = False, + api_key: str = "X2eRgXPamxGK_TXS6seGGYy541mQuVJdH1CYljrvSPuc38je5J4KK4Aw0y5X2oVRFMjA4B1fo9sdsr4VJcl-VBae7H0Mr4U9GIkFnGx3hSs=", + proxy: str = None, + cookies: Cookies = None, + conversation_id: str = None, + conversation: Conversation = None, + return_conversation: bool = False, + **kwargs + ) -> AsyncResult: + if not model: + model = cls.default_model + if cookies is None: + cookies = get_cookies(".github.com") + async with StreamSession( + proxy=proxy, + impersonate="chrome", + cookies=cookies, + headers={ + "GitHub-Verified-Fetch": "true", + } + ) as session: + headers = {} + if api_key is None: + async with session.post("https://github.com/github-copilot/chat/token") as response: + await raise_for_status(response, "Get token") + api_key = (await response.json()).get("token") + headers = { + "Authorization": f"GitHub-Bearer {api_key}", + } + if conversation is not None: + conversation_id = conversation.conversation_id + if conversation_id is None: + print(headers) + async with session.post("https://api.individual.githubcopilot.com/github/chat/threads", headers=headers) as response: + await raise_for_status(response) + conversation_id = (await response.json()).get("thread_id") + if return_conversation: + yield Conversation(conversation_id) + content = messages[-1]["content"] + else: + content = format_prompt(messages) + json_data = { + "content": content, + "intent": "conversation", + "references":[], + "context": [], + "currentURL": f"https://github.com/copilot/c/{conversation_id}", + "streaming": True, + "confirmations": [], + "customInstructions": [], + "model": model, + "mode": "immersive" + } + async with session.post( + f"https://api.individual.githubcopilot.com/github/chat/threads/{conversation_id}/messages", + json=json_data, + headers=headers + ) as response: + async for line in response.iter_lines(): + if line.startswith(b"data: "): + data = json.loads(line[6:]) + if data.get("type") == "content": + yield data.get("body")
\ No newline at end of file diff --git a/g4f/Provider/needs_auth/OpenaiChat.py b/g4f/Provider/needs_auth/OpenaiChat.py index 074c9161..37bdf074 100644 --- a/g4f/Provider/needs_auth/OpenaiChat.py +++ b/g4f/Provider/needs_auth/OpenaiChat.py @@ -111,7 +111,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): # Post the image data to the service and get the image data async with session.post(f"{cls.url}/backend-api/files", json=data, headers=headers) as response: cls._update_request_args(session) - await raise_for_status(response) + await raise_for_status(response, "Create file failed") image_data = { **data, **await response.json(), @@ -129,7 +129,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): "x-ms-blob-type": "BlockBlob" } ) as response: - await raise_for_status(response) + await raise_for_status(response, "Send file failed") # Post the file ID to the service and get the download URL async with session.post( f"{cls.url}/backend-api/files/{image_data['file_id']}/uploaded", @@ -137,12 +137,12 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): headers=headers ) as response: cls._update_request_args(session) - await raise_for_status(response) + await raise_for_status(response, "Get download url failed") image_data["download_url"] = (await response.json())["download_url"] return ImageRequest(image_data) @classmethod - def create_messages(cls, messages: Messages, image_request: ImageRequest = None): + def create_messages(cls, messages: Messages, image_request: ImageRequest = None, system_hints: list = None): """ Create a list of messages for the user input @@ -160,7 +160,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): "id": str(uuid.uuid4()), "create_time": int(time.time()), "id": str(uuid.uuid4()), - "metadata": {"serialization_metadata": {"custom_symbol_offsets": []}} + "metadata": {"serialization_metadata": {"custom_symbol_offsets": []}, "system_hints": system_hints}, } for message in messages] # Check if there is an image response @@ -189,7 +189,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): return messages @classmethod - async def get_generated_image(cls, session: StreamSession, headers: dict, element: dict) -> ImageResponse: + async def get_generated_image(cls, session: StreamSession, headers: dict, element: dict, prompt: str = None) -> ImageResponse: """ Retrieves the image response based on the message content. @@ -211,6 +211,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): try: prompt = element["metadata"]["dalle"]["prompt"] file_id = element["asset_pointer"].split("file-service://", 1)[1] + except TypeError: + return except Exception as e: raise RuntimeError(f"No Image: {e.__class__.__name__}: {e}") try: @@ -240,6 +242,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): image_name: str = None, return_conversation: bool = False, max_retries: int = 3, + web_search: bool = False, **kwargs ) -> AsyncResult: """ @@ -331,14 +334,15 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): "conversation_mode": {"kind":"primary_assistant"}, "websocket_request_id": str(uuid.uuid4()), "supported_encodings": ["v1"], - "supports_buffering": True + "supports_buffering": True, + "system_hints": ["search"] if web_search else None } if conversation.conversation_id is not None: data["conversation_id"] = conversation.conversation_id debug.log(f"OpenaiChat: Use conversation: {conversation.conversation_id}") if action != "continue": messages = messages if conversation_id is None else [messages[-1]] - data["messages"] = cls.create_messages(messages, image_request) + data["messages"] = cls.create_messages(messages, image_request, ["search"] if web_search else None) headers = { **cls._headers, "accept": "text/event-stream", @@ -419,9 +423,9 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin): generated_images = [] for element in c.get("parts"): if isinstance(element, dict) and element.get("content_type") == "image_asset_pointer": - generated_images.append( - cls.get_generated_image(session, cls._headers, element) - ) + image = cls.get_generated_image(session, cls._headers, element) + if image is not None: + generated_images.append(image) for image_response in await asyncio.gather(*generated_images): yield image_response if m.get("author", {}).get("role") == "assistant": diff --git a/g4f/Provider/needs_auth/__init__.py b/g4f/Provider/needs_auth/__init__.py index 1c7fe7c5..f3391706 100644 --- a/g4f/Provider/needs_auth/__init__.py +++ b/g4f/Provider/needs_auth/__init__.py @@ -7,6 +7,7 @@ from .DeepInfra import DeepInfra from .DeepInfraImage import DeepInfraImage from .Gemini import Gemini from .GeminiPro import GeminiPro +from .GithubCopilot import GithubCopilot from .Groq import Groq from .HuggingFace import HuggingFace from .HuggingFace2 import HuggingFace2 |