返回提交历史
Modified
.github/workflows/publish-workflow.yaml
+14
-3
Modified
README.md
+4
-4
Modified
docker-compose.yml
+3
-3
Modified
docker/Dockerfile
+3
-1
Renamed
docker/background.png
+0
-0
Modified
docker/supervisor.conf
+1
-1
Modified
g4f/Provider/MyShell.py
+5
-13
Added
g4f/Provider/unfinished/AiChatting.py
+66
-0
Modified
g4f/Provider/unfinished/__init__.py
+2
-1
Modified
g4f/__init__.py
+38
-19
Modified
g4f/debug.py
+2
-1
Modified
g4f/gui/client/css/style.css
+3
-0
Modified
g4f/gui/client/html/index.html
+4
-0
Modified
g4f/gui/client/js/chat.v1.js
+15
-0
Modified
g4f/gui/server/backend.py
+17
-7
Modified
g4f/gui/server/internet.py
+139
-48
Modified
g4f/requests.py
+2
-26
Modified
g4f/webdriver.py
+40
-8
Modified
requirements.txt
+2
-1
XFEstudio/gpt4free
Add websearch to gui (#1314)
* Add websearch to gui * Fix version_check config * Add version badge in README.md * Show version in gui * Add docker hub build * Fix gui backend, improve style
484b96d8
代码差异
19 个文件
+360
-136
@@ -9,21 +9,30 @@ jobs:
9
9
publish:
10
10
runs-on: ubuntu-latest
11
11
steps:
12
- name: Setup Buildx
13
uses: docker/setup-buildx-action@v3
14
12
- name: Checkout repository
15
13
uses: actions/checkout@v4
14
16
15
- name: Get metadata for Docker
17
16
id: metadata
18
17
uses: docker/metadata-action@v5
19
18
with:
20
images: ghcr.io/${{ github.repository }}
19
images: |
20
hlohaus789/g4f
21
ghcr.io/${{ github.repository }}
22
23
- name: Log in to Docker Hub
24
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
25
with:
26
username: ${{ secrets.DOCKER_USERNAME }}
27
password: ${{ secrets.DOCKER_PASSWORD }}
28
21
29
- name: Login to GitHub Container Registry
22
30
uses: docker/login-action@v3
23
31
with:
24
32
registry: ghcr.io
25
33
username: ${{ github.repository_owner }}
26
34
password: ${{ secrets.GHCR_PAT }}
35
27
36
- name: Build and push image
28
37
uses: docker/build-push-action@v5
29
38
with:
@@ -32,3 +41,5 @@ jobs:
32
41
push: true
33
42
tags: ${{ steps.metadata.outputs.tags }}
34
43
labels: ${{ steps.metadata.outputs.labels }}
44
build-args: |
45
G4F_VERSION=${{ github.ref_name }}
@@ -1,4 +1,4 @@
1

1

2
2
3
3
<a href='https://ko-fi.com/xtekky' target='_blank'><img height='35' style='border:0px;height:46px;' src='https://az743702.vo.msecnd.net/cdn/kofi3.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
4
4
<div id="top"></div>
@@ -6,7 +6,8 @@
6
6
> By using this repository or any code related to it, you agree to the [legal notice](LEGAL_NOTICE.md). The author is not responsible for any copies, forks, re-uploads made by other users, or anything else related to GPT4Free. This is the author's only account and repository. To prevent impersonation or irresponsible actions, please comply with the GNU GPL license this Repository uses.
7
7
8
8
> [!Note]
9
> Latest pypi version: [`0.1.9.2`](https://pypi.org/project/g4f/0.1.9.2)
9
Lastet version:
10
>> [](https://pypi.org/project/g4f)
10
11
```sh
11
12
pip install -U g4f
12
13
```
@@ -165,8 +166,7 @@ docker-compose down
165
166
import g4f
166
167
167
168
g4f.debug.logging = True # Enable logging
168
g4f.check_version = False # Disable automatic version checking
169
print(g4f.version) # Check version
169
g4f.debug.check_version = False # Disable automatic version checking
170
170
print(g4f.Provider.Ails.params) # Supported args
171
171
172
172
# Automatic selection of provider
@@ -2,13 +2,13 @@ version: '3'
2
2
3
3
services:
4
4
gpt4free:
5
image: ghcr.io/xtekky/gpt4free:latest
5
image: hlohaus789/g4f:latest
6
6
shm_size: 2gb
7
7
build:
8
8
context: .
9
9
dockerfile: docker/Dockerfile
10
volumes:
11
- .:/app
10
# volumes:
11
# - .:/app
12
12
ports:
13
13
- '8080:80'
14
14
- '1337:1337'
@@ -3,6 +3,8 @@ FROM selenium/node-chrome
3
3
ENV SE_SCREEN_WIDTH 1850
4
4
ENV G4F_LOGIN_URL http://localhost:7900/?autoconnect=1&resize=scale&password=secret
5
5
ENV PYTHONUNBUFFERED 1
6
ARG G4F_VERSION
7
ENV G4F_VERSION ${G4F_VERSION}
6
8
7
9
USER root
8
10
@@ -22,7 +24,7 @@ RUN rm -rf /var/lib/apt/lists/* /var/cache/apt/* \
22
24
COPY docker/supervisor.conf /etc/supervisor/conf.d/selenium.conf
23
25
24
26
# Change background image
25
COPY g4f.png /usr/share/images/fluxbox/ubuntu-light.png
27
COPY docker/background.png /usr/share/images/fluxbox/ubuntu-light.png
26
28
27
29
# Switch user
28
30
USER 1200
二进制文件已变更,无法进行逐行预览。
@@ -49,7 +49,7 @@ stderr_logfile_backups=5
49
49
stdout_capture_maxbytes=50MB
50
50
stderr_capture_maxbytes=50MB
51
51
52
[program:g4f-cli]
52
[program:g4f-api]
53
53
priority=15
54
54
command=python -m g4f.cli api
55
55
directory=/app
@@ -5,7 +5,7 @@ import time, json
5
5
from ..typing import CreateResult, Messages
6
6
from .base_provider import BaseProvider
7
7
from .helper import format_prompt
8
from ..webdriver import WebDriver, WebDriverSession
8
from ..webdriver import WebDriver, WebDriverSession, bypass_cloudflare
9
9
10
10
class MyShell(BaseProvider):
11
11
url = "https://app.myshell.ai/chat"
@@ -25,16 +25,8 @@ class MyShell(BaseProvider):
25
25
**kwargs
26
26
) -> CreateResult:
27
27
with WebDriverSession(webdriver, "", proxy=proxy) as driver:
28
from selenium.webdriver.common.by import By
29
from selenium.webdriver.support.ui import WebDriverWait
30
from selenium.webdriver.support import expected_conditions as EC
31
32
driver.get(cls.url)
33
34
# Wait for page load and cloudflare validation
35
WebDriverWait(driver, timeout).until(
36
EC.presence_of_element_located((By.CSS_SELECTOR, "body:not(.no-js)"))
37
)
28
bypass_cloudflare(driver, cls.url, timeout)
29
38
30
# Send request with message
39
31
data = {
40
32
"botId": "4738",
@@ -58,11 +50,11 @@ window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
58
50
driver.execute_script(script.replace("{body}", json.dumps(data)))
59
51
script = """
60
52
chunk = await window._reader.read();
61
if (chunk['done']) {
53
if (chunk.done) {
62
54
return null;
63
55
}
64
56
content = '';
65
chunk['value'].split('\\n').forEach((line, index) => {
57
chunk.value.split('\\n').forEach((line, index) => {
66
58
if (line.startsWith('data: ')) {
67
59
try {
68
60
const data = JSON.parse(line.substring('data: '.length));
@@ -0,0 +1,66 @@
1
from __future__ import annotations
2
3
from urllib.parse import unquote
4
5
from ...typing import AsyncResult, Messages
6
from ..base_provider import BaseProvider
7
from ...webdriver import WebDriver
8
from ...requests import Session, get_session_from_browser
9
10
class AiChatting(BaseProvider):
11
url = "https://www.aichatting.net"
12
supports_gpt_35_turbo = True
13
_session: Session = None
14
15
@classmethod
16
def create_completion(
17
cls,
18
model: str,
19
messages: Messages,
20
stream: bool,
21
proxy: str = None,
22
timeout: int = 120,
23
webdriver: WebDriver = None,
24
**kwargs
25
) -> AsyncResult:
26
if not cls._session:
27
cls._session = get_session_from_browser(cls.url, webdriver, proxy, timeout)
28
visitorId = unquote(cls._session.cookies.get("aichatting.website.visitorId"))
29
30
headers = {
31
"accept": "application/json, text/plain, */*",
32
"lang": "en",
33
"source": "web"
34
}
35
data = {
36
"roleId": 0,
37
}
38
try:
39
response = cls._session.post("https://aga-api.aichatting.net/aigc/chat/record/conversation/create", json=data, headers=headers)
40
response.raise_for_status()
41
conversation_id = response.json()["data"]["conversationId"]
42
except Exception as e:
43
cls.reset()
44
raise e
45
headers = {
46
"authority": "aga-api.aichatting.net",
47
"accept": "text/event-stream,application/json, text/event-stream",
48
"lang": "en",
49
"source": "web",
50
"vtoken": visitorId,
51
}
52
data = {
53
"spaceHandle": True,
54
"roleId": 0,
55
"messages": messages,
56
"conversationId": conversation_id,
57
}
58
response = cls._session.post("https://aga-api.aichatting.net/aigc/chat/v2/stream", json=data, headers=headers, stream=True)
59
response.raise_for_status()
60
for chunk in response.iter_lines():
61
if chunk.startswith(b"data:"):
62
yield chunk[5:].decode().replace("-=- --", " ").replace("-=-n--", "\n").replace("--@DONE@--", "")
63
64
@classmethod
65
def reset(cls):
66
cls._session = None
@@ -1,3 +1,4 @@
1
1
from .MikuChat import MikuChat
2
2
from .Komo import Komo
3
from .ChatAiGpt import ChatAiGpt
3
from .ChatAiGpt import ChatAiGpt
4
from .AiChatting import AiChatting
@@ -1,25 +1,44 @@
1
1
from __future__ import annotations
2
from requests import get
3
from .models import Model, ModelUtils, _all_models
4
from .Provider import BaseProvider, AsyncGeneratorProvider, RetryProvider
5
from .typing import Messages, CreateResult, AsyncResult, Union, List
6
from . import debug
7
2
8
version = '0.1.9.2'
9
version_check = True
3
import os
4
from requests import get
5
from importlib.metadata import version as get_package_version, PackageNotFoundError
6
from subprocess import check_output, CalledProcessError, PIPE
10
7
11
def check_pypi_version() -> None:
12
try:
13
response = get("https://pypi.org/pypi/g4f/json").json()
14
latest_version = response["info"]["version"]
8
from .models import Model, ModelUtils, _all_models
9
from .Provider import BaseProvider, AsyncGeneratorProvider, RetryProvider
10
from .typing import Messages, CreateResult, AsyncResult, Union, List
11
from . import debug
15
12
16
if version != latest_version:
17
print(f'New pypi version: {latest_version} (current: {version}) | pip install -U g4f')
18
return False
19
return True
13
def get_version() -> str:
14
# Read from package manager
15
try:
16
return get_package_version("g4f")
17
except PackageNotFoundError:
18
pass
19
# Read from docker environment
20
current_version = os.environ.get("G4F_VERSION")
21
if current_version:
22
return current_version
23
# Read from git repository
24
try:
25
command = ["git", "describe", "--tags", "--abbrev=0"]
26
return check_output(command, text=True, stderr=PIPE).strip()
27
except CalledProcessError:
28
pass
29
30
def get_lastet_version() -> str:
31
response = get("https://pypi.org/pypi/g4f/json").json()
32
return response["info"]["version"]
20
33
34
def check_pypi_version() -> None:
35
try:
36
version = get_version()
37
latest_version = get_lastet_version()
21
38
except Exception as e:
22
39
print(f'Failed to check g4f pypi version: {e}')
40
if version != latest_version:
41
print(f'New pypi version: {latest_version} (current: {version}) | pip install -U g4f')
23
42
24
43
def get_model_and_provider(model : Union[Model, str],
25
44
provider : Union[type[BaseProvider], None],
@@ -27,6 +46,9 @@ def get_model_and_provider(model : Union[Model, str],
27
46
ignored : List[str] = None,
28
47
ignore_working: bool = False,
29
48
ignore_stream: bool = False) -> tuple[Model, type[BaseProvider]]:
49
if debug.version_check:
50
check_pypi_version()
51
debug.version_check = False
30
52
31
53
if isinstance(model, str):
32
54
if model in ModelUtils.convert:
@@ -118,7 +140,4 @@ class Completion:
118
140
119
141
result = provider.create_completion(model.name, [{"role": "user", "content": prompt}], stream, **kwargs)
120
142
121
return result if stream else ''.join(result)
122
123
if version_check:
124
check_pypi_version()
143
return result if stream else ''.join(result)
@@ -1 +1,2 @@
1
logging = False
1
logging = False
2
version_check = True
@@ -211,6 +211,9 @@ body {
211
211
.convo-title {
212
212
color: var(--colour-3);
213
213
font-size: 14px;
214
text-overflow: ellipsis;
215
overflow: hidden;
216
white-space: nowrap;
214
217
}
215
218
216
219
.message {
@@ -88,6 +88,10 @@
88
88
<span class="convo-title">github ~ <a href="https://github.com/xtekky/gpt4free">@gpt4free</a>
89
89
</span>
90
90
</div>
91
<div class="info">
92
<i class="fa-solid fa-star"></i>
93
<span id="version_text" class="convo-title"></span>
94
</div>
91
95
</div>
92
96
</div>
93
97
<div class="conversation">