返回提交历史
Added
etc/tool/improve_file.py
+44
-0
Modified
g4f/Provider/base_provider.py
+11
-9
Modified
g4f/Provider/retry_provider.py
+16
-16
Modified
g4f/__init__.py
+36
-36
Modified
g4f/requests.py
+40
-41
XFEstudio/gpt4free
Improve code by AI
f7bb3003
代码差异
5 个文件
+147
-102
@@ -0,0 +1,44 @@
1
2
import sys, re
3
from pathlib import Path
4
from os import path
5
6
sys.path.append(str(Path(__file__).parent.parent.parent))
7
8
import g4f
9
10
def read_code(text):
11
match = re.search(r"```(python|py|)\n(?P<code>[\S\s]+?)\n```", text)
12
if match:
13
return match.group("code")
14
15
path = input("Path: ")
16
17
with open(path, "r") as file:
18
code = file.read()
19
20
prompt = f"""
21
Improve the code in this file:
22
```py
23
{code}
24
```
25
Don't remove anything. Add type hints if possible.
26
"""
27
28
print("Create code...")
29
response = []
30
for chunk in g4f.ChatCompletion.create(
31
model=g4f.models.gpt_35_long,
32
messages=[{"role": "user", "content": prompt}],
33
timeout=0,
34
stream=True
35
):
36
response.append(chunk)
37
print(chunk, end="", flush=True)
38
print()
39
response = "".join(response)
40
41
code = read_code(response)
42
if code:
43
with open(path, "w") as file:
44
file.write(code)
@@ -10,11 +10,11 @@ from ..typing import AsyncGenerator, CreateResult
10
10
11
11
class BaseProvider(ABC):
12
12
url: str
13
working = False
14
needs_auth = False
15
supports_stream = False
16
supports_gpt_35_turbo = False
17
supports_gpt_4 = False
13
working: bool = False
14
needs_auth: bool = False
15
supports_stream: bool = False
16
supports_gpt_35_turbo: bool = False
17
supports_gpt_4: bool = False
18
18
19
19
@staticmethod
20
20
@abstractmethod
@@ -38,13 +38,15 @@ class BaseProvider(ABC):
38
38
) -> str:
39
39
if not loop:
40
40
loop = get_event_loop()
41
def create_func():
41
42
def create_func() -> str:
42
43
return "".join(cls.create_completion(
43
44
model,
44
45
messages,
45
46
False,
46
47
**kwargs
47
48
))
49
48
50
return await loop.run_in_executor(
49
51
executor,
50
52
create_func
@@ -52,7 +54,7 @@ class BaseProvider(ABC):
52
54
53
55
@classmethod
54
56
@property
55
def params(cls):
57
def params(cls) -> str:
56
58
params = [
57
59
("model", "str"),
58
60
("messages", "list[dict[str, str]]"),
@@ -103,7 +105,7 @@ class AsyncGeneratorProvider(AsyncProvider):
103
105
stream=stream,
104
106
**kwargs
105
107
)
106
gen = generator.__aiter__()
108
gen = generator.__aiter__()
107
109
while True:
108
110
try:
109
111
yield loop.run_until_complete(gen.__anext__())
@@ -125,7 +127,7 @@ class AsyncGeneratorProvider(AsyncProvider):
125
127
**kwargs
126
128
)
127
129
])
128
130
129
131
@staticmethod
130
132
@abstractmethod
131
133
def create_async_generator(
@@ -1,33 +1,33 @@
1
1
from __future__ import annotations
2
2
3
3
import random
4
4
from typing import List, Type, Dict
5
5
from ..typing import CreateResult
6
6
from .base_provider import BaseProvider, AsyncProvider
7
7
from ..debug import logging
8
8
9
9
10
10
class RetryProvider(AsyncProvider):
11
__name__ = "RetryProvider"
12
working = True
13
needs_auth = False
14
supports_stream = True
15
supports_gpt_35_turbo = False
16
supports_gpt_4 = False
11
__name__: str = "RetryProvider"
12
working: bool = True
13
needs_auth: bool = False
14
supports_stream: bool = True
15
supports_gpt_35_turbo: bool = False
16
supports_gpt_4: bool = False
17
17
18
18
def __init__(
19
19
self,
20
providers: list[type[BaseProvider]],
20
providers: List[Type[BaseProvider]],
21
21
shuffle: bool = True
22
22
) -> None:
23
self.providers = providers
24
self.shuffle = shuffle
23
self.providers: List[Type[BaseProvider]] = providers
24
self.shuffle: bool = shuffle
25
25
26
26
27
27
def create_completion(
28
28
self,
29
29
model: str,
30
messages: list[dict[str, str]],
30
messages: List[Dict[str, str]],
31
31
stream: bool = False,
32
32
**kwargs
33
33
) -> CreateResult:
@@ -38,8 +38,8 @@ class RetryProvider(AsyncProvider):
38
38
if self.shuffle:
39
39
random.shuffle(providers)
40
40
41
self.exceptions = {}
42
started = False
41
self.exceptions: Dict[str, Exception] = {}
42
started: bool = False
43
43
for provider in providers:
44
44
try:
45
45
if logging:
@@ -61,14 +61,14 @@ class RetryProvider(AsyncProvider):
61
61
async def create_async(
62
62
self,
63
63
model: str,
64
messages: list[dict[str, str]],
64
messages: List[Dict[str, str]],
65
65
**kwargs
66
66
) -> str:
67
67
providers = [provider for provider in self.providers]
68
68
if self.shuffle:
69
69
random.shuffle(providers)
70
70
71
self.exceptions = {}
71
self.exceptions: Dict[str, Exception] = {}
72
72
for provider in providers:
73
73
try:
74
74
return await provider.create_async(model, messages, **kwargs)
@@ -79,7 +79,7 @@ class RetryProvider(AsyncProvider):
79
79
80
80
self.raise_exceptions()
81
81
82
def raise_exceptions(self):
82
def raise_exceptions(self) -> None:
83
83
if self.exceptions:
84
84
raise RuntimeError("\n".join(["All providers failed:"] + [
85
85
f"{p}: {self.exceptions[p].__class__.__name__}: {self.exceptions[p]}" for p in self.exceptions
@@ -1,30 +1,30 @@
1
1
from __future__ import annotations
2
2
3
from g4f import models
4
from .Provider import BaseProvider
5
from .typing import CreateResult, Union
6
from .debug import logging
7
from requests import get
3
from requests import get
4
from g4f.models import Model, ModelUtils
5
from .Provider import BaseProvider
6
from .typing import CreateResult, Union
7
from .debug import logging
8
8
9
9
version = '0.1.5.4'
10
10
11
def check_pypi_version():
11
def check_pypi_version() -> None:
12
12
try:
13
response = get(f"https://pypi.org/pypi/g4f/json").json()
13
response = get("https://pypi.org/pypi/g4f/json").json()
14
14
latest_version = response["info"]["version"]
15
15
16
16
if version != latest_version:
17
17
print(f'New pypi version: {latest_version} (current: {version}) | pip install -U g4f')
18
18
19
19
except Exception as e:
20
20
print(f'Failed to check g4f pypi version: {e}')
21
21
22
22
check_pypi_version()
23
23
24
def get_model_and_provider(model: Union[models.Model, str], provider: type[BaseProvider], stream: bool):
24
def get_model_and_provider(model: Union[Model, str], provider: Union[type[BaseProvider], None], stream: bool) -> tuple[Model, type[BaseProvider]]:
25
25
if isinstance(model, str):
26
if model in models.ModelUtils.convert:
27
model = models.ModelUtils.convert[model]
26
if model in ModelUtils.convert:
27
model = ModelUtils.convert[model]
28
28
else:
29
29
raise Exception(f'The model: {model} does not exist')
30
30
@@ -33,14 +33,13 @@ def get_model_and_provider(model: Union[models.Model, str], provider: type[BaseP
33
33
34
34
if not provider:
35
35
raise Exception(f'No provider found for model: {model}')
36
36
37
37
if not provider.working:
38
38
raise Exception(f'{provider.__name__} is not working')
39
39
40
40
if not provider.supports_stream and stream:
41
raise Exception(
42
f'ValueError: {provider.__name__} does not support "stream" argument')
43
41
raise Exception(f'ValueError: {provider.__name__} does not support "stream" argument')
42
44
43
if logging:
45
44
print(f'Using {provider.__name__} provider')
46
45
@@ -49,11 +48,11 @@ def get_model_and_provider(model: Union[models.Model, str], provider: type[BaseP
49
48
class ChatCompletion:
50
49
@staticmethod
51
50
def create(
52
model : Union[models.Model, str],
53
messages : list[dict[str, str]],
54
provider : Union[type[BaseProvider], None] = None,
55
stream : bool = False,
56
auth : Union[str, None] = None,
51
model: Union[Model, str],
52
messages: list[dict[str, str]],
53
provider: Union[type[BaseProvider], None] = None,
54
stream: bool = False,
55
auth: Union[str, None] = None,
57
56
**kwargs
58
57
) -> Union[CreateResult, str]:
59
58
@@ -62,7 +61,7 @@ class ChatCompletion:
62
61
if provider.needs_auth and not auth:
63
62
raise Exception(
64
63
f'ValueError: {provider.__name__} requires authentication (use auth=\'cookie or token or jwt ...\' param)')
65
64
66
65
if provider.needs_auth:
67
66
kwargs['auth'] = auth
68
67
@@ -71,9 +70,9 @@ class ChatCompletion:
71
70
72
71
@staticmethod
73
72
async def create_async(
74
model : Union[models.Model, str],
75
messages : list[dict[str, str]],
76
provider : Union[type[BaseProvider], None] = None,
73
model: Union[Model, str],
74
messages: list[dict[str, str]],
75
provider: Union[type[BaseProvider], None] = None,
77
76
**kwargs
78
77
) -> str:
79
78
model, provider = get_model_and_provider(model, provider, False)
@@ -83,11 +82,13 @@ class ChatCompletion:
83
82
class Completion:
84
83
@staticmethod
85
84
def create(
86
model : Union[models.Model, str],
87
prompt : str,
88
provider : Union[type[BaseProvider], None] = None,
89
stream : bool = False, **kwargs) -> Union[CreateResult, str]:
90
85
model: str,
86
prompt: str,
87
provider: Union[type[BaseProvider], None] = None,
88
stream: bool = False,
89
**kwargs
90
) -> Union[CreateResult, str]:
91
91
92
allowed_models = [
92
93
'code-davinci-002',
93
94
'text-ada-001',
@@ -96,13 +97,12 @@ class Completion:
96
97
'text-davinci-002',
97
98
'text-davinci-003'
98
99
]
99
100
100
101
if model not in allowed_models:
101
102
raise Exception(f'ValueError: Can\'t use {model} with Completion.create()')
102
103
103
104
model, provider = get_model_and_provider(model, provider, stream)
104
105
105
result = provider.create_completion(model.name,
106
[{"role": "user", "content": prompt}], stream, **kwargs)
106
result = provider.create_completion(model.name, [{"role": "user", "content": prompt}], stream, **kwargs)
107
107
108
return result if stream else ''.join(result)
108
return result if stream else ''.join(result)
@@ -1,47 +1,44 @@
1
1
from __future__ import annotations
2
2
3
import warnings, json, asyncio
4
3
import warnings
4
import json
5
import asyncio
5
6
from functools import partialmethod
6
7
from asyncio import Future, Queue
7
8
from typing import AsyncGenerator
8
9
9
10
from curl_cffi.requests import AsyncSession, Response
10
11
11
import curl_cffi
12
12
13
is_newer_0_5_8 = hasattr(AsyncSession, "_set_cookies") or hasattr(curl_cffi.requests.Cookies, "get_cookies_for_curl")
14
is_newer_0_5_9 = hasattr(curl_cffi.AsyncCurl, "remove_handle")
15
is_newer_0_5_10 = hasattr(AsyncSession, "release_curl")
13
is_newer_0_5_8: bool = hasattr(AsyncSession, "_set_cookies") or hasattr(curl_cffi.requests.Cookies, "get_cookies_for_curl")
14
is_newer_0_5_9: bool = hasattr(curl_cffi.AsyncCurl, "remove_handle")
15
is_newer_0_5_10: bool = hasattr(AsyncSession, "release_curl")
16
16
17
17
18
class StreamResponse:
18
def __init__(self, inner: Response, queue: Queue):
19
self.inner = inner
20
self.queue = queue
19
def __init__(self, inner: Response, queue: Queue[bytes]) -> None:
20
self.inner: Response = inner
21
self.queue: Queue[bytes] = queue
21
22
self.request = inner.request
22
self.status_code = inner.status_code
23
self.reason = inner.reason
24
self.ok = inner.ok
23
self.status_code: int = inner.status_code
24
self.reason: str = inner.reason
25
self.ok: bool = inner.ok
25
26
self.headers = inner.headers
26
27
self.cookies = inner.cookies
27
28
28
29
async def text(self) -> str:
29
content = await self.read()
30
content: bytes = await self.read()
30
31
return content.decode()
31
32
32
def raise_for_status(self):
33
def raise_for_status(self) -> None:
33
34
if not self.ok:
34
35
raise RuntimeError(f"HTTP Error {self.status_code}: {self.reason}")
35
36
36
async def json(self, **kwargs):
37
async def json(self, **kwargs) -> dict:
37
38
return json.loads(await self.read(), **kwargs)
38
39
async def iter_lines(self, chunk_size=None, decode_unicode=False, delimiter=None) -> AsyncGenerator[bytes]:
40
"""
41
Copied from: https://requests.readthedocs.io/en/latest/_modules/requests/models/
42
which is under the License: Apache 2.0
43
"""
44
pending = None
39
40
async def iter_lines(self, chunk_size=None, decode_unicode=False, delimiter=None) -> AsyncGenerator[bytes, None]:
41
pending: bytes = None
45
42
46
43
async for chunk in self.iter_content(
47
44
chunk_size=chunk_size, decode_unicode=decode_unicode
@@ -63,7 +60,7 @@ class StreamResponse:
63
60
if pending is not None:
64
61
yield pending
65
62
66
async def iter_content(self, chunk_size=None, decode_unicode=False) -> As:
63
async def iter_content(self, chunk_size=None, decode_unicode=False) -> AsyncGenerator[bytes, None]:
67
64
if chunk_size:
68
65
warnings.warn("chunk_size is ignored, there is no way to tell curl that.")
69
66
if decode_unicode:
@@ -77,22 +74,23 @@ class StreamResponse:
77
74
async def read(self) -> bytes:
78
75
return b"".join([chunk async for chunk in self.iter_content()])
79
76
77
80
78
class StreamRequest:
81
def __init__(self, session: AsyncSession, method: str, url: str, **kwargs):
82
self.session = session
83
self.loop = session.loop if session.loop else asyncio.get_running_loop()
84
self.queue = Queue()
85
self.method = method
86
self.url = url
87
self.options = kwargs
88
self.handle = None
89
90
def _on_content(self, data):
79
def __init__(self, session: AsyncSession, method: str, url: str, **kwargs) -> None:
80
self.session: AsyncSession = session
81
self.loop: asyncio.AbstractEventLoop = session.loop if session.loop else asyncio.get_running_loop()
82
self.queue: Queue[bytes] = Queue()
83
self.method: str = method
84
self.url: str = url
85
self.options: dict = kwargs
86
self.handle: curl_cffi.AsyncCurl = None
87
88
def _on_content(self, data: bytes) -> None:
91
89
if not self.enter.done():
92
90
self.enter.set_result(None)
93
91
self.queue.put_nowait(data)
94
92
95
def _on_done(self, task: Future):
93
def _on_done(self, task: Future) -> None:
96
94
if not self.enter.done():
97
95
self.enter.set_result(None)
98
96
self.queue.put_nowait(None)
@@ -102,8 +100,8 @@ class StreamRequest:
102
100
async def fetch(self) -> StreamResponse:
103
101
if self.handle:
104
102
raise RuntimeError("Request already started")
105
self.curl = await self.session.pop_curl()
106
self.enter = self.loop.create_future()
103
self.curl: curl_cffi.AsyncCurl = await self.session.pop_curl()
104
self.enter: asyncio.Future = self.loop.create_future()
107
105
if is_newer_0_5_10:
108
106
request, _, header_buffer, _, _ = self.session._set_curl_options(
109
107
self.curl,
@@ -121,7 +119,7 @@ class StreamRequest:
121
119
**self.options
122
120
)
123
121
if is_newer_0_5_9:
124
self.handle = self.session.acurl.add_handle(self.curl)
122
self.handle = self.session.acurl.add_handle(self.curl)
125
123
else:
126
124
await self.session.acurl.add_handle(self.curl, False)
127
125
self.handle = self.session.acurl._curl2future[self.curl]
@@ -140,14 +138,14 @@ class StreamRequest:
140
138
response,
141
139
self.queue
142
140
)
143
141
144
142
async def __aenter__(self) -> StreamResponse:
145
143
return await self.fetch()
146
144
147
async def __aexit__(self, *args):
145
async def __aexit__(self, *args) -> None:
148
146
self.release_curl()
149
147
150
def release_curl(self):
148
def release_curl(self) -> None:
151
149
if is_newer_0_5_10:
152
150
self.session.release_curl(self.curl)
153
151
return
@@ -162,6 +160,7 @@ class StreamRequest:
162
160
self.session.push_curl(self.curl)
163
161
self.curl = None
164
162
163
165
164
class StreamSession(AsyncSession):
166
165
def request(
167
166
self,
@@ -170,7 +169,7 @@ class StreamSession(AsyncSession):
170
169
**kwargs
171
170
) -> StreamRequest:
172
171
return StreamRequest(self, method, url, **kwargs)
173
172
174
173
head = partialmethod(request, "HEAD")
175
174
get = partialmethod(request, "GET")
176
175
post = partialmethod(request, "POST")