Skip to content

Commit de4f374

Browse files
authored
Merge pull request xtekky#2387 from hlohaus/info
Add image upload to Copilot provider, Add --cookie-browsers argument to cli
2 parents 3aa497f + 2754043 commit de4f374

File tree

9 files changed

+84
-84
lines changed

9 files changed

+84
-84
lines changed

g4f/Provider/Copilot.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,13 @@
1515
has_nodriver = True
1616
except ImportError:
1717
has_nodriver = False
18-
try:
19-
from platformdirs import user_config_dir
20-
has_platformdirs = True
21-
except ImportError:
22-
has_platformdirs = False
2318

2419
from .base_provider import AbstractProvider, BaseConversation
2520
from .helper import format_prompt
2621
from ..typing import CreateResult, Messages, ImageType
2722
from ..errors import MissingRequirementsError
2823
from ..requests.raise_for_status import raise_for_status
24+
from ..requests import get_nodriver
2925
from ..image import to_bytes, is_accepted_format
3026
from .. import debug
3127

@@ -130,6 +126,7 @@ def create_completion(
130126
except:
131127
break
132128
if msg.get("event") == "appendText":
129+
is_started = True
133130
yield msg.get("text")
134131
elif msg.get("event") in ["done", "partCompleted"]:
135132
break
@@ -138,14 +135,7 @@ def create_completion(
138135

139136
@classmethod
140137
async def get_access_token_and_cookies(cls, proxy: str = None):
141-
if not has_nodriver:
142-
raise MissingRequirementsError('Install "nodriver" package | pip install -U nodriver')
143-
user_data_dir = user_config_dir("g4f-nodriver") if has_platformdirs else None
144-
debug.log(f"Copilot: Open nodriver with user_dir: {user_data_dir}")
145-
browser = await nodriver.start(
146-
user_data_dir=user_data_dir,
147-
browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
148-
)
138+
browser = await get_nodriver(proxy=proxy)
149139
page = await browser.get(cls.url)
150140
access_token = None
151141
while access_token is None:

g4f/Provider/You.py

+16-66
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
import re
44
import json
5-
import base64
65
import uuid
76

87
from ..typing import AsyncResult, Messages, ImageType, Cookies
98
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
109
from .helper import format_prompt
1110
from ..image import ImageResponse, ImagePreview, EXTENSIONS_MAP, to_bytes, is_accepted_format
12-
from ..requests import StreamSession, FormData, raise_for_status
13-
from .you.har_file import get_telemetry_ids
11+
from ..requests import StreamSession, FormData, raise_for_status, get_nodriver
12+
from ..cookies import get_cookies
13+
from ..errors import MissingRequirementsError
1414
from .. import debug
1515

1616
class You(AsyncGeneratorProvider, ProviderModelMixin):
@@ -57,6 +57,7 @@ async def create_async_generator(
5757
proxy: str = None,
5858
timeout: int = 240,
5959
chat_mode: str = "default",
60+
cookies: Cookies = None,
6061
**kwargs,
6162
) -> AsyncResult:
6263
if image is not None or model == cls.default_vision_model:
@@ -69,12 +70,22 @@ async def create_async_generator(
6970
else:
7071
chat_mode = "custom"
7172
model = cls.get_model(model)
73+
if cookies is None and chat_mode != "default":
74+
try:
75+
cookies = get_cookies(".you.com")
76+
except MissingRequirementsError:
77+
browser = await get_nodriver(proxy=proxy)
78+
page = await browser.get(cls.url)
79+
await page.wait_for('[data-testid="user-profile-button"]', timeout=900)
80+
cookies = {}
81+
for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
82+
cookies[c.name] = c.value
83+
await page.close()
7284
async with StreamSession(
7385
proxy=proxy,
7486
impersonate="chrome",
7587
timeout=(30, timeout)
7688
) as session:
77-
cookies = await cls.get_cookies(session) if chat_mode != "default" else None
7889
upload = ""
7990
if image is not None:
8091
upload_file = await cls.upload_file(
@@ -156,65 +167,4 @@ async def upload_file(cls, client: StreamSession, cookies: Cookies, file: bytes,
156167
result = await response.json()
157168
result["user_filename"] = filename
158169
result["size"] = len(file)
159-
return result
160-
161-
@classmethod
162-
async def get_cookies(cls, client: StreamSession) -> Cookies:
163-
if not cls._cookies or cls._cookies_used >= 5:
164-
cls._cookies = await cls.create_cookies(client)
165-
cls._cookies_used = 0
166-
cls._cookies_used += 1
167-
return cls._cookies
168-
169-
@classmethod
170-
def get_sdk(cls) -> str:
171-
return base64.standard_b64encode(json.dumps({
172-
"event_id":f"event-id-{str(uuid.uuid4())}",
173-
"app_session_id":f"app-session-id-{str(uuid.uuid4())}",
174-
"persistent_id":f"persistent-id-{uuid.uuid4()}",
175-
"client_sent_at":"","timezone":"",
176-
"stytch_user_id":f"user-live-{uuid.uuid4()}",
177-
"stytch_session_id":f"session-live-{uuid.uuid4()}",
178-
"app":{"identifier":"you.com"},
179-
"sdk":{"identifier":"Stytch.js Javascript SDK","version":"3.3.0"
180-
}}).encode()).decode()
181-
182-
def get_auth() -> str:
183-
auth_uuid = "507a52ad-7e69-496b-aee0-1c9863c7c819"
184-
auth_token = f"public-token-live-{auth_uuid}:public-token-live-{auth_uuid}"
185-
auth = base64.standard_b64encode(auth_token.encode()).decode()
186-
return f"Basic {auth}"
187-
188-
@classmethod
189-
async def create_cookies(cls, client: StreamSession) -> Cookies:
190-
if not cls._telemetry_ids:
191-
cls._telemetry_ids = await get_telemetry_ids()
192-
user_uuid = str(uuid.uuid4())
193-
telemetry_id = cls._telemetry_ids.pop()
194-
if debug.logging:
195-
print(f"Use telemetry_id: {telemetry_id}")
196-
async with client.post(
197-
"https://web.stytch.com/sdk/v1/passwords",
198-
headers={
199-
"Authorization": cls.get_auth(),
200-
"X-SDK-Client": cls.get_sdk(),
201-
"X-SDK-Parent-Host": cls.url,
202-
"Origin": "https://you.com",
203-
"Referer": "https://you.com/"
204-
},
205-
json={
206-
"dfp_telemetry_id": telemetry_id,
207-
"email": f"{user_uuid}@gmail.com",
208-
"password": f"{user_uuid}#{user_uuid}",
209-
"session_duration_minutes": 129600
210-
}
211-
) as response:
212-
await raise_for_status(response)
213-
session = (await response.json())["data"]
214-
215-
return {
216-
"stytch_session": session["session_token"],
217-
'stytch_session_jwt': session["session_jwt"],
218-
'ydc_stytch_session': session["session_token"],
219-
'ydc_stytch_session_jwt': session["session_jwt"],
220-
}
170+
return result

g4f/Provider/needs_auth/DeepInfraImage.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async def create_async(
7373
async with session.post(f"{api_base.rstrip('/')}/{model}", json=data) as response:
7474
await raise_for_status(response)
7575
data = await response.json()
76-
images = data["output"] if "output" in data else data["images"]
76+
images = data.get("output", data.get("images"))
7777
if not images:
7878
raise RuntimeError(f"Response: {data}")
7979
images = images[0] if len(images) == 1 else images

g4f/cli.py

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from g4f import Provider
66
from g4f.gui.run import gui_parser, run_gui_args
7+
import g4f.cookies
78

89
def main():
910
parser = argparse.ArgumentParser(description="Run gpt4free")
@@ -23,6 +24,8 @@ def main():
2324
api_parser.add_argument("--g4f-api-key", type=str, default=None, help="Sets an authentication key for your API. (incompatible with --reload and --workers)")
2425
api_parser.add_argument("--ignored-providers", nargs="+", choices=[provider.__name__ for provider in Provider.__providers__ if provider.working],
2526
default=[], help="List of providers to ignore when processing request. (incompatible with --reload and --workers)")
27+
api_parser.add_argument("--cookie-browsers", nargs="+", choices=[browser.__name__ for browser in g4f.cookies.browsers],
28+
default=[], help="List of browsers to access or retrieve cookies from. (incompatible with --reload and --workers)")
2629
api_parser.add_argument("--reload", action="store_true", help="Enable reloading.")
2730
subparsers.add_parser("gui", parents=[gui_parser()], add_help=False)
2831

@@ -47,6 +50,7 @@ def run_api_args(args):
4750
proxy=args.proxy,
4851
model=args.model
4952
)
53+
g4f.cookies.browsers = [g4f.cookies[browser] for browser in args.cookie_browsers]
5054
run_api(
5155
bind=args.bind,
5256
debug=args.debug,

g4f/cookies.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,32 @@
1515
brave, edge, vivaldi, firefox,
1616
_LinuxPasswordManager, BrowserCookieError
1717
)
18+
19+
def _g4f(domain_name: str) -> list:
20+
"""
21+
Load cookies from the 'g4f' browser (if exists).
22+
23+
Args:
24+
domain_name (str): The domain for which to load cookies.
25+
26+
Returns:
27+
list: List of cookies.
28+
"""
29+
if not has_platformdirs:
30+
return []
31+
user_data_dir = user_config_dir("g4f")
32+
cookie_file = os.path.join(user_data_dir, "Default", "Cookies")
33+
return [] if not os.path.exists(cookie_file) else chrome(cookie_file, domain_name)
34+
35+
browsers = [
36+
_g4f,
37+
chrome, chromium, opera, opera_gx,
38+
brave, edge, vivaldi, firefox,
39+
]
1840
has_browser_cookie3 = True
1941
except ImportError:
2042
has_browser_cookie3 = False
43+
browsers = []
2144

2245
from .typing import Dict, Cookies
2346
from .errors import MissingRequirementsError
@@ -114,7 +137,7 @@ def get_domain(v: dict) -> str:
114137

115138
harFiles = []
116139
cookieFiles = []
117-
for root, dirs, files in os.walk(CookiesConfig.cookies_dir if dirPath is None else dirPath):
140+
for root, _, files in os.walk(CookiesConfig.cookies_dir if dirPath is None else dirPath):
118141
for file in files:
119142
if file.endswith(".har"):
120143
harFiles.append(os.path.join(root, file))

g4f/gui/client/static/css/style.css

+12-2
Original file line numberDiff line numberDiff line change
@@ -500,14 +500,24 @@ body {
500500
animation: show_popup 0.4s;
501501
}
502502

503+
.toolbar .regenerate {
504+
left: 50%;
505+
transform: translateX(-50%);
506+
right: auto;
507+
}
508+
509+
.toolbar .regenerate span {
510+
display: none;
511+
}
512+
503513
@media only screen and (min-width: 40em) {
504514
.stop_generating {
505515
left: 50%;
506516
transform: translateX(-50%);
507517
right: auto;
508518
}
509-
.toolbar .regenerate {
510-
right: 5px;
519+
.toolbar .regenerate span {
520+
display: block;
511521
}
512522
}
513523

g4f/gui/gui_parser.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from argparse import ArgumentParser
22

3+
from ..cookies import browsers
4+
35
def gui_parser():
46
parser = ArgumentParser(description="Run the GUI")
57
parser.add_argument("--host", type=str, default="0.0.0.0", help="hostname")
68
parser.add_argument("--port", "-p", type=int, default=8080, help="port")
79
parser.add_argument("--debug", "-d", "-debug", action="store_true", help="debug mode")
810
parser.add_argument("--ignore-cookie-files", action="store_true", help="Don't read .har and cookie files.")
11+
parser.add_argument("--cookie-browsers", nargs="+", choices=[browser.__name__ for browser in browsers],
12+
default=[], help="List of browsers to access or retrieve cookies from.")
913
return parser

g4f/gui/run.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .gui_parser import gui_parser
22
from ..cookies import read_cookie_files
3+
import g4f.cookies
34
import g4f.debug
45

56
def run_gui_args(args):
@@ -11,6 +12,7 @@ def run_gui_args(args):
1112
host = args.host
1213
port = args.port
1314
debug = args.debug
15+
g4f.cookies.browsers = [g4f.cookies[browser] for browser in args.cookie_browsers]
1416
run_gui(host, port, debug)
1517

1618
if __name__ == "__main__":

g4f/requests/__init__.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@
2020
try:
2121
import nodriver
2222
from nodriver.cdp.network import CookieParam
23+
from nodriver import Browser
2324
has_nodriver = True
2425
except ImportError:
2526
has_nodriver = False
27+
try:
28+
from platformdirs import user_config_dir
29+
has_platformdirs = True
30+
except ImportError:
31+
has_platformdirs = False
2632

2733
from .. import debug
2834
from .raise_for_status import raise_for_status
@@ -165,4 +171,15 @@ def merge_cookies(cookies: Iterator[Morsel], response: Response) -> Cookies:
165171
if cookies is None:
166172
cookies = {}
167173
for cookie in response.cookies.jar:
168-
cookies[cookie.name] = cookie.value
174+
cookies[cookie.name] = cookie.value
175+
176+
async def get_nodriver(proxy: str = None, **kwargs)-> Browser:
177+
if not has_nodriver:
178+
raise MissingRequirementsError('Install "nodriver" package | pip install -U nodriver')
179+
user_data_dir = user_config_dir("g4f-nodriver") if has_platformdirs else None
180+
debug.log(f"Copilot: Open nodriver with user_dir: {user_data_dir}")
181+
return await nodriver.start(
182+
user_data_dir=user_data_dir,
183+
browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
184+
**kwargs
185+
)

0 commit comments

Comments
 (0)