返回提交历史
Modified
g4f/Provider/PollinationsAI.py
+1
-1
Modified
g4f/Provider/needs_auth/Gemini.py
+33
-20
Modified
g4f/tools/run_tools.py
+11
-8
XFEstudio/gpt4free
Refactor PollinationsAI: simplify prompt encoding and improve whitespace handling; update Gemini imports and response handling; enhance usage tracking in run_tools
97a85d6b
代码差异
3 个文件
+45
-29
@@ -334,7 +334,7 @@ class PollinationsAI(AsyncGeneratorProvider, ProviderModelMixin):
334
334
**params
335
335
}, "1:1" if aspect_ratio is None else aspect_ratio)
336
336
query = "&".join(f"{k}={quote(str(v))}" for k, v in params.items() if v is not None)
337
encoded_prompt = prompt.strip(". \n?")
337
encoded_prompt = prompt.strip()
338
338
if model == "gptimage" and aspect_ratio is not None:
339
339
encoded_prompt = f"{encoded_prompt} aspect-ratio: {aspect_ratio}"
340
340
encoded_prompt = quote_plus(encoded_prompt)[:4096 - len(cls.image_api_endpoint) - len(query) - 8].rstrip("%")
@@ -20,12 +20,12 @@ except ImportError:
20
20
21
21
from ... import debug
22
22
from ...typing import Messages, Cookies, MediaListType, AsyncResult, AsyncIterator
23
from ...providers.response import JsonConversation, Reasoning, RequestLogin, ImageResponse, YouTubeResponse, AudioResponse, TitleGeneration
23
from ...providers.response import JsonConversation, Reasoning, RequestLogin, ImageResponse, YouTubeResponse, AudioResponse, TitleGeneration, JsonResponse
24
24
from ...requests.raise_for_status import raise_for_status
25
25
from ...requests.aiohttp import get_connector
26
26
from ...requests import get_nodriver
27
27
from ...image.copy_images import get_filename, get_media_dir, ensure_media_dir
28
from ...errors import MissingAuthError, ModelNotFoundError
28
from ...errors import MissingAuthError
29
29
from ...image import to_bytes
30
30
from ...cookies import get_cookies_dir
31
31
from ...tools.media import merge_media
@@ -83,6 +83,7 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
83
83
84
84
needs_auth = True
85
85
working = True
86
active_by_default = True
86
87
use_nodriver = True
87
88
88
89
default_model = ""
@@ -244,12 +245,14 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
244
245
continue
245
246
if not isinstance(line, list):
246
247
continue
247
if len(line[0]) < 3 or not line[0][2]:
248
yield JsonResponse(data=line, model=model)
249
if not line or len(line[0]) < 3 or not line[0][2]:
248
250
continue
249
251
response_part = json.loads(line[0][2])
250
if response_part[10]:
252
yield JsonResponse(data=response_part, model=model)
253
if len(response_part) > 11 and response_part[10]:
251
254
yield TitleGeneration(response_part[10][0].strip())
252
if not response_part[4]:
255
if len(response_part) < 5:
253
256
continue
254
257
if return_conversation:
255
258
yield Conversation(response_part[1][0], response_part[1][1], response_part[4][0][0], model)
@@ -270,20 +273,23 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
270
273
skip -= 1
271
274
continue
272
275
yield item
273
reasoning = "\n\n".join(find_str(response_part[4][0], 3))
274
reasoning = re.sub(r"<b>|</b>", "**", reasoning)
275
def replace_image(match):
276
return f"})"
277
reasoning = re.sub(r"//yt3.(?:ggpht.com|googleusercontent.com/ytc)/[\w=-]+", replace_image, reasoning)
278
reasoning = re.sub(r"\nyoutube\n", "\n\n\n", reasoning)
279
reasoning = re.sub(r"\nyoutube_tool\n", "\n\n", reasoning)
280
reasoning = re.sub(r"\nYouTube\n", "\nYouTube ", reasoning)
281
reasoning = reasoning.replace('\nhttps://www.gstatic.com/images/branding/productlogos/youtube/v9/192px.svg', '<i class="fa-brands fa-youtube"></i>')
282
youtube_ids = list(find_youtube_ids(reasoning))
283
content = response_part[4][0][1][0]
284
if reasoning:
285
yield Reasoning(reasoning, status="🤔")
276
if response_part[4]:
277
reasoning = "\n\n".join(find_str(response_part[4][0], 3))
278
reasoning = re.sub(r"<b>|</b>", "**", reasoning)
279
def replace_image(match):
280
return f"})"
281
reasoning = re.sub(r"//yt3.(?:ggpht.com|googleusercontent.com/ytc)/[\w=-]+", replace_image, reasoning)
282
reasoning = re.sub(r"\nyoutube\n", "\n\n\n", reasoning)
283
reasoning = re.sub(r"\nyoutube_tool\n", "\n\n", reasoning)
284
reasoning = re.sub(r"\nYouTube\n", "\nYouTube ", reasoning)
285
reasoning = reasoning.replace('\nhttps://www.gstatic.com/images/branding/productlogos/youtube/v9/192px.svg', '<i class="fa-brands fa-youtube"></i>')
286
youtube_ids = list(find_youtube_ids(reasoning))
287
content = response_part[4][0][1][0]
288
if reasoning:
289
yield Reasoning(reasoning, status="🤔")
286
290
except (ValueError, KeyError, TypeError, IndexError) as e:
291
if kwargs.get("debug_mode", False):
292
raise e
287
293
debug.error(f"{cls.__name__} {type(e).__name__}: {e}")
288
294
continue
289
295
match = re.search(r'\[Imagen of (.*?)\]', content)
@@ -413,15 +419,22 @@ class Gemini(AsyncGeneratorProvider, ProviderModelMixin):
413
419
414
420
@classmethod
415
421
async def fetch_snlm0e(cls, session: ClientSession, cookies: Cookies):
422
response_text = ""
416
423
async with session.get(cls.url, cookies=cookies) as response:
417
await raise_for_status(response)
418
response_text = await response.text()
424
if response.ok:
425
response_text = await response.text()
419
426
match = re.search(r'SNlM0e\":\"(.*?)\"', response_text)
420
427
if match:
421
428
cls._snlm0e = match.group(1)
422
429
sid_match = re.search(r'"FdrFJe":"([\d-]+)"', response_text)
423
430
if sid_match:
424
431
cls._sid = sid_match.group(1)
432
cls.active_by_default = True
433
cls.live += 1
434
else:
435
cls.active_by_default = False
436
cls.live = 0
437
await raise_for_status(response)
425
438
426
439
class Conversation(JsonConversation):
427
440
def __init__(self,
@@ -257,16 +257,19 @@ async def async_iter_run_tools(
257
257
elif isinstance(chunk, Usage):
258
258
usage = chunk
259
259
yield chunk
260
if usage is None:
261
usage = get_usage(messages, completion_tokens)
262
yield usage
263
usage = {"user": kwargs.get("user"), "model": usage_model, "provider": usage_provider, **usage.get_dict()}
264
usage_dir = Path(get_cookies_dir()) / ".usage"
265
usage_file = usage_dir / f"{datetime.date.today()}.jsonl"
266
usage_dir.mkdir(parents=True, exist_ok=True)
260
267
if has_aiofile:
261
if usage is None:
262
usage = get_usage(messages, completion_tokens)
263
yield usage
264
usage = {"user": kwargs.get("user"), "model": usage_model, "provider": usage_provider, **usage.get_dict()}
265
usage_dir = Path(get_cookies_dir()) / ".usage"
266
usage_file = usage_dir / f"{datetime.date.today()}.jsonl"
267
usage_dir.mkdir(parents=True, exist_ok=True)
268
268
async with async_open(usage_file, "a") as f:
269
await f.write(f"{json.dumps(usage)}\n")
269
asyncio.create_task(f.write(f"{json.dumps(usage)}\n"))
270
else:
271
with usage_file.open("a") as f:
272
f.write(f"{json.dumps(usage)}\n")
270
273
if completion_tokens > 0:
271
274
provider.live += 1
272
275
except: