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

XFEstudio/gpt4free

Update pa providers download, Add LLM7 provider

a6491d7c
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

3 个文件 +94 -15
Modified g4f/Provider/__init__.py +11 -0
@@ -242,6 +242,17 @@ def _resolve_provider(name: str) -> ProviderType:
242 242 _loaded_providers[name].active_by_default = True
243 243 _loaded_providers[name].default_model = "kilo-auto/free"
244 244 return _loaded_providers[name]
245 elif name == "LLM7":
246 from ..client.factory import AbstractClientFactory
247 _loaded_providers[name] = AbstractClientFactory.create_provider(
248 None, "https://api.llm7.io/v1"
249 )
250 _loaded_providers[name].__name__ = name
251 _loaded_providers[name].active_by_default = True
252 _loaded_providers[name].default_model = "default"
253 _loaded_providers[name].models = ["default"]
254 _loaded_providers[name].add_user = False
255 return _loaded_providers[name]
245 256 elif name == "Ollama":
246 257 from g4f.Provider.local.Ollama import Ollama
247 258
Modified g4f/Provider/template/OpenaiTemplate.py +5 -2
@@ -76,6 +76,7 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
76 76 def is_provider_api_key(cls, api_key: str) -> bool:
77 77 return (
78 78 api_key
79 and isinstance(api_key, str)
79 80 and not api_key.startswith("g4f_")
80 81 and not api_key.startswith("gfs_")
81 82 )
@@ -101,10 +102,11 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
101 102 base_url = cls.base_url
102 103 else:
103 104 if cls.backup_url is None:
104 api_key = None
105 105 base_url = cls.base_url
106 106 else:
107 107 base_url = cls.backup_url
108 if not base_url.startswith(SPACE_URL):
109 api_key = None
108 110 if base_url is None:
109 111 raise NotImplementedError(
110 112 "No base_url or backup_url specified."
@@ -237,10 +239,11 @@ class OpenaiTemplate(AsyncGeneratorProvider, ProviderModelMixin, RaiseErrorMixin
237 239 base_url = cls.base_url
238 240 else:
239 241 if cls.backup_url is None:
240 api_key = None
241 242 base_url = cls.base_url
242 243 else:
243 244 base_url = cls.backup_url
245 if not base_url.startswith(SPACE_URL):
246 api_key = None
244 247 if base_url is None:
245 248 raise NotImplementedError(
246 249 "No base_url or backup_url specified."
Modified g4f/mcp/pa_downloader.py +78 -13
@@ -24,6 +24,7 @@ from __future__ import annotations
24 24 import os
25 25 import json
26 26 import time
27 from concurrent.futures import ThreadPoolExecutor
27 28 from pathlib import Path
28 29 from typing import List, Optional
29 30 from urllib.request import Request, urlopen
@@ -49,11 +50,16 @@ GITHUB_API = "https://api.github.com"
49 50 #: Per-request timeout (seconds) for GitHub API calls and raw downloads.
50 51 DEFAULT_TIMEOUT: float = 30.0
51 52
53 # Limit concurrent requests while keeping bulk downloads substantially faster.
54 DOWNLOAD_WORKERS = 8
55
52 56 #: Marker file written into the workspace after a successful auto-download.
53 57 #: Its mtime is used to decide when the next auto-download is allowed, so we
54 58 #: do not hit GitHub on every single server start.
55 59 AUTO_DOWNLOAD_MARKER = ".pa_auto_downloaded"
56 60
61 DELETED_FILE = ".deleted"
62
57 63 #: Minimum seconds between two automatic downloads.
58 64 AUTO_DOWNLOAD_INTERVAL: float = 6 * 60 * 60 # 6 hours
59 65
@@ -97,6 +103,10 @@ def _is_pa_file(name: str) -> bool:
97 103 Accepted: ``*.py``, ``*.wasm``, plus browser scripts named ``pa-*.js``
98 104 or ``*.pa.js``.
99 105 """
106 if name == DELETED_FILE:
107 return True
108 if name.startswith("test_"):
109 return False
100 110 if name.endswith(".py") or name.endswith(".wasm"):
101 111 return True
102 112 if name.endswith(".js"):
@@ -142,6 +152,42 @@ def _workspace_target(directory: Optional[str] = None) -> Path:
142 152 return target
143 153
144 154
155 def _read_deleted_manifest(target: Path) -> bytes:
156 """Return the local deletion manifest, or empty bytes if absent."""
157 try:
158 return (target / DELETED_FILE).read_bytes()
159 except OSError:
160 return b""
161
162
163 def _remove_deleted_files(target: Path, content: bytes) -> None:
164 """Remove files named one-per-line in a deletion manifest."""
165 try:
166 names = content.decode("utf-8").splitlines()
167 except UnicodeDecodeError as e:
168 debug.error("pa-providers: invalid .deleted manifest:", e)
169 return
170
171 root = target.resolve()
172 for name in names:
173 name = name.strip()
174 if not name or name.startswith("#"):
175 continue
176 candidate = (target / name).resolve()
177 try:
178 candidate.relative_to(root)
179 except ValueError:
180 debug.error(f"pa-providers: refusing to delete outside workspace: {name}")
181 continue
182 if candidate == target / DELETED_FILE or not candidate.is_file():
183 continue
184 try:
185 candidate.unlink()
186 print(f"pa-providers: removed deleted file {name}")
187 except OSError as e:
188 debug.error(f"pa-providers: failed to remove deleted file {name}:", e)
189
190
145 191 # ---------------------------------------------------------------------------
146 192 # Public API
147 193 # ---------------------------------------------------------------------------
@@ -171,6 +217,7 @@ def run_pa_download(
171 217 """
172 218 target = _workspace_target(directory)
173 219 written: List[Path] = []
220 deleted_manifest = _read_deleted_manifest(target)
174 221
175 222 try:
176 223 if only:
@@ -182,6 +229,7 @@ def run_pa_download(
182 229 debug.error(f"pa-providers: failed to list repository {repo}@{ref}:", e)
183 230 return written
184 231
232 pending = []
185 233 for name in names:
186 234 if not _is_pa_file(name):
187 235 continue
@@ -189,19 +237,36 @@ def run_pa_download(
189 237 if dest.exists() and not force:
190 238 debug.log(f"pa-providers: skip existing {name}")
191 239 continue
192 try:
193 content = _download_raw(repo, ref, name, timeout)
194 except (URLError, HTTPError, OSError) as e:
195 debug.error(f"pa-providers: failed to download {name}:", e)
196 continue
197 try:
198 dest.write_bytes(content)
199 written.append(dest)
200 print(f"pa-providers: downloaded {name} ({len(content)} bytes)")
201 except OSError as e:
202 debug.error(f"pa-providers: failed to write {name}:", e)
203
204 print(f"pa-providers: downloaded {len(written)} file(s) from {repo}@{ref}")
240 pending.append((name, dest))
241
242 total_size = 0
243
244 # Network requests run concurrently; handling results in submission order
245 # keeps output and the returned list stable for callers.
246 with ThreadPoolExecutor(max_workers=DOWNLOAD_WORKERS) as executor:
247 downloads = {
248 name: executor.submit(_download_raw, repo, ref, name, timeout)
249 for name, _ in pending
250 }
251 for name, dest in pending:
252 try:
253 content = downloads[name].result()
254 except (URLError, HTTPError, OSError) as e:
255 debug.error(f"pa-providers: failed to download {name}:", e)
256 continue
257 if name == DELETED_FILE:
258 deleted_manifest = content
259 continue
260 try:
261 dest.write_bytes(content)
262 written.append(dest)
263 total_size += len(content)
264 except OSError as e:
265 debug.error(f"pa-providers: failed to write {name}:", e)
266
267 _remove_deleted_files(target, deleted_manifest)
268
269 print(f"pa-providers: downloaded {len(written)} file(s) ({total_size/1e3} kb) from {repo}@{ref}")
205 270 if written:
206 271 # Touch the auto-download marker so the startup path does not re-download
207 272 # immediately after an explicit `g4f pa download`.