summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md20
-rw-r--r--g4f/api/__init__.py87
-rw-r--r--g4f/cli.py26
3 files changed, 76 insertions, 57 deletions
diff --git a/README.md b/README.md
index d44a84a4..73916af6 100644
--- a/README.md
+++ b/README.md
@@ -859,8 +859,8 @@ A list of all contributors is available [here](https://github.com/xtekky/gpt4fre
<a href="https://github.com/Commenter123321" target="_blank"><img src="https://avatars.githubusercontent.com/u/36051603?v=4&s=45" width="45" title="Commenter123321"></a>
<a href="https://github.com/DanielShemesh" target="_blank"><img src="https://avatars.githubusercontent.com/u/20585236?v=4&s=45" width="45" title="DanielShemesh"></a>
<a href="https://github.com/Luneye" target="_blank"><img src="https://avatars.githubusercontent.com/u/73485421?v=4&s=45" width="45" title="Luneye"></a>
-<a href="https://github.com/enganese" target="_blank"><img src="https://avatars.githubusercontent.com/u/69082498?v=4&s=45" width="45" title="enganese"></a>
<a href="https://github.com/ezerinz" target="_blank"><img src="https://avatars.githubusercontent.com/u/100193740?v=4&s=45" width="45" title="ezerinz"></a>
+<a href="https://github.com/enganese" target="_blank"><img src="https://avatars.githubusercontent.com/u/69082498?v=4&s=45" width="45" title="enganese"></a>
<a href="https://github.com/Lin-jun-xiang" target="_blank"><img src="https://avatars.githubusercontent.com/u/63782903?v=4&s=45" width="45" title="Lin-jun-xiang"></a>
<a href="https://github.com/nullstreak" target="_blank"><img src="https://avatars.githubusercontent.com/u/139914347?v=4&s=45" width="45" title="nullstreak"></a>
<a href="https://github.com/valerii-chirkov" target="_blank"><img src="https://avatars.githubusercontent.com/u/81074936?v=4&s=45" width="45" title="valerii-chirkov"></a>
@@ -868,16 +868,16 @@ A list of all contributors is available [here](https://github.com/xtekky/gpt4fre
<a href="https://github.com/repollo" target="_blank"><img src="https://avatars.githubusercontent.com/u/2671466?v=4&s=45" width="45" title="repollo"></a>
<a href="https://github.com/hpsj" target="_blank"><img src="https://avatars.githubusercontent.com/u/54535414?v=4&s=45" width="45" title="hpsj"></a>
<a href="https://github.com/taiyi747" target="_blank"><img src="https://avatars.githubusercontent.com/u/63543716?v=4&s=45" width="45" title="taiyi747"></a>
-<a href="https://github.com/ostix360" target="_blank"><img src="https://avatars.githubusercontent.com/u/55257054?v=4&s=45" width="45" title="ostix360"></a>
-<a href="https://github.com/WdR-Tech" target="_blank"><img src="https://avatars.githubusercontent.com/u/143020293?v=4&s=45" width="45" title="WdR-Tech"></a>
-<a href="https://github.com/HexyeDEV" target="_blank"><img src="https://avatars.githubusercontent.com/u/65314629?v=4&s=45" width="45" title="HexyeDEV"></a>
<a href="https://github.com/9fo" target="_blank"><img src="https://avatars.githubusercontent.com/u/71867245?v=4&s=45" width="45" title="9fo"></a>
-<a href="https://github.com/eltociear" target="_blank"><img src="https://avatars.githubusercontent.com/u/22633385?v=4&s=45" width="45" title="eltociear"></a>
-<a href="https://github.com/ramonvc" target="_blank"><img src="https://avatars.githubusercontent.com/u/13617054?v=4&s=45" width="45" title="ramonvc"></a>
-<a href="https://github.com/naa7" target="_blank"><img src="https://avatars.githubusercontent.com/u/44613678?v=4&s=45" width="45" title="naa7"></a>
-<a href="https://github.com/zeng-rr" target="_blank"><img src="https://avatars.githubusercontent.com/u/47846202?v=4&s=45" width="45" title="zeng-rr"></a>
-<a href="https://github.com/editor-syntax" target="_blank"><img src="https://avatars.githubusercontent.com/u/109844019?v=4&s=45" width="45" title="editor-syntax"></a>
+<a href="https://github.com/HexyeDEV" target="_blank"><img src="https://avatars.githubusercontent.com/u/65314629?v=4&s=45" width="45" title="HexyeDEV"></a>
+<a href="https://github.com/WdR-Tech" target="_blank"><img src="https://avatars.githubusercontent.com/u/143020293?v=4&s=45" width="45" title="WdR-Tech"></a>
+<a href="https://github.com/ostix360" target="_blank"><img src="https://avatars.githubusercontent.com/u/55257054?v=4&s=45" width="45" title="ostix360"></a>
<a href="https://github.com/devAdityaa" target="_blank"><img src="https://avatars.githubusercontent.com/u/77636021?v=4&s=45" width="45" title="devAdityaa"></a>
+<a href="https://github.com/editor-syntax" target="_blank"><img src="https://avatars.githubusercontent.com/u/109844019?v=4&s=45" width="45" title="editor-syntax"></a>
+<a href="https://github.com/zeng-rr" target="_blank"><img src="https://avatars.githubusercontent.com/u/47846202?v=4&s=45" width="45" title="zeng-rr"></a>
+<a href="https://github.com/naa7" target="_blank"><img src="https://avatars.githubusercontent.com/u/44613678?v=4&s=45" width="45" title="naa7"></a>
+<a href="https://github.com/ramonvc" target="_blank"><img src="https://avatars.githubusercontent.com/u/13617054?v=4&s=45" width="45" title="ramonvc"></a>
+<a href="https://github.com/eltociear" target="_blank"><img src="https://avatars.githubusercontent.com/u/22633385?v=4&s=45" width="45" title="eltociear"></a>
<a href="https://github.com/kggn" target="_blank"><img src="https://avatars.githubusercontent.com/u/95663228?v=4&s=45" width="45" title="kggn"></a>
<a href="https://github.com/xiangsx" target="_blank"><img src="https://avatars.githubusercontent.com/u/29322721?v=4&s=45" width="45" title="xiangsx"></a>
<a href="https://github.com/ggindinson" target="_blank"><img src="https://avatars.githubusercontent.com/u/97807772?v=4&s=45" width="45" title="ggindinson"></a>
@@ -886,12 +886,14 @@ A list of all contributors is available [here](https://github.com/xtekky/gpt4fre
<img src="https://avatars.githubusercontent.com/u/12299238?s=45&v=4" width="45" title="xqdoo00o">
<img src="https://avatars.githubusercontent.com/u/97126670?s=45&v=4" width="45" title="nathanrchn">
<img src="https://avatars.githubusercontent.com/u/81407603?v=4&s=45" width="45" title="dsdanielpark">
+<img src="https://avatars.githubusercontent.com/u/55200481?v=4&s=45" width="45" title="missuo">
- The [`Vercel.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/Vercel.py) file contains code from [vercel-llm-api](https://github.com/ading2210/vercel-llm-api) by [@ading2210](https://github.com/ading2210)
- The [`har_file.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/openai/har_file.py) has input from [xqdoo00o/ChatGPT-to-API](https://github.com/xqdoo00o/ChatGPT-to-API)
- The [`PerplexityLabs.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/openai/har_file.py) has input from [nathanrchn/perplexityai](https://github.com/nathanrchn/perplexityai)
- The [`Gemini.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/needs_auth/Gemini.py) has input from [dsdanielpark/Gemini-API](https://github.com/dsdanielpark/Gemini-API)
- The [`MetaAI.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/MetaAI.py) file contains code from [meta-ai-api](https://github.com/Strvm/meta-ai-api) by [@Strvm](https://github.com/Strvm)
+- The [`proofofwork.py`](https://github.com/xtekky/gpt4free/blob/main/g4f/Provider/openai/proofofwork.py) has input from [missuo/FreeGPT35](https://github.com/missuo/FreeGPT35)
*Having input implies that the AI's code generation utilized it as one of many sources.*
diff --git a/g4f/api/__init__.py b/g4f/api/__init__.py
index d379653f..f252ab71 100644
--- a/g4f/api/__init__.py
+++ b/g4f/api/__init__.py
@@ -19,16 +19,23 @@ import g4f
import g4f.debug
from g4f.client import AsyncClient
from g4f.typing import Messages
+from g4f.cookies import read_cookie_files
-def create_app(g4f_api_key:str = None):
+def create_app():
app = FastAPI()
- api = Api(app, g4f_api_key=g4f_api_key)
+ api = Api(app)
api.register_routes()
api.register_authorization()
api.register_validation_exception_handler()
+ if not AppConfig.ignore_cookie_files:
+ read_cookie_files()
return app
-class ChatCompletionsConfig(BaseModel):
+def create_app_debug():
+ g4f.debug.logging = True
+ return create_app()
+
+class ChatCompletionsForm(BaseModel):
messages: Messages
model: str
provider: Optional[str] = None
@@ -40,23 +47,33 @@ class ChatCompletionsConfig(BaseModel):
web_search: Optional[bool] = None
proxy: Optional[str] = None
-list_ignored_providers: list[str] = None
+class AppConfig():
+ list_ignored_providers: Optional[list[str]] = None
+ g4f_api_key: Optional[str] = None
+ ignore_cookie_files: bool = False
+
+ @classmethod
+ def set_list_ignored_providers(cls, ignored: list[str]):
+ cls.list_ignored_providers = ignored
+
+ @classmethod
+ def set_g4f_api_key(cls, key: str = None):
+ cls.g4f_api_key = key
-def set_list_ignored_providers(ignored: list[str]):
- global list_ignored_providers
- list_ignored_providers = ignored
+ @classmethod
+ def set_ignore_cookie_files(cls, value: bool):
+ cls.ignore_cookie_files = value
class Api:
- def __init__(self, app: FastAPI, g4f_api_key=None) -> None:
+ def __init__(self, app: FastAPI) -> None:
self.app = app
self.client = AsyncClient()
- self.g4f_api_key = g4f_api_key
self.get_g4f_api_key = APIKeyHeader(name="g4f-api-key")
def register_authorization(self):
@self.app.middleware("http")
async def authorization(request: Request, call_next):
- if self.g4f_api_key and request.url.path in ["/v1/chat/completions", "/v1/completions"]:
+ if AppConfig.g4f_api_key and request.url.path in ["/v1/chat/completions", "/v1/completions"]:
try:
user_g4f_api_key = await self.get_g4f_api_key(request)
except HTTPException as e:
@@ -65,26 +82,22 @@ class Api:
status_code=HTTP_401_UNAUTHORIZED,
content=jsonable_encoder({"detail": "G4F API key required"}),
)
- if not secrets.compare_digest(self.g4f_api_key, user_g4f_api_key):
+ if not secrets.compare_digest(AppConfig.g4f_api_key, user_g4f_api_key):
return JSONResponse(
- status_code=HTTP_403_FORBIDDEN,
- content=jsonable_encoder({"detail": "Invalid G4F API key"}),
- )
-
- response = await call_next(request)
- return response
+ status_code=HTTP_403_FORBIDDEN,
+ content=jsonable_encoder({"detail": "Invalid G4F API key"}),
+ )
+ return await call_next(request)
def register_validation_exception_handler(self):
@self.app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
details = exc.errors()
- modified_details = []
- for error in details:
- modified_details.append({
- "loc": error["loc"],
- "message": error["msg"],
- "type": error["type"],
- })
+ modified_details = [{
+ "loc": error["loc"],
+ "message": error["msg"],
+ "type": error["type"],
+ } for error in details]
return JSONResponse(
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder({"detail": modified_details}),
@@ -103,10 +116,10 @@ class Api:
@self.app.get("/v1/models")
async def models():
- model_list = dict(
- (model, g4f.models.ModelUtils.convert[model])
+ model_list = {
+ model: g4f.models.ModelUtils.convert[model]
for model in g4f.Model.__all__()
- )
+ }
model_list = [{
'id': model_id,
'object': 'model',
@@ -129,7 +142,7 @@ class Api:
return JSONResponse({"error": "The model does not exist."})
@self.app.post("/v1/chat/completions")
- async def chat_completions(config: ChatCompletionsConfig, request: Request = None, provider: str = None):
+ async def chat_completions(config: ChatCompletionsForm, request: Request = None, provider: str = None):
try:
config.provider = provider if config.provider is None else config.provider
if config.api_key is None and request is not None:
@@ -140,7 +153,7 @@ class Api:
config.api_key = auth_header
response = self.client.chat.completions.create(
**config.dict(exclude_none=True),
- ignored=list_ignored_providers
+ ignored=AppConfig.list_ignored_providers
)
except Exception as e:
logging.exception(e)
@@ -166,7 +179,7 @@ class Api:
async def completions():
return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
-def format_exception(e: Exception, config: ChatCompletionsConfig) -> str:
+def format_exception(e: Exception, config: ChatCompletionsForm) -> str:
last_provider = g4f.get_last_provider(True)
return json.dumps({
"error": {"message": f"{e.__class__.__name__}: {e}"},
@@ -180,14 +193,18 @@ def run_api(
bind: str = None,
debug: bool = False,
workers: int = None,
- use_colors: bool = None,
- g4f_api_key: str = None
+ use_colors: bool = None
) -> None:
print(f'Starting server... [g4f v-{g4f.version.utils.current_version}]' + (" (debug)" if debug else ""))
if use_colors is None:
use_colors = debug
if bind is not None:
host, port = bind.split(":")
- if debug:
- g4f.debug.logging = True
- uvicorn.run(create_app(g4f_api_key), host=host, port=int(port), workers=workers, use_colors=use_colors) \ No newline at end of file
+ uvicorn.run(
+ f"g4f.api:{'create_app_debug' if debug else 'create_app'}",
+ host=host, port=int(port),
+ workers=workers,
+ use_colors=use_colors,
+ factory=True,
+ reload=debug
+ ) \ No newline at end of file
diff --git a/g4f/cli.py b/g4f/cli.py
index 9037a6f1..fe219b38 100644
--- a/g4f/cli.py
+++ b/g4f/cli.py
@@ -4,8 +4,6 @@ import argparse
from g4f import Provider
from g4f.gui.run import gui_parser, run_gui_args
-from g4f.cookies import read_cookie_files
-from g4f import debug
def main():
parser = argparse.ArgumentParser(description="Run gpt4free")
@@ -16,9 +14,9 @@ def main():
api_parser.add_argument("--workers", type=int, default=None, help="Number of workers.")
api_parser.add_argument("--disable-colors", action="store_true", help="Don't use colors.")
api_parser.add_argument("--ignore-cookie-files", action="store_true", help="Don't read .har and cookie files.")
- api_parser.add_argument("--g4f-api-key", type=str, default=None, help="Sets an authentication key for your API.")
- api_parser.add_argument("--ignored-providers", nargs="+", choices=[provider for provider in Provider.__map__],
- default=[], help="List of providers to ignore when processing request.")
+ api_parser.add_argument("--g4f-api-key", type=str, default=None, help="Sets an authentication key for your API. (incompatible with --debug and --workers)")
+ api_parser.add_argument("--ignored-providers", nargs="+", choices=[provider.__name__ for provider in Provider.__providers__ if provider.working],
+ default=[], help="List of providers to ignore when processing request. (incompatible with --debug and --workers)")
subparsers.add_parser("gui", parents=[gui_parser()], add_help=False)
args = parser.parse_args()
@@ -31,19 +29,21 @@ def main():
exit(1)
def run_api_args(args):
- if args.debug:
- debug.logging = True
- if not args.ignore_cookie_files:
- read_cookie_files()
- import g4f.api
- g4f.api.set_list_ignored_providers(
+ from g4f.api import AppConfig, run_api
+
+ AppConfig.set_ignore_cookie_files(
+ args.ignore_cookie_files
+ )
+ AppConfig.set_list_ignored_providers(
args.ignored_providers
)
- g4f.api.run_api(
+ AppConfig.set_g4f_api_key(
+ args.g4f_api_key
+ )
+ run_api(
bind=args.bind,
debug=args.debug,
workers=args.workers,
- g4f_api_key=args.g4f_api_key,
use_colors=not args.disable_colors
)