返回提交历史
Added
etc/examples/api.py
+19
-0
Renamed
etc/examples/ecosia.py
+0
-0
Renamed
etc/examples/openaichat.py
+0
-0
Modified
g4f/Provider/MetaAI.py
+37
-34
Modified
g4f/api/__init__.py
+39
-34
Modified
g4f/api/run.py
+1
-3
Modified
g4f/cli.py
+6
-4
Modified
g4f/webdriver.py
+1
-1
XFEstudio/gpt4free
Add workers and use_colors options to api
83484c0a
代码差异
8 个文件
+103
-76
@@ -0,0 +1,19 @@
1
import requests
2
import json
3
url = "http://localhost:1337/v1/chat/completions"
4
body = {
5
"model": "",
6
"provider": "MetaAI",
7
"stream": True,
8
"messages": [
9
{"role": "assistant", "content": "What can you do? Who are you?"}
10
]
11
}
12
lines = requests.post(url, json=body, stream=True).iter_lines()
13
for line in lines:
14
if line.startswith(b"data: "):
15
try:
16
print(json.loads(line[6:]).get("choices", [{"delta": {}}])[0]["delta"].get("content", ""), end="")
17
except json.JSONDecodeError:
18
pass
19
print()
此文件没有可显示的逐行差异。
此文件没有可显示的逐行差异。
@@ -9,9 +9,15 @@ from aiohttp import ClientSession, BaseConnector
9
9
10
10
from ..typing import AsyncResult, Messages, Cookies
11
11
from ..requests import raise_for_status, DEFAULT_HEADERS
12
from ..image import ImageResponse
13
12
from .base_provider import AsyncGeneratorProvider
14
from .helper import format_prompt, get_connector, get_cookies
13
from .helper import format_prompt, get_connector
14
15
class Sources():
16
def __init__(self, list: List[Dict[str, str]]) -> None:
17
self.list = list
18
19
def __str__(self) -> str:
20
return "\n\n" + ("\n".join([f"[{link['title']}]({link['link']})" for link in self.list]))
15
21
16
22
class MetaAI(AsyncGeneratorProvider):
17
23
url = "https://www.meta.ai"
@@ -19,6 +25,8 @@ class MetaAI(AsyncGeneratorProvider):
19
25
20
26
def __init__(self, proxy: str = None, connector: BaseConnector = None):
21
27
self.session = ClientSession(connector=get_connector(connector, proxy), headers=DEFAULT_HEADERS)
28
self.cookies: Cookies = None
29
self.access_token: str = None
22
30
23
31
@classmethod
24
32
async def create_async_generator(
@@ -32,11 +40,11 @@ class MetaAI(AsyncGeneratorProvider):
32
40
async for chunk in cls(proxy).prompt(format_prompt(messages)):
33
41
yield chunk
34
42
35
async def get_access_token(self, cookies: Cookies, birthday: str = "1999-01-01") -> str:
43
async def get_access_token(self, birthday: str = "1999-01-01") -> str:
36
44
url = "https://www.meta.ai/api/graphql/"
37
45
38
46
payload = {
39
"lsd": cookies["lsd"],
47
"lsd": self.lsd,
40
48
"fb_api_caller_class": "RelayModern",
41
49
"fb_api_req_friendly_name": "useAbraAcceptTOSForTempUserMutation",
42
50
"variables": json.dumps({
@@ -48,29 +56,30 @@ class MetaAI(AsyncGeneratorProvider):
48
56
}
49
57
headers = {
50
58
"x-fb-friendly-name": "useAbraAcceptTOSForTempUserMutation",
51
"x-fb-lsd": cookies["lsd"],
59
"x-fb-lsd": self.lsd,
52
60
"x-asbd-id": "129477",
53
61
"alt-used": "www.meta.ai",
54
62
"sec-fetch-site": "same-origin"
55
63
}
56
async with self.session.post(url, headers=headers, cookies=cookies, data=payload) as response:
64
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
57
65
await raise_for_status(response, "Fetch access_token failed")
58
66
auth_json = await response.json(content_type=None)
59
67
access_token = auth_json["data"]["xab_abra_accept_terms_of_service"]["new_temp_user_auth"]["access_token"]
60
68
return access_token
61
69
62
70
async def prompt(self, message: str, cookies: Cookies = None) -> AsyncResult:
63
access_token = None
64
if cookies is None:
65
cookies = await self.get_cookies()
66
access_token = await self.get_access_token(cookies)
67
else:
68
cookies = await self.get_cookies(cookies)
71
if cookies is not None:
72
self.cookies = cookies
73
self.access_token = None
74
if self.cookies is None:
75
self.cookies = await self.get_cookies()
76
if self.access_token is None:
77
self.access_token = await self.get_access_token()
69
78
70
79
url = "https://graph.meta.ai/graphql?locale=user"
71
80
#url = "https://www.meta.ai/api/graphql/"
72
81
payload = {
73
"access_token": access_token,
82
"access_token": self.access_token,
74
83
#"lsd": cookies["lsd"],
75
84
"fb_api_caller_class": "RelayModern",
76
85
"fb_api_req_friendly_name": "useAbraSendMessageMutation",
@@ -95,7 +104,7 @@ class MetaAI(AsyncGeneratorProvider):
95
104
"x-fb-friendly-name": "useAbraSendMessageMutation",
96
105
#"x-fb-lsd": cookies["lsd"],
97
106
}
98
async with self.session.post(url, headers=headers, cookies=cookies, data=payload) as response:
107
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
99
108
await raise_for_status(response, "Fetch response failed")
100
109
last_snippet_len = 0
101
110
fetch_id = None
@@ -106,25 +115,25 @@ class MetaAI(AsyncGeneratorProvider):
106
115
continue
107
116
bot_response_message = json_line.get("data", {}).get("node", {}).get("bot_response_message", {})
108
117
streaming_state = bot_response_message.get("streaming_state")
109
fetch_id = bot_response_message.get("fetch_id")
118
fetch_id = bot_response_message.get("fetch_id") or fetch_id
110
119
if streaming_state in ("STREAMING", "OVERALL_DONE"):
111
120
#imagine_card = bot_response_message["imagine_card"]
112
121
snippet = bot_response_message["snippet"]
113
yield snippet[last_snippet_len:]
114
last_snippet_len = len(snippet)
115
elif streaming_state == "OVERALL_DONE":
116
break
122
new_snippet_len = len(snippet)
123
if new_snippet_len > last_snippet_len:
124
yield snippet[last_snippet_len:]
125
last_snippet_len = new_snippet_len
117
126
#if last_streamed_response is None:
118
127
# if attempts > 3:
119
128
# raise Exception("MetaAI is having issues and was not able to respond (Server Error)")
120
129
# access_token = await self.get_access_token()
121
130
# return await self.prompt(message=message, attempts=attempts + 1)
122
131
if fetch_id is not None:
123
sources = await self.fetch_sources(fetch_id, cookies, access_token)
132
sources = await self.fetch_sources(fetch_id)
124
133
if sources is not None:
125
134
yield sources
126
135
127
async def get_cookies(self, cookies: Cookies = None) -> dict:
136
async def get_cookies(self, cookies: Cookies = None) -> Cookies:
128
137
async with self.session.get("https://www.meta.ai/", cookies=cookies) as response:
129
138
await raise_for_status(response, "Fetch home failed")
130
139
text = await response.text()
@@ -134,13 +143,13 @@ class MetaAI(AsyncGeneratorProvider):
134
143
"abra_csrf": self.extract_value(text, "abra_csrf"),
135
144
"datr": self.extract_value(text, "datr"),
136
145
}
137
cookies["lsd"] = self.extract_value(text, start_str='"LSD",[],{"token":"', end_str='"}')
146
self.lsd = self.extract_value(text, start_str='"LSD",[],{"token":"', end_str='"}')
138
147
return cookies
139
148
140
async def fetch_sources(self, fetch_id: str, cookies: Cookies, access_token: str) -> List[Dict]:
149
async def fetch_sources(self, fetch_id: str) -> Sources:
141
150
url = "https://graph.meta.ai/graphql?locale=user"
142
151
payload = {
143
"access_token": access_token,
152
"access_token": self.access_token,
144
153
"fb_api_caller_class": "RelayModern",
145
154
"fb_api_req_friendly_name": "AbraSearchPluginDialogQuery",
146
155
"variables": json.dumps({"abraMessageFetchID": fetch_id}),
@@ -151,7 +160,7 @@ class MetaAI(AsyncGeneratorProvider):
151
160
"authority": "graph.meta.ai",
152
161
"x-fb-friendly-name": "AbraSearchPluginDialogQuery",
153
162
}
154
async with self.session.post(url, headers=headers, cookies=cookies, data=payload) as response:
163
async with self.session.post(url, headers=headers, cookies=self.cookies, data=payload) as response:
155
164
await raise_for_status(response)
156
165
response_json = await response.json()
157
166
try:
@@ -171,7 +180,8 @@ class MetaAI(AsyncGeneratorProvider):
171
180
if start >= 0:
172
181
start+= len(start_str)
173
182
end = text.find(end_str, start)
174
return text[start:end]
183
if end >= 0:
184
return text[start:end]
175
185
176
186
def generate_offline_threading_id() -> str:
177
187
"""
@@ -189,11 +199,4 @@ def generate_offline_threading_id() -> str:
189
199
# Combine timestamp and random value
190
200
threading_id = (timestamp << 22) | (random_value & ((1 << 22) - 1))
191
201
192
return str(threading_id)
193
194
class Sources():
195
def __init__(self, list: List[Dict[str, str]]) -> None:
196
self.list = list
197
198
def __str__(self) -> str:
199
return "\n\n" + ("\n".join([f"[{link['title']}]({link['link']})" for link in self.list]))
202
return str(threading_id)
@@ -15,6 +15,8 @@ import g4f.debug
15
15
from g4f.client import AsyncClient
16
16
from g4f.typing import Messages
17
17
18
app = FastAPI()
19
18
20
class ChatCompletionsConfig(BaseModel):
19
21
messages: Messages
20
22
model: str
@@ -25,53 +27,44 @@ class ChatCompletionsConfig(BaseModel):
25
27
stop: Union[list[str], str, None] = None
26
28
api_key: Optional[str] = None
27
29
web_search: Optional[bool] = None
30
proxy: Optional[str] = None
28
31
29
32
class Api:
30
def __init__(self, engine: g4f, debug: bool = True, sentry: bool = False,
31
list_ignored_providers: List[str] = None) -> None:
32
self.engine = engine
33
self.debug = debug
34
self.sentry = sentry
33
def __init__(self, list_ignored_providers: List[str] = None) -> None:
35
34
self.list_ignored_providers = list_ignored_providers
36
37
if debug:
38
g4f.debug.logging = True
39
35
self.client = AsyncClient()
40
self.app = FastAPI()
41
42
self.routes()
43
self.register_validation_exception_handler()
36
37
def set_list_ignored_providers(self, list: list):
38
self.list_ignored_providers = list
44
39
45
40
def register_validation_exception_handler(self):
46
@self.app.exception_handler(RequestValidationError)
41
@app.exception_handler(RequestValidationError)
47
42
async def validation_exception_handler(request: Request, exc: RequestValidationError):
48
43
details = exc.errors()
49
44
modified_details = []
50
45
for error in details:
51
modified_details.append(
52
{
53
"loc": error["loc"],
54
"message": error["msg"],
55
"type": error["type"],
56
}
57
)
46
modified_details.append({
47
"loc": error["loc"],
48
"message": error["msg"],
49
"type": error["type"],
50
})
58
51
return JSONResponse(
59
52
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
60
53
content=jsonable_encoder({"detail": modified_details}),
61
54
)
62
55
63
def routes(self):
64
@self.app.get("/")
56
def register_routes(self):
57
@app.get("/")
65
58
async def read_root():
66
59
return RedirectResponse("/v1", 302)
67
60
68
@self.app.get("/v1")
61
@app.get("/v1")
69
62
async def read_root_v1():
70
63
return HTMLResponse('g4f API: Go to '
71
64
'<a href="/v1/chat/completions">chat/completions</a> '
72
65
'or <a href="/v1/models">models</a>.')
73
66
74
@self.app.get("/v1/models")
67
@app.get("/v1/models")
75
68
async def models():
76
69
model_list = dict(
77
70
(model, g4f.models.ModelUtils.convert[model])
@@ -85,7 +78,7 @@ class Api:
85
78
} for model_id, model in model_list.items()]
86
79
return JSONResponse(model_list)
87
80
88
@self.app.get("/v1/models/{model_name}")
81
@app.get("/v1/models/{model_name}")
89
82
async def model_info(model_name: str):
90
83
try:
91
84
model_info = g4f.models.ModelUtils.convert[model_name]
@@ -98,7 +91,7 @@ class Api:
98
91
except:
99
92
return JSONResponse({"error": "The model does not exist."})
100
93
101
@self.app.post("/v1/chat/completions")
94
@app.post("/v1/chat/completions")
102
95
async def chat_completions(config: ChatCompletionsConfig = None, request: Request = None, provider: str = None):
103
96
try:
104
97
config.provider = provider if config.provider is None else config.provider
@@ -132,13 +125,13 @@ class Api:
132
125
133
126
return StreamingResponse(streaming(), media_type="text/event-stream")
134
127
135
@self.app.post("/v1/completions")
128
@app.post("/v1/completions")
136
129
async def completions():
137
130
return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
138
131
139
def run(self, ip, use_colors : bool = False):
140
split_ip = ip.split(":")
141
uvicorn.run(app=self.app, host=split_ip[0], port=int(split_ip[1]), use_colors=use_colors)
132
api = Api()
133
api.register_routes()
134
api.register_validation_exception_handler()
142
135
143
136
def format_exception(e: Exception, config: ChatCompletionsConfig) -> str:
144
137
last_provider = g4f.get_last_provider(True)
@@ -148,7 +141,19 @@ def format_exception(e: Exception, config: ChatCompletionsConfig) -> str:
148
141
"provider": last_provider.get("name") if last_provider else config.provider
149
142
})
150
143
151
def run_api(host: str = '0.0.0.0', port: int = 1337, debug: bool = False, use_colors=True) -> None:
152
print(f'Starting server... [g4f v-{g4f.version.utils.current_version}]')
153
app = Api(engine=g4f, debug=debug)
154
app.run(f"{host}:{port}", use_colors=use_colors)
144
def run_api(
145
host: str = '0.0.0.0',
146
port: int = 1337,
147
bind: str = None,
148
debug: bool = False,
149
workers: int = None,
150
use_colors: bool = None
151
) -> None:
152
print(f'Starting server... [g4f v-{g4f.version.utils.current_version}]' + (" (debug)" if debug else ""))
153
if use_colors is None:
154
use_colors = debug
155
if bind is not None:
156
host, port = bind.split(":")
157
if debug:
158
g4f.debug.logging = True
159
uvicorn.run("g4f.api:app", host=host, port=int(port), workers=workers, use_colors=use_colors)#
@@ -1,6 +1,4 @@
1
import g4f
2
1
import g4f.api
3
2
4
3
if __name__ == "__main__":
5
print(f'Starting server... [g4f v-{g4f.version.utils.current_version}]')
6
g4f.api.Api(engine = g4f, debug = True).run(ip = "0.0.0.0:10000")
4
g4f.api.run_api(debug=True)
@@ -15,16 +15,18 @@ def main():
15
15
subparsers = parser.add_subparsers(dest="mode", help="Mode to run the g4f in.")
16
16
api_parser=subparsers.add_parser("api")
17
17
api_parser.add_argument("--bind", default="0.0.0.0:1337", help="The bind string.")
18
api_parser.add_argument("--debug", type=bool, default=False, help="Enable verbose logging")
18
api_parser.add_argument("--debug", type=bool, default=False, help="Enable verbose logging.")
19
api_parser.add_argument("--workers", type=int, default=None, help="Number of workers.")
20
api_parser.add_argument("--use_colors", type=bool, default=None, help="Use colors.")
19
21
api_parser.add_argument("--ignored-providers", nargs="+", choices=[provider.name for provider in IgnoredProviders],
20
22
default=[], help="List of providers to ignore when processing request.")
21
23
subparsers.add_parser("gui", parents=[gui_parser()], add_help=False)
22
24
23
25
args = parser.parse_args()
24
26
if args.mode == "api":
25
from g4f.api import Api
26
controller=Api(engine=g4f, debug=args.debug, list_ignored_providers=args.ignored_providers)
27
controller.run(args.bind)
27
import g4f.api
28
g4f.api.api.set_list_ignored_providers(args.ignored_providers)
29
g4f.api.run_api(bind=args.bind, debug=args.debug, workers=args.workers, use_colors=args.use_colors)
28
30
elif args.mode == "gui":
29
31
run_gui_args(args)
30
32
else:
@@ -65,7 +65,7 @@ def get_browser(
65
65
WebDriver: An instance of WebDriver configured with the specified options.
66
66
"""
67
67
if not has_requirements:
68
raise MissingRequirementsError('Webdriver packages are not installed | pip install -U g4f[webdriver]')
68
raise MissingRequirementsError('Install Webdriver packages | pip install -U g4f[webdriver]')
69
69
browser = find_chrome_executable()
70
70
if browser is None:
71
71
raise MissingRequirementsError('Install "Google Chrome" browser')