网上很多方案都是直接更换采用gradio-offline
的包。但这个包很久不更新了并且是直接修改源码,所以自己打包也比较麻烦。因此这里提供了一种非侵入式的方法,动态替换部分资源的使用并重定向到本地静态资源,根据需要自己下载资源到本地就可以了。
本方案在gradio 5.34.0上测试通过。理论上兼容一个大版本应该没问题,如果有其他需求可以自己改一下。
使用方法
- 把
gr_offline.py
放到你的项目中 - 导入补丁并在使用gradio之前调用
patch
函数 - 下载离线的静态资源到
./static
中
使用样例
import gr_offline
import gradio as gr
# 必须在使用gradio前调用一次
gr_offline.patch()
# 这个自己根据需要修改
gr.set_static_paths("./static")
def greet(name, intensity):
return "Hello, " + name + "!" * int(intensity)
demo = gr.Interface(
fn=greet,
inputs=["text", "slider"],
outputs=["text"],
)
demo.launch()
资源替换
-
CDN
旧:https://cdnjs.cloudflare.com/{}
新:./static/{}
-
Google Font
旧:https://fonts.googleapis.com/css2?family={file_name}:wght@{weight}&display=swap
新:./static/fonts/{file_name}/{file_name}-{weight}.woff2
原始资源下载链接
https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js
https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600&display=swap
gr_offline.py
def _patch_env() -> None:
import os
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
def _patch_font() -> None:
from gradio.themes.utils.fonts import GoogleFont, LocalFont
GoogleFont.__init__ = LocalFont.__init__ # type: ignore
GoogleFont.stylesheet = LocalFont.stylesheet # type: ignore
def _patch_templates() -> None:
import re
import types
import jinja2
from gradio import routes
from fastapi.templating import Jinja2Templates
remove_regex: list[re.Pattern] = [
re.compile(
r'<meta\b[^>]*?property=["']og:[^"'>]*["'][^>]*?>',
flags=re.IGNORECASE | re.DOTALL,
),
re.compile(
r'<meta\b[^>]*?name=["']twitter:[^"'>]*["'][^>]*?>',
flags=re.IGNORECASE | re.DOTALL,
),
re.compile(
r'<link\b[^>]*?href=["']?[^"'>]*fonts.googleapis.com[^"'>]*["']?[^>]*?>',
flags=re.IGNORECASE | re.DOTALL,
),
re.compile(
r'<link\b[^>]*?href=["']?[^"'>]*fonts.gstatic.com[^"'>]*["']?[^>]*?>',
flags=re.IGNORECASE | re.DOTALL,
),
]
cdn_regex: list[re.Pattern] = [re.compile(r"https?://cdnjs.cloudflare.com/.*?")]
def _do_patch(html: str) -> str:
for pattern in remove_regex:
html = re.sub(pattern, "", html)
for pattern in cdn_regex:
html = re.sub(pattern, "static/", html)
return html
def _patched_render(self: jinja2.Template, *args, **kwargs) -> str:
html = jinja2.Template.render(self, *args, **kwargs)
return _do_patch(html)
async def _patched_render_async(self: jinja2.Template, *args, **kwargs) -> str:
html = await jinja2.Template.render_async(self, *args, **kwargs)
return _do_patch(html)
class PatchedJinja2Templates(Jinja2Templates):
def get_template(self, name: str) -> jinja2.Template:
template: jinja2.Template = super().get_template(name)
template.render = types.MethodType(_patched_render, template)
template.render_async = types.MethodType(_patched_render_async, template)
return template
routes.templates = PatchedJinja2Templates(directory=routes.STATIC_TEMPLATE_LIB)
routes.templates.env.filters["toorjson"] = routes.toorjson
def patch() -> None:
_patch_env()
_patch_font()
_patch_templates()
Github:Gist