返回提交历史
Modified
g4f/client/async_client.py
+162
-160
XFEstudio/gpt4free
Restored old version(g4f/client/async_client.py)
85c95be2
代码差异
1 个文件
+162
-160
@@ -1,27 +1,32 @@
1
1
from __future__ import annotations
2
2
3
import os
4
3
import time
5
4
import random
6
5
import string
7
import logging
8
6
import asyncio
9
from typing import Union, AsyncIterator
10
from ..providers.base_provider import AsyncGeneratorProvider
11
from ..image import ImageResponse, to_image, to_data_uri
12
from ..typing import Messages, ImageType
13
from ..providers.types import BaseProvider, ProviderType, FinishReason
14
from ..providers.conversation import BaseConversation
15
from ..image import ImageResponse as ImageProviderResponse
16
from ..errors import NoImageResponseError
17
from .stubs import ChatCompletion, ChatCompletionChunk, Image, ImagesResponse
18
from .image_models import ImageModels
19
from .types import IterResponse, ImageProvider
7
import base64
8
from aiohttp import ClientSession, BaseConnector
9
20
10
from .types import Client as BaseClient
21
from .service import get_model_and_provider, get_last_provider
22
from .helper import find_stop, filter_json, filter_none
23
from ..models import ModelUtils
24
from ..Provider import IterListProvider
11
from .types import ProviderType, FinishReason
12
from .stubs import ChatCompletion, ChatCompletionChunk, ImagesResponse, Image
13
from .types import AsyncIterResponse, ImageProvider
14
from .image_models import ImageModels
15
from .helper import filter_json, find_stop, filter_none, cast_iter_async
16
from .service import get_last_provider, get_model_and_provider
17
from ..Provider import ProviderUtils
18
from ..typing import Union, Messages, AsyncIterator, ImageType
19
from ..errors import NoImageResponseError, ProviderNotFoundError
20
from ..requests.aiohttp import get_connector
21
from ..providers.conversation import BaseConversation
22
from ..image import ImageResponse as ImageProviderResponse, ImageDataResponse
23
24
try:
25
anext
26
except NameError:
27
async def anext(iter):
28
async for chunk in iter:
29
return chunk
25
30
26
31
async def iter_response(
27
32
response: AsyncIterator[str],
@@ -29,37 +34,30 @@ async def iter_response(
29
34
response_format: dict = None,
30
35
max_tokens: int = None,
31
36
stop: list = None
32
) -> AsyncIterator[ChatCompletion | ChatCompletionChunk]:
37
) -> AsyncIterResponse:
33
38
content = ""
34
39
finish_reason = None
35
40
completion_id = ''.join(random.choices(string.ascii_letters + string.digits, k=28))
36
37
async for idx, chunk in enumerate(response):
41
count: int = 0
42
async for chunk in response:
38
43
if isinstance(chunk, FinishReason):
39
44
finish_reason = chunk.reason
40
45
break
41
46
elif isinstance(chunk, BaseConversation):
42
47
yield chunk
43
48
continue
44
45
49
content += str(chunk)
46
47
if max_tokens is not None and idx + 1 >= max_tokens:
50
count += 1
51
if max_tokens is not None and count >= max_tokens:
48
52
finish_reason = "length"
49
50
first, content, chunk = find_stop(stop, content, chunk if stream else None)
51
53
first, content, chunk = find_stop(stop, content, chunk)
52
54
if first != -1:
53
55
finish_reason = "stop"
54
55
56
if stream:
56
57
yield ChatCompletionChunk(chunk, None, completion_id, int(time.time()))
57
58
58
if finish_reason is not None:
59
59
break
60
61
60
finish_reason = "stop" if finish_reason is None else finish_reason
62
63
61
if stream:
64
62
yield ChatCompletionChunk(None, finish_reason, completion_id, int(time.time()))
65
63
else:
@@ -68,12 +66,12 @@ async def iter_response(
68
66
content = filter_json(content)
69
67
yield ChatCompletion(content, finish_reason, completion_id, int(time.time()))
70
68
71
async def iter_append_model_and_provider(response: AsyncIterator) -> AsyncIterator:
69
async def iter_append_model_and_provider(response: AsyncIterResponse) -> AsyncIterResponse:
72
70
last_provider = None
73
71
async for chunk in response:
74
72
last_provider = get_last_provider(True) if last_provider is None else last_provider
75
73
chunk.model = last_provider.get("model")
76
chunk.provider = last_provider.get("name")
74
chunk.provider = last_provider.get("name")
77
75
yield chunk
78
76
79
77
class AsyncClient(BaseClient):
@@ -82,32 +80,59 @@ class AsyncClient(BaseClient):
82
80
provider: ProviderType = None,
83
81
image_provider: ImageProvider = None,
84
82
**kwargs
85
) -> None:
83
):
86
84
super().__init__(**kwargs)
87
85
self.chat: Chat = Chat(self, provider)
88
self._images: Images = Images(self, image_provider)
86
self.images: Images = Images(self, image_provider)
89
87
90
@property
91
def images(self) -> Images:
92
return self._images
88
def create_response(
89
messages: Messages,
90
model: str,
91
provider: ProviderType = None,
92
stream: bool = False,
93
proxy: str = None,
94
max_tokens: int = None,
95
stop: list[str] = None,
96
api_key: str = None,
97
**kwargs
98
):
99
has_asnyc = hasattr(provider, "create_async_generator")
100
if has_asnyc:
101
create = provider.create_async_generator
102
else:
103
create = provider.create_completion
104
response = create(
105
model, messages,
106
stream=stream,
107
**filter_none(
108
proxy=proxy,
109
max_tokens=max_tokens,
110
stop=stop,
111
api_key=api_key
112
),
113
**kwargs
114
)
115
if not has_asnyc:
116
response = cast_iter_async(response)
117
return response
93
118
94
class Completions:
119
class Completions():
95
120
def __init__(self, client: AsyncClient, provider: ProviderType = None):
96
121
self.client: AsyncClient = client
97
122
self.provider: ProviderType = provider
98
123
99
async def create(
124
def create(
100
125
self,
101
126
messages: Messages,
102
127
model: str,
103
128
provider: ProviderType = None,
104
129
stream: bool = False,
105
130
proxy: str = None,
106
response_format: dict = None,
107
131
max_tokens: int = None,
108
132
stop: Union[list[str], str] = None,
109
133
api_key: str = None,
110
ignored: list[str] = None,
134
response_format: dict = None,
135
ignored : list[str] = None,
111
136
ignore_working: bool = False,
112
137
ignore_stream: bool = False,
113
138
**kwargs
@@ -118,156 +143,133 @@ class Completions:
118
143
stream,
119
144
ignored,
120
145
ignore_working,
121
ignore_stream,
146
ignore_stream
122
147
)
123
124
148
stop = [stop] if isinstance(stop, str) else stop
125
126
response = await provider.create_completion(
127
model,
128
messages,
129
stream=stream,
130
**filter_none(
131
proxy=self.client.get_proxy() if proxy is None else proxy,
132
max_tokens=max_tokens,
133
stop=stop,
134
api_key=self.client.api_key if api_key is None else api_key
135
),
149
response = create_response(
150
messages, model,
151
provider, stream,
152
proxy=self.client.get_proxy() if proxy is None else proxy,
153
max_tokens=max_tokens,
154
stop=stop,
155
api_key=self.client.api_key if api_key is None else api_key,
136
156
**kwargs
137
157
)
138
139
158
response = iter_response(response, stream, response_format, max_tokens, stop)
140
159
response = iter_append_model_and_provider(response)
141
142
return response if stream else await anext(response)
160
return response if stream else anext(response)
143
161
144
class Chat:
162
class Chat():
145
163
completions: Completions
146
164
147
165
def __init__(self, client: AsyncClient, provider: ProviderType = None):
148
166
self.completions = Completions(client, provider)
149
167
150
async def iter_image_response(response: AsyncIterator) -> Union[ImagesResponse, None]:
151
logging.info("Starting iter_image_response")
168
async def iter_image_response(
169
response: AsyncIterator,
170
response_format: str = None,
171
connector: BaseConnector = None,
172
proxy: str = None
173
) -> Union[ImagesResponse, None]:
152
174
async for chunk in response:
153
logging.info(f"Processing chunk: {chunk}")
154
175
if isinstance(chunk, ImageProviderResponse):
155
logging.info("Found ImageProviderResponse")
156
return ImagesResponse([Image(image) for image in chunk.get_list()])
157
158
logging.warning("No ImageProviderResponse found in the response")
159
return None
160
161
async def create_image(client: AsyncClient, provider: ProviderType, prompt: str, model: str = "", **kwargs) -> AsyncIterator:
162
logging.info(f"Creating image with provider: {provider}, model: {model}, prompt: {prompt}")
176
if response_format == "b64_json":
177
async with ClientSession(
178
connector=get_connector(connector, proxy),
179
cookies=chunk.options.get("cookies")
180
) as session:
181
async def fetch_image(image):
182
async with session.get(image) as response:
183
return base64.b64encode(await response.content.read()).decode()
184
images = await asyncio.gather(*[fetch_image(image) for image in chunk.get_list()])
185
return ImagesResponse([Image(None, image, chunk.alt) for image in images], int(time.time()))
186
return ImagesResponse([Image(image, None, chunk.alt) for image in chunk.get_list()], int(time.time()))
187
elif isinstance(chunk, ImageDataResponse):
188
return ImagesResponse([Image(None, image, chunk.alt) for image in chunk.get_list()], int(time.time()))
163
189
190
def create_image(provider: ProviderType, prompt: str, model: str = "", **kwargs) -> AsyncIterator:
164
191
if isinstance(provider, type) and provider.__name__ == "You":
165
192
kwargs["chat_mode"] = "create"
166
193
else:
167
prompt = f"create an image with: {prompt}"
168
169
response = await provider.create_completion(
194
prompt = f"create a image with: {prompt}"
195
return provider.create_async_generator(
170
196
model,
171
197
[{"role": "user", "content": prompt}],
172
198
stream=True,
173
proxy=client.get_proxy(),
174
199
**kwargs
175
200
)
176
177
logging.info(f"Response from create_completion: {response}")
178
return response
179
201
180
class Images:
202
class Images():
181
203
def __init__(self, client: AsyncClient, provider: ImageProvider = None):
182
204
self.client: AsyncClient = client
183
205
self.provider: ImageProvider = provider
184
206
self.models: ImageModels = ImageModels(client)
185
207
186
async def generate(self, prompt: str, model: str = None, **kwargs) -> ImagesResponse:
187
logging.info(f"Starting asynchronous image generation for model: {model}, prompt: {prompt}")
188
provider = self.models.get(model, self.provider)
189
if provider is None:
190
raise ValueError(f"Unknown model: {model}")
191
192
logging.info(f"Provider: {provider}")
193
194
if isinstance(provider, IterListProvider):
195
if provider.providers:
196
provider = provider.providers[0]
197
logging.info(f"Using first provider from IterListProvider: {provider}")
208
def get_provider(self, model: str, provider: ProviderType = None):
209
if isinstance(provider, str):
210
if provider in ProviderUtils.convert:
211
provider = ProviderUtils.convert[provider]
198
212
else:
199
raise ValueError(f"IterListProvider for model {model} has no providers")
200
201
if isinstance(provider, type) and issubclass(provider, AsyncGeneratorProvider):
202
logging.info("Using AsyncGeneratorProvider")
203
messages = [{"role": "user", "content": prompt}]
204
async for response in provider.create_async_generator(model, messages, **kwargs):
205
if isinstance(response, ImageResponse):
206
return self._process_image_response(response)
207
elif isinstance(response, str):
208
image_response = ImageResponse([response], prompt)
209
return self._process_image_response(image_response)
210
elif hasattr(provider, 'create'):
211
logging.info("Using provider's create method")
212
if asyncio.iscoroutinefunction(provider.create):
213
response = await provider.create(prompt)
214
else:
215
response = provider.create(prompt)
216
217
if isinstance(response, ImageResponse):
218
return self._process_image_response(response)
219
elif isinstance(response, str):
220
image_response = ImageResponse([response], prompt)
221
return self._process_image_response(image_response)
213
raise ProviderNotFoundError(f'Provider not found: {provider}')
222
214
else:
223
raise ValueError(f"Provider {provider} does not support image generation")
224
225
logging.error(f"Unexpected response type: {type(response)}")
226
raise NoImageResponseError(f"Unexpected response type: {type(response)}")
227
228
def _process_image_response(self, response: ImageResponse) -> ImagesResponse:
229
processed_images = []
230
for image_data in response.get_list():
231
if image_data.startswith('http://') or image_data.startswith('https://'):
232
processed_images.append(Image(url=image_data))
233
else:
234
image = to_image(image_data)
235
file_name = self._save_image(image)
236
processed_images.append(Image(url=file_name))
237
return ImagesResponse(processed_images)
238
239
def _save_image(self, image: 'PILImage') -> str:
240
os.makedirs('generated_images', exist_ok=True)
241
file_name = f"generated_images/image_{int(time.time())}.png"
242
image.save(file_name)
243
return file_name
244
245
async def create_variation(self, image: Union[str, bytes], model: str = None, **kwargs) -> ImagesResponse:
246
provider = self.models.get(model, self.provider)
247
if provider is None:
248
raise ValueError(f"Unknown model: {model}")
215
provider = self.models.get(model, self.provider)
216
return provider
249
217
250
if isinstance(provider, type) and issubclass(provider, AsyncGeneratorProvider):
251
messages = [{"role": "user", "content": "create a variation of this image"}]
252
image_data = to_data_uri(image)
253
async for response in provider.create_async_generator(model, messages, image=image_data, **kwargs):
254
if isinstance(response, ImageResponse):
255
return self._process_image_response(response)
256
elif isinstance(response, str):
257
image_response = ImageResponse([response], "Image variation")
258
return self._process_image_response(image_response)
259
elif hasattr(provider, 'create_variation'):
260
if asyncio.iscoroutinefunction(provider.create_variation):
261
response = await provider.create_variation(image, **kwargs)
262
else:
263
response = provider.create_variation(image, **kwargs)
264
265
if isinstance(response, ImageResponse):
266
return self._process_image_response(response)
267
elif isinstance(response, str):
268
image_response = ImageResponse([response], "Image variation")
269
return self._process_image_response(image_response)
218
async def generate(
219
self,
220
prompt,
221
model: str = "",
222
provider: ProviderType = None,
223
response_format: str = None,
224
connector: BaseConnector = None,
225
proxy: str = None,
226
**kwargs
227
) -> ImagesResponse:
228
provider = self.get_provider(model, provider)
229
if hasattr(provider, "create_async_generator"):
230
response = create_image(
231
provider,
232
prompt,
233
**filter_none(
234
response_format=response_format,
235
connector=connector,
236
proxy=self.client.get_proxy() if proxy is None else proxy,
237
),
238
**kwargs
239
)
270
240
else:
271
raise ValueError(f"Provider {provider} does not support image variation")
241
response = await provider.create_async(prompt)
242
return ImagesResponse([Image(image) for image in response.get_list()])
243
image = await iter_image_response(response, response_format, connector, proxy)
244
if image is None:
245
raise NoImageResponseError()
246
return image
272
247
273
raise NoImageResponseError("Failed to create image variation")
248
async def create_variation(
249
self,
250
image: ImageType,
251
model: str = None,
252
response_format: str = None,
253
connector: BaseConnector = None,
254
proxy: str = None,
255
**kwargs
256
):
257
provider = self.get_provider(model, provider)
258
result = None
259
if hasattr(provider, "create_async_generator"):
260
response = provider.create_async_generator(
261
"",
262
[{"role": "user", "content": "create a image like this"}],
263
stream=True,
264
image=image,
265
**filter_none(
266
response_format=response_format,
267
connector=connector,
268
proxy=self.client.get_proxy() if proxy is None else proxy,
269
),
270
**kwargs
271
)
272
result = iter_image_response(response, response_format, connector, proxy)
273
if result is None:
274
raise NoImageResponseError()
275
return result