返回提交历史
Modified
etc/unittest/backend.py
+1
-1
Modified
g4f/client/__init__.py
+10
-10
Modified
g4f/client/stubs.py
+28
-21
XFEstudio/gpt4free
Fix deprecated construct method, fix unittests
20ad0802
代码差异
3 个文件
+39
-32
@@ -35,7 +35,7 @@ class TestBackendApi(unittest.TestCase):
35
35
36
36
def test_get_providers(self):
37
37
response = self.api.get_providers()
38
self.assertIsInstance(response, dict)
38
self.assertIsInstance(response, list)
39
39
self.assertTrue(len(response) > 0)
40
40
41
41
def test_search(self):
@@ -74,7 +74,7 @@ def iter_response(
74
74
finish_reason = "stop"
75
75
76
76
if stream:
77
yield ChatCompletionChunk.construct(chunk, None, completion_id, int(time.time()))
77
yield ChatCompletionChunk.model_construct(chunk, None, completion_id, int(time.time()))
78
78
79
79
if finish_reason is not None:
80
80
break
@@ -84,12 +84,12 @@ def iter_response(
84
84
finish_reason = "stop" if finish_reason is None else finish_reason
85
85
86
86
if stream:
87
yield ChatCompletionChunk.construct(None, finish_reason, completion_id, int(time.time()))
87
yield ChatCompletionChunk.model_construct(None, finish_reason, completion_id, int(time.time()))
88
88
else:
89
89
if response_format is not None and "type" in response_format:
90
90
if response_format["type"] == "json_object":
91
91
content = filter_json(content)
92
yield ChatCompletion.construct(content, finish_reason, completion_id, int(time.time()))
92
yield ChatCompletion.model_construct(content, finish_reason, completion_id, int(time.time()))
93
93
94
94
# Synchronous iter_append_model_and_provider function
95
95
def iter_append_model_and_provider(response: ChatCompletionResponseType) -> ChatCompletionResponseType:
@@ -138,7 +138,7 @@ async def async_iter_response(
138
138
finish_reason = "stop"
139
139
140
140
if stream:
141
yield ChatCompletionChunk.construct(chunk, None, completion_id, int(time.time()))
141
yield ChatCompletionChunk.model_construct(chunk, None, completion_id, int(time.time()))
142
142
143
143
if finish_reason is not None:
144
144
break
@@ -146,12 +146,12 @@ async def async_iter_response(
146
146
finish_reason = "stop" if finish_reason is None else finish_reason
147
147
148
148
if stream:
149
yield ChatCompletionChunk.construct(None, finish_reason, completion_id, int(time.time()))
149
yield ChatCompletionChunk.model_construct(None, finish_reason, completion_id, int(time.time()))
150
150
else:
151
151
if response_format is not None and "type" in response_format:
152
152
if response_format["type"] == "json_object":
153
153
content = filter_json(content)
154
yield ChatCompletion.construct(content, finish_reason, completion_id, int(time.time()))
154
yield ChatCompletion.model_construct(content, finish_reason, completion_id, int(time.time()))
155
155
finally:
156
156
await safe_aclose(response)
157
157
@@ -422,7 +422,7 @@ class Images:
422
422
last_provider = get_last_provider(True)
423
423
if response_format == "url":
424
424
# Return original URLs without saving locally
425
images = [Image.construct(url=image, revised_prompt=response.alt) for image in response.get_list()]
425
images = [Image.model_construct(url=image, revised_prompt=response.alt) for image in response.get_list()]
426
426
else:
427
427
# Save locally for None (default) case
428
428
images = await copy_images(response.get_list(), response.get("cookies"), proxy)
@@ -430,11 +430,11 @@ class Images:
430
430
async def process_image_item(image_file: str) -> Image:
431
431
with open(os.path.join(images_dir, os.path.basename(image_file)), "rb") as file:
432
432
image_data = base64.b64encode(file.read()).decode()
433
return Image.construct(b64_json=image_data, revised_prompt=response.alt)
433
return Image.model_construct(b64_json=image_data, revised_prompt=response.alt)
434
434
images = await asyncio.gather(*[process_image_item(image) for image in images])
435
435
else:
436
images = [Image.construct(url=f"/images/{os.path.basename(image)}", revised_prompt=response.alt) for image in images]
437
return ImagesResponse.construct(
436
images = [Image.model_construct(url=f"/images/{os.path.basename(image)}", revised_prompt=response.alt) for image in images]
437
return ImagesResponse.model_construct(
438
438
created=int(time.time()),
439
439
data=images,
440
440
model=last_provider.get("model") if model is None else model,
@@ -10,7 +10,7 @@ try:
10
10
except ImportError:
11
11
class BaseModel():
12
12
@classmethod
13
def construct(cls, **data):
13
def model_construct(cls, **data):
14
14
new = cls()
15
15
for key, value in data.items():
16
16
setattr(new, key, value)
@@ -19,6 +19,13 @@ except ImportError:
19
19
def __init__(self, **config):
20
20
pass
21
21
22
class BaseModel(BaseModel):
23
@classmethod
24
def model_construct(cls, **data):
25
if hasattr(super(), "model_construct"):
26
return super().model_construct(**data)
27
return cls.construct(**data)
28
22
29
class ChatCompletionChunk(BaseModel):
23
30
id: str
24
31
object: str
@@ -28,21 +35,21 @@ class ChatCompletionChunk(BaseModel):
28
35
choices: List[ChatCompletionDeltaChoice]
29
36
30
37
@classmethod
31
def construct(
38
def model_construct(
32
39
cls,
33
40
content: str,
34
41
finish_reason: str,
35
42
completion_id: str = None,
36
43
created: int = None
37
44
):
38
return super().construct(
45
return super().model_construct(
39
46
id=f"chatcmpl-{completion_id}" if completion_id else None,
40
47
object="chat.completion.cunk",
41
48
created=created,
42
49
model=None,
43
50
provider=None,
44
choices=[ChatCompletionDeltaChoice.construct(
45
ChatCompletionDelta.construct(content),
51
choices=[ChatCompletionDeltaChoice.model_construct(
52
ChatCompletionDelta.model_construct(content),
46
53
finish_reason
47
54
)]
48
55
)
@@ -52,8 +59,8 @@ class ChatCompletionMessage(BaseModel):
52
59
content: str
53
60
54
61
@classmethod
55
def construct(cls, content: str):
56
return super().construct(role="assistant", content=content)
62
def model_construct(cls, content: str):
63
return super().model_construct(role="assistant", content=content)
57
64
58
65
class ChatCompletionChoice(BaseModel):
59
66
index: int
@@ -61,8 +68,8 @@ class ChatCompletionChoice(BaseModel):
61
68
finish_reason: str
62
69
63
70
@classmethod
64
def construct(cls, message: ChatCompletionMessage, finish_reason: str):
65
return super().construct(index=0, message=message, finish_reason=finish_reason)
71
def model_construct(cls, message: ChatCompletionMessage, finish_reason: str):
72
return super().model_construct(index=0, message=message, finish_reason=finish_reason)
66
73
67
74
class ChatCompletion(BaseModel):
68
75
id: str
@@ -78,21 +85,21 @@ class ChatCompletion(BaseModel):
78
85
}])
79
86
80
87
@classmethod
81
def construct(
88
def model_construct(
82
89
cls,
83
90
content: str,
84
91
finish_reason: str,
85
92
completion_id: str = None,
86
93
created: int = None
87
94
):
88
return super().construct(
95
return super().model_construct(
89
96
id=f"chatcmpl-{completion_id}" if completion_id else None,
90
97
object="chat.completion",
91
98
created=created,
92
99
model=None,
93
100
provider=None,
94
choices=[ChatCompletionChoice.construct(
95
ChatCompletionMessage.construct(content),
101
choices=[ChatCompletionChoice.model_construct(
102
ChatCompletionMessage.model_construct(content),
96
103
finish_reason
97
104
)],
98
105
usage={
@@ -107,8 +114,8 @@ class ChatCompletionDelta(BaseModel):
107
114
content: str
108
115
109
116
@classmethod
110
def construct(cls, content: Optional[str]):
111
return super().construct(role="assistant", content=content)
117
def model_construct(cls, content: Optional[str]):
118
return super().model_construct(role="assistant", content=content)
112
119
113
120
class ChatCompletionDeltaChoice(BaseModel):
114
121
index: int
@@ -116,8 +123,8 @@ class ChatCompletionDeltaChoice(BaseModel):
116
123
finish_reason: Optional[str]
117
124
118
125
@classmethod
119
def construct(cls, delta: ChatCompletionDelta, finish_reason: Optional[str]):
120
return super().construct(index=0, delta=delta, finish_reason=finish_reason)
126
def model_construct(cls, delta: ChatCompletionDelta, finish_reason: Optional[str]):
127
return super().model_construct(index=0, delta=delta, finish_reason=finish_reason)
121
128
122
129
class Image(BaseModel):
123
130
url: Optional[str]
@@ -125,8 +132,8 @@ class Image(BaseModel):
125
132
revised_prompt: Optional[str]
126
133
127
134
@classmethod
128
def construct(cls, url: str = None, b64_json: str = None, revised_prompt: str = None):
129
return super().construct(**filter_none(
135
def model_construct(cls, url: str = None, b64_json: str = None, revised_prompt: str = None):
136
return super().model_construct(**filter_none(
130
137
url=url,
131
138
b64_json=b64_json,
132
139
revised_prompt=revised_prompt
@@ -139,10 +146,10 @@ class ImagesResponse(BaseModel):
139
146
created: int
140
147
141
148
@classmethod
142
def construct(cls, data: List[Image], created: int = None, model: str = None, provider: str = None):
149
def model_construct(cls, data: List[Image], created: int = None, model: str = None, provider: str = None):
143
150
if created is None:
144
151
created = int(time())
145
return super().construct(
152
return super().model_construct(
146
153
data=data,
147
154
model=model,
148
155
provider=provider,