mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-10-16 13:20:43 +08:00
Fix Bing Provider, Add Account Support for Meta AI
Use default headers in OpenaiChat
This commit is contained in:
@@ -10,7 +10,7 @@ except ImportError:
|
|||||||
from g4f.client import Client, ChatCompletion
|
from g4f.client import Client, ChatCompletion
|
||||||
from g4f.Provider import Bing, OpenaiChat, DuckDuckGo
|
from g4f.Provider import Bing, OpenaiChat, DuckDuckGo
|
||||||
|
|
||||||
DEFAULT_MESSAGES = [{"role": "system", "content": 'Response in json, Example: {"success: true"}'},
|
DEFAULT_MESSAGES = [{"role": "system", "content": 'Response in json, Example: {"success": false}'},
|
||||||
{"role": "user", "content": "Say success true in json"}]
|
{"role": "user", "content": "Say success true in json"}]
|
||||||
|
|
||||||
class TestProviderIntegration(unittest.TestCase):
|
class TestProviderIntegration(unittest.TestCase):
|
||||||
|
@@ -7,13 +7,13 @@ import time
|
|||||||
import asyncio
|
import asyncio
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from aiohttp import ClientSession, ClientTimeout, BaseConnector, WSMsgType
|
|
||||||
|
|
||||||
from ..typing import AsyncResult, Messages, ImageType, Cookies
|
from ..typing import AsyncResult, Messages, ImageType, Cookies
|
||||||
from ..image import ImageRequest
|
from ..image import ImageRequest
|
||||||
from ..errors import ResponseStatusError, RateLimitError
|
from ..errors import ResponseError, ResponseStatusError, RateLimitError
|
||||||
|
from ..requests import StreamSession, DEFAULT_HEADERS
|
||||||
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||||
from .helper import get_connector, get_random_hex
|
from .helper import get_random_hex
|
||||||
from .bing.upload_image import upload_image
|
from .bing.upload_image import upload_image
|
||||||
from .bing.conversation import Conversation, create_conversation, delete_conversation
|
from .bing.conversation import Conversation, create_conversation, delete_conversation
|
||||||
from .BingCreateImages import BingCreateImages
|
from .BingCreateImages import BingCreateImages
|
||||||
@@ -49,7 +49,6 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
timeout: int = 900,
|
timeout: int = 900,
|
||||||
api_key: str = None,
|
api_key: str = None,
|
||||||
cookies: Cookies = None,
|
cookies: Cookies = None,
|
||||||
connector: BaseConnector = None,
|
|
||||||
tone: str = None,
|
tone: str = None,
|
||||||
image: ImageType = None,
|
image: ImageType = None,
|
||||||
web_search: bool = False,
|
web_search: bool = False,
|
||||||
@@ -79,7 +78,6 @@ class Bing(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
|
|
||||||
return stream_generate(
|
return stream_generate(
|
||||||
prompt, tone, image, context, cookies, api_key,
|
prompt, tone, image, context, cookies, api_key,
|
||||||
get_connector(connector, proxy, True),
|
|
||||||
proxy, web_search, gpt4_turbo, timeout,
|
proxy, web_search, gpt4_turbo, timeout,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
@@ -102,25 +100,53 @@ def get_ip_address() -> str:
|
|||||||
return f"13.{random.randint(104, 107)}.{random.randint(0, 255)}.{random.randint(0, 255)}"
|
return f"13.{random.randint(104, 107)}.{random.randint(0, 255)}.{random.randint(0, 255)}"
|
||||||
|
|
||||||
def get_default_cookies():
|
def get_default_cookies():
|
||||||
|
#muid = get_random_hex().upper()
|
||||||
|
sid = get_random_hex().upper()
|
||||||
|
guid = get_random_hex().upper()
|
||||||
|
isodate = date.today().isoformat()
|
||||||
|
timestamp = int(time.time())
|
||||||
|
zdate = "0001-01-01T00:00:00.0000000"
|
||||||
return {
|
return {
|
||||||
'SRCHD' : 'AF=NOFORM',
|
"_C_Auth": "",
|
||||||
'PPLState' : '1',
|
#"MUID": muid,
|
||||||
'KievRPSSecAuth': '',
|
#"MUIDB": muid,
|
||||||
'SUID' : '',
|
"_EDGE_S": f"F=1&SID={sid}",
|
||||||
'SRCHUSR' : f'DOB={date.today().strftime("%Y%m%d")}&T={int(time.time())}',
|
"_EDGE_V": "1",
|
||||||
'SRCHHPGUSR' : f'HV={int(time.time())}',
|
"SRCHD": "AF=hpcodx",
|
||||||
'BCP' : 'AD=1&AL=1&SM=1',
|
"SRCHUID": f"V=2&GUID={guid}&dmnchg=1",
|
||||||
'_Rwho' : f'u=d&ts={date.today().isoformat()}',
|
"_RwBf": (
|
||||||
|
f"r=0&ilt=1&ihpd=0&ispd=0&rc=3&rb=0&gb=0&rg=200&pc=0&mtu=0&rbb=0&g=0&cid="
|
||||||
|
f"&clo=0&v=1&l={isodate}&lft={zdate}&aof=0&ard={zdate}"
|
||||||
|
f"&rwdbt={zdate}&rwflt={zdate}&o=2&p=&c=&t=0&s={zdate}"
|
||||||
|
f"&ts={isodate}&rwred=0&wls=&wlb="
|
||||||
|
"&wle=&ccp=&cpt=&lka=0&lkt=0&aad=0&TH="
|
||||||
|
),
|
||||||
|
'_Rwho': f'u=d&ts={isodate}',
|
||||||
|
"_SS": f"SID={sid}&R=3&RB=0&GB=0&RG=200&RP=0",
|
||||||
|
"SRCHUSR": f"DOB={date.today().strftime('%Y%m%d')}&T={timestamp}",
|
||||||
|
"SRCHHPGUSR": f"HV={int(time.time())}",
|
||||||
|
"BCP": "AD=1&AL=1&SM=1",
|
||||||
|
"ipv6": f"hit={timestamp}",
|
||||||
|
'_C_ETH' : '1',
|
||||||
}
|
}
|
||||||
|
|
||||||
def create_headers(cookies: Cookies = None, api_key: str = None) -> dict:
|
async def create_headers(cookies: Cookies = None, api_key: str = None) -> dict:
|
||||||
if cookies is None:
|
if cookies is None:
|
||||||
|
# import nodriver as uc
|
||||||
|
# browser = await uc.start(headless=False)
|
||||||
|
# page = await browser.get(Defaults.home)
|
||||||
|
# await asyncio.sleep(10)
|
||||||
|
# cookies = {}
|
||||||
|
# for c in await page.browser.cookies.get_all():
|
||||||
|
# if c.domain.endswith(".bing.com"):
|
||||||
|
# cookies[c.name] = c.value
|
||||||
|
# user_agent = await page.evaluate("window.navigator.userAgent")
|
||||||
|
# await page.close()
|
||||||
cookies = get_default_cookies()
|
cookies = get_default_cookies()
|
||||||
if api_key is not None:
|
if api_key is not None:
|
||||||
cookies["_U"] = api_key
|
cookies["_U"] = api_key
|
||||||
headers = Defaults.headers.copy()
|
headers = Defaults.headers.copy()
|
||||||
headers["cookie"] = "; ".join(f"{k}={v}" for k, v in cookies.items())
|
headers["cookie"] = "; ".join(f"{k}={v}" for k, v in cookies.items())
|
||||||
headers["x-forwarded-for"] = get_ip_address()
|
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
class Defaults:
|
class Defaults:
|
||||||
@@ -246,25 +272,13 @@ class Defaults:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Default headers for requests
|
# Default headers for requests
|
||||||
home = 'https://www.bing.com/chat?q=Bing+AI&FORM=hpcodx'
|
home = "https://www.bing.com/chat?q=Microsoft+Copilot&FORM=hpcodx"
|
||||||
headers = {
|
headers = {
|
||||||
'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
**DEFAULT_HEADERS,
|
||||||
'sec-ch-ua-mobile': '?0',
|
"accept": "application/json",
|
||||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
|
"referer": home,
|
||||||
'sec-ch-ua-arch': '"x86"',
|
|
||||||
'sec-ch-ua-full-version': '"122.0.6261.69"',
|
|
||||||
'accept': 'application/json',
|
|
||||||
'sec-ch-ua-platform-version': '"15.0.0"',
|
|
||||||
"x-ms-client-request-id": str(uuid.uuid4()),
|
"x-ms-client-request-id": str(uuid.uuid4()),
|
||||||
'sec-ch-ua-full-version-list': '"Chromium";v="122.0.6261.69", "Not(A:Brand";v="24.0.0.0", "Google Chrome";v="122.0.6261.69"',
|
"x-ms-useragent": "azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.15.1 OS/Windows",
|
||||||
'x-ms-useragent': 'azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.12.3 OS/Windows',
|
|
||||||
'sec-ch-ua-model': '""',
|
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
|
||||||
'sec-fetch-site': 'same-origin',
|
|
||||||
'sec-fetch-mode': 'cors',
|
|
||||||
'sec-fetch-dest': 'empty',
|
|
||||||
'referer': home,
|
|
||||||
'accept-language': 'en-US,en;q=0.9',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def format_message(msg: dict) -> str:
|
def format_message(msg: dict) -> str:
|
||||||
@@ -368,7 +382,6 @@ async def stream_generate(
|
|||||||
context: str = None,
|
context: str = None,
|
||||||
cookies: dict = None,
|
cookies: dict = None,
|
||||||
api_key: str = None,
|
api_key: str = None,
|
||||||
connector: BaseConnector = None,
|
|
||||||
proxy: str = None,
|
proxy: str = None,
|
||||||
web_search: bool = False,
|
web_search: bool = False,
|
||||||
gpt4_turbo: bool = False,
|
gpt4_turbo: bool = False,
|
||||||
@@ -393,14 +406,12 @@ async def stream_generate(
|
|||||||
:param timeout: Timeout for the request.
|
:param timeout: Timeout for the request.
|
||||||
:return: An asynchronous generator yielding responses.
|
:return: An asynchronous generator yielding responses.
|
||||||
"""
|
"""
|
||||||
headers = create_headers(cookies, api_key)
|
headers = await create_headers(cookies, api_key)
|
||||||
new_conversation = conversation is None
|
new_conversation = conversation is None
|
||||||
max_retries = (5 if new_conversation else 0) if max_retries is None else max_retries
|
max_retries = (5 if new_conversation else 0) if max_retries is None else max_retries
|
||||||
async with ClientSession(
|
first = True
|
||||||
timeout=ClientTimeout(total=timeout), connector=connector
|
while first or conversation is None:
|
||||||
) as session:
|
async with StreamSession(timeout=timeout, proxy=proxy) as session:
|
||||||
first = True
|
|
||||||
while first or conversation is None:
|
|
||||||
first = False
|
first = False
|
||||||
do_read = True
|
do_read = True
|
||||||
try:
|
try:
|
||||||
@@ -408,13 +419,13 @@ async def stream_generate(
|
|||||||
conversation = await create_conversation(session, headers, tone)
|
conversation = await create_conversation(session, headers, tone)
|
||||||
if return_conversation:
|
if return_conversation:
|
||||||
yield conversation
|
yield conversation
|
||||||
except ResponseStatusError as e:
|
except (ResponseStatusError, RateLimitError) as e:
|
||||||
max_retries -= 1
|
max_retries -= 1
|
||||||
if max_retries < 1:
|
if max_retries < 1:
|
||||||
raise e
|
raise e
|
||||||
if debug.logging:
|
if debug.logging:
|
||||||
print(f"Bing: Retry: {e}")
|
print(f"Bing: Retry: {e}")
|
||||||
headers = create_headers()
|
headers = await create_headers()
|
||||||
await asyncio.sleep(sleep_retry)
|
await asyncio.sleep(sleep_retry)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -434,7 +445,7 @@ async def stream_generate(
|
|||||||
) as wss:
|
) as wss:
|
||||||
await wss.send_str(format_message({'protocol': 'json', 'version': 1}))
|
await wss.send_str(format_message({'protocol': 'json', 'version': 1}))
|
||||||
await wss.send_str(format_message({"type": 6}))
|
await wss.send_str(format_message({"type": 6}))
|
||||||
await wss.receive(timeout=timeout)
|
await wss.receive_str()
|
||||||
await wss.send_str(create_message(
|
await wss.send_str(create_message(
|
||||||
conversation, prompt, tone,
|
conversation, prompt, tone,
|
||||||
context if new_conversation else None,
|
context if new_conversation else None,
|
||||||
@@ -445,16 +456,15 @@ async def stream_generate(
|
|||||||
returned_text = ''
|
returned_text = ''
|
||||||
message_id = None
|
message_id = None
|
||||||
while do_read:
|
while do_read:
|
||||||
msg = await wss.receive(timeout=timeout)
|
msg = await wss.receive_str()
|
||||||
if msg.type == WSMsgType.CLOSED:
|
objects = msg.split(Defaults.delimiter)
|
||||||
break
|
|
||||||
if msg.type != WSMsgType.TEXT or not msg.data:
|
|
||||||
continue
|
|
||||||
objects = msg.data.split(Defaults.delimiter)
|
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if obj is None or not obj:
|
if obj is None or not obj:
|
||||||
continue
|
continue
|
||||||
response = json.loads(obj)
|
try:
|
||||||
|
response = json.loads(obj)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
continue
|
||||||
if response and response.get('type') == 1 and response['arguments'][0].get('messages'):
|
if response and response.get('type') == 1 and response['arguments'][0].get('messages'):
|
||||||
message = response['arguments'][0]['messages'][0]
|
message = response['arguments'][0]['messages'][0]
|
||||||
if message_id is not None and message_id != message["messageId"]:
|
if message_id is not None and message_id != message["messageId"]:
|
||||||
@@ -462,7 +472,7 @@ async def stream_generate(
|
|||||||
message_id = message["messageId"]
|
message_id = message["messageId"]
|
||||||
image_response = None
|
image_response = None
|
||||||
if (raise_apology and message['contentOrigin'] == 'Apology'):
|
if (raise_apology and message['contentOrigin'] == 'Apology'):
|
||||||
raise RuntimeError("Apology Response Error")
|
raise ResponseError("Apology Response Error")
|
||||||
if 'adaptiveCards' in message:
|
if 'adaptiveCards' in message:
|
||||||
card = message['adaptiveCards'][0]['body'][0]
|
card = message['adaptiveCards'][0]['body'][0]
|
||||||
if "text" in card:
|
if "text" in card:
|
||||||
@@ -488,6 +498,7 @@ async def stream_generate(
|
|||||||
yield image_response
|
yield image_response
|
||||||
elif response.get('type') == 2:
|
elif response.get('type') == 2:
|
||||||
result = response['item']['result']
|
result = response['item']['result']
|
||||||
|
do_read = False
|
||||||
if result.get('error'):
|
if result.get('error'):
|
||||||
max_retries -= 1
|
max_retries -= 1
|
||||||
if max_retries < 1:
|
if max_retries < 1:
|
||||||
@@ -497,10 +508,12 @@ async def stream_generate(
|
|||||||
raise RuntimeError(f"{result['value']}: {result['message']}")
|
raise RuntimeError(f"{result['value']}: {result['message']}")
|
||||||
if debug.logging:
|
if debug.logging:
|
||||||
print(f"Bing: Retry: {result['value']}: {result['message']}")
|
print(f"Bing: Retry: {result['value']}: {result['message']}")
|
||||||
headers = create_headers()
|
headers = await create_headers()
|
||||||
do_read = False
|
|
||||||
conversation = None
|
conversation = None
|
||||||
await asyncio.sleep(sleep_retry)
|
await asyncio.sleep(sleep_retry)
|
||||||
break
|
break
|
||||||
return
|
elif response.get('type') == 3:
|
||||||
await delete_conversation(session, conversation, headers)
|
do_read = False
|
||||||
|
break
|
||||||
|
if conversation is not None:
|
||||||
|
await delete_conversation(session, conversation, headers)
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
import random
|
import random
|
||||||
@@ -8,6 +10,8 @@ from aiohttp import ClientSession, BaseConnector
|
|||||||
|
|
||||||
from ..typing import AsyncResult, Messages, Cookies
|
from ..typing import AsyncResult, Messages, Cookies
|
||||||
from ..requests import raise_for_status, DEFAULT_HEADERS
|
from ..requests import raise_for_status, DEFAULT_HEADERS
|
||||||
|
from ..image import ImageResponse, ImagePreview
|
||||||
|
from ..errors import ResponseError
|
||||||
from .base_provider import AsyncGeneratorProvider
|
from .base_provider import AsyncGeneratorProvider
|
||||||
from .helper import format_prompt, get_connector
|
from .helper import format_prompt, get_connector
|
||||||
|
|
||||||
@@ -22,6 +26,7 @@ class AbraGeoBlockedError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class MetaAI(AsyncGeneratorProvider):
|
class MetaAI(AsyncGeneratorProvider):
|
||||||
|
label = "Meta AI"
|
||||||
url = "https://www.meta.ai"
|
url = "https://www.meta.ai"
|
||||||
working = True
|
working = True
|
||||||
|
|
||||||
@@ -38,11 +43,10 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
proxy: str = None,
|
proxy: str = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
) -> AsyncResult:
|
) -> AsyncResult:
|
||||||
#cookies = get_cookies(".meta.ai", False, True)
|
|
||||||
async for chunk in cls(proxy).prompt(format_prompt(messages)):
|
async for chunk in cls(proxy).prompt(format_prompt(messages)):
|
||||||
yield chunk
|
yield chunk
|
||||||
|
|
||||||
async def get_access_token(self, birthday: str = "1999-01-01") -> str:
|
async def update_access_token(self, birthday: str = "1999-01-01"):
|
||||||
url = "https://www.meta.ai/api/graphql/"
|
url = "https://www.meta.ai/api/graphql/"
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
@@ -66,25 +70,37 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
|
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
|
||||||
await raise_for_status(response, "Fetch access_token failed")
|
await raise_for_status(response, "Fetch access_token failed")
|
||||||
auth_json = await response.json(content_type=None)
|
auth_json = await response.json(content_type=None)
|
||||||
access_token = auth_json["data"]["xab_abra_accept_terms_of_service"]["new_temp_user_auth"]["access_token"]
|
self.access_token = auth_json["data"]["xab_abra_accept_terms_of_service"]["new_temp_user_auth"]["access_token"]
|
||||||
return access_token
|
|
||||||
|
|
||||||
async def prompt(self, message: str, cookies: Cookies = None) -> AsyncResult:
|
async def prompt(self, message: str, cookies: Cookies = None) -> AsyncResult:
|
||||||
if cookies is not None:
|
|
||||||
self.cookies = cookies
|
|
||||||
self.access_token = None
|
|
||||||
if self.cookies is None:
|
if self.cookies is None:
|
||||||
self.cookies = await self.get_cookies()
|
await self.update_cookies(cookies)
|
||||||
if self.access_token is None:
|
if cookies is not None:
|
||||||
self.access_token = await self.get_access_token()
|
self.access_token = None
|
||||||
|
if self.access_token is None and cookies is None:
|
||||||
|
await self.update_access_token()
|
||||||
|
|
||||||
url = "https://graph.meta.ai/graphql?locale=user"
|
if self.access_token is None:
|
||||||
#url = "https://www.meta.ai/api/graphql/"
|
url = "https://www.meta.ai/api/graphql/"
|
||||||
|
payload = {"lsd": self.lsd, 'fb_dtsg': self.dtsg}
|
||||||
|
headers = {'x-fb-lsd': self.lsd}
|
||||||
|
else:
|
||||||
|
url = "https://graph.meta.ai/graphql?locale=user"
|
||||||
|
payload = {"access_token": self.access_token}
|
||||||
|
headers = {}
|
||||||
|
headers = {
|
||||||
|
'content-type': 'application/x-www-form-urlencoded',
|
||||||
|
'cookie': "; ".join([f"{k}={v}" for k, v in cookies.items()]),
|
||||||
|
'origin': 'https://www.meta.ai',
|
||||||
|
'referer': 'https://www.meta.ai/',
|
||||||
|
'x-asbd-id': '129477',
|
||||||
|
'x-fb-friendly-name': 'useAbraSendMessageMutation',
|
||||||
|
**headers
|
||||||
|
}
|
||||||
payload = {
|
payload = {
|
||||||
"access_token": self.access_token,
|
**payload,
|
||||||
#"lsd": cookies["lsd"],
|
'fb_api_caller_class': 'RelayModern',
|
||||||
"fb_api_caller_class": "RelayModern",
|
'fb_api_req_friendly_name': 'useAbraSendMessageMutation',
|
||||||
"fb_api_req_friendly_name": "useAbraSendMessageMutation",
|
|
||||||
"variables": json.dumps({
|
"variables": json.dumps({
|
||||||
"message": {"sensitive_string_value": message},
|
"message": {"sensitive_string_value": message},
|
||||||
"externalConversationId": str(uuid.uuid4()),
|
"externalConversationId": str(uuid.uuid4()),
|
||||||
@@ -98,19 +114,16 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
|
"__relay_internal__pv__AbraDebugDevOnlyrelayprovider": False,
|
||||||
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
|
"__relay_internal__pv__WebPixelRatiorelayprovider": 1,
|
||||||
}),
|
}),
|
||||||
"server_timestamps": "true",
|
'server_timestamps': 'true',
|
||||||
"doc_id": "7783822248314888",
|
'doc_id': '7783822248314888'
|
||||||
}
|
}
|
||||||
headers = {
|
async with self.session.post(url, headers=headers, data=payload) as response:
|
||||||
"x-asbd-id": "129477",
|
|
||||||
"x-fb-friendly-name": "useAbraSendMessageMutation",
|
|
||||||
#"x-fb-lsd": cookies["lsd"],
|
|
||||||
}
|
|
||||||
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
|
|
||||||
await raise_for_status(response, "Fetch response failed")
|
await raise_for_status(response, "Fetch response failed")
|
||||||
last_snippet_len = 0
|
last_snippet_len = 0
|
||||||
fetch_id = None
|
fetch_id = None
|
||||||
async for line in response.content:
|
async for line in response.content:
|
||||||
|
if b"<h1>Something Went Wrong</h1>" in line:
|
||||||
|
raise ResponseError("Response: Something Went Wrong")
|
||||||
try:
|
try:
|
||||||
json_line = json.loads(line)
|
json_line = json.loads(line)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
@@ -119,7 +132,14 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
streaming_state = bot_response_message.get("streaming_state")
|
streaming_state = bot_response_message.get("streaming_state")
|
||||||
fetch_id = bot_response_message.get("fetch_id") or fetch_id
|
fetch_id = bot_response_message.get("fetch_id") or fetch_id
|
||||||
if streaming_state in ("STREAMING", "OVERALL_DONE"):
|
if streaming_state in ("STREAMING", "OVERALL_DONE"):
|
||||||
#imagine_card = bot_response_message["imagine_card"]
|
imagine_card = bot_response_message.get("imagine_card")
|
||||||
|
if imagine_card is not None:
|
||||||
|
imagine_session = imagine_card.get("session")
|
||||||
|
if imagine_session is not None:
|
||||||
|
imagine_medias = imagine_session.get("media_sets", {}).pop().get("imagine_media")
|
||||||
|
if imagine_medias is not None:
|
||||||
|
image_class = ImageResponse if streaming_state == "OVERALL_DONE" else ImagePreview
|
||||||
|
yield image_class([media["uri"] for media in imagine_medias], imagine_medias[0]["prompt"])
|
||||||
snippet = bot_response_message["snippet"]
|
snippet = bot_response_message["snippet"]
|
||||||
new_snippet_len = len(snippet)
|
new_snippet_len = len(snippet)
|
||||||
if new_snippet_len > last_snippet_len:
|
if new_snippet_len > last_snippet_len:
|
||||||
@@ -135,7 +155,7 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
if sources is not None:
|
if sources is not None:
|
||||||
yield sources
|
yield sources
|
||||||
|
|
||||||
async def get_cookies(self, cookies: Cookies = None) -> Cookies:
|
async def update_cookies(self, cookies: Cookies = None):
|
||||||
async with self.session.get("https://www.meta.ai/", cookies=cookies) as response:
|
async with self.session.get("https://www.meta.ai/", cookies=cookies) as response:
|
||||||
await raise_for_status(response, "Fetch home failed")
|
await raise_for_status(response, "Fetch home failed")
|
||||||
text = await response.text()
|
text = await response.text()
|
||||||
@@ -148,12 +168,20 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
"datr": self.extract_value(text, "datr"),
|
"datr": self.extract_value(text, "datr"),
|
||||||
}
|
}
|
||||||
self.lsd = self.extract_value(text, start_str='"LSD",[],{"token":"', end_str='"}')
|
self.lsd = self.extract_value(text, start_str='"LSD",[],{"token":"', end_str='"}')
|
||||||
return cookies
|
self.dtsg = self.extract_value(text, start_str='"DTSGInitialData",[],{"token":"', end_str='"}')
|
||||||
|
self.cookies = cookies
|
||||||
|
|
||||||
async def fetch_sources(self, fetch_id: str) -> Sources:
|
async def fetch_sources(self, fetch_id: str) -> Sources:
|
||||||
url = "https://graph.meta.ai/graphql?locale=user"
|
if self.access_token is None:
|
||||||
|
url = "https://www.meta.ai/api/graphql/"
|
||||||
|
payload = {"lsd": self.lsd, 'fb_dtsg': self.dtsg}
|
||||||
|
headers = {'x-fb-lsd': self.lsd}
|
||||||
|
else:
|
||||||
|
url = "https://graph.meta.ai/graphql?locale=user"
|
||||||
|
payload = {"access_token": self.access_token}
|
||||||
|
headers = {}
|
||||||
payload = {
|
payload = {
|
||||||
"access_token": self.access_token,
|
**payload,
|
||||||
"fb_api_caller_class": "RelayModern",
|
"fb_api_caller_class": "RelayModern",
|
||||||
"fb_api_req_friendly_name": "AbraSearchPluginDialogQuery",
|
"fb_api_req_friendly_name": "AbraSearchPluginDialogQuery",
|
||||||
"variables": json.dumps({"abraMessageFetchID": fetch_id}),
|
"variables": json.dumps({"abraMessageFetchID": fetch_id}),
|
||||||
@@ -163,18 +191,22 @@ class MetaAI(AsyncGeneratorProvider):
|
|||||||
headers = {
|
headers = {
|
||||||
"authority": "graph.meta.ai",
|
"authority": "graph.meta.ai",
|
||||||
"x-fb-friendly-name": "AbraSearchPluginDialogQuery",
|
"x-fb-friendly-name": "AbraSearchPluginDialogQuery",
|
||||||
|
**headers
|
||||||
}
|
}
|
||||||
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
|
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
|
||||||
await raise_for_status(response)
|
await raise_for_status(response)
|
||||||
response_json = await response.json()
|
text = await response.text()
|
||||||
|
if "<h1>Something Went Wrong</h1>" in text:
|
||||||
|
raise ResponseError("Response: Something Went Wrong")
|
||||||
try:
|
try:
|
||||||
|
response_json = json.loads(text)
|
||||||
message = response_json["data"]["message"]
|
message = response_json["data"]["message"]
|
||||||
if message is not None:
|
if message is not None:
|
||||||
searchResults = message["searchResults"]
|
searchResults = message["searchResults"]
|
||||||
if searchResults is not None:
|
if searchResults is not None:
|
||||||
return Sources(searchResults["references"])
|
return Sources(searchResults["references"])
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError, json.JSONDecodeError):
|
||||||
raise RuntimeError(f"Response: {response_json}")
|
raise RuntimeError(f"Response: {text}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def extract_value(text: str, key: str = None, start_str = None, end_str = '",') -> str:
|
def extract_value(text: str, key: str = None, start_str = None, end_str = '",') -> str:
|
||||||
|
21
g4f/Provider/MetaAIAccount.py
Normal file
21
g4f/Provider/MetaAIAccount.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ..typing import AsyncResult, Messages, Cookies
|
||||||
|
from .helper import format_prompt, get_cookies
|
||||||
|
from .MetaAI import MetaAI
|
||||||
|
|
||||||
|
class MetaAIAccount(MetaAI):
|
||||||
|
needs_auth = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def create_async_generator(
|
||||||
|
cls,
|
||||||
|
model: str,
|
||||||
|
messages: Messages,
|
||||||
|
proxy: str = None,
|
||||||
|
cookies: Cookies = None,
|
||||||
|
**kwargs
|
||||||
|
) -> AsyncResult:
|
||||||
|
cookies = get_cookies(".meta.ai", True, True) if cookies is None else cookies
|
||||||
|
async for chunk in cls(proxy).prompt(format_prompt(messages), cookies):
|
||||||
|
yield chunk
|
@@ -10,7 +10,7 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
|||||||
from .helper import format_prompt
|
from .helper import format_prompt
|
||||||
from ..image import ImageResponse, to_bytes, is_accepted_format
|
from ..image import ImageResponse, to_bytes, is_accepted_format
|
||||||
from ..requests import StreamSession, FormData, raise_for_status
|
from ..requests import StreamSession, FormData, raise_for_status
|
||||||
from .you.har_file import get_dfp_telemetry_id
|
from .you.har_file import get_telemetry_ids
|
||||||
|
|
||||||
class You(AsyncGeneratorProvider, ProviderModelMixin):
|
class You(AsyncGeneratorProvider, ProviderModelMixin):
|
||||||
url = "https://you.com"
|
url = "https://you.com"
|
||||||
@@ -35,6 +35,7 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
}
|
}
|
||||||
_cookies = None
|
_cookies = None
|
||||||
_cookies_used = 0
|
_cookies_used = 0
|
||||||
|
_telemetry_ids = []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_async_generator(
|
async def create_async_generator(
|
||||||
@@ -159,6 +160,8 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_cookies(cls, client: StreamSession) -> Cookies:
|
async def create_cookies(cls, client: StreamSession) -> Cookies:
|
||||||
|
if not cls._telemetry_ids:
|
||||||
|
cls._telemetry_ids = await get_telemetry_ids()
|
||||||
user_uuid = str(uuid.uuid4())
|
user_uuid = str(uuid.uuid4())
|
||||||
async with client.post(
|
async with client.post(
|
||||||
"https://web.stytch.com/sdk/v1/passwords",
|
"https://web.stytch.com/sdk/v1/passwords",
|
||||||
@@ -170,7 +173,7 @@ class You(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
"Referer": "https://you.com/"
|
"Referer": "https://you.com/"
|
||||||
},
|
},
|
||||||
json={
|
json={
|
||||||
"dfp_telemetry_id": await get_dfp_telemetry_id(),
|
"dfp_telemetry_id": cls._telemetry_ids.pop(),
|
||||||
"email": f"{user_uuid}@gmail.com",
|
"email": f"{user_uuid}@gmail.com",
|
||||||
"password": f"{user_uuid}#{user_uuid}",
|
"password": f"{user_uuid}#{user_uuid}",
|
||||||
"session_duration_minutes": 129600
|
"session_duration_minutes": 129600
|
||||||
|
@@ -43,6 +43,7 @@ from .Liaobots import Liaobots
|
|||||||
from .Llama import Llama
|
from .Llama import Llama
|
||||||
from .Local import Local
|
from .Local import Local
|
||||||
from .MetaAI import MetaAI
|
from .MetaAI import MetaAI
|
||||||
|
from .MetaAIAccount import MetaAIAccount
|
||||||
from .PerplexityLabs import PerplexityLabs
|
from .PerplexityLabs import PerplexityLabs
|
||||||
from .Pi import Pi
|
from .Pi import Pi
|
||||||
from .ReplicateImage import ReplicateImage
|
from .ReplicateImage import ReplicateImage
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from aiohttp import ClientSession
|
from ...requests import StreamSession, raise_for_status
|
||||||
from ...requests import raise_for_status
|
|
||||||
from ...errors import RateLimitError
|
from ...errors import RateLimitError
|
||||||
from ...providers.conversation import BaseConversation
|
from ...providers.conversation import BaseConversation
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ class Conversation(BaseConversation):
|
|||||||
self.clientId = clientId
|
self.clientId = clientId
|
||||||
self.conversationSignature = conversationSignature
|
self.conversationSignature = conversationSignature
|
||||||
|
|
||||||
async def create_conversation(session: ClientSession, headers: dict, tone: str) -> Conversation:
|
async def create_conversation(session: StreamSession, headers: dict, tone: str) -> Conversation:
|
||||||
"""
|
"""
|
||||||
Create a new conversation asynchronously.
|
Create a new conversation asynchronously.
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ async def create_conversation(session: ClientSession, headers: dict, tone: str)
|
|||||||
raise RuntimeError('Empty fields: Failed to create conversation')
|
raise RuntimeError('Empty fields: Failed to create conversation')
|
||||||
return Conversation(conversationId, clientId, conversationSignature)
|
return Conversation(conversationId, clientId, conversationSignature)
|
||||||
|
|
||||||
async def list_conversations(session: ClientSession) -> list:
|
async def list_conversations(session: StreamSession) -> list:
|
||||||
"""
|
"""
|
||||||
List all conversations asynchronously.
|
List all conversations asynchronously.
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ async def list_conversations(session: ClientSession) -> list:
|
|||||||
response = await response.json()
|
response = await response.json()
|
||||||
return response["chats"]
|
return response["chats"]
|
||||||
|
|
||||||
async def delete_conversation(session: ClientSession, conversation: Conversation, headers: dict) -> bool:
|
async def delete_conversation(session: StreamSession, conversation: Conversation, headers: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Delete a conversation asynchronously.
|
Delete a conversation asynchronously.
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ except ImportError:
|
|||||||
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
||||||
from ...webdriver import get_browser
|
from ...webdriver import get_browser
|
||||||
from ...typing import AsyncResult, Messages, Cookies, ImageType, AsyncIterator
|
from ...typing import AsyncResult, Messages, Cookies, ImageType, AsyncIterator
|
||||||
from ...requests import get_args_from_browser, raise_for_status
|
from ...requests import DEFAULT_HEADERS, get_args_from_browser, raise_for_status
|
||||||
from ...requests.aiohttp import StreamSession
|
from ...requests.aiohttp import StreamSession
|
||||||
from ...image import to_image, to_bytes, ImageResponse, ImageRequest
|
from ...image import to_image, to_bytes, ImageResponse, ImageRequest
|
||||||
from ...errors import MissingAuthError, ResponseError
|
from ...errors import MissingAuthError, ResponseError
|
||||||
@@ -360,7 +360,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
if debug.logging:
|
if debug.logging:
|
||||||
print("OpenaiChat: Load default_model failed")
|
print("OpenaiChat: Load default_model failed")
|
||||||
print(f"{e.__class__.__name__}: {e}")
|
print(f"{e.__class__.__name__}: {e}")
|
||||||
|
|
||||||
|
|
||||||
arkose_token = None
|
arkose_token = None
|
||||||
if cls.default_model is None:
|
if cls.default_model is None:
|
||||||
@@ -377,7 +376,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
cls.default_model = cls.get_model(await cls.get_default_model(session, cls._headers))
|
cls.default_model = cls.get_model(await cls.get_default_model(session, cls._headers))
|
||||||
|
|
||||||
async with session.post(
|
async with session.post(
|
||||||
f"{cls.url}/backend-anon/sentinel/chat-requirements" if not cls._api_key else
|
f"{cls.url}/backend-anon/sentinel/chat-requirements"
|
||||||
|
if not cls._api_key else
|
||||||
f"{cls.url}/backend-api/sentinel/chat-requirements",
|
f"{cls.url}/backend-api/sentinel/chat-requirements",
|
||||||
json={"conversation_mode_kind": "primary_assistant"},
|
json={"conversation_mode_kind": "primary_assistant"},
|
||||||
headers=cls._headers
|
headers=cls._headers
|
||||||
@@ -388,7 +388,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
|
|||||||
blob = data["arkose"]["dx"]
|
blob = data["arkose"]["dx"]
|
||||||
need_arkose = data["arkose"]["required"]
|
need_arkose = data["arkose"]["required"]
|
||||||
chat_token = data["token"]
|
chat_token = data["token"]
|
||||||
|
|
||||||
if debug.logging:
|
if debug.logging:
|
||||||
print(f'Arkose: {need_arkose} Turnstile: {data["turnstile"]["required"]}')
|
print(f'Arkose: {need_arkose} Turnstile: {data["turnstile"]["required"]}')
|
||||||
|
|
||||||
@@ -595,8 +595,7 @@ this.fetch = async (url, options) => {
|
|||||||
print(f"Open nodriver with user_dir: {user_data_dir}")
|
print(f"Open nodriver with user_dir: {user_data_dir}")
|
||||||
browser = await uc.start(user_data_dir=user_data_dir)
|
browser = await uc.start(user_data_dir=user_data_dir)
|
||||||
page = await browser.get("https://chat.openai.com/")
|
page = await browser.get("https://chat.openai.com/")
|
||||||
while await page.find("[id^=headlessui-menu-button-]") is None:
|
await page.select("[id^=headlessui-menu-button-]", 240)
|
||||||
await asyncio.sleep(1)
|
|
||||||
api_key = await page.evaluate(
|
api_key = await page.evaluate(
|
||||||
"(async () => {"
|
"(async () => {"
|
||||||
"let session = await fetch('/api/auth/session');"
|
"let session = await fetch('/api/auth/session');"
|
||||||
@@ -662,16 +661,10 @@ this.fetch = async (url, options) => {
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_default_headers() -> dict:
|
def get_default_headers() -> dict:
|
||||||
return {
|
return {
|
||||||
"accept-language": "en-US",
|
**DEFAULT_HEADERS,
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"oai-device-id": str(uuid.uuid4()),
|
"oai-device-id": str(uuid.uuid4()),
|
||||||
"oai-language": "en-US",
|
"oai-language": "en-US",
|
||||||
"sec-ch-ua": "\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\"",
|
|
||||||
"sec-ch-ua-mobile": "?0",
|
|
||||||
"sec-ch-ua-platform": "\"Linux\"",
|
|
||||||
"sec-fetch-dest": "empty",
|
|
||||||
"sec-fetch-mode": "cors",
|
|
||||||
"sec-fetch-site": "same-origin"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -696,11 +689,11 @@ this.fetch = async (url, options) => {
|
|||||||
def _set_api_key(cls, api_key: str):
|
def _set_api_key(cls, api_key: str):
|
||||||
cls._api_key = api_key
|
cls._api_key = api_key
|
||||||
cls._expires = int(time.time()) + 60 * 60 * 4
|
cls._expires = int(time.time()) + 60 * 60 * 4
|
||||||
cls._headers["Authorization"] = f"Bearer {api_key}"
|
cls._headers["authorization"] = f"Bearer {api_key}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _update_cookie_header(cls):
|
def _update_cookie_header(cls):
|
||||||
cls._headers["Cookie"] = cls._format_cookies(cls._cookies)
|
cls._headers["cookie"] = cls._format_cookies(cls._cookies)
|
||||||
|
|
||||||
class Conversation(BaseConversation):
|
class Conversation(BaseConversation):
|
||||||
"""
|
"""
|
||||||
|
@@ -3,11 +3,10 @@ from __future__ import annotations
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import uuid
|
|
||||||
import asyncio
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from ...requests import StreamSession, raise_for_status
|
from ...requests import StreamSession, raise_for_status
|
||||||
|
from ... import debug
|
||||||
|
|
||||||
class NoValidHarFileError(Exception):
|
class NoValidHarFileError(Exception):
|
||||||
...
|
...
|
||||||
@@ -67,60 +66,49 @@ async def sendRequest(tmpArk: arkReq, proxy: str = None):
|
|||||||
return await response.text()
|
return await response.text()
|
||||||
|
|
||||||
async def get_dfp_telemetry_id(proxy: str = None):
|
async def get_dfp_telemetry_id(proxy: str = None):
|
||||||
return await telemetry_id_with_driver(proxy)
|
|
||||||
global chatArks
|
global chatArks
|
||||||
if chatArks is None:
|
if chatArks is None:
|
||||||
chatArks = readHAR()
|
chatArks = readHAR()
|
||||||
return await sendRequest(random.choice(chatArks), proxy)
|
return await sendRequest(random.choice(chatArks), proxy)
|
||||||
|
|
||||||
async def telemetry_id_with_driver(proxy: str = None):
|
def read_telemetry_file() -> list:
|
||||||
from ...debug import logging
|
with open("hardir/you.com_telemetry_ids.txt", "r") as f:
|
||||||
if logging:
|
ids = f.readlines()
|
||||||
print('getting telemetry_id for you.com with nodriver')
|
random.shuffle(ids)
|
||||||
|
return ids
|
||||||
|
|
||||||
|
async def get_telemetry_ids(proxy: str = None) -> list:
|
||||||
|
if debug.logging:
|
||||||
|
print('Getting telemetry_id for you.com with nodriver')
|
||||||
try:
|
try:
|
||||||
import nodriver as uc
|
from nodriver import start
|
||||||
from nodriver import start, cdp, loop
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if logging:
|
if debug.logging:
|
||||||
print('nodriver not found, random uuid (may fail)')
|
print('Install "nodriver" package | pip install -U nodriver')
|
||||||
return str(uuid.uuid4())
|
return read_telemetry_file()
|
||||||
|
|
||||||
CAN_EVAL = False
|
|
||||||
payload_received = False
|
|
||||||
payload = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
browser = await start()
|
browser = await start()
|
||||||
tab = browser.main_tab
|
tab = browser.main_tab
|
||||||
|
|
||||||
async def send_handler(event: cdp.network.RequestWillBeSent):
|
|
||||||
nonlocal CAN_EVAL, payload_received, payload
|
|
||||||
if 'telemetry.js' in event.request.url:
|
|
||||||
CAN_EVAL = True
|
|
||||||
if "/submit" in event.request.url:
|
|
||||||
payload = event.request.post_data
|
|
||||||
payload_received = True
|
|
||||||
|
|
||||||
tab.add_handler(cdp.network.RequestWillBeSent, send_handler)
|
|
||||||
await browser.get("https://you.com")
|
await browser.get("https://you.com")
|
||||||
|
|
||||||
while not CAN_EVAL:
|
while not await tab.evaluate('"GetTelemetryID" in this'):
|
||||||
await tab.sleep(1)
|
await tab.sleep(1)
|
||||||
|
|
||||||
await tab.evaluate('window.GetTelemetryID("public-token-live-507a52ad-7e69-496b-aee0-1c9863c7c819", "https://telemetry.stytch.com/submit");')
|
async def get_telemetry_id():
|
||||||
|
public_token = "public-token-live-507a52ad-7e69-496b-aee0-1c9863c7c819"
|
||||||
|
telemetry_url = "https://telemetry.stytch.com/submit"
|
||||||
|
return await tab.evaluate(f'this.GetTelemetryID("{public_token}", "{telemetry_url}");', await_promise=True)
|
||||||
|
|
||||||
while not payload_received:
|
# for _ in range(500):
|
||||||
await tab.sleep(.1)
|
# with open("hardir/you.com_telemetry_ids.txt", "a") as f:
|
||||||
|
# f.write((await get_telemetry_id()) + "\n")
|
||||||
except Exception as e:
|
|
||||||
print(f"Error occurred: {str(e)}")
|
|
||||||
|
|
||||||
|
return [await get_telemetry_id() for _ in range(10)]
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
await tab.close()
|
await tab.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error occurred while closing tab: {str(e)}")
|
print(f"Error occurred while closing tab: {str(e)}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await browser.stop()
|
await browser.stop()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@@ -41,7 +41,9 @@ appStorage = window.localStorage || {
|
|||||||
length: 0
|
length: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const markdown = window.markdownit();
|
const markdown = window.markdownit({
|
||||||
|
html: true,
|
||||||
|
});
|
||||||
const markdown_render = (content) => {
|
const markdown_render = (content) => {
|
||||||
return markdown.render(content
|
return markdown.render(content
|
||||||
.replaceAll(/<!-- generated images start -->|<!-- generated images end -->/gm, "")
|
.replaceAll(/<!-- generated images start -->|<!-- generated images end -->/gm, "")
|
||||||
@@ -312,6 +314,8 @@ async function add_message_chunk(message) {
|
|||||||
window.error = message.error
|
window.error = message.error
|
||||||
console.error(message.error);
|
console.error(message.error);
|
||||||
content_inner.innerHTML += `<p><strong>An error occured:</strong> ${message.error}</p>`;
|
content_inner.innerHTML += `<p><strong>An error occured:</strong> ${message.error}</p>`;
|
||||||
|
} else if (message.type == "preview") {
|
||||||
|
content_inner.innerHTML = markdown_render(message.preview);
|
||||||
} else if (message.type == "content") {
|
} else if (message.type == "content") {
|
||||||
window.text += message.content;
|
window.text += message.content;
|
||||||
html = markdown_render(window.text);
|
html = markdown_render(window.text);
|
||||||
@@ -545,7 +549,7 @@ const load_conversation = async (conversation_id, scroll=true) => {
|
|||||||
last_model = item.provider?.model;
|
last_model = item.provider?.model;
|
||||||
let next_i = parseInt(i) + 1;
|
let next_i = parseInt(i) + 1;
|
||||||
let next_provider = item.provider ? item.provider : (messages.length > next_i ? messages[next_i].provider : null);
|
let next_provider = item.provider ? item.provider : (messages.length > next_i ? messages[next_i].provider : null);
|
||||||
let provider_label = item.provider?.label ? item.provider?.label : item.provider?.name;
|
let provider_label = item.provider?.label ? item.provider.label : item.provider?.name;
|
||||||
let provider_link = item.provider?.name ? `<a href="${item.provider.url}" target="_blank">${provider_label}</a>` : "";
|
let provider_link = item.provider?.name ? `<a href="${item.provider.url}" target="_blank">${provider_label}</a>` : "";
|
||||||
let provider = provider_link ? `
|
let provider = provider_link ? `
|
||||||
<div class="provider">
|
<div class="provider">
|
||||||
|
@@ -7,6 +7,7 @@ from typing import Iterator
|
|||||||
from g4f import version, models
|
from g4f import version, models
|
||||||
from g4f import get_last_provider, ChatCompletion
|
from g4f import get_last_provider, ChatCompletion
|
||||||
from g4f.errors import VersionNotFoundError
|
from g4f.errors import VersionNotFoundError
|
||||||
|
from g4f.image import ImagePreview
|
||||||
from g4f.Provider import ProviderType, __providers__, __map__
|
from g4f.Provider import ProviderType, __providers__, __map__
|
||||||
from g4f.providers.base_provider import ProviderModelMixin, FinishReason
|
from g4f.providers.base_provider import ProviderModelMixin, FinishReason
|
||||||
from g4f.providers.conversation import BaseConversation
|
from g4f.providers.conversation import BaseConversation
|
||||||
@@ -146,6 +147,8 @@ class Api():
|
|||||||
elif isinstance(chunk, Exception):
|
elif isinstance(chunk, Exception):
|
||||||
logging.exception(chunk)
|
logging.exception(chunk)
|
||||||
yield self._format_json("message", get_error_message(chunk))
|
yield self._format_json("message", get_error_message(chunk))
|
||||||
|
elif isinstance(chunk, ImagePreview):
|
||||||
|
yield self._format_json("preview", chunk.to_string())
|
||||||
elif not isinstance(chunk, FinishReason):
|
elif not isinstance(chunk, FinishReason):
|
||||||
yield self._format_json("content", str(chunk))
|
yield self._format_json("content", str(chunk))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
11
g4f/image.py
11
g4f/image.py
@@ -210,7 +210,9 @@ def format_images_markdown(images: Union[str, list], alt: str, preview: Union[st
|
|||||||
if not isinstance(preview, list):
|
if not isinstance(preview, list):
|
||||||
preview = [preview.replace('{image}', image) if preview else image for image in images]
|
preview = [preview.replace('{image}', image) if preview else image for image in images]
|
||||||
result = "\n".join(
|
result = "\n".join(
|
||||||
f"[]({image})" for idx, image in enumerate(images)
|
#f"[]({image})"
|
||||||
|
f'[<img src="{preview[idx]}" width="200" alt="#{idx+1} {alt}">]({image})'
|
||||||
|
for idx, image in enumerate(images)
|
||||||
)
|
)
|
||||||
start_flag = "<!-- generated images start -->\n"
|
start_flag = "<!-- generated images start -->\n"
|
||||||
end_flag = "<!-- generated images end -->\n"
|
end_flag = "<!-- generated images end -->\n"
|
||||||
@@ -259,6 +261,13 @@ class ImageResponse:
|
|||||||
def get_list(self) -> list[str]:
|
def get_list(self) -> list[str]:
|
||||||
return [self.images] if isinstance(self.images, str) else self.images
|
return [self.images] if isinstance(self.images, str) else self.images
|
||||||
|
|
||||||
|
class ImagePreview(ImageResponse):
|
||||||
|
def __str__(self):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
return super().__str__()
|
||||||
|
|
||||||
class ImageRequest:
|
class ImageRequest:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@@ -24,6 +24,7 @@ class StreamSession(ClientSession):
|
|||||||
headers: dict = {},
|
headers: dict = {},
|
||||||
timeout: int = None,
|
timeout: int = None,
|
||||||
connector: BaseConnector = None,
|
connector: BaseConnector = None,
|
||||||
|
proxy: str = None,
|
||||||
proxies: dict = {},
|
proxies: dict = {},
|
||||||
impersonate = None,
|
impersonate = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
@@ -38,11 +39,13 @@ class StreamSession(ClientSession):
|
|||||||
connect, timeout = timeout;
|
connect, timeout = timeout;
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
timeout = ClientTimeout(timeout, connect)
|
timeout = ClientTimeout(timeout, connect)
|
||||||
|
if proxy is None:
|
||||||
|
proxy = proxies.get("all", proxies.get("https"))
|
||||||
super().__init__(
|
super().__init__(
|
||||||
**kwargs,
|
**kwargs,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
response_class=StreamResponse,
|
response_class=StreamResponse,
|
||||||
connector=get_connector(connector, proxies.get("all", proxies.get("https"))),
|
connector=get_connector(connector, proxy),
|
||||||
headers=headers
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -1,21 +1,27 @@
|
|||||||
|
try:
|
||||||
|
import brotli
|
||||||
|
has_brotli = True
|
||||||
|
except ImportError:
|
||||||
|
has_brotli = False
|
||||||
|
|
||||||
DEFAULT_HEADERS = {
|
DEFAULT_HEADERS = {
|
||||||
"sec-ch-ua": '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',
|
|
||||||
"sec-ch-ua-mobile": "?0",
|
|
||||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
|
|
||||||
"ec-ch-ua-arch": '"x86"',
|
|
||||||
"sec-ch-ua-full-version": '"122.0.6261.69"',
|
|
||||||
"accept": "*/*",
|
"accept": "*/*",
|
||||||
"sec-ch-ua-platform-version:": '"6.5.0"',
|
"accept-encoding": "gzip, deflate" + (", br" if has_brotli else ""),
|
||||||
"sec-ch-ua-full-version-list": '"Chromium";v="122.0.6261.69", "Not(A:Brand";v="24.0.0.0", "Google Chrome";v="122.0.6261.69"',
|
|
||||||
"sec-ch-ua-bitness": '"64"',
|
|
||||||
"sec-ch-ua-model": '""',
|
|
||||||
"sec-ch-ua-platform": '"Windows"',
|
|
||||||
"sec-fetch-site": "same-site",
|
|
||||||
"sec-fetch-mode": "cors",
|
|
||||||
"sec-fetch-dest": "empty",
|
|
||||||
"referer": "",
|
|
||||||
"accept-encoding": "gzip, deflate, br",
|
|
||||||
"accept-language": "en-US",
|
"accept-language": "en-US",
|
||||||
|
"referer": "",
|
||||||
|
"sec-ch-ua": "\"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\"",
|
||||||
|
"sec-ch-ua-arch": "\"x86\"",
|
||||||
|
"sec-ch-ua-bitness": "\"64\"",
|
||||||
|
"sec-ch-ua-full-version": "\"123.0.6312.122\"",
|
||||||
|
"sec-ch-ua-full-version-list": "\"Google Chrome\";v=\"123.0.6312.122\", \"Not:A-Brand\";v=\"8.0.0.0\", \"Chromium\";v=\"123.0.6312.122\"",
|
||||||
|
"sec-ch-ua-mobile": "?0",
|
||||||
|
"sec-ch-ua-model": "\"\"",
|
||||||
|
"sec-ch-ua-platform": "\"Windows\"",
|
||||||
|
"sec-ch-ua-platform-version": '"15.0.0"',
|
||||||
|
"sec-fetch-dest": "empty",
|
||||||
|
"sec-fetch-mode": "cors",
|
||||||
|
"sec-fetch-site": "same-origin",
|
||||||
|
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
||||||
}
|
}
|
||||||
WEBVIEW_HAEDERS = {
|
WEBVIEW_HAEDERS = {
|
||||||
"Accept": "*/*",
|
"Accept": "*/*",
|
||||||
|
Reference in New Issue
Block a user