fix: keep Gradio 4 compatible with Starlette and containers - #200
Merged
Conversation
## 背景
FunClip 在以下环境中启动后访问页面报 500 错误:
| 依赖 | 版本 |
|------|------|
| gradio | 4.44.1 |
| starlette | 1.3.1 |
| fastapi | 0.141.1 |
| jinja2 | 3.1.6 |
## 问题
### 问题 1:`TypeError: unhashable type: 'dict'`
Jinja2 的 LRUCache 在缓存模板时,cache key 因 Starlette/Jinja2 版本矩阵
不兼容而变为不可哈希的 dict,导致模板渲染阶段直接崩溃。
### 问题 2:`AttributeError: 'dict' object has no attribute 'split'`(核心问题)
Starlette >= 1.0 破坏性变更了 `Jinja2Templates.TemplateResponse` 的签名:
- 旧签名:`TemplateResponse(name, context, ...)`
- 新签名:`TemplateResponse(request, name, context, ...)`
Gradio 4.44.x 仍按旧签名调用,导致 context dict 被当作模板名传入
`split("/")`,触发 AttributeError。
### 问题 3:`ValueError: When localhost is not accessible`
容器/无头环境中 Gradio 的 localhost 自检(HTTP HEAD)失败,直接抛异常
阻止启动。
## 修复
所有修复集中在 `funclip/launch.py`,不改动第三方库源码:
1. **禁用 Jinja2 模板缓存**:`templates.env.cache = None`,
规避不可哈希 key 问题。
2. **猴子补丁 TemplateResponse**:通过首参类型自动判定新旧签名,
对旧式 `(name, context)` 调用做参数适配后转发给新版 Starlette,
实现 backward-compatible。
3. **启动容错**:传入 `_frontend=False` 跳过 localhost 自检;
增加 `ValueError` 捕获,检测失败时自动降级为 `share=True`。
## 测试验证
| 路径 | 状态码 | 说明 |
|------|--------|------|
| `/` | 200 | 81455 bytes HTML,含 `gradio_config` |
| `/info` | 200 | API 元数据正常 |
| `/config` | 200 | UI 配置正常 |
启动命令:`python funclip/launch.py -p 12235 --listen`
Contributor
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Signed-off-by: zhifu gao <zhifu.gzf@alibaba-inc.com>
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
starlette<1.0;--listenmode;--sharechoice instead of automatically creating a public tunnel;Root cause
Gradio 4.44.1 still calls
Jinja2Templates.TemplateResponse(name, context). Starlette 1.x requiresTemplateResponse(request, name, context), so the same signature mismatch can surface as eitherTypeError: unhashable type: 'dict'orAttributeError: 'dict' object has no attribute 'split'.This is resolved at dependency resolution time rather than by globally monkey-patching Gradio/Starlette or disabling Jinja's template cache.
User impact
Existing FunClip installations using the supported Gradio 4 range render the web UI again after reinstalling/upgrading
requirements.txt. Container users can explicitly pass--listenwithout the internal localhost probe preventing startup. FunClip never turns on Gradio's public sharing tunnel unless the user passes--share.Validation
5 failed;6 passed;67 passed, 1 skipped(the skip is the live TwelveLabs test requiringTWELVELABS_API_KEY);gradio_configfor both supported endpoints:pip check, Ruff for new files, workflow YAML parsing,py_compile, andgit diff --checkpass.Notes for reviewers
The only private Gradio argument used is
_frontend=False, scoped to explicit--listenmode. In Gradio 4.31.3 and 4.44.1 it only bypasses the localhost reachability probe; binding and public sharing remain controlled byserver_nameand the explicit--shareflag.