From 46038c6a207a594d32a88e98d5ed6532f0bd17f3 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Mon, 25 Nov 2024 13:27:56 +0100 Subject: [PATCH] Add .har file support for Copilot Update provider in Vision documentation Hide --- docs/async_client.md | 11 +++--- docs/client.md | 5 +-- g4f/Provider/Copilot.py | 53 ++++++++++++++++++++++++++--- g4f/cli.py | 6 ++-- g4f/gui/client/static/css/style.css | 4 +++ 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/docs/async_client.md b/docs/async_client.md index fe6f46ff..e501aefa 100644 --- a/docs/async_client.md +++ b/docs/async_client.md @@ -154,13 +154,14 @@ import asyncio from g4f.client import AsyncClient async def main(): - client = AsyncClient() - + client = AsyncClient( + provider=g4f.Provider.CopilotAccount + ) + image = requests.get("https://raw.githubusercontent.com/xtekky/gpt4free/refs/heads/main/docs/cat.jpeg", stream=True).raw - + response = await client.chat.completions.create( model=g4f.models.default, - provider=g4f.Provider.Bing, messages=[ { "role": "user", @@ -169,7 +170,7 @@ async def main(): ], image=image ) - + print(response.choices[0].message.content) asyncio.run(main()) diff --git a/docs/client.md b/docs/client.md index da45d7fd..c318bee3 100644 --- a/docs/client.md +++ b/docs/client.md @@ -265,7 +265,9 @@ from g4f.client import Client image = requests.get("https://raw.githubusercontent.com/xtekky/gpt4free/refs/heads/main/docs/cat.jpeg", stream=True).raw # Or: image = open("docs/cat.jpeg", "rb") -client = Client() +client = Client( + provider=CopilotAccount +) response = client.chat.completions.create( model=g4f.models.default, @@ -275,7 +277,6 @@ response = client.chat.completions.create( "content": "What are on this image?" } ], - provider=g4f.Provider.Bing, image=image # Add any other necessary parameters ) diff --git a/g4f/Provider/Copilot.py b/g4f/Provider/Copilot.py index 2f37b1eb..5721f377 100644 --- a/g4f/Provider/Copilot.py +++ b/g4f/Provider/Copilot.py @@ -1,5 +1,6 @@ from __future__ import annotations +import os import json import asyncio from http.cookiejar import CookieJar @@ -21,9 +22,11 @@ from .helper import format_prompt from ..typing import CreateResult, Messages, ImageType from ..errors import MissingRequirementsError from ..requests.raise_for_status import raise_for_status -from ..providers.helper import format_cookies +from ..providers.asyncio import get_running_loop +from ..Provider.openai.har_file import NoValidHarFileError, get_headers from ..requests import get_nodriver from ..image import ImageResponse, to_bytes, is_accepted_format +from ..cookies import get_cookies_dir from .. import debug class Conversation(BaseConversation): @@ -69,7 +72,15 @@ class Copilot(AbstractProvider): cookies = conversation.cookie_jar if conversation is not None else None if cls.needs_auth or image is not None: if conversation is None or conversation.access_token is None: - access_token, cookies = asyncio.run(cls.get_access_token_and_cookies(proxy)) + try: + access_token, cookies = readHAR() + except NoValidHarFileError as h: + debug.log(f"Copilot: {h}") + try: + get_running_loop(check_nested=True) + access_token, cookies = asyncio.run(cls.get_access_token_and_cookies(proxy)) + except MissingRequirementsError: + raise h else: access_token = conversation.access_token debug.log(f"Copilot: Access token: {access_token[:7]}...{access_token[-5:]}") @@ -159,7 +170,9 @@ class Copilot(AbstractProvider): for (var i = 0; i < localStorage.length; i++) { try { item = JSON.parse(localStorage.getItem(localStorage.key(i))); - if (item.credentialType == "AccessToken") { + if (item.credentialType == "AccessToken" + && item.expiresOn > Math.floor(Date.now() / 1000) + && item.target.includes("ChatAI")) { return item.secret; } } catch(e) {} @@ -172,4 +185,36 @@ class Copilot(AbstractProvider): for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])): cookies[c.name] = c.value await page.close() - return access_token, cookies \ No newline at end of file + return access_token, cookies + +def readHAR(): + harPath = [] + for root, _, files in os.walk(get_cookies_dir()): + for file in files: + if file.endswith(".har"): + harPath.append(os.path.join(root, file)) + if not harPath: + raise NoValidHarFileError("No .har file found") + api_key = None + cookies = None + for path in harPath: + with open(path, 'rb') as file: + try: + harFile = json.loads(file.read()) + except json.JSONDecodeError: + # Error: not a HAR file! + continue + for v in harFile['log']['entries']: + v_headers = get_headers(v) + if v['request']['url'].startswith(Copilot.url): + try: + if "authorization" in v_headers: + api_key = v_headers["authorization"].split(maxsplit=1).pop() + except Exception as e: + debug.log(f"Error on read headers: {e}") + if v['request']['cookies']: + cookies = {c['name']: c['value'] for c in v['request']['cookies']} + if api_key is None: + raise NoValidHarFileError("No access token found in .har files") + + return api_key, cookies \ No newline at end of file diff --git a/g4f/cli.py b/g4f/cli.py index 90ec37fa..a8a038a2 100644 --- a/g4f/cli.py +++ b/g4f/cli.py @@ -10,8 +10,9 @@ def main(): parser = argparse.ArgumentParser(description="Run gpt4free") subparsers = parser.add_subparsers(dest="mode", help="Mode to run the g4f in.") api_parser = subparsers.add_parser("api") - api_parser.add_argument("--bind", default="0.0.0.0:1337", help="The bind string.") - api_parser.add_argument("--debug", action="store_true", help="Enable verbose logging.") + api_parser.add_argument("--bind", default=None, help="The bind string. (Default: 0.0.0.0:1337)") + api_parser.add_argument("--port", default=None, help="Change the port of the server.") + api_parser.add_argument("--debug", "-d", action="store_true", help="Enable verbose logging.") api_parser.add_argument("--gui", "-g", default=False, action="store_true", help="Add gui to the api.") api_parser.add_argument("--model", default=None, help="Default model for chat completion. (incompatible with --reload and --workers)") api_parser.add_argument("--provider", choices=[provider.__name__ for provider in Provider.__providers__ if provider.working], @@ -55,6 +56,7 @@ def run_api_args(args): g4f.cookies.browsers = [g4f.cookies[browser] for browser in args.cookie_browsers] run_api( bind=args.bind, + port=args.port, debug=args.debug, workers=args.workers, use_colors=not args.disable_colors, diff --git a/g4f/gui/client/static/css/style.css b/g4f/gui/client/static/css/style.css index 57b75bae..856f9fb5 100644 --- a/g4f/gui/client/static/css/style.css +++ b/g4f/gui/client/static/css/style.css @@ -177,6 +177,10 @@ body { filter: blur(calc(0.5 * 70vw)) opacity(var(--opacity)); } +body.white .gradient{ + display: none; +} + .conversations { display: flex; flex-direction: column;