返回提交历史
Modified
g4f/api/__init__.py
+141
-200
XFEstudio/gpt4free
Update __init__.py
1e0b09b8
代码差异
1 个文件
+141
-200
@@ -1,227 +1,168 @@
1
import typing
2
from .. import BaseProvider
3
import g4f; g4f.debug.logging = True
1
from fastapi import FastAPI, Response, Request
2
from fastapi.middleware.cors import CORSMiddleware
3
from typing import List, Union, Any, Dict, AnyStr
4
from ._tokenizer import tokenize
5
import sqlite3
6
import g4f
4
7
import time
5
8
import json
6
9
import random
7
10
import string
8
import logging
9
10
from typing import Union
11
from loguru import logger
12
from waitress import serve
13
from ._logging import hook_logging
14
from ._tokenizer import tokenize
15
from flask_cors import CORS
16
from werkzeug.serving import WSGIRequestHandler
17
from werkzeug.exceptions import default_exceptions
18
from werkzeug.middleware.proxy_fix import ProxyFix
19
20
from flask import (
21
Flask,
22
jsonify,
23
make_response,
24
request,
11
import uvicorn
12
import nest_asyncio
13
14
app = FastAPI()
15
nest_asyncio.apply()
16
17
origins = [
18
"http://localhost",
19
"http://localhost:1337",
20
]
21
22
app.add_middleware(
23
CORSMiddleware,
24
allow_origins=origins,
25
allow_credentials=True,
26
allow_methods=["*"],
27
allow_headers=["*"],
25
28
)
26
29
27
class Api:
28
__default_ip = '127.0.0.1'
29
__default_port = 1337
30
31
def __init__(self, engine: g4f, debug: bool = True, sentry: bool = False,
32
list_ignored_providers:typing.List[typing.Union[str, BaseProvider]]=None) -> None:
33
self.engine = engine
34
self.debug = debug
35
self.sentry = sentry
36
self.list_ignored_providers = list_ignored_providers
37
self.log_level = logging.DEBUG if debug else logging.WARN
38
39
hook_logging(level=self.log_level, format='[%(asctime)s] %(levelname)s in %(module)s: %(message)s')
40
self.logger = logging.getLogger('waitress')
41
42
self.app = Flask(__name__)
43
self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_port=1)
44
self.app.after_request(self.__after_request)
45
46
def run(self, bind_str, threads=8):
47
host, port = self.__parse_bind(bind_str)
48
49
CORS(self.app, resources={r'/v1/*': {'supports_credentials': True, 'expose_headers': [
50
'Content-Type',
51
'Authorization',
52
'X-Requested-With',
53
'Accept',
54
'Origin',
55
'Access-Control-Request-Method',
56
'Access-Control-Request-Headers',
57
'Content-Disposition'], 'max_age': 600}})
58
59
self.app.route('/v1/models', methods=['GET'])(self.models)
60
self.app.route('/v1/models/<model_id>', methods=['GET'])(self.model_info)
61
62
self.app.route('/v1/chat/completions', methods=['POST'])(self.chat_completions)
63
self.app.route('/v1/completions', methods=['POST'])(self.completions)
64
65
for ex in default_exceptions:
66
self.app.register_error_handler(ex, self.__handle_error)
67
68
if not self.debug:
69
self.logger.warning(f'Serving on http://{host}:{port}')
70
71
WSGIRequestHandler.protocol_version = 'HTTP/1.1'
72
serve(self.app, host=host, port=port, ident=None, threads=threads)
73
74
def __handle_error(self, e: Exception):
75
self.logger.error(e)
76
77
return make_response(jsonify({
78
'code': e.code,
79
'message': str(e.original_exception if self.debug and hasattr(e, 'original_exception') else e.name)}), 500)
80
81
@staticmethod
82
def __after_request(resp):
83
resp.headers['X-Server'] = f'g4f/{g4f.version}'
30
JSONObject = Dict[AnyStr, Any]
31
JSONArray = List[Any]
32
JSONStructure = Union[JSONArray, JSONObject]
33
34
@app.get("/")
35
async def read_root():
36
return Response(content=json.dumps({"info": "G4F API"}, indent=4), media_type="application/json")
37
38
@app.get("/v1")
39
async def read_root_v1():
40
return Response(content=json.dumps({"info": "Go to /v1/chat/completions or /v1/models."}, indent=4), media_type="application/json")
41
42
@app.get("/v1/models")
43
async def models():
44
model_list = [{
45
'id': model,
46
'object': 'model',
47
'created': 0,
48
'owned_by': 'g4f'} for model in g4f.Model.__all__()]
49
50
return Response(content=json.dumps({
51
'object': 'list',
52
'data': model_list}, indent=4), media_type="application/json")
53
54
@app.get("/v1/models/{model_name}")
55
async def model_info(model_name: str):
56
try:
57
model_info = (g4f.ModelUtils.convert[model_name])
84
58
85
return resp
86
87
def __parse_bind(self, bind_str):
88
sections = bind_str.split(':', 2)
89
if len(sections) < 2:
90
try:
91
port = int(sections[0])
92
return self.__default_ip, port
93
except ValueError:
94
return sections[0], self.__default_port
95
96
return sections[0], int(sections[1])
97
98
async def home(self):
99
return 'Hello world | https://127.0.0.1:1337/v1'
59
return Response(content=json.dumps({
60
'id': model_name,
61
'object': 'model',
62
'created': 0,
63
'owned_by': model_info.base_provider
64
}, indent=4), media_type="application/json")
65
except:
66
return Response(content=json.dumps({"error": "The model does not exist."}, indent=4), media_type="application/json")
67
68
@app.post("/v1/chat/completions")
69
async def chat_completions(request: Request, item: JSONStructure = None):
70
71
item_data = {
72
'model': 'gpt-3.5-turbo',
73
'stream': False,
74
}
100
75
101
async def chat_completions(self):
102
model = request.json.get('model', 'gpt-3.5-turbo')
103
stream = request.json.get('stream', False)
104
messages = request.json.get('messages')
105
106
logger.info(f'model: {model}, stream: {stream}, request: {messages[-1]["content"]}')
76
item_data.update(item or {})
77
model = item_data.get('model')
78
stream = item_data.get('stream')
79
messages = item_data.get('messages')
80
81
try:
82
response = g4f.ChatCompletion.create(model=model, stream=stream, messages=messages)
83
except:
84
return Response(content=json.dumps({"error": "An error occurred while generating the response."}, indent=4), media_type="application/json")
85
86
completion_id = ''.join(random.choices(string.ascii_letters + string.digits, k=28))
87
completion_timestamp = int(time.time())
88
89
if not stream:
90
prompt_tokens, _ = tokenize(''.join([message['content'] for message in messages]))
91
completion_tokens, _ = tokenize(response)
92
93
json_data = {
94
'id': f'chatcmpl-{completion_id}',
95
'object': 'chat.completion',
96
'created': completion_timestamp,
97
'model': model,
98
'choices': [
99
{
100
'index': 0,
101
'message': {
102
'role': 'assistant',
103
'content': response,
104
},
105
'finish_reason': 'stop',
106
}
107
],
108
'usage': {
109
'prompt_tokens': prompt_tokens,
110
'completion_tokens': completion_tokens,
111
'total_tokens': prompt_tokens + completion_tokens,
112
},
113
}
107
114
108
config = None
109
proxy = None
115
return Response(content=json.dumps(json_data, indent=4), media_type="application/json")
110
116
117
def streaming():
111
118
try:
112
config = json.load(open("config.json","r",encoding="utf-8"))
113
proxy = config["proxy"]
119
for chunk in response:
120
completion_data = {
121
'id': f'chatcmpl-{completion_id}',
122
'object': 'chat.completion.chunk',
123
'created': completion_timestamp,
124
'model': model,
125
'choices': [
126
{
127
'index': 0,
128
'delta': {
129
'content': chunk,
130
},
131
'finish_reason': None,
132
}
133
],
134
}
114
135
115
except Exception:
116
pass
136
content = json.dumps(completion_data, separators=(',', ':'))
137
yield f'data: {content}\n\n'
138
time.sleep(0.03)
117
139
118
if proxy != None:
119
response = self.engine.ChatCompletion.create(model=model,
120
stream=stream, messages=messages,
121
ignored=self.list_ignored_providers,
122
proxy=proxy)
123
else:
124
response = self.engine.ChatCompletion.create(model=model,
125
stream=stream, messages=messages,
126
ignored=self.list_ignored_providers)
127
128
completion_id = ''.join(random.choices(string.ascii_letters + string.digits, k=28))
129
completion_timestamp = int(time.time())
130
131
if not stream:
132
prompt_tokens, _ = tokenize(''.join([message['content'] for message in messages]))
133
completion_tokens, _ = tokenize(response)
134
135
return {
140
end_completion_data = {
136
141
'id': f'chatcmpl-{completion_id}',
137
'object': 'chat.completion',
142
'object': 'chat.completion.chunk',
138
143
'created': completion_timestamp,
139
144
'model': model,
140
145
'choices': [
141
146
{
142
147
'index': 0,
143
'message': {
144
'role': 'assistant',
145
'content': response,
146
},
148
'delta': {},
147
149
'finish_reason': 'stop',
148
150
}
149
151
],
150
'usage': {
151
'prompt_tokens': prompt_tokens,
152
'completion_tokens': completion_tokens,
153
'total_tokens': prompt_tokens + completion_tokens,
154
},
155
152
}
156
153
157
def streaming():
158
try:
159
for chunk in response:
160
completion_data = {
161
'id': f'chatcmpl-{completion_id}',
162
'object': 'chat.completion.chunk',
163
'created': completion_timestamp,
164
'model': model,
165
'choices': [
166
{
167
'index': 0,
168
'delta': {
169
'content': chunk,
170
},
171
'finish_reason': None,
172
}
173
],
174
}
154
content = json.dumps(end_completion_data, separators=(',', ':'))
155
yield f'data: {content}\n\n'
175
156
176
content = json.dumps(completion_data, separators=(',', ':'))
177
yield f'data: {content}\n\n'
178
time.sleep(0.03)
157
except GeneratorExit:
158
pass
179
159
180
end_completion_data = {
181
'id': f'chatcmpl-{completion_id}',
182
'object': 'chat.completion.chunk',
183
'created': completion_timestamp,
184
'model': model,
185
'choices': [
186
{
187
'index': 0,
188
'delta': {},
189
'finish_reason': 'stop',
190
}
191
],
192
}
193
194
content = json.dumps(end_completion_data, separators=(',', ':'))
195
yield f'data: {content}\n\n'
196
197
logger.success(f'model: {model}, stream: {stream}')
198
199
except GeneratorExit:
200
pass
160
return Response(content=json.dumps(streaming(), indent=4), media_type="application/json")
201
161
202
return self.app.response_class(streaming(), mimetype='text/event-stream')
203
204
async def completions(self):
205
return 'not working yet', 500
206
207
async def model_info(self, model_name):
208
model_info = (g4f.ModelUtils.convert[model_name])
209
210
return jsonify({
211
'id' : model_name,
212
'object' : 'model',
213
'created' : 0,
214
'owned_by' : model_info.base_provider
215
})
216
217
async def models(self):
218
model_list = [{
219
'id' : model,
220
'object' : 'model',
221
'created' : 0,
222
'owned_by' : 'g4f'} for model in g4f.Model.__all__()]
223
224
return jsonify({
225
'object': 'list',
226
'data': model_list})
227
162
@app.post("/v1/completions")
163
async def completions():
164
return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
165
166
def run(ip):
167
split_ip = ip.split(":")
168
uvicorn.run(app, host=split_ip[0], port=int(split_ip[1]), use_colors=False, loop='asyncio')