XFEstudio/gpt4free
feat: add image size support and update nodriver args handling
- **ApiAirforce.py**: Added `use_image_size = True` class attribute. - **EasyChat.py**: Added `user_data_dir=None` argument when calling `get_args_from_nodriver`. - **LMArenaBeta.py**: - Only set `cls.share_url` from `G4F_SHARE_URL` if `cls.share_url` is `None`. - Added `user_data_dir=None` argument when calling `get_args_from_nodriver`. - Modified media filtering to check `url` is a `str` before `startswith("https://")`. - **OpenaiTemplate.py**: - Added `use_image_size = False` class attribute. - Modified image generation payload to optionally include `"size"` key when `use_image_size` is `True` and width/height present. - Refactored `read_response` to store `content` in a variable, strip on first chunk, and yield `ToolCalls` directly from `tool_calls` variable. - **g4f/requests/__init__.py**: - Added `user_data_dir` parameter (default `"nodriver"`) to `get_args_from_nodriver`. - Passed `user_data_dir` to `get_nodriver` call.
4132b0a4
代码差异
@@ -9,4 +9,5 @@ class ApiAirforce(OpenaiTemplate):
login_url = "https://panel.api.airforce/dashboard"
api_base = "https://api.airforce/v1"
working = True
active_by_default = True
active_by_default = True
use_image_size = True
@@ -120,7 +120,7 @@ class EasyChat(OpenaiTemplate, AuthFileMixin):
return
for _ in range(2):
if not args:
args = await get_args_from_nodriver(cls.url, proxy=proxy, callback=callback)
args = await get_args_from_nodriver(cls.url, proxy=proxy, callback=callback, user_data_dir=None)
if extra_body is None:
extra_body = {}
extra_body.setdefault("captchaToken", cls.captchaToken)
@@ -194,7 +194,8 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
else:
raise ModelNotFoundError(f"Model '{model}' is not supported by LMArena Beta.")
cls.share_url = os.getenv("G4F_SHARE_URL")
if cls.share_url is None:
cls.share_url = os.getenv("G4F_SHARE_URL")
prompt = get_last_user_message(messages)
cache_file = cls.get_cache_file()
args = None
@@ -233,7 +234,7 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
await asyncio.sleep(1)
while not await page.evaluate('document.querySelector(\'textarea\')'):
await asyncio.sleep(1)
args = await get_args_from_nodriver(cls.url, proxy=proxy, callback=callback)
args = await get_args_from_nodriver(cls.url, proxy=proxy, callback=callback, user_data_dir=None)
elif not cls.looked:
cls.looked = True
try:
@@ -275,7 +276,7 @@ class LMArenaBeta(AsyncGeneratorProvider, ProviderModelMixin, AuthFileMixin):
"url": url
}
for url, name in list(merge_media(media, messages))
if url.startswith("https://")
if isinstance(url, str) and url.startswith("https://")
],
"parentMessageIds": [] if conversation is None else conversation.message_ids,
"participantPosition": "a",
@@ -27,6 +27,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
use_model_names = False
ssl = None
add_user = True
use_image_size = False
@classmethod
def get_models(cls, api_key: str = None, api_base: str = None) -> list[str]:
@@ -101,11 +102,10 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
# Proxy for image generation feature
if model and model in cls.image_models:
prompt = format_media_prompt(messages, prompt)
data = {
"prompt": prompt,
"model": model,
**use_aspect_ratio({"width": kwargs.get("width"), "height": kwargs.get("height")}, kwargs.get("aspect_ratio", None))
}
size = use_aspect_ratio({"width": kwargs.get("width"), "height": kwargs.get("height")}, kwargs.get("aspect_ratio", None))
size = {"size": f"{size['width']}x{size['height']}", **size} if cls.use_image_size and "width" in size and "height" in size else size
data = {"prompt": prompt, "model": model, **size}
# Handle media if provided
if media is not None:
data["image_url"] = next(iter([data for data, _ in media if data and isinstance(data, str) and data.startswith("http://") or data.startswith("https://")]), None)
@@ -202,19 +202,19 @@ async def read_response(response: StreamResponse, stream: bool, prompt: str, pro
model_returned = True
choice = next(iter(data["choices"]), None)
if choice:
if "content" in choice["delta"] and choice["delta"]["content"]:
delta = choice["delta"]["content"]
content = choice.get("delta", {}).get("content")
if content:
if first:
delta = delta.lstrip()
if delta:
content = content.lstrip()
if content:
first = False
if reasoning:
yield Reasoning(status="")
reasoning = False
yield delta
yield content
tool_calls = choice.get("delta", {}).get("tool_calls")
if tool_calls:
yield ToolCalls(choice["delta"]["tool_calls"])
yield ToolCalls(tool_calls)
reasoning_content = choice.get("delta", {}).get("reasoning_content", choice.get("delta", {}).get("reasoning"))
if reasoning_content:
reasoning = True
@@ -92,10 +92,11 @@ async def get_args_from_nodriver(
wait_for: str = None,
callback: callable = None,
cookies: Cookies = None,
browser: Browser = None
browser: Browser = None,
user_data_dir: str = "nodriver"
) -> dict:
if browser is None:
browser, stop_browser = await get_nodriver(proxy=proxy, timeout=timeout)
browser, stop_browser = await get_nodriver(proxy=proxy, timeout=timeout, user_data_dir=user_data_dir)
else:
def stop_browser():
pass