XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

XFEstudio/gpt4free

Add workers and use_colors options to api

83484c0a
Heiner Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

8 个文件 +103 -76
Added etc/examples/api.py +19 -0
@@ -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()
Renamed etc/examples/ecosia.py +0 -0
此文件没有可显示的逐行差异。
Renamed etc/examples/openaichat.py +0 -0
此文件没有可显示的逐行差异。
Modified g4f/Provider/MetaAI.py +37 -34
@@ -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)
Modified g4f/api/__init__.py +39 -34
@@ -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)#
Modified g4f/api/run.py +1 -3
@@ -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)
Modified g4f/cli.py +6 -4
@@ -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:
Modified g4f/webdriver.py +1 -1
@@ -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')