返回提交历史
Added
g4f/client/async.py
+239
-0
XFEstudio/gpt4free
Update client
b913a8f2
代码差异
1 个文件
+239
-0
@@ -0,0 +1,239 @@
1
from __future__ import annotations
2
3
import re
4
import os
5
import time
6
import random
7
import string
8
9
from .stubs import ChatCompletion, ChatCompletionChunk, Image, ImagesResponse
10
from .typing import Union, Iterator, Messages, ImageType
11
from .providers.types import BaseProvider, ProviderType, FinishReason
12
from .image import ImageResponse as ImageProviderResponse
13
from .errors import NoImageResponseError, RateLimitError, MissingAuthError
14
from . import get_model_and_provider, get_last_provider
15
16
from .Provider.BingCreateImages import BingCreateImages
17
from .Provider.needs_auth import Gemini, OpenaiChat
18
from .Provider.You import You
19
20
def read_json(text: str) -> dict:
21
"""
22
Parses JSON code block from a string.
23
24
Args:
25
text (str): A string containing a JSON code block.
26
27
Returns:
28
dict: A dictionary parsed from the JSON code block.
29
"""
30
match = re.search(r"```(json|)\n(?P<code>[\S\s]+?)\n```", text)
31
if match:
32
return match.group("code")
33
return text
34
35
def iter_response(
36
response: iter[str],
37
stream: bool,
38
response_format: dict = None,
39
max_tokens: int = None,
40
stop: list = None
41
) -> IterResponse:
42
content = ""
43
finish_reason = None
44
completion_id = ''.join(random.choices(string.ascii_letters + string.digits, k=28))
45
for idx, chunk in enumerate(response):
46
if isinstance(chunk, FinishReason):
47
finish_reason = chunk.reason
48
break
49
content += str(chunk)
50
if max_tokens is not None and idx + 1 >= max_tokens:
51
finish_reason = "length"
52
first = -1
53
word = None
54
if stop is not None:
55
for word in list(stop):
56
first = content.find(word)
57
if first != -1:
58
content = content[:first]
59
break
60
if stream and first != -1:
61
first = chunk.find(word)
62
if first != -1:
63
chunk = chunk[:first]
64
else:
65
first = 0
66
if first != -1:
67
finish_reason = "stop"
68
if stream:
69
yield ChatCompletionChunk(chunk, None, completion_id, int(time.time()))
70
if finish_reason is not None:
71
break
72
finish_reason = "stop" if finish_reason is None else finish_reason
73
if stream:
74
yield ChatCompletionChunk(None, finish_reason, completion_id, int(time.time()))
75
else:
76
if response_format is not None and "type" in response_format:
77
if response_format["type"] == "json_object":
78
content = read_json(content)
79
yield ChatCompletion(content, finish_reason, completion_id, int(time.time()))
80
81
def iter_append_model_and_provider(response: IterResponse) -> IterResponse:
82
last_provider = None
83
for chunk in response:
84
last_provider = get_last_provider(True) if last_provider is None else last_provider
85
chunk.model = last_provider.get("model")
86
chunk.provider = last_provider.get("name")
87
yield chunk
88
89
class Client():
90
91
def __init__(
92
self,
93
api_key: str = None,
94
proxies: Proxies = None,
95
provider: ProviderType = None,
96
image_provider: ImageProvider = None,
97
**kwargs
98
) -> None:
99
self.api_key: str = api_key
100
self.proxies: Proxies = proxies
101
self.chat: Chat = Chat(self, provider)
102
self.images: Images = Images(self, image_provider)
103
104
def get_proxy(self) -> Union[str, None]:
105
if isinstance(self.proxies, str):
106
return self.proxies
107
elif self.proxies is None:
108
return os.environ.get("G4F_PROXY")
109
elif "all" in self.proxies:
110
return self.proxies["all"]
111
elif "https" in self.proxies:
112
return self.proxies["https"]
113
114
def filter_none(**kwargs):
115
for key in list(kwargs.keys()):
116
if kwargs[key] is None:
117
del kwargs[key]
118
return kwargs
119
120
class Completions():
121
def __init__(self, client: Client, provider: ProviderType = None):
122
self.client: Client = client
123
self.provider: ProviderType = provider
124
125
def create(
126
self,
127
messages: Messages,
128
model: str,
129
provider: ProviderType = None,
130
stream: bool = False,
131
response_format: dict = None,
132
max_tokens: int = None,
133
stop: Union[list[str], str] = None,
134
api_key: str = None,
135
ignored : list[str] = None,
136
ignore_working: bool = False,
137
ignore_stream: bool = False,
138
**kwargs
139
) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]:
140
model, provider = get_model_and_provider(
141
model,
142
self.provider if provider is None else provider,
143
stream,
144
ignored,
145
ignore_working,
146
ignore_stream,
147
**kwargs
148
)
149
stop = [stop] if isinstance(stop, str) else stop
150
response = provider.create_completion(
151
model, messages, stream,
152
**filter_none(
153
proxy=self.client.get_proxy(),
154
max_tokens=max_tokens,
155
stop=stop,
156
api_key=self.client.api_key if api_key is None else api_key
157
),
158
**kwargs
159
)
160
response = iter_response(response, stream, response_format, max_tokens, stop)
161
response = iter_append_model_and_provider(response)
162
return response if stream else next(response)
163
164
class Chat():
165
completions: Completions
166
167
def __init__(self, client: Client, provider: ProviderType = None):
168
self.completions = Completions(client, provider)
169
170
class ImageModels():
171
gemini = Gemini
172
openai = OpenaiChat
173
you = You
174
175
def __init__(self, client: Client) -> None:
176
self.client = client
177
self.default = BingCreateImages(proxy=self.client.get_proxy())
178
179
def get(self, name: str, default: ImageProvider = None) -> ImageProvider:
180
return getattr(self, name) if hasattr(self, name) else default or self.default
181
182
def iter_image_response(response: Iterator) -> Union[ImagesResponse, None]:
183
for chunk in list(response):
184
if isinstance(chunk, ImageProviderResponse):
185
return ImagesResponse([Image(image) for image in chunk.get_list()])
186
187
def create_image(client: Client, provider: ProviderType, prompt: str, model: str = "", **kwargs) -> Iterator:
188
prompt = f"create a image with: {prompt}"
189
return provider.create_completion(
190
model,
191
[{"role": "user", "content": prompt}],
192
True,
193
proxy=client.get_proxy(),
194
**kwargs
195
)
196
197
class Images():
198
def __init__(self, client: Client, provider: ImageProvider = None):
199
self.client: Client = client
200
self.provider: ImageProvider = provider
201
self.models: ImageModels = ImageModels(client)
202
203
def generate(self, prompt, model: str = None, **kwargs) -> ImagesResponse:
204
provider = self.models.get(model, self.provider)
205
if isinstance(provider, type) and issubclass(provider, BaseProvider):
206
response = create_image(self.client, provider, prompt, **kwargs)
207
else:
208
try:
209
response = list(provider.create(prompt))
210
except (RateLimitError, MissingAuthError) as e:
211
# Fallback for default provider
212
if self.provider is None:
213
response = create_image(self.client, self.models.you, prompt, model or "dall-e", **kwargs)
214
else:
215
raise e
216
image = iter_image_response(response)
217
if image is None:
218
raise NoImageResponseError()
219
return image
220
221
def create_variation(self, image: ImageType, model: str = None, **kwargs):
222
provider = self.models.get(model, self.provider)
223
result = None
224
if isinstance(provider, type) and issubclass(provider, BaseProvider):
225
response = provider.create_completion(
226
"",
227
[{"role": "user", "content": "create a image like this"}],
228
True,
229
image=image,
230
proxy=self.client.get_proxy(),
231
**kwargs
232
)
233
for chunk in response:
234
if isinstance(chunk, ImageProviderResponse):
235
result = ([chunk.images] if isinstance(chunk.images, str) else chunk.images)
236
result = ImagesResponse([Image(image)for image in result])
237
if result is None:
238
raise NoImageResponseError()
239
return result