返回提交历史
Modified
etc/examples/api.py
+1
-1
Modified
g4f/Provider/Liaobots.py
+56
-23
Modified
g4f/Provider/needs_auth/Gemini.py
+19
-17
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+6
-6
Modified
g4f/Provider/openai/har_file.py
+21
-9
Modified
g4f/Provider/openai/proofofwork.py
+32
-16
Modified
g4f/api/__init__.py
+45
-21
Modified
g4f/client/async_client.py
+75
-15
Modified
g4f/client/service.py
+4
-2
Modified
g4f/client/stubs.py
+17
-6
Modified
g4f/image.py
+12
-0
XFEstudio/gpt4free
Improve Liabots provider, Add image api support
b1dafc0e
代码差异
11 个文件
+288
-116
@@ -3,7 +3,7 @@ import json
3
3
url = "http://localhost:1337/v1/chat/completions"
4
4
body = {
5
5
"model": "",
6
"provider": "MetaAI",
6
"provider": "",
7
7
"stream": True,
8
8
"messages": [
9
9
{"role": "assistant", "content": "What can you do? Who are you?"}
@@ -10,6 +10,15 @@ from .helper import get_connector
10
10
from ..requests import raise_for_status
11
11
12
12
models = {
13
"gpt-4o": {
14
"context": "8K",
15
"id": "gpt-4o-free",
16
"maxLength": 31200,
17
"model": "ChatGPT",
18
"name": "GPT-4o-free",
19
"provider": "OpenAI",
20
"tokenLimit": 7800,
21
},
13
22
"gpt-3.5-turbo": {
14
23
"id": "gpt-3.5-turbo",
15
24
"name": "GPT-3.5-Turbo",
@@ -95,7 +104,7 @@ class Liaobots(AsyncGeneratorProvider, ProviderModelMixin):
95
104
model_aliases = {
96
105
"claude-v2": "claude-2"
97
106
}
98
_auth_code = None
107
_auth_code = ""
99
108
_cookie_jar = None
100
109
101
110
@classmethod
@@ -120,7 +129,13 @@ class Liaobots(AsyncGeneratorProvider, ProviderModelMixin):
120
129
cookie_jar=cls._cookie_jar,
121
130
connector=get_connector(connector, proxy, True)
122
131
) as session:
123
cls._auth_code = auth if isinstance(auth, str) else cls._auth_code
132
data = {
133
"conversationId": str(uuid.uuid4()),
134
"model": models[cls.get_model(model)],
135
"messages": messages,
136
"key": "",
137
"prompt": kwargs.get("system_message", "You are a helpful assistant."),
138
}
124
139
if not cls._auth_code:
125
140
async with session.post(
126
141
"https://liaobots.work/recaptcha/api/login",
@@ -128,31 +143,49 @@ class Liaobots(AsyncGeneratorProvider, ProviderModelMixin):
128
143
verify_ssl=False
129
144
) as response:
130
145
await raise_for_status(response)
146
try:
131
147
async with session.post(
132
148
"https://liaobots.work/api/user",
133
json={"authcode": ""},
149
json={"authcode": cls._auth_code},
134
150
verify_ssl=False
135
151
) as response:
136
152
await raise_for_status(response)
137
153
cls._auth_code = (await response.json(content_type=None))["authCode"]
154
if not cls._auth_code:
155
raise RuntimeError("Empty auth code")
138
156
cls._cookie_jar = session.cookie_jar
139
140
data = {
141
"conversationId": str(uuid.uuid4()),
142
"model": models[cls.get_model(model)],
143
"messages": messages,
144
"key": "",
145
"prompt": kwargs.get("system_message", "You are a helpful assistant."),
146
}
147
async with session.post(
148
"https://liaobots.work/api/chat",
149
json=data,
150
headers={"x-auth-code": cls._auth_code},
151
verify_ssl=False
152
) as response:
153
await raise_for_status(response)
154
async for chunk in response.content.iter_any():
155
if b"<html coupert-item=" in chunk:
156
raise RuntimeError("Invalid session")
157
if chunk:
158
yield chunk.decode(errors="ignore")
157
async with session.post(
158
"https://liaobots.work/api/chat",
159
json=data,
160
headers={"x-auth-code": cls._auth_code},
161
verify_ssl=False
162
) as response:
163
await raise_for_status(response)
164
async for chunk in response.content.iter_any():
165
if b"<html coupert-item=" in chunk:
166
raise RuntimeError("Invalid session")
167
if chunk:
168
yield chunk.decode(errors="ignore")
169
except:
170
async with session.post(
171
"https://liaobots.work/api/user",
172
json={"authcode": "pTIQr4FTnVRfr"},
173
verify_ssl=False
174
) as response:
175
await raise_for_status(response)
176
cls._auth_code = (await response.json(content_type=None))["authCode"]
177
if not cls._auth_code:
178
raise RuntimeError("Empty auth code")
179
cls._cookie_jar = session.cookie_jar
180
async with session.post(
181
"https://liaobots.work/api/chat",
182
json=data,
183
headers={"x-auth-code": cls._auth_code},
184
verify_ssl=False
185
) as response:
186
await raise_for_status(response)
187
async for chunk in response.content.iter_any():
188
if b"<html coupert-item=" in chunk:
189
raise RuntimeError("Invalid session")
190
if chunk:
191
yield chunk.decode(errors="ignore")
@@ -4,6 +4,7 @@ import os
4
4
import json
5
5
import random
6
6
import re
7
import base64
7
8
8
9
from aiohttp import ClientSession, BaseConnector
9
10
@@ -22,7 +23,7 @@ from ..base_provider import AsyncGeneratorProvider
22
23
from ..helper import format_prompt, get_cookies
23
24
from ...requests.raise_for_status import raise_for_status
24
25
from ...errors import MissingAuthError, MissingRequirementsError
25
from ...image import to_bytes, to_data_uri, ImageResponse
26
from ...image import to_bytes, ImageResponse, ImageDataResponse
26
27
from ...webdriver import get_browser, get_driver_cookies
27
28
28
29
REQUEST_HEADERS = {
@@ -122,6 +123,7 @@ class Gemini(AsyncGeneratorProvider):
122
123
connector: BaseConnector = None,
123
124
image: ImageType = None,
124
125
image_name: str = None,
126
response_format: str = None,
125
127
**kwargs
126
128
) -> AsyncResult:
127
129
prompt = format_prompt(messages)
@@ -192,22 +194,22 @@ class Gemini(AsyncGeneratorProvider):
192
194
if image_prompt:
193
195
images = [image[0][3][3] for image in response_part[4][0][12][7][0]]
194
196
resolved_images = []
195
preview = []
196
for image in images:
197
async with client.get(image, allow_redirects=False) as fetch:
198
image = fetch.headers["location"]
199
async with client.get(image, allow_redirects=False) as fetch:
200
image = fetch.headers["location"]
201
resolved_images.append(image)
202
preview.append(image.replace('=s512', '=s200'))
203
# preview_url = image.replace('=s512', '=s200')
204
# async with client.get(preview_url) as fetch:
205
# preview_data = to_data_uri(await fetch.content.read())
206
# async with client.get(image) as fetch:
207
# data = to_data_uri(await fetch.content.read())
208
# preview.append(preview_data)
209
# resolved_images.append(data)
210
yield ImageResponse(resolved_images, image_prompt, {"orginal_links": images, "preview": preview})
197
if response_format == "b64_json":
198
for image in images:
199
async with client.get(image) as response:
200
data = base64.b64encode(await response.content.read()).decode()
201
resolved_images.append(data)
202
yield ImageDataResponse(resolved_images, image_prompt)
203
else:
204
preview = []
205
for image in images:
206
async with client.get(image, allow_redirects=False) as fetch:
207
image = fetch.headers["location"]
208
async with client.get(image, allow_redirects=False) as fetch:
209
image = fetch.headers["location"]
210
resolved_images.append(image)
211
preview.append(image.replace('=s512', '=s200'))
212
yield ImageResponse(resolved_images, image_prompt, {"orginal_links": images, "preview": preview})
211
213
212
214
def build_request(
213
215
prompt: str,
@@ -61,7 +61,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
61
61
supports_system_message = True
62
62
default_model = None
63
63
default_vision_model = "gpt-4o"
64
models = ["gpt-3.5-turbo", "gpt-4", "gpt-4-gizmo", "gpt-4o"]
64
models = ["gpt-3.5-turbo", "gpt-4", "gpt-4-gizmo", "gpt-4o", "auto"]
65
65
model_aliases = {
66
66
"text-davinci-002-render-sha": "gpt-3.5-turbo",
67
67
"": "gpt-3.5-turbo",
@@ -394,10 +394,11 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
394
394
print(f"{e.__class__.__name__}: {e}")
395
395
396
396
arkose_token = None
397
proofTokens = None
397
398
if cls.default_model is None:
398
399
error = None
399
400
try:
400
arkose_token, api_key, cookies, headers = await getArkoseAndAccessToken(proxy)
401
arkose_token, api_key, cookies, headers, proofTokens = await getArkoseAndAccessToken(proxy)
401
402
cls._create_request_args(cookies, headers)
402
403
cls._set_api_key(api_key)
403
404
except NoValidHarFileError as e:
@@ -413,17 +414,17 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
413
414
if cls._api_key is None else
414
415
f"{cls.url}/backend-api/sentinel/chat-requirements",
415
416
json={"conversation_mode_kind": "primary_assistant"},
417
#json={"p": generate_proof_token(True, user_agent=cls._headers["user-agent"], proofTokens=proofTokens)},
416
418
headers=cls._headers
417
419
) as response:
418
420
cls._update_request_args(session)
419
421
await raise_for_status(response)
420
422
data = await response.json()
421
blob = data["arkose"]["dx"]
422
need_arkose = data["arkose"]["required"]
423
need_arkose = data.get("arkose", {}).get("required")
423
424
chat_token = data["token"]
424
425
proofofwork = ""
425
426
if "proofofwork" in data:
426
proofofwork = generate_proof_token(**data["proofofwork"], user_agent=cls._headers["user-agent"])
427
proofofwork = generate_proof_token(**data["proofofwork"], user_agent=cls._headers["user-agent"], proofTokens=proofTokens)
427
428
428
429
if need_arkose and arkose_token is None:
429
430
arkose_token, api_key, cookies, headers = await getArkoseAndAccessToken(proxy)
@@ -435,7 +436,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
435
436
if debug.logging:
436
437
print(
437
438
'Arkose:', False if not need_arkose else arkose_token[:12]+"...",
438
'Turnstile:', data["turnstile"]["required"],
439
439
'Proofofwork:', False if proofofwork is None else proofofwork[:12]+"...",
440
440
)
441
441
@@ -12,6 +12,7 @@ from copy import deepcopy
12
12
13
13
from .crypt import decrypt, encrypt
14
14
from ...requests import StreamSession
15
from ... import debug
15
16
16
17
class NoValidHarFileError(Exception):
17
18
...
@@ -31,6 +32,7 @@ chatArk: arkReq = None
31
32
accessToken: str = None
32
33
cookies: dict = None
33
34
headers: dict = None
35
proofTokens: list = []
34
36
35
37
def readHAR():
36
38
dirPath = "./"
@@ -54,6 +56,15 @@ def readHAR():
54
56
# Error: not a HAR file!
55
57
continue
56
58
for v in harFile['log']['entries']:
59
v_headers = get_headers(v)
60
try:
61
if "openai-sentinel-proof-token" in v_headers:
62
proofTokens.append(json.loads(base64.b64decode(
63
v_headers["openai-sentinel-proof-token"].split("gAAAAAB", 1)[-1].encode()
64
).decode()))
65
except Exception as e:
66
if debug.logging:
67
print(f"Read proof token: {e}")
57
68
if arkPreURL in v['request']['url']:
58
69
chatArks.append(parseHAREntry(v))
59
70
elif v['request']['url'] == sessionUrl:
@@ -61,13 +72,13 @@ def readHAR():
61
72
accessToken = json.loads(v["response"]["content"]["text"]).get("accessToken")
62
73
except KeyError:
63
74
continue
64
cookies = {c['name']: c['value'] for c in v['request']['cookies']}
65
headers = get_headers(v)
75
cookies = {c['name']: c['value'] for c in v['request']['cookies'] if c['name'] != "oai-did"}
76
headers = v_headers
66
77
if not accessToken:
67
78
raise NoValidHarFileError("No accessToken found in .har files")
68
79
if not chatArks:
69
return None, accessToken, cookies, headers
70
return chatArks.pop(), accessToken, cookies, headers
80
return None, accessToken, cookies, headers, proofTokens
81
return chatArks.pop(), accessToken, cookies, headers, proofTokens
71
82
72
83
def get_headers(entry) -> dict:
73
84
return {h['name'].lower(): h['value'] for h in entry['request']['headers'] if h['name'].lower() not in ['content-length', 'cookie'] and not h['name'].startswith(':')}
@@ -101,7 +112,8 @@ def genArkReq(chatArk: arkReq) -> arkReq:
101
112
async def sendRequest(tmpArk: arkReq, proxy: str = None):
102
113
async with StreamSession(headers=tmpArk.arkHeader, cookies=tmpArk.arkCookies, proxies={"https": proxy}) as session:
103
114
async with session.post(tmpArk.arkURL, data=tmpArk.arkBody) as response:
104
arkose = (await response.json()).get("token")
115
data = await response.json()
116
arkose = data.get("token")
105
117
if "sup=1|rid=" not in arkose:
106
118
return RuntimeError("No valid arkose token generated")
107
119
return arkose
@@ -131,10 +143,10 @@ def getN() -> str:
131
143
return base64.b64encode(timestamp.encode()).decode()
132
144
133
145
async def getArkoseAndAccessToken(proxy: str) -> tuple[str, str, dict, dict]:
134
global chatArk, accessToken, cookies, headers
146
global chatArk, accessToken, cookies, headers, proofTokens
135
147
if chatArk is None or accessToken is None:
136
chatArk, accessToken, cookies, headers = readHAR()
148
chatArk, accessToken, cookies, headers, proofTokens = readHAR()
137
149
if chatArk is None:
138
return None, accessToken, cookies, headers
150
return None, accessToken, cookies, headers, proofTokens
139
151
newReq = genArkReq(chatArk)
140
return await sendRequest(newReq, proxy), accessToken, cookies, headers
152
return await sendRequest(newReq, proxy), accessToken, cookies, headers, proofTokens
@@ -2,35 +2,51 @@ import random
2
2
import hashlib
3
3
import json
4
4
import base64
5
from datetime import datetime, timedelta, timezone
5
from datetime import datetime, timezone
6
6
7
def generate_proof_token(required: bool, seed: str, difficulty: str, user_agent: str):
7
proof_token_cache: dict = {}
8
9
def generate_proof_token(required: bool, seed: str = None, difficulty: str = None, user_agent: str = None, proofTokens: list = None):
8
10
if not required:
9
11
return
10
11
cores = [8, 12, 16, 24]
12
screens = [3000, 4000, 6000]
13
14
core = random.choice(cores)
15
screen = random.choice(screens)
12
if seed is not None and seed in proof_token_cache:
13
return proof_token_cache[seed]
16
14
17
15
# Get current UTC time
18
16
now_utc = datetime.now(timezone.utc)
19
17
parse_time = now_utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
20
18
21
config = [core + screen, parse_time, None, 0, user_agent, "https://tcr9i.chat.openai.com/v2/35536E1E-65B4-4D96-9D97-6ADB7EFF8147/api.js","dpl=53d243de46ff04dadd88d293f088c2dd728f126f","en","en-US",442,"plugins−[object PluginArray]","","alert"]
22
23
diff_len = len(difficulty) // 2
24
19
if proofTokens:
20
config = random.choice(proofTokens)
21
else:
22
screen = random.choice([3008, 4010, 6000]) * random.choice([1, 2, 4])
23
config = [
24
screen, parse_time,
25
None, 0, user_agent,
26
"https://tcr9i.chat.openai.com/v2/35536E1E-65B4-4D96-9D97-6ADB7EFF8147/api.js",
27
"dpl=1440a687921de39ff5ee56b92807faaadce73f13","en","en-US",
28
None,
29
"plugins−[object PluginArray]",
30
random.choice(["_reactListeningcfilawjnerp", "_reactListening9ne2dfo1i47", "_reactListening410nzwhan2a"]),
31
random.choice(["alert", "ontransitionend", "onprogress"])
32
]
33
34
config[1] = parse_time
35
config[4] = user_agent
36
config[7] = random.randint(101, 2100)
37
38
diff_len = None if difficulty is None else len(difficulty)
25
39
for i in range(100000):
26
40
config[3] = i
27
41
json_data = json.dumps(config)
28
42
base = base64.b64encode(json_data.encode()).decode()
29
hash_value = hashlib.sha3_512((seed + base).encode()).digest()
43
hash_value = hashlib.sha3_512((seed or "" + base).encode()).digest()
30
44
31
if hash_value.hex()[:diff_len] <= difficulty:
32
result = "gAAAAAB" + base
33
return result
45
if difficulty is None or hash_value.hex()[:diff_len] <= difficulty:
46
if seed is None:
47
return "gAAAAAC" + base
48
proof_token_cache[seed] = "gAAAAAB" + base
49
return proof_token_cache[seed]
34
50
35
51
fallback_base = base64.b64encode(f'"{seed}"'.encode()).decode()
36
52
return "gAAAAABwQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D" + fallback_base
@@ -47,6 +47,14 @@ class ChatCompletionsForm(BaseModel):
47
47
web_search: Optional[bool] = None
48
48
proxy: Optional[str] = None
49
49
50
class ImagesGenerateForm(BaseModel):
51
model: Optional[str] = None
52
provider: Optional[str] = None
53
prompt: str
54
response_format: Optional[str] = None
55
api_key: Optional[str] = None
56
proxy: Optional[str] = None
57
50
58
class AppConfig():
51
59
list_ignored_providers: Optional[list[str]] = None
52
60
g4f_api_key: Optional[str] = None
@@ -149,37 +157,53 @@ class Api:
149
157
if auth_header and auth_header != "Bearer":
150
158
config.api_key = auth_header
151
159
response = self.client.chat.completions.create(
152
**{
153
**AppConfig.defaults,
154
**config.dict(exclude_none=True),
155
},
156
160
**{
161
**AppConfig.defaults,
162
**config.dict(exclude_none=True),
163
},
157
164
ignored=AppConfig.list_ignored_providers
158
165
)
166
if not config.stream:
167
return JSONResponse((await response).to_json())
168
169
async def streaming():
170
try:
171
async for chunk in response:
172
yield f"data: {json.dumps(chunk.to_json())}\n\n"
173
except GeneratorExit:
174
pass
175
except Exception as e:
176
logging.exception(e)
177
yield f'data: {format_exception(e, config)}\n\n'
178
yield "data: [DONE]\n\n"
179
return StreamingResponse(streaming(), media_type="text/event-stream")
180
159
181
except Exception as e:
160
182
logging.exception(e)
161
183
return Response(content=format_exception(e, config), status_code=500, media_type="application/json")
162
184
163
if not config.stream:
164
return JSONResponse((await response).to_json())
165
166
async def streaming():
167
try:
168
async for chunk in response:
169
yield f"data: {json.dumps(chunk.to_json())}\n\n"
170
except GeneratorExit:
171
pass
172
except Exception as e:
173
logging.exception(e)
174
yield f'data: {format_exception(e, config)}\n\n'
175
yield "data: [DONE]\n\n"
176
177
return StreamingResponse(streaming(), media_type="text/event-stream")
178
179
185
@self.app.post("/v1/completions")
180
186
async def completions():
181
187
return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
182
188
189
@self.app.post("/v1/images/generations")
190
async def images_generate(config: ImagesGenerateForm, request: Request = None, provider: str = None):
191
try:
192
config.provider = provider if config.provider is None else config.provider
193
if config.api_key is None and request is not None:
194
auth_header = request.headers.get("Authorization")
195
if auth_header is not None:
196
auth_header = auth_header.split(None, 1)[-1]
197
if auth_header and auth_header != "Bearer":
198
config.api_key = auth_header
199
response = self.client.images.generate(
200
**config.dict(exclude_none=True),
201
)
202
return JSONResponse((await response).to_json())
203
except Exception as e:
204
logging.exception(e)
205
return Response(content=format_exception(e, config), status_code=500, media_type="application/json")
206
183
207
def format_exception(e: Exception, config: ChatCompletionsForm) -> str:
184
208
last_provider = g4f.get_last_provider(True)
185
209
return json.dumps({
@@ -3,6 +3,9 @@ from __future__ import annotations
3
3
import time
4
4
import random
5
5
import string
6
import asyncio
7
import base64
8
from aiohttp import ClientSession, BaseConnector
6
9
7
10
from .types import Client as BaseClient
8
11
from .types import ProviderType, FinishReason
@@ -11,9 +14,11 @@ from .types import AsyncIterResponse, ImageProvider
11
14
from .image_models import ImageModels
12
15
from .helper import filter_json, find_stop, filter_none, cast_iter_async
13
16
from .service import get_last_provider, get_model_and_provider
17
from ..Provider import ProviderUtils
14
18
from ..typing import Union, Messages, AsyncIterator, ImageType
15
from ..errors import NoImageResponseError
16
from ..image import ImageResponse as ImageProviderResponse
19
from ..errors import NoImageResponseError, ProviderNotFoundError
20
from ..requests.aiohttp import get_connector
21
from ..image import ImageResponse as ImageProviderResponse, ImageDataResponse
17
22
18
23
try:
19
24
anext
@@ -156,12 +161,28 @@ class Chat():
156
161
def __init__(self, client: AsyncClient, provider: ProviderType = None):
157
162
self.completions = Completions(client, provider)
158
163
159
async def iter_image_response(response: AsyncIterator) -> Union[ImagesResponse, None]:
164
async def iter_image_response(
165
response: AsyncIterator,
166
response_format: str = None,
167
connector: BaseConnector = None,
168
proxy: str = None
169
) -> Union[ImagesResponse, None]:
160
170
async for chunk in response:
161
171
if isinstance(chunk, ImageProviderResponse):
162
return ImagesResponse([Image(image) for image in chunk.get_list()])
172
if response_format == "b64_json":
173
async with ClientSession(
174
connector=get_connector(connector, proxy)
175
) as session:
176
async def fetch_image(image):
177
async with session.get(image) as response:
178
return base64.b64encode(await response.content.read()).decode()
179
images = await asyncio.gather(*[fetch_image(image) for image in chunk.get_list()])
180
return ImagesResponse([Image(None, image, chunk.alt) for image in images], int(time.time()))
181
return ImagesResponse([Image(image, None, chunk.alt) for image in chunk.get_list()], int(time.time()))
182
elif isinstance(chunk, ImageDataResponse):
183
return ImagesResponse([Image(None, image, chunk.alt) for image in chunk.get_list()], int(time.time()))
163
184
164
def create_image(client: AsyncClient, provider: ProviderType, prompt: str, model: str = "", **kwargs) -> AsyncIterator:
185
def create_image(provider: ProviderType, prompt: str, model: str = "", **kwargs) -> AsyncIterator:
165
186
prompt = f"create a image with: {prompt}"
166
187
if provider.__name__ == "You":
167
188
kwargs["chat_mode"] = "create"
@@ -169,7 +190,6 @@ def create_image(client: AsyncClient, provider: ProviderType, prompt: str, model
169
190
model,
170
191
[{"role": "user", "content": prompt}],
171
192
stream=True,
172
proxy=client.get_proxy(),
173
193
**kwargs
174
194
)
175
195
@@ -179,31 +199,71 @@ class Images():
179
199
self.provider: ImageProvider = provider
180
200
self.models: ImageModels = ImageModels(client)
181
201
182
async def generate(self, prompt, model: str = "", **kwargs) -> ImagesResponse:
183
provider = self.models.get(model, self.provider)
202
def get_provider(self, model: str, provider: ProviderType = None):
203
if isinstance(provider, str):
204
if provider in ProviderUtils.convert:
205
provider = ProviderUtils.convert[provider]
206
else:
207
raise ProviderNotFoundError(f'Provider not found: {provider}')
208
else:
209
provider = self.models.get(model, self.provider)
210
return provider
211
212
async def generate(
213
self,
214
prompt,
215
model: str = "",
216
provider: ProviderType = None,
217
response_format: str = None,
218
connector: BaseConnector = None,
219
proxy: str = None,
220
**kwargs
221
) -> ImagesResponse:
222
provider = self.get_provider(model, provider)
184
223
if hasattr(provider, "create_async_generator"):
185
response = create_image(self.client, provider, prompt, **kwargs)
224
response = create_image(
225
provider,
226
prompt,
227
**filter_none(
228
response_format=response_format,
229
connector=connector,
230
proxy=self.client.get_proxy() if proxy is None else proxy,
231
),
232
**kwargs
233
)
186
234
else:
187
235
response = await provider.create_async(prompt)
188
236
return ImagesResponse([Image(image) for image in response.get_list()])
189
image = await iter_image_response(response)
237
image = await iter_image_response(response, response_format, connector, proxy)
190
238
if image is None:
191
239
raise NoImageResponseError()
192
240
return image
193
241
194
async def create_variation(self, image: ImageType, model: str = None, **kwargs):
195
provider = self.models.get(model, self.provider)
242
async def create_variation(
243
self,
244
image: ImageType,
245
model: str = None,
246
response_format: str = None,
247
connector: BaseConnector = None,
248
proxy: str = None,
249
**kwargs
250
):
251
provider = self.get_provider(model, provider)
196
252
result = None
197
253
if hasattr(provider, "create_async_generator"):
198
254
response = provider.create_async_generator(
199
255
"",
200
256
[{"role": "user", "content": "create a image like this"}],
201
True,
257
stream=True,
202
258
image=image,
203
proxy=self.client.get_proxy(),
259
**filter_none(
260
response_format=response_format,
261
connector=connector,
262
proxy=self.client.get_proxy() if proxy is None else proxy,
263
),
204
264
**kwargs
205
265
)
206
result = iter_image_response(response)
266
result = iter_image_response(response, response_format, connector, proxy)
207
267
if result is None:
208
268
raise NoImageResponseError()
209
269
return result
@@ -4,7 +4,7 @@ from typing import Union
4
4
5
5
from .. import debug, version
6
6
from ..errors import ProviderNotFoundError, ModelNotFoundError, ProviderNotWorkingError, StreamNotSupportedError
7
from ..models import Model, ModelUtils
7
from ..models import Model, ModelUtils, default
8
8
from ..Provider import ProviderUtils
9
9
from ..providers.types import BaseRetryProvider, ProviderType
10
10
from ..providers.retry_provider import IterProvider
@@ -60,7 +60,9 @@ def get_model_and_provider(model : Union[Model, str],
60
60
model = ModelUtils.convert[model]
61
61
62
62
if not provider:
63
if isinstance(model, str):
63
if not model:
64
model = default
65
elif isinstance(model, str):
64
66
raise ModelNotFoundError(f'Model not found: {model}')
65
67
provider = model.best_provider
66
68
@@ -96,13 +96,24 @@ class ChatCompletionDeltaChoice(Model):
96
96
}
97
97
98
98
class Image(Model):
99
url: str
99
def __init__(self, url: str = None, b64_json: str = None, revised_prompt: str = None) -> None:
100
if url is not None:
101
self.url = url
102
if b64_json is not None:
103
self.b64_json = b64_json
104
if revised_prompt is not None:
105
self.revised_prompt = revised_prompt
100
106
101
def __init__(self, url: str) -> None:
102
self.url = url
107
def to_json(self):
108
return self.__dict__
103
109
104
110
class ImagesResponse(Model):
105
data: list[Image]
106
107
def __init__(self, data: list) -> None:
111
def __init__(self, data: list[Image], created: int = 0) -> None:
108
112
self.data = data
113
self.created = created
114
115
def to_json(self):
116
return {
117
**self.__dict__,
118
"data": [image.to_json() for image in self.data]
119
}
@@ -275,6 +275,18 @@ class ImagePreview(ImageResponse):
275
275
def to_string(self):
276
276
return super().__str__()
277
277
278
class ImageDataResponse():
279
def __init__(
280
self,
281
images: Union[str, list],
282
alt: str,
283
):
284
self.images = images
285
self.alt = alt
286
287
def get_list(self) -> list[str]:
288
return [self.images] if isinstance(self.images, str) else self.images
289
278
290
class ImageRequest:
279
291
def __init__(
280
292
self,