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

XFEstudio/gpt4free

perf(gui): cache provider metadata and precompiled template in website server

4c633be1
Anand Mall <anand@example.com>
提交于

代码差异

1 个文件 +85 -74
Modified g4f/gui/server/website.py +85 -74
@@ -4,6 +4,8 @@ import asyncio
4 4 import os
5 5 import inspect
6 6 import requests
7 import re
8 import time
7 9 from datetime import datetime
8 10 from urllib.parse import quote, unquote
9 11 from flask import send_from_directory, redirect, request
@@ -15,6 +17,12 @@ from ...config import STATIC_URL, DOWNLOAD_URL, DIST_DIR, GITHUB_URL
15 17 from ... import version
16 18
17 19 _gui_session = requests.Session()
20 _CONTENT_PATTERN = re.compile(r"<!-- CONTENT_START -->.*?<!-- CONTENT_END -->", re.DOTALL)
21 _providers_cache: list[dict] | None = None
22 _providers_cache_time: float = 0.0
23 _providers_cards_cache: str | None = None
24 _PROVIDERS_TTL: float = 300.0
25 _template_cache: dict[str, str] = {}
18 26
19 27
20 28 def redirect_home():
@@ -173,7 +181,12 @@ class Website:
173 181 return render("stats")
174 182
175 183 def _get_providers(self):
176 """Load all providers and return a list of dicts with their attributes."""
184 """Load all providers and return a list of dicts with their attributes (cached with 300s TTL)."""
185 global _providers_cache, _providers_cache_time
186 now = time.time()
187 if _providers_cache is not None and (now - _providers_cache_time) < _PROVIDERS_TTL:
188 return _providers_cache
189
177 190 from g4f.Provider import ProviderLoader
178 191
179 192 providers = []
@@ -206,65 +219,66 @@ class Website:
206 219 })
207 220 except Exception:
208 221 pass
222 _providers_cache = providers
223 _providers_cache_time = now
209 224 return providers
210 225
211 226 def _providers(self):
227 global _providers_cards_cache
212 228 providers = self._get_providers()
213 229
214 # Build HTML cards
215 cards_html = """
216 <div class="page-header">
217 <h1>Available Providers</h1>
218 <p>Browse the list of AI providers supported by G4F</p>
219 </div>
230 template_path = os.path.join(os.path.dirname(__file__), "providers.html")
231 if not os.path.exists(template_path):
232 return "Providers template not found"
220 233
221 <div class="providers-list">
222 """
223 for p in providers:
224 models_html = ""
225 if p["models"]:
226 models_list = ", ".join(p["models"][:5]) if isinstance(p["models"], list) else ""
227 if len(p["models"]) > 5:
228 models_list += f" (+{len(p['models']) - 5} more)"
229 models_html = f"<div class='provider-details'><strong>Models:</strong> {models_list}</div>"
230 else:
231 models_html = "<div class='provider-details'><em>No specific models</em></div>"
232
233 url_html = f"<div class='provider-url'>{p['url']}</div>" if p["url"] else ""
234 auth_html = "<div class='provider-details'><strong>Auth:</strong> Required</div>" if p["needs_auth"] else ""
235 working_html = "<div class='provider-details'><strong>Status:</strong> Working</div>" if p["working"] else ""
236
237 cards_html += f"""
238 <div class="provider-card" onclick="window.location.href='/providers/{p['name']}'">
239 <div class="provider-name">{p['name']}</div>
240 {url_html}
241 {models_html}
242 {auth_html}
243 {working_html}
244 <div class="provider-actions">
245 <a href="/providers/{p['name']}" class="btn btn-primary">Details</a>
246 <a href="{p['url']}" target="_blank" class="btn btn-secondary">Website</a>
247 </div>
234 if template_path not in _template_cache:
235 with open(template_path, "r", encoding="utf-8") as f:
236 _template_cache[template_path] = f.read()
237 html = _template_cache[template_path]
238
239 if _providers_cards_cache is None or (time.time() - _providers_cache_time) >= _PROVIDERS_TTL:
240 # Build HTML cards
241 cards_html = """
242 <div class="page-header">
243 <h1>Available Providers</h1>
244 <p>Browse the list of AI providers supported by G4F</p>
248 245 </div>
249 """
250 cards_html += "\n </div>"
251 246
252 # Read the template
253 template_path = os.path.join(os.path.dirname(__file__), "providers.html")
254 if os.path.exists(template_path):
255 with open(template_path, "r", encoding="utf-8") as f:
256 html = f.read()
257 # Replace content between markers
258 import re
259 html = re.sub(
260 r"<!-- CONTENT_START -->.*?<!-- CONTENT_END -->",
261 f"<!-- CONTENT_START -->{cards_html}<!-- CONTENT_END -->",
262 html,
263 flags=re.DOTALL,
264 )
265 return html
247 <div class="providers-list">
248 """
249 for p in providers:
250 models_html = ""
251 if p["models"]:
252 models_list = ", ".join(p["models"][:5]) if isinstance(p["models"], list) else ""
253 if len(p["models"]) > 5:
254 models_list += f" (+{len(p['models']) - 5} more)"
255 models_html = f"<div class='provider-details'><strong>Models:</strong> {models_list}</div>"
256 else:
257 models_html = "<div class='provider-details'><em>No specific models</em></div>"
258
259 url_html = f"<div class='provider-url'>{p['url']}</div>" if p["url"] else ""
260 auth_html = "<div class='provider-details'><strong>Auth:</strong> Required</div>" if p["needs_auth"] else ""
261 working_html = "<div class='provider-details'><strong>Status:</strong> Working</div>" if p["working"] else ""
262
263 cards_html += f"""
264 <div class="provider-card" onclick="window.location.href='/providers/{p['name']}'">
265 <div class="provider-name">{p['name']}</div>
266 {url_html}
267 {models_html}
268 {auth_html}
269 {working_html}
270 <div class="provider-actions">
271 <a href="/providers/{p['name']}" class="btn btn-primary">Details</a>
272 <a href="{p['url']}" target="_blank" class="btn btn-secondary">Website</a>
273 </div>
274 </div>
275 """
276 cards_html += "\n </div>"
277 _providers_cards_cache = cards_html
266 278 else:
267 return "Providers template not found"
279 cards_html = _providers_cards_cache
280
281 return _CONTENT_PATTERN.sub(f"<!-- CONTENT_START -->{cards_html}<!-- CONTENT_END -->", html)
268 282
269 283 def _provider_detail(self, name: str = ""):
270 284 from html import escape
@@ -288,15 +302,16 @@ class Website:
288 302
289 303 # Build models list HTML
290 304 if p["models"]:
291 if callable(p["models"]):
305 models = p["models"]
306 if callable(models):
292 307 try:
293 p["models"] = p["models"]()
308 models = models()
294 309 except Exception:
295 p["models"] = []
296 if inspect.isawaitable(p["models"]):
297 p["models"] = asyncio.run(p["models"])
310 models = []
311 if inspect.isawaitable(models):
312 models = []
298 313 models_html = "<ul class='model-list'>" + "".join(
299 f"<li>{escape(str(m))}</li>" for m in p["models"]
314 f"<li>{escape(str(m))}</li>" for m in (models if isinstance(models, list) else list(models) if models else [])
300 315 ) + "</ul>"
301 316 else:
302 317 models_html = "<p><em>No specific models listed</em></p>"
@@ -439,25 +454,21 @@ class Website:
439 454
440 455 # Read the template and inject detail content
441 456 template_path = os.path.join(os.path.dirname(__file__), "providers.html")
442 if os.path.exists(template_path):
443 with open(template_path, "r", encoding="utf-8") as f:
444 html = f.read()
445 # Replace content between markers
446 import re
447 html = re.sub(
448 r"<!-- CONTENT_START -->.*?<!-- CONTENT_END -->",
449 f"<!-- CONTENT_START -->{detail_html}<!-- CONTENT_END -->",
450 html,
451 flags=re.DOTALL,
452 )
453 html = html.replace(
454 "<title>Providers</title>",
455 f"<title>{escape(p['name'])} – Provider Details</title>"
456 )
457 return html
458 else:
457 if not os.path.exists(template_path):
459 458 return "Providers template not found"
460 459
460 if template_path not in _template_cache:
461 with open(template_path, "r", encoding="utf-8") as f:
462 _template_cache[template_path] = f.read()
463 html = _template_cache[template_path]
464
465 html = _CONTENT_PATTERN.sub(f"<!-- CONTENT_START -->{detail_html}<!-- CONTENT_END -->", html)
466 html = html.replace(
467 "<title>Providers</title>",
468 f"<title>{escape(p['name'])} – Provider Details</title>"
469 )
470 return html
471
461 472 def _chat(self, filename=""):
462 473 filename = f"chat/{filename}" if filename else "chat/index"
463 474 return render(filename)