XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

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
H Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

19 个文件 +360 -136
Modified .github/workflows/publish-workflow.yaml +14 -3
@@ -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 }}
Modified README.md +4 -4
@@ -1,4 +1,4 @@
1 ![g4f](g4f.png)
1 ![248433934-7886223b-c1d1-4260-82aa-da5741f303bb](https://github.com/xtekky/gpt4free/assets/98614666/ea012c87-76e0-496a-8ac4-e2de090cc6c9)
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 >> [![PyPI version](https://badge.fury.io/py/g4f.svg)](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
Modified docker-compose.yml +3 -3
@@ -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'
Modified docker/Dockerfile +3 -1
@@ -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
Renamed docker/background.png +0 -0
二进制文件已变更,无法进行逐行预览。
Modified docker/supervisor.conf +1 -1
@@ -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
Modified g4f/Provider/MyShell.py +5 -13
@@ -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));
Added g4f/Provider/unfinished/AiChatting.py +66 -0
@@ -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
Modified g4f/Provider/unfinished/__init__.py +2 -1
@@ -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
Modified g4f/__init__.py +38 -19
@@ -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)
Modified g4f/debug.py +2 -1
@@ -1 +1,2 @@
1 logging = False
1 logging = False
2 version_check = True
Modified g4f/gui/client/css/style.css +3 -0
@@ -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 {
Modified g4f/gui/client/html/index.html +4 -0
@@ -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">
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