mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-10-25 01:00:28 +08:00
142 lines
6.3 KiB
Python
142 lines
6.3 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import json
|
|
import time
|
|
from typing import Dict, Any, AsyncIterator
|
|
|
|
from ...typing import Messages, Cookies, AsyncResult
|
|
from ...providers.response import JsonConversation, Reasoning, ImagePreview, ImageResponse, TitleGeneration, AuthResult, RequestLogin
|
|
from ...requests import StreamSession, get_args_from_nodriver, DEFAULT_HEADERS
|
|
from ...requests.raise_for_status import raise_for_status
|
|
from ..base_provider import AsyncAuthedProvider, ProviderModelMixin
|
|
from ..helper import format_prompt, get_cookies, get_last_user_message
|
|
|
|
class Conversation(JsonConversation):
|
|
def __init__(self,
|
|
conversation_id: str
|
|
) -> None:
|
|
self.conversation_id = conversation_id
|
|
|
|
class Grok(AsyncAuthedProvider, ProviderModelMixin):
|
|
label = "Grok AI"
|
|
url = "https://grok.com"
|
|
cookie_domain = ".grok.com"
|
|
assets_url = "https://assets.grok.com"
|
|
conversation_url = "https://grok.com/rest/app-chat/conversations"
|
|
|
|
needs_auth = True
|
|
working = True
|
|
|
|
default_model = "grok-3"
|
|
models = [default_model, "grok-3-thinking", "grok-2"]
|
|
model_aliases = {"grok-3-r1": "grok-3-thinking"}
|
|
|
|
@classmethod
|
|
async def on_auth_async(cls, cookies: Cookies = None, proxy: str = None, **kwargs) -> AsyncIterator:
|
|
if cookies is None:
|
|
cookies = get_cookies(cls.cookie_domain, False, True, False)
|
|
if cookies is not None and "sso" in cookies:
|
|
yield AuthResult(
|
|
cookies=cookies,
|
|
impersonate="chrome",
|
|
proxy=proxy,
|
|
headers=DEFAULT_HEADERS
|
|
)
|
|
return
|
|
yield RequestLogin(cls.__name__, os.environ.get("G4F_LOGIN_URL") or "")
|
|
yield AuthResult(
|
|
**await get_args_from_nodriver(
|
|
cls.url,
|
|
proxy=proxy,
|
|
wait_for='[href="/chat#private"]'
|
|
)
|
|
)
|
|
|
|
@classmethod
|
|
async def _prepare_payload(cls, model: str, message: str) -> Dict[str, Any]:
|
|
return {
|
|
"temporary": False,
|
|
"modelName": "grok-latest" if model == "grok-2" else "grok-3",
|
|
"message": message,
|
|
"fileAttachments": [],
|
|
"imageAttachments": [],
|
|
"disableSearch": False,
|
|
"enableImageGeneration": True,
|
|
"returnImageBytes": False,
|
|
"returnRawGrokInXaiRequest": False,
|
|
"enableImageStreaming": True,
|
|
"imageGenerationCount": 2,
|
|
"forceConcise": False,
|
|
"toolOverrides": {},
|
|
"enableSideBySide": True,
|
|
"isPreset": False,
|
|
"sendFinalMetadata": True,
|
|
"customInstructions": "",
|
|
"deepsearchPreset": "",
|
|
"isReasoning": model.endswith("-thinking") or model.endswith("-r1"),
|
|
}
|
|
|
|
@classmethod
|
|
async def create_authed(
|
|
cls,
|
|
model: str,
|
|
messages: Messages,
|
|
auth_result: AuthResult,
|
|
cookies: Cookies = None,
|
|
return_conversation: bool = False,
|
|
conversation: Conversation = None,
|
|
**kwargs
|
|
) -> AsyncResult:
|
|
conversation_id = None if conversation is None else conversation.conversation_id
|
|
prompt = format_prompt(messages) if conversation_id is None else get_last_user_message(messages)
|
|
async with StreamSession(
|
|
**auth_result.get_dict()
|
|
) as session:
|
|
payload = await cls._prepare_payload(model, prompt)
|
|
if conversation_id is None:
|
|
url = f"{cls.conversation_url}/new"
|
|
else:
|
|
url = f"{cls.conversation_url}/{conversation_id}/responses"
|
|
async with session.post(url, json=payload) as response:
|
|
await raise_for_status(response)
|
|
|
|
thinking_duration = None
|
|
async for line in response.iter_lines():
|
|
if line:
|
|
try:
|
|
json_data = json.loads(line)
|
|
result = json_data.get("result", {})
|
|
if conversation_id is None:
|
|
conversation_id = result.get("conversation", {}).get("conversationId")
|
|
response_data = result.get("response", {})
|
|
image = response_data.get("streamingImageGenerationResponse", None)
|
|
if image is not None:
|
|
yield ImagePreview(f'{cls.assets_url}/{image["imageUrl"]}', "", {"cookies": cookies, "headers": headers})
|
|
token = response_data.get("token", result.get("token"))
|
|
is_thinking = response_data.get("isThinking", result.get("isThinking"))
|
|
if token:
|
|
if is_thinking:
|
|
if thinking_duration is None:
|
|
thinking_duration = time.time()
|
|
yield Reasoning(status="🤔 Is thinking...")
|
|
yield Reasoning(token)
|
|
else:
|
|
if thinking_duration is not None:
|
|
thinking_duration = time.time() - thinking_duration
|
|
status = f"Thought for {thinking_duration:.2f}s" if thinking_duration > 1 else "Finished"
|
|
thinking_duration = None
|
|
yield Reasoning(status=status)
|
|
yield token
|
|
generated_images = response_data.get("modelResponse", {}).get("generatedImageUrls", None)
|
|
if generated_images:
|
|
yield ImageResponse([f'{cls.assets_url}/{image}' for image in generated_images], "", {"cookies": cookies, "headers": headers})
|
|
title = result.get("title", {}).get("newTitle", "")
|
|
if title:
|
|
yield TitleGeneration(title)
|
|
|
|
|
|
except json.JSONDecodeError:
|
|
continue
|
|
if return_conversation and conversation_id is not None:
|
|
yield Conversation(conversation_id) |